Repository navigation
fix(pkg,gcp): logging level race, MaskToken short-input leak, registry-lock I/O, GetCredentials RPC - #1076
Conversation
…ntials RPC Two High-severity correctness fixes in the shared provider layer. 10-H4: Registry.GetProvider/GetProviderWithConfig/GetAllProviders invoked the provider factory while holding r.mu. The GCP factory does multi-page network I/O (Projects.List walk) when no project ID is set, so a slow/hung call blocked every other registry reader and any writer (e.g. Unregister) for its duration, and GetAllProviders serialized N providers' network init under one lock. Now the factory (or a copy of the name->factory map) is snapshotted under the lock and invoked after releasing it. 10-H3: gcp.GetCredentials gated on IsConfigured(), which issues a live GetProject RPC purely to report the credential source. Credential introspection (which source) was conflated with validation (do they work), adding a redundant round-trip on top of DetectAvailableProviders' existing checks. GetCredentials now determines the source from local inspection only (GOOGLE_APPLICATION_- CREDENTIALS env var, the well-known gcloud ADC file, or a configured project for the metadata-server fallback) with no network call; ValidateCredentials remains the explicit validity check. Regression tests: - TestRegistry_FactoryRunsOutsideLock: a factory that takes the write lock would deadlock if the read lock were still held; guarded by a timeout so the pre-fix hang fails fast. - GetCredentials tests assert the reported source per scenario and that the projects client is never opened (no RPC).
…s matching 10-L5: pkg/logging stored the level as a plain int read by every Debug/Info/ Warn/Error call and written by SetLevel/SetLevelValue with no synchronization, a data race when the level is changed after worker goroutines launch (the concurrent fan-out logs from many goroutines). Store the level in an atomic.Int32 accessed via getLevel/setLevel. New TestSetLevel_NoDataRace exercises concurrent writers + readers and fails under -race pre-fix. 10-L6: MaskToken returned inputs of <=8 chars verbatim, so a short secret a future caller might pass would be logged whole. Short non-empty inputs are now fully redacted to "(redacted)". 10-N4: errors.Is on the package error types matches purely on dynamic type, ignoring the target's fields. Documented this type-level-sentinel contract on the package and each Is method, and added a test that locks the field- insensitive behaviour.
06-N2: RedactedDSN duplicated the host/port/user/.../connect_timeout format string from DSN, so a future field change had to be made in two places or the redacted log line would silently drift from the real connection string. Extract a private dsn(password) formatter that both DSN and RedactedDSN call (RedactedDSN passes "*****"). Add a test asserting RedactedDSN equals DSN with only the password swapped, guarding the two against future divergence.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughThis PR fixes six correctness issues: atomic logger-level storage and race test, registry lock release before provider factory calls, short-token masking tightened, GCP credential-source detection via local inspection (no RPC), error Is documentation clarified, and centralized DSN formatting with a redaction regression test. ChangesConcurrency, Security, & Documentation Fixes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
|
@coderabbitai review |
✅ Action performedReview finished.
|
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@providers/gcp/provider.go`:
- Around line 280-283: The detectCredentialSource method incorrectly treats an
empty GOOGLE_APPLICATION_CREDENTIALS as a file because it only uses
os.LookupEnv; change the check in detectCredentialSource to read the env value
and ensure it's non-empty (e.g., val :=
os.Getenv("GOOGLE_APPLICATION_CREDENTIALS"); if val != "" { return
provider.CredentialSourceFile, true }) so empty strings are ignored, keeping the
same non-empty style used for CLOUDSDK_CONFIG and APPDATA.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 3c4ded47-c9ed-423a-afb6-607305829a81
📒 Files selected for processing (12)
internal/database/config.gointernal/database/coverage_extra_test.gopkg/common/tokens.gopkg/common/tokens_test.gopkg/errors/errors.gopkg/errors/errors_test.gopkg/logging/logger.gopkg/logging/logger_test.gopkg/provider/registry.gopkg/provider/registry_test.goproviders/gcp/provider.goproviders/gcp/provider_test.go
os.LookupEnv returns ok=true when the variable is set to an empty string, causing detectCredentialSource to incorrectly report CredentialSourceFile even when no path is configured. Replace with os.Getenv(...) != "" so an empty value is treated identically to an unset variable, matching the behavior of CLOUDSDK_CONFIG and APPDATA. Adds a regression test (TestGCPProvider_GetCredentials_EmptyEnvVarNotFile) that fails on the pre-fix code and passes after.
CR finding addressedFinding (CodeRabbit, 2026-06-07): Empty Root cause: Fix: Replaced Regression test: Added Commit: c72807b @coderabbitai review |
|
🧠 Learnings used✅ Action performedReview finished.
|
Closes #1054
Groups six code-review findings in the shared
pkg/module and the GCP providerthat no in-flight PR touches, two of them High severity.
Findings fixed
Registry.GetProvider/GetProviderWithConfig/GetAllProviderssnapshot the factory underr.muand invoke it after releasing the lock, so the GCP factory's network I/O no longer blocks every registry reader/writer.gcp.GetCredentialsreports the credential source from local inspection only (env var / well-known gcloud ADC file / configured project) with noGetProjectRPC;ValidateCredentialsstays the explicit validity check.pkg/logginglevel is now anatomic.Int32, fixing the data race betweenSetLevel/SetLevelValueand the per-call level reads under the concurrent fan-out.MaskTokenfully redacts short (<=8 char) inputs to(redacted)instead of echoing them verbatim.errors.Ismatching contract on the package and eachIsmethod.RedactedDSNderives from a singledsn()formatter shared withDSN, so the two can't drift.Regression tests
TestRegistry_FactoryRunsOutsideLock(provider) — a factory that takes thewrite lock would deadlock if the read lock were still held; a 5s timeout makes
the pre-fix hang fail fast. Covers all three registry methods.
TestSetLevel_NoDataRace(logging) — concurrent writers + readers; fails under-raceon the pre-fix plain-int field.TestMaskToken_EmptyAndShortupdated to assert short inputs are fully redacted.GetCredentialstests assert the reported source per scenario and that theprojects client is never opened (no RPC).
Is is field-insensitivesubtest locks the documentederrors.Iscontract.TestRedactedDSN_SharesLayoutWithDSNasserts the redacted DSN equals the realDSN with only the password swapped.
Verification
pkg/module (its own go.mod):go build ./...,go vet,go test -race ./...— 434 tests pass, no races.
providers/gcpmodule (its own go.mod):go build ./...,go vet ./...,go test ./...— 230 tests pass.go test ./internal/database/...— 173 tests pass.Scope note
providers/gcp/services/*is owned by PR #1047 (fix/gcp-recs-count-pricing).This PR touches only
providers/gcp/provider.go(not in #1047's file set), sothere is no overlap.
pkg/*andinternal/database/config.goare untouched byany in-flight PR.
Summary by CodeRabbit
New Features
Bug Fixes
Security Improvements
Documentation