feat: render AuthBridge layer-3 plugin presets from AgentRuntime.spec - #524
feat: render AuthBridge layer-3 plugin presets from AgentRuntime.spec#524webchang wants to merge 2 commits into
Conversation
|
Companion backend PR: rossoctl/rossoctl#2488 (sets the |
cwiklik
left a comment
There was a problem hiding this comment.
Solid implementation — pipeline synthesis logic is correct, well-tested (7 focused unit tests covering canonical order, membership/policy, overrides, mutex, base-config seeding, IBAC judge stamping, and the missing-judge warning), and integrates cleanly with existing pod_mutator flow (seeds from base, doesn't replace). deepCopyMap/indexPipelineConfigs handle nil safely throughout.
Must-fix:
- Commit is missing a
Signed-off-by:trailer — DCO CI check is failing. Amend with--signoffand force-push. - Commit uses
Co-Authored-By: Claude Opus 4.8— org convention (CLAUDE.md) prohibitsCo-authored-byfor AI attribution (inflates GitHub contributor stats). Replace withAssisted-By: Claude (Anthropic AI) <noreply@anthropic.com>.
Suggestions (non-blocking):
judgeBearerin ConfigMap — the bearer token sourced fromvalues.yamlends up in a ConfigMap (plaintext), readable by anyone with namespace access. Consider asecretKeyReffor a follow-up so the credential stays in a Secret.- Mutex at admission — the token-exchange/token-broker mutex is enforced at render time (
synthesizePresetPipeline), not at webhook admission. A CR withpluginPreset: full+plugins: ["token-broker:enforce"]is admitted but pod injection fails later with a confusing error. Moving the mutex check intocheckPluginPresetValidwould give fail-fast UX at CR creation time.
| # LLM traffic from tool traffic. Omitted from the plugin config when empty. | ||
| agentLlmHost: "" | ||
| # Optional: bearer token for the judge endpoint. Omitted when empty. | ||
| judgeBearer: "" |
There was a problem hiding this comment.
suggestion: judgeBearer will end up in a ConfigMap (plaintext). For a bearer token, consider sourcing from a Secret reference in a follow-up — avoids credential-in-ConfigMap for anyone with namespace read.
| if !ok { | ||
| return nil, nil, fmt.Errorf("unknown plugin preset %q (want auth-only, ibac-only, or full)", preset) | ||
| } | ||
| if chainDefault != "" && !supportedPolicies[chainDefault] { |
There was a problem hiding this comment.
suggestion: This mutex check is only enforced at render time, not at webhook admission (ValidatePlugins/checkPluginPresetValid). A CR with pluginPreset: full + plugins: ["token-broker:enforce"] is admitted (no webhook error) but pod injection fails later. Consider adding the check to webhook validation for fail-fast UX.
Add spec.pluginPreset / spec.plugins / spec.onError to AgentRuntime and render the full canonical AuthBridge plugin pipeline into the per-agent authbridge-config-<name> ConfigMap when a preset is set (Option B). Ported from the workload-harness pipeline-merge.py: - Presets auth-only / ibac-only / full select plugin membership; every supported plugin is emitted in fixed canonical order (inbound [a2a-parser, jwt-validation]; outbound [token-exchange, token-broker, inference-parser, mcp-parser, ibac]), unselected ones at on_error: off. - Per-plugin policy enforce|observe|off maps to on_error (enforce omits it); spec.onError sets the chain default, spec.plugins "NAME:POLICY" tokens override per plugin. - token-exchange XOR token-broker on the outbound chain (mutex rejected). - Per-plugin config is seeded from the operator's already-rendered base (jwt-validation issuer, token-exchange identity) so it survives — never replaced wholesale (prevents "issuer is required" reload failures). - ibac judge config (endpoint/model/timeout/host/bearer) comes from a new platform IBACConfig (Helm defaults.ibac.*); the judge system prompt is baked into the operator binary. Validating webhook rejects malformed spec.plugins tokens via AgentRuntimeSpec.ValidatePlugins (in the leaf api package to avoid an injector import cycle). CRD + deepcopy regenerated. Unit tests cover synthesis, membership, overrides, mutex, base-config seeding, and ibac. Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com> Signed-off-by: Rong Chang <rong@us.ibm.com>
2f30d6f to
c86679f
Compare
|
Thanks for the review, @cwiklik! Must-fix items — done:
Non-blocking suggestions — tracked as follow-up issues (kept out of this PR to avoid ballooning a focused change):
Heads-up: syncing this branch with |
Resolve the semantic conflict with rossoctl#517: ensurePerAgentConfigMap now returns (configCMName, routesCMName, err); update the preset-render error path to the 3-value signature. Signed-off-by: Rong Chang <rong@us.ibm.com> Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com>
Closes #523.
What
Renders the full AuthBridge layer-3 plugin pipeline from
AgentRuntime.specwhen a preset isrequested, instead of the default two-plugin (
jwt-validation+token-exchange) synthesis.Consumes the fields set by the backend agent-create API (companion: rossoctl/rossoctl#2487).
New spec fields (CRD enums +
ValidatePlugins):pluginPreset(auth-only|ibac-only|full),plugins(name:policyoverride tokens),onError(enforce|observe|off).How
synthesizePresetPipeline(a port of the harnesspipeline-merge.py):[a2a-parser, jwt-validation],OUTBOUND
[token-exchange, token-broker, inference-parser, mcp-parser, ibac]; non-selectedplugins get
on_error: off.enforceomitson_error;observe/offemitted explicitly.spec.onErroris the chain default;spec.pluginstokens override per plugin.token-exchangeXORtoken-brokeroutbound mutex.config:from the already-rendered base (issuer / keycloak_* / identity)rather than replacing it, so base config survives sidecar reloads.
ibacis active, stamps judge config from a new platform-configibacblock(
judgeEndpoint/judgeModel/timeoutMs/agentLlmHost/judgeBearer) plus a bakedsystem_prompt. A webhook warning fires ifibacis selected whilejudgeEndpointis unset(the sidecar rejects
ibacat config-build time without a judge endpoint).Changed
api/v1alpha1/agentruntime_types.go(+ regenerated CRD +zz_generated.deepcopy.go),agentruntime_webhook.go— spec fields + validation.internal/webhook/injector/preset_pipeline.go(new) +pod_mutator.go— pipeline synthesis.internal/webhook/config/{types.go,defaults.go},charts/operator/values.yaml—ibacplatform-config block.
preset_pipeline_test.go,agentruntime_plugins_test.go.Test plan
go test ./...green. Validated end-to-end cross-cluster: rendered per-agent config matched theexpected preset pipeline for
auth-only/ibac-only/full; the AuthBridge sidecar loadedwithout reload errors; and a small IBAC-comparison benchmark showed the
enforce(blocks) vsobserve(passes) contrast.Assisted-By: Claude Code