Skip to content

fix: stop error text being read as a format string - #1280

Merged
AlexKantor87 merged 2 commits into
mainfrom
fix/logger-error-format-string
Oct 21, 2026
Merged

AlexKantor87 merged 2 commits into
mainfrom
fix/logger-error-format-string

Conversation

@AlexKantor87

Copy link
Copy Markdown
Contributor

Fixes #1279

What was wrong

The logger's Error, Warn, Info and Debug treat their first argument as a format string. main.go passed the error text there, so any % in an error was garbled. A URL-encoded slash (%2F) printed as %!F(MISSING).

Why vet missed it

go vet rejects a format string that isn't a constant. It only does this for functions it knows are printf-style. Each logger method changed format before using it, so vet couldn't tell.

Fix

  • Logger: each method now calls fmt.Sprintf(format, v...) directly. Output is the same for every well-formed call. Vet, and golangci-lint in CI, now check every logger call.
  • Call sites: fixed all 18 that vet then flagged. Message text is now always an argument, as in logger.Error("%s", err.Error()).
  • Azure debug: three lines passed values with no %s, so they printed %!(EXTRA ...). Fixed too.

fmt.Errorf, fmt.Printf and log.Printf already had vet coverage, with no findings.

Test

TestMainErrorKeepsPercentEncoding runs main() in a child process, because logger.Error exits the process. It passes --short=feature%2Fx to kosli version and checks the error keeps %2F.

  • Red against the old line (with -vet=off): invalid argument "feature%!F(MISSING)x".
  • Green with the fix.
  • Putting the old line back also fails go vet, go test and golangci-lint.

Full suite run locally against a local server: 3637 tests, all green.

🤖 Generated with Claude Code

The logger's Error, Warn, Info and Debug treat their first argument
as a format string. Passing message text there garbled any % in it,
so a URL-encoded slash (%2F) printed as %!F(MISSING).

Each logger method now calls fmt.Sprintf(format, v...) directly. That
lets go vet, and golangci-lint in CI, see them as printf-style and
reject a format that isn't a constant. Fixed the 18 call sites it
found, plus three Azure debug lines that passed values with no %s.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added fix go Pull requests that update go code and removed fix labels Oct 21, 2026
@claude

claude Bot commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Claude finished @AlexKantor87's task in 27s —— View job


Follow-up review complete

Reviewed 9eafae51..69a1150f (the two new commits: test now derives the child path from os.Executable() and uses require.ErrorAs).

  • Fetch existing review comments and prior findings
  • Diff BEFORE..AFTER commits
  • Assess status of each prior finding
  • Check for new bugs/security issues in changed lines
  • Post inline comments for new issues (none needed)
  • Post summary comment

Comment thread cmd/kosli/main_test.go Fixed
Comment thread cmd/kosli/main_test.go Resolved
Snyk Code treats os.Args as untrusted input reaching exec.Command.
os.Executable gives the same test binary without that path.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@AlexKantor87

Copy link
Copy Markdown
Contributor Author

On the suggestion to add a logger unit test: declined. A test like l.Info("%s", "a%2Fb") passes against the old logger too. The old logger only garbled text when the text itself was the format string, and vet now refuses that at build time. So the test could never go red.

no search: this reply changes no code
no mutation: this reply adds no test

🤖 Addressed by Claude Code

@github-actions github-actions Bot added the fix label Oct 21, 2026
@claude

claude Bot commented Oct 21, 2026

Copy link
Copy Markdown
Contributor

Follow-up review of latest commits (9eafae51..69a1150f)

Prior findings — status:

  1. github-advanced-security bot (command injection via exec.Command(os.Args[0], ...)): Resolved. The child process path is now obtained from os.Executable() instead of os.Args[0], so no CLI-supplied input reaches exec.Command — the child is always this test binary with a fixed -test.run argument.
  2. claude bot nit (use require.ErrorAs instead of require.True(errors.As(...))): Resolved. Switched to require.ErrorAs, and the now-unused errors import was dropped.

New issues in the changed lines: none found. The err reuse (self, err := os.Executable() then err = cmd.Run()) and the require.ErrorAs call are both correct.

No new inline comments posted.

@AlexKantor87
AlexKantor87 merged commit 2df2405 into main Oct 21, 2026
32 of 37 checks passed
@AlexKantor87
AlexKantor87 deleted the fix/logger-error-format-string branch October 21, 2026 09:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fix go Pull requests that update go code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Error messages with % in them print garbled (%2F shows as %!F(MISSING))

3 participants