Fix: preserve explicitly-set authbridge-config keys per namespace (#433)#434
Conversation
AuthbridgeConfigReconciler unconditionally overwrote every key of an existing authbridge-config ConfigMap with platform-global defaults on each reconcile, silently discarding any explicitly-set per-namespace value such as KEYCLOAK_REALM. A workload in a namespace using a non-default realm (e.g. tx-e2e) had its realm reset to "kagenti" within one reconcile cycle, so the client-registration controller registered its client in the wrong realm and client_credentials grants returned invalid_client (401). Regression introduced in cdbed3b. authbridge-config is a namespace-defaults source (kagenti.io/defaults= true), so defaults should fill gaps, not override explicit values. On the update path, only fill keys that are missing or empty; preserve any existing non-empty value. The create path (fresh kagenti-enabled namespace gets full operator-provided defaults) and label stamping are unchanged. Adds authbridgeconfig_controller_test.go (the controller previously had no test) covering: per-namespace realm preservation, full-defaults creation, missing/empty-key fill, label stamping on externally-created ConfigMaps, and the non-kagenti-enabled skip. Fixes rossoctl#433 Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com> Signed-off-by: Paolo Dettori <dettori@us.ibm.com>
5240ce3 to
2072fc7
Compare
esnible
left a comment
There was a problem hiding this comment.
Summary
Clean, focused fix. The update path now fills only missing/empty keys instead of clobbering every key, so an explicitly-set per-namespace value (e.g. KEYCLOAK_REALM=tx-e2e) survives reconciliation while the create path still gets full operator-provided defaults. This matches Option 1 in #433 and correctly preserves the cdbed3b defaulting behavior for fresh namespaces.
Verified against upstream/main: the diff applies to the pre-fix clobbering loop; LabelNamespaceDefaults == "kagenti.io/defaults", authbridgeConfigCM, and clientRegistrationTestScheme all exist and are used consistently; and authbridge-config is genuinely consumed as a namespace-defaults source (via MatchingLabels{LabelNamespaceDefaults: "true"}). Good first test for a controller that previously had none — the regression case is written to fail on the old behavior.
One behavior trade-off worth noting (non-blocking): once a key is non-empty, the operator can no longer push an updated platform default to it on the update path. That's the intended "defaults fill gaps, don't override" semantics per #433, so this is correct as designed.
Author: pdettori (MEMBER — maintainer)
Areas reviewed: Go (controller + test)
Agent/IDE config (.claude/.vscode): none
Commits: 1 commit, signed-off: yes
CI status: passing (all 16 checks green, incl. E2E + Integration + Unit)
Add missing workloadKind parameter to 10 InjectAuthBridge test calls introduced by upstream PRs (rossoctl#436 egress enforcement, rossoctl#434 namespace realm, rossoctl#432 iptables backend) that merged after this branch diverged. Signed-off-by: Varsha Prasad Narsing <varshaprasad96@gmail.com> Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com> Signed-off-by: Varsha Prasad Narsing <varshaprasad96@gmail.com>
Summary
AuthbridgeConfigReconcilerunconditionally overwrote every key of an existingauthbridge-configConfigMap with platform-global defaults on each reconcile, silently discarding any explicitly-set per-namespace value such asKEYCLOAK_REALM. A workload in a namespace using a non-default realm had its realm reset tokagentiwithin one reconcile cycle, so the client-registration controller registered the client in the wrong realm andclient_credentialsgrants returnedinvalid_client(401). Regression introduced incdbed3b.Fixes #433.
Root cause
In the update path of
authbridgeconfig_controller.go:Fix
authbridge-configis a namespace-defaults source (labeledkagenti.io/defaults=true, consumed bydefaults_config_reconciler.go/agentruntime_controller.go), andcdbed3bintroduced it purely as operator-driven defaulting. Defaults should fill gaps, not override explicit values. On the update path the reconciler now only fills keys that are missing or empty, preserving any existing non-empty value:Unchanged: the create path (a fresh
kagenti-enablednamespace still receives full operator-provided defaults) and the ownership/defaults label stamping. So thecdbed3bdefaulting behavior is preserved for namespaces that have no config yet.Tests
The controller previously had no test. Adds
authbridgeconfig_controller_test.go(plaintesting+ fake client, matchingclientregistration_controller_test.go) covering:KEYCLOAK_REALM=tx-e2esurvives reconcile (the regression)managed-by+kagenti.io/defaultskagenti-enablednamespace → no CM createdThe first two/three cases were written failing first (clobber reproduced), then made green by the fix.
gofmt,go vet, andgo build ./...clean.Cross-refs
Assisted-By: Claude Code