Skip to content

feat(webhook): Emit per-plugin authbridge config schema#335

Merged
huang195 merged 1 commit into
rossoctl:mainfrom
huang195:feat/authbridge-per-plugin-config
May 7, 2026
Merged

feat(webhook): Emit per-plugin authbridge config schema#335
huang195 merged 1 commit into
rossoctl:mainfrom
huang195:feat/authbridge-per-plugin-config

Conversation

@huang195

@huang195 huang195 commented May 7, 2026

Copy link
Copy Markdown
Member

Summary

Follow-up to kagenti/kagenti-extensions#378,
which replaces authbridge's top-level inbound: / outbound: /
identity: / bypass: / routes: YAML blocks with per-plugin config
under pipeline.*.plugins[].config. The new authbridge binary rejects
any config whose pipeline is empty (the silent result of yaml.v3
dropping the old top-level keys), so the webhook has to stop
synthesizing the old shape.

Depends on #378 — once it merges and :latest for
authbridge-envoy / authbridge-light is published, this PR's CI picks
up the new image.

What changes

pod_mutator.goensurePerAgentConfigMap fallback synthesis

The fallback branch that runs when authbridge-runtime-config in the
target namespace has no pipeline: section is rewritten. Previously
synthesized top-level inbound:, outbound:, identity:, bypass:
from NamespaceConfig. Now synthesizes a pipeline: section with:

  • jwt-validation (inbound) — config carries issuer from
    NamespaceConfig.Issuer.
  • token-exchange (outbound) — config carries keycloak_url,
    keycloak_realm, default_policy, and identity.type (mapping
    federated-jwtspiffe).

File-path defaults (audience_file, client_id_file, client_secret_file,
jwt_svid_path) are no longer emitted by the webhook — the plugin
applies them from its own convention layer at Configure time (see
authbridge/authlib/plugins/CONVENTIONS.md). Keeps the webhook
schema-agnostic about filesystem paths and reduces duplication.

When baseYAML already has a pipeline: section (which the
post-migration Kagenti Helm chart emits), synthesis is skipped; only
mode + listener overrides layer on top. The chart owns plugin
config contents; the webhook owns per-agent mode selection.

Tests updated

  • pod_mutator_test.go:

    • TestEnsurePerAgentConfigMap_EmptyBaseYAML_FallbackFromNsConfig
      now asserts the synthesized pipeline via a new pluginConfigAt
      helper that navigates pipeline.<direction>.plugins[<name>].config.
    • TestEnsurePerAgentConfigMap_BaseYAML_PreservesExistingFields
      — baseYAML rewritten to new shape; preservation assertions
      updated accordingly.
    • TestEnsurePerAgentConfigMap_ListenerOverrides_Merged
      baseYAML rewritten; listener assertions unchanged (listener is
      top-level in both schemas).
    • TestEnsurePerAgentConfigMap_FederatedJWT_MapsToSpiffe
      asserts identity.type = spiffe under token-exchange config.
      Dropped assertions on default file paths (those moved into
      the plugin).
  • test/e2e/fixtures.go — two hardcoded authbridge-runtime-config
    ConfigMaps rewritten to emit the new per-plugin shape.

No image tag bumps

The operator references authbridge images as :latest throughout
(values.yaml, webhook defaults, e2e suite). Once #378 merges and
publishes :latest, operator CI picks it up. Version-pinning and
the atomic authbridge-operator cutover live in the kagenti Helm
chart PR that comes next (tracked separately).

Test plan

  • go build ./... clean.
  • go vet ./... clean.
  • All unit tests pass (including the rewritten pod_mutator tests).
  • E2E tests — require a live cluster + the new authbridge image.
    Will run after Feat: MLflow operand controller for CR lifecycle and OTEL RBAC #378 merges and :latest is published.
  • Local kind-cluster smoke test via the Kagenti installer with
    the matched authbridge image — pre-merge gate alongside the
    kagenti Helm chart PR.

Draft

Draft until #378 lands and the kagenti Helm chart PR is ready —
all three flip from draft to ready together.

Assisted-By: Claude (Anthropic AI) noreply@anthropic.com

Follow-up to kagenti-extensions PR rossoctl#378, which replaced authbridge's
top-level `inbound:` / `outbound:` / `identity:` / `bypass:` /
`routes:` YAML blocks with per-plugin config under
`pipeline.*.plugins[].config`. The new binary rejects any config
whose pipeline is empty (which is what yaml.v3's silent drop of
unknown keys produces when the top-level blocks are removed), so
the webhook had to stop synthesizing the old shape.

What changed in pod_mutator.go:

ensurePerAgentConfigMap's fallback-synthesis branch is rewritten.
Previously: if baseYAML was missing any of `inbound`, `outbound`,
`identity`, or `bypass`, synthesize each from NamespaceConfig values.
Now: if baseYAML has no `pipeline:` section at all, synthesize one
with jwt-validation (inbound) and token-exchange (outbound) entries
whose configs carry Issuer / Keycloak URL / realm / default policy /
identity type from NamespaceConfig.

File-path defaults (audience_file, client_id_file, client_secret_file,
jwt_svid_path) are no longer emitted by the webhook — the authbridge
plugin applies them from its own convention layer at Configure time
(see authbridge/authlib/plugins/CONVENTIONS.md). This keeps the
webhook schema-agnostic about paths and reduces duplication.

When baseYAML already has a `pipeline:` section (the post-migration
Kagenti Helm chart emits it), synthesis is skipped entirely. Only
mode + listener overrides layer on top. The Helm chart owns plugin
config contents; the webhook owns per-agent mode selection.

Tests:

- TestEnsurePerAgentConfigMap_EmptyBaseYAML_FallbackFromNsConfig:
  asserts the synthesized pipeline has the correct plugin names
  and config values. Navigates pipeline.<direction>.plugins[<name>]
  via a new pluginConfigAt helper to keep assertions compact.
- TestEnsurePerAgentConfigMap_BaseYAML_PreservesExistingFields:
  baseYAML rewritten to new shape; asserts plugin config is
  preserved verbatim.
- TestEnsurePerAgentConfigMap_ListenerOverrides_Merged: baseYAML
  rewritten to new shape; listener assertions unchanged (listener
  is top-level in both schemas).
- TestEnsurePerAgentConfigMap_FederatedJWT_MapsToSpiffe: asserts
  identity.type = spiffe under token-exchange. Dropped assertions
  for file-path defaults (those moved into the plugin).

E2E fixtures:

- test/e2e/fixtures.go: two hardcoded ConfigMaps with old-shape
  YAML rewritten to new per-plugin shape.

Image tags: none bumped. The operator references authbridge images
as `:latest` throughout — once PR rossoctl#378 merges and CI publishes new
`:latest`, operator CI picks it up. The version-pinning (and
atomic authbridge+operator cutover) lives in the kagenti Helm
chart PR that comes next.

Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com>
Signed-off-by: Hai Huang <huang195@gmail.com>
@huang195
huang195 marked this pull request as ready for review May 7, 2026 15:04
@huang195
huang195 requested a review from a team as a code owner May 7, 2026 15:04

@pdettori pdettori left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clean migration from flat authbridge config schema to per-plugin pipeline: structure. Logic is straightforward and well-tested — if cfg["pipeline"] is nil, synthesize from NamespaceConfig; otherwise let the Helm chart's config stand. Bypass-paths default removal is explicitly documented as moved to the plugin's convention layer.

All 16 CI checks pass.

Two minor suggestions:

  1. pod_mutator.gosynthesizePipeline: When ClientAuthType is non-empty and not FederatedJWT, its value is passed through directly as identity["type"]. Might be worth a brief comment noting which values the plugin considers valid here — helps future readers understand whether the webhook should validate or just pass through.

  2. pod_mutator_test.gopluginConfigAt: The local variable cfg in the return shadows the outer cfg that callers typically have in scope. Consider naming it pluginCfg to avoid confusion when reading tests.

@huang195
huang195 merged commit 2934cf0 into rossoctl:main May 7, 2026
20 of 21 checks passed
@github-project-automation github-project-automation Bot moved this from Backlog to Done in Kagenti Issue Prioritization May 7, 2026
@huang195
huang195 deleted the feat/authbridge-per-plugin-config branch May 7, 2026 16:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants