Problem
A code-review pass over the shared pkg/ module and the GCP provider surfaced
several 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/GetAllProviders call the factory while
holding 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 that
under r.mu.RLock() blocks every other registry reader (and any writer, e.g.
Unregister) for the duration of an arbitrary user-supplied callback that
performs network calls. GetAllProviders additionally 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.GetCredentials issues a live GetProject RPC
(providers/gcp/provider.go:270-293).
GetCredentials gates on IsConfigured(), which constructs a
resourcemanager client and performs a GetProject round-trip purely to
report the credential source. DetectAvailableProviders already calls
IsConfigured() + ValidateCredentials(), so a follow-on GetCredentials()
triggers a third GetProject. Credential introspection (which source) is
conflated with validation (do they work).
Fix: report the source from env/ADC inspection without a network call.
Low / Nit
-
10-L5 - pkg/logging level read/write data race
(pkg/logging/logger.go). defaultLogger.level is read in every
Debug/Info/... and written by SetLevel/SetLevelValue with no
synchronization -> a real -race data race if SetLevel is called after
goroutines launch (the concurrent fan-out logs from many goroutines).
Fix: store the level in an atomic.Int32.
-
10-L6 - MaskToken leaks 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.Is matches 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 Is method.
-
06-N2 - RedactedDSN duplicates the DSN format string
(internal/database/config.go:171). The redacted variant copies the host=... port=... user=... format from DSN; a future field change must be made in two
places. 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 -race and the MaskToken
short-input case).
Files
pkg/provider/registry.go
providers/gcp/provider.go
pkg/logging/logger.go
pkg/common/tokens.go
pkg/errors/errors.go
internal/database/config.go
Findings
10-H3, 10-H4, 10-L5, 10-L6, 10-N4, 06-N2.
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.