Repository navigation
fix(pkg,gcp): logging level race, MaskToken short-input leak, registry-lock I/O, GetCredentials RPC #1054
Description
Activity
- addedtriagedItem has been triagedItem has been triagedpriority/p1Next up; this sprintNext up; this sprintseverity/highSignificant harmSignificant harmurgency/this-sprintWithin the current sprintWithin the current sprintimpact/internalTeam-internal onlyTeam-internal onlyeffort/mDaysDaystype/bugDefectDefectpr-createdA PR has been opened for this issue (dedup guard for the auto-PR loop)A PR has been opened for this issue (dedup guard for the auto-PR loop)pr-mergedThe PR for this issue has been mergedThe PR for this issue has been merged
on Jun 7, 2026 Verification sweep against
main(101f099fb) on 2026-07-27 finds this already resolved.
All six items are fixed: atomic logging level, registry lock, GetCredentials without RPC, MaskToken short-input handling, errors doc, and DSN dedup.
Evidence: commit 43a009c (PR #1076).
Recommending close. Reopen if any of the six sub-items regressed.Already implemented on
main. Closing with evidence rather than scheduling work.Verified against
origin/main(ae1e632cb), spot-checking the findings this issue names:- Logging level race:
pkg/logging/logger.go:37storeslevel atomic.Int32, with the comment at :32 recording thatSetLevel/SetLevelValueare called at runtime concurrently with reads. MaskTokenshort-input leak:pkg/common/tokens.go:78returns(none)for empty and(redacted)forlen(token) <= 8, only truncating attoken[:8] + "..."above that. A short token can no longer be echoed whole.RedactedDSNdrift:internal/database/config.go:166isreturn c.dsn("*****"), deriving from the same builder as the real DSN rather than re-implementing the layout, so the two cannot diverge.TestRedactedDSN_SharesLayoutWithDSNpins exactly that.
The registry-lock finding (factories snapshotted outside the lock,
GetCredentialsdoing zero RPC) and theerrors.Isdocumentation are addressed in the same change,43a009c7e, which carried no closing trailer.If a residual axis remains that this does not cover, please reopen naming it specifically.
- Logging level race:
Problem
A code-review pass over the shared
pkg/module and the GCP provider surfacedseveral correctness bugs, two of them High severity, that none of the
in-flight PRs (#1012-#1035, #1036-#1049) touch. Grouping them here.
High
10-H4 -
Registry.GetProvider/GetAllProviderscall the factory whileholding the registry lock (
pkg/provider/registry.go:60-105).The GCP factory does multi-page network I/O (
getDefaultProject->Projects.List().Pages(...)) when no project ID is configured. Running thatunder
r.mu.RLock()blocks every other registry reader (and any writer, e.g.Unregister) for the duration of an arbitrary user-supplied callback thatperforms network calls.
GetAllProvidersadditionally serializes N providers'network init under one lock.
Fix: snapshot the factory (and name) under the lock, release it, then call the
factory outside the critical section.
10-H3 -
gcp.GetCredentialsissues a liveGetProjectRPC(
providers/gcp/provider.go:270-293).GetCredentialsgates onIsConfigured(), which constructs aresourcemanagerclient and performs aGetProjectround-trip purely toreport the credential source.
DetectAvailableProvidersalready callsIsConfigured()+ValidateCredentials(), so a follow-onGetCredentials()triggers a third
GetProject. Credential introspection (which source) isconflated with validation (do they work).
Fix: report the source from env/ADC inspection without a network call.
Low / Nit
10-L5 -
pkg/logginglevel read/write data race(
pkg/logging/logger.go).defaultLogger.levelis read in everyDebug/Info/...and written bySetLevel/SetLevelValuewith nosynchronization -> a real
-racedata race ifSetLevelis called aftergoroutines launch (the concurrent fan-out logs from many goroutines).
Fix: store the level in an
atomic.Int32.10-L6 -
MaskTokenleaks short inputs verbatim(
pkg/common/tokens.go). The function returns inputs of <=8 chars unchanged.Current callers only pass 64-char hex tokens, but the generic "return
unchanged" branch is a footgun for any future short secret.
Fix: redact short non-empty inputs to
(redacted)instead of echoing them.10-N4 -
errors.Ismatches purely on type(
pkg/errors/errors.go).errors.Is(specificNotFound, &NotFoundError{ID:"x"})returns true regardless of struct fields. This is the documented intent
(type-level sentinel matching), but the field-insensitivity is undocumented.
Fix: document the type-level matching contract on each
Ismethod.06-N2 -
RedactedDSNduplicates the DSN format string(
internal/database/config.go:171). The redacted variant copies thehost=... port=... user=...format fromDSN; a future field change must be made in twoplaces. Fix: derive the redacted form from a single source.
Fix
See per-finding fixes above. Each correctness fix gets a regression test
(notably the logging-level data race under
-raceand theMaskTokenshort-input case).
Files
pkg/provider/registry.goproviders/gcp/provider.gopkg/logging/logger.gopkg/common/tokens.gopkg/errors/errors.gointernal/database/config.goFindings
10-H3, 10-H4, 10-L5, 10-L6, 10-N4, 06-N2.