Repository navigation
fix(insurance): keep the API key out of every field fmt can print - #331
Merged
Merged
Conversation
A *Client in an unexported struct field printed the key under %s and %q, and a Client or Config held by value leaked under every verb, because fmt never calls Format on unexported fields. Client now keeps the key only inside setAuth and redact closures and the org ID as a plain identifier. Client.Format is removed as redundant; Config.Format stays. Closes #325 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
|
Warning Review limit reached
This review includes 2 billable files and costs up to $0.50.
Reviews can continue after your included limit without a manual trigger. An admin must approve usage-based billing. Or wait 53 minutes for your next included review. View limit details
Comment |
Member
Author
|
Gate review (security: credential redaction) at 84a9a5c: content verdict CLEAN, no blocking findings.
|
Member
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #325. Follow-up for the remaining
Config.APIKeyexposure: #330.Cause
fmtdoes not callFormaton unexported struct fields, and for%s/%qit dereferences a*Clientand prints every field, includingcfg.APIKey. AClientorConfigheld by value in an unexported field printed the key under every verb.Change
Clientno longer stores aConfigor any string containing the key: it keepsbaseURL,orgID(a UUID identifier),hc, and two closures (setAuthwritesx-api-keyper request;redactmasks an echoed key in vendor messages, no-op on an empty key).Client.Formatis removed as redundant (deletion probe:TestConfigAndClient_NeverFormatTheKeypasses without it).Config.Formatstays; its doc now says a caller-heldConfigin an unexported field still prints raw (#330).NewClientstill copies the caller'shttp.Client(noRedirect := *hc) and adds no headers to it; onlysetAuthwrites the header, per request. Public API unchanged. Hex/quoted echoes of the key in vendor messages stay out of scope, as before.Pre-fix control (56db459 client.go + the new test): 48 failing subtests, including
TestClientKeyNeverPrintedWherever/unexported_*Client/%sand/%q(the issue's reproducer;&unexported_*Client/%sand/%qtoo).../unexported_Client_value/{Sprint,Sprintln,%v,%+v,%#v,%s,%q,%x,...}TestClientHoldsNoStringContainingKey(reflection walk findsClient*.cfg.APIKey)After the change all pass.
Evidence (offline)
[]any, wrapped error) xSprint Sprintln %v %+v %#v %s %q %x %X %d %T %p, forbidding the key, its hex, base64 and quoted forms; plusjson.Marshal.Client(unexported included) asserts no string or byte slice contains the key, independent of fmt behavior.Clientfield fails 56 subtests including the walk;redactreturning its input failsTestClient_ErrorMessageIsSanitized. A package-level variable holding the key is not reachable from anyClientvalue, so it is not a printable path and noClienttest can see it (not claimed). Dropping the empty-key guard inredactis unreachable (NewClientrejects a blank key) and survives; kept as a no-op guard on request of the review.go vet,golangci-lint,go test ./...in pkg pass.Consumers
Nothing outside
pkg/insuranceusesClientfields (rg over platform, cli, mcp and their worktrees: onlyNewClient/*insurance.Client). After merge, platform, cli and mcp each bump their pkg pin; they can then drop theatomic.Pointerand own-Formatworkarounds in a later cleanup. Until then keep the client in locals oratomic.Pointer.🤖 Generated with Claude Code