fix: invalidate cached AuthManager when ProviderConfig contents change - #5
Conversation
SharedConnector.Connect cached the AuthManager keyed by ProviderConfig
UID alone. A ProviderConfig UPDATE keeps its UID, so any change to
management-uri, credentials, credentials-type or oauth-issuer-url kept
returning an AuthManager built for the old values until the provider pod
was restarted. Observed in the field: after management moved from plain
HTTP in-cluster to a public TLS endpoint, every reconcile kept dialing
the old URI ("error unmarshalling body: invalid character ..."), and a
rotated token is likewise never picked up.
Pair the cache entry with a fingerprint (sha256 over the length-prefixed
endpoint, extracted credentials, credentials type and issuer URL) and
rebuild the AuthManager when the fingerprint differs. Unchanged configs
still reuse the cached manager, so token refresh behaviour and the
one-manager-per-ProviderConfig model are preserved.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
📝 WalkthroughWalkthroughThis PR introduces content-based fingerprinting for cached AuthManager instances in SharedConnector.Connect. A new configFingerprint helper hashes ManagementURI, credentials, CredentialsType, and OauthIssuerUrl, stored alongside the manager in a cacheEntry, invalidating stale cache entries when ProviderConfig content changes despite a constant UID. Tests validate reuse and rebuild behavior. ChangesAuth Cache Fingerprinting
Estimated code review effort: 2 (Simple) | ~15 minutes Sequence Diagram(s)sequenceDiagram
participant Caller
participant Connect
participant Cache
participant AuthManager
Caller->>Connect: Connect(NbGroup, ProviderConfig)
Connect->>Connect: configFingerprint(endpoint, creds, credType, issuerURL)
Connect->>Cache: load(pc.UID)
alt entry found and fingerprint matches
Cache-->>Connect: cached AuthManager
Connect-->>Caller: return cached AuthManager
else no entry or fingerprint mismatch
Connect->>AuthManager: create new AuthManager
Connect->>Cache: store cacheEntry{fingerprint, manager}
Connect-->>Caller: return new AuthManager
end
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
internal/controller/nb/auth_test.go (1)
80-113: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winConsider testing credential and credentials-type changes too.
The PR objectives mention fingerprint invalidation for
credentials,credentials-type, andoauth-issuer-urlchanges, but the tests only coverManagementURI. Adding table-driven cases for the other fields would increase confidence that the fingerprint mechanism covers all inputs correctly.🧪 Suggested additional test
func TestConnectRebuildsManagerOnCredentialsTypeChange(t *testing.T) { c := testConnector() mg := &vpnv1alpha1.NbGroup{} pc := testProviderConfig("uid-1", "https://mgmt.example.com") pc.Spec.CredentialsType = "token" first, err := c.Connect(context.Background(), mg, pc) if err != nil { t.Fatalf("first Connect: %v", err) } pc.Spec.CredentialsType = "oauth" second, err := c.Connect(context.Background(), mg, pc) if err != nil { t.Fatalf("second Connect: %v", err) } if first == second { t.Fatal("expected a rebuilt AuthManager after CredentialsType changed") } }🤖 Prompt for 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. In `@internal/controller/nb/auth_test.go` around lines 80 - 113, The existing Connect rebuild test only covers ManagementURI changes, but the fingerprint should also invalidate on credentials, credentials-type, and oauth-issuer-url changes. Extend TestConnectRebuildsManagerOnConfigChange in auth_test.go, ideally with table-driven subtests, to mutate ProviderConfig.Spec.Credentials, CredentialsType, and OAuthIssuerURL after an initial Connect and assert the returned AuthManager is rebuilt and then cached again. Reuse the same Connect, testConnector, and testProviderConfig helpers so the new cases verify all fingerprint inputs.
🤖 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.
Nitpick comments:
In `@internal/controller/nb/auth_test.go`:
- Around line 80-113: The existing Connect rebuild test only covers
ManagementURI changes, but the fingerprint should also invalidate on
credentials, credentials-type, and oauth-issuer-url changes. Extend
TestConnectRebuildsManagerOnConfigChange in auth_test.go, ideally with
table-driven subtests, to mutate ProviderConfig.Spec.Credentials,
CredentialsType, and OAuthIssuerURL after an initial Connect and assert the
returned AuthManager is rebuilt and then cached again. Reuse the same Connect,
testConnector, and testProviderConfig helpers so the new cases verify all
fingerprint inputs.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: e10b66bd-e2c1-4586-bc7b-3575b8541404
📒 Files selected for processing (2)
internal/controller/nb/auth.gointernal/controller/nb/auth_test.go
Problem
SharedConnector.Connectcaches theAuthManagerkeyed by ProviderConfig UID alone. A ProviderConfig update keeps its UID, so any change tomanagement-uri, credentials,credentials-type, oroauth-issuer-urlkeeps returning anAuthManagerbuilt for the old values until the provider pod is restarted.Observed in the field: after a management server moved from plain HTTP in-cluster to a public TLS endpoint (ProviderConfig
management-uriupdated), every reconcile kept dialing the old URI — all managed resources for that config stuck inReconcileError(error code 400, error unmarshalling body: invalid character ...) until a manualrollout restartof the provider.A rotated token has the same failure mode:
Connectre-extracts the credential Secret on every call, but discards it on cache hit — andrefreshTokenreuses the constructor-time credentials, so a rotated token is never picked up either.Fix
Pair each cache entry with a fingerprint (sha256 over the length-prefixed endpoint, extracted credentials, credentials type, and issuer URL) and rebuild the
AuthManagerwhen the fingerprint differs. Unchanged configs still reuse the cached manager, so token-refresh behaviour and the one-manager-per-ProviderConfig model are preserved — the cache continues to prevent re-authenticating on every reconcile.Tests
TestConnectReusesManagerWhileConfigUnchanged— unchanged config → same cached manager.TestConnectRebuildsManagerOnConfigChange— same UID, updatedmanagement-uri→ rebuilt manager with the new endpoint, which is then itself cached.Full test suite passes (
go test ./...,go vet ./...clean).Summary by CodeRabbit