Skip to content

refactor(cmd): split unified authbridge binary into 3 mode-specific binaries#411

Merged
huang195 merged 2 commits into
rossoctl:mainfrom
huang195:feat/three-binaries
May 15, 2026
Merged

refactor(cmd): split unified authbridge binary into 3 mode-specific binaries#411
huang195 merged 2 commits into
rossoctl:mainfrom
huang195:feat/three-binaries

Conversation

@huang195

Copy link
Copy Markdown
Member

Summary

Splits the unified cmd/authbridge/ binary into three mode-specific binaries with build-time mode selection. Fixes the bug where Dockerfile.proxy was silently building the lite binary (no parsers), which broke abctl session-event observability for proxy-sidecar deployments after PR #409 merged.

Directory Mode Plugins
cmd/authbridge-proxy/ (default) proxy-sidecar full (jwt-validation, token-exchange, a2a-parser, mcp-parser, inference-parser)
cmd/authbridge-envoy/ envoy-sidecar (ext_proc) full
cmd/authbridge-lite/ proxy-sidecar lite (auth gates only)

Each binary has its own main.go + go.mod + Dockerfile + entrypoint.sh. The unified cmd/authbridge/ directory is removed; its listeners move into authlib/listener/{extauthz,extproc} alongside the existing forwardproxy and reverseproxy listeners so binaries no longer own listener code.

CI publishes three images now (plus the unchanged proxy-init):

  • ghcr.io/kagenti/kagenti-extensions/authbridge — proxy-sidecar combined, what the operator points at by default
  • ghcr.io/kagenti/kagenti-extensions/authbridge-envoy — envoy-sidecar combined
  • ghcr.io/kagenti/kagenti-extensions/authbridge-lite — proxy-sidecar lite combined (new)

Why this PR

Two motivations stacked:

Naming was misleading. Pre-PR the layout was cmd/authbridge (full, all modes) + cmd/authbridge-envoy (lite envoy-only) + cmd/authbridge-proxy (lite proxy-only). The mode-suffixed names looked like they should be the mode-specific full binaries; instead they were size-optimized lite variants. Dockerfile.proxy was silently using the lite proxy as the proxy-sidecar combined image — which had no parsers, so abctl couldn't render protocol context for proxy-sidecar deployments.

Mode is a build-time decision, not a runtime decision. Operators set the mode via the per-pod ConfigMap the operator generates; nobody actually flips --mode at runtime. Splitting by binary makes each main.go a flat 270-line file with no per-mode branching, and makes the Dockerfile contracts unambiguous.

Operator (kagenti-operator) impact

None. The operator references authbridge and authbridge-envoy images by name. Image names, container ports, and the --config /etc/authbridge/config.yaml entrypoint contract are all stable. The image contents change (now built from the new mode-specific dirs, with parsers in the proxy combined), but no operator-side change is needed.

Waypoint mode

Preserved but not currently shipped as a binary. The ModeWaypoint constant in authlib/config and the extauthz listener in authlib/listener/extauthz/ stay so the code path is intact. If waypoint comes back as a deployed mode, a separate cmd/authbridge-waypoint/ binary can be added without touching the rest.

Dependency / Go version bump

authlib absorbed the listener code that pulls in envoyproxy/go-control-plane and gRPC, which require Go 1.25. go.work and the Dockerfile golang base images bump from 1.24 → 1.25 accordingly.

Test plan

  • go build ./... clean for authlib + all 3 cmd/ binaries
  • go test ./... clean across authlib (44 packages, all pass)
  • All 3 images build with podman build from the new Dockerfile paths
  • All 3 images load into kind cluster
  • Weather-agent in team1 namespace boots in proxy-sidecar mode against the new authbridge:latest image
    • 5 plugins registered (no unknown plugin errors)
    • Mode resolved as proxy-sidecar source=cluster-default from operator log
    • SPIRE_ENABLED=true on container env, bundled spiffe-helper started
  • CI pipeline (build.yaml) — needs to run on this PR to confirm the new matrix builds all 3 images
  • Manual: pull the new authbridge-lite image and verify it can run in place of authbridge for a workload that doesn't need parsers (separate test, not blocking)

Follow-ups

  • kagenti chart (kagenti/kagenti) image pins reference the old authbridge-light name. The PR-C work for the operator's mode-resolution change will also need to update those.
  • Once an external consumer wants the size-optimized image, point them at ghcr.io/kagenti/kagenti-extensions/authbridge-lite:<tag>.

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

@huang195

Copy link
Copy Markdown
Member Author

Replaced 49875da with ab11ed8 — the previous push fixed CI by working around an unnecessary problem; this version removes the problem.

Root cause of the CI breaks: my go mod tidy on the moved listener code opportunistically bumped google.golang.org/grpc from v1.80.0 (what cmd/authbridge was on) to v1.81.1. grpc 1.81 raises its minimum Go version to 1.25, which cascaded: authlib/go.mod jumped to go 1.25.0, go.work jumped, the cmd/* binaries jumped, the Dockerfile golang base needed bumping, and CI's go-extractor (running 1.24.13) couldn't list packages with a 1.25-required workspace.

The listener move itself doesn't require any of that — it's the same listener code with the same envoyproxy/go-control-plane v1.37.0 dep that worked fine on Go 1.24 before. The grpc bump was incidental.

Fix in ab11ed8: pinned the deps back to what cmd/authbridge had:

Dep Was (this PR) Now (matches old cmd/authbridge)
google.golang.org/grpc v1.81.1 v1.80.0
genproto/googleapis/rpc 2026-05-11 2026-01-20
cncf/xds/go 2026-02-02 2025-12-10
protoc-gen-validate v1.3.3 v1.3.0
golang.org/x/net v0.51.0 v0.49.0
golang.org/x/sys v0.42.0 v0.41.0

After the pin:

  • authbridge/authlib/go.mod: go 1.24.0 (was 1.25.0)
  • authbridge/cmd/authbridge-{proxy,envoy,lite}/go.mod: go 1.24.0 (was 1.25.0)
  • authbridge/cmd/abctl/go.mod: go 1.24.2 (was 1.25.0)
  • authbridge/go.work: go 1.24.2 (was 1.25.0)
  • Dockerfile builders: golang:1.24-alpine (was 1.25-alpine)

Reverts the previous push's CI changes:

  • ci.yaml — drops the GOWORK: "off" additions to go-ci (authproxy) and go-ci-authlib. Only the matrix change to go-ci-authbridge-cmd remains, which is genuinely needed because we now have 3 binaries.
  • security-scans.yaml — drops the setup-go step and the fail-fast: false addition I made.

Verified locally on Go 1.24.5:

  • go test ./authlib/... — all 27 packages pass
  • go build ./... for each cmd/* binary with GOWORK=off (CI mode) — clean
  • podman build of all 3 Dockerfiles with golang:1.24-alpine base — all succeed

Net effect on the PR: same 3-binary structural change, no spurious version bumps, no CI workflow changes beyond the matrix update for the new binaries. Diff vs upstream main is now ~750 lines structural + 0 lines version-churn.

Thanks for the push-back — the previous push was treating a self-inflicted symptom.

…inaries

The unified `cmd/authbridge/` binary picked its mode at runtime via a
`--mode` flag, but operators always pin the mode via the per-pod
config the operator generates — there's no real runtime selection
happening. The unified shape also caused the recent regression where
`Dockerfile.proxy` silently built the wrong (lite) binary for the
proxy-sidecar combined image, dropping the parser plugins and breaking
abctl observability for proxy-sidecar deployments.

This PR replaces the runtime `--mode` selection with build-time
selection: three mode-specific binaries, one per deployment shape.
Each binary's `main.go` is small and unambiguous (~270 LOC), no
per-mode if/else, and imports exactly the listener and plugins it
needs.

New layout under `cmd/`:

  authbridge-proxy/   proxy-sidecar mode (default). HTTP forward +
                     reverse proxies. Full plugin set including the
                     a2a/mcp/inference parsers, so abctl session
                     events render protocol context.
  authbridge-envoy/   envoy-sidecar mode. ext_proc gRPC server hooked
                     into Envoy. Full plugin set.
  authbridge-lite/    proxy-sidecar mode, lite plugin set (auth gates
                     only — jwt-validation + token-exchange — parsers
                     dropped) for size-optimized deployments.

Each binary lives in its own directory with main.go + go.mod + Dockerfile
+ entrypoint.sh. The CI matrix in .github/workflows/build.yaml now
publishes three images: `authbridge` (proxy combined, default),
`authbridge-envoy` (envoy combined), `authbridge-lite` (proxy combined,
lite). `proxy-init` continues to ship unchanged.

Listener implementations move from cmd/authbridge/listener/ into authlib/
to match the existing forwardproxy/reverseproxy layout — the binaries
no longer own listener code, only main.go composition. authlib/listener/
now has all four listeners (extauthz, extproc, forwardproxy, reverseproxy)
and the binaries import only what they need.

The waypoint mode constant is preserved in authlib/config and the
extauthz listener is preserved in authlib/listener/extauthz, but no
binary registers it currently — waypoint deployments need to wait for
a follow-up PR to bring it back as its own binary if there's demand.

Side effects:
* go.mod files bump to Go 1.25 (envoyproxy/go-control-plane requires it
  after authlib absorbed the listener code).
* Dockerfile golang base bumps from 1.24-alpine to 1.25-alpine to match.
* CLAUDE.md (root and authbridge/) refreshed to describe the new
  three-binary layout, the new image set, and the new code conventions.
* Operator (kagenti-operator) needs no changes — it references
  `authbridge` and `authbridge-envoy` images by name; their content
  changes (now built from the new mode-specific dirs) but the image
  names + ports + entrypoint contracts are stable.
* `authbridge-lite` is a new image not referenced by any current
  consumer; it's available for future size-constrained deployments.

Verified locally: all three images build cleanly, all three load into
kind, weather-agent in proxy-sidecar mode boots with all 5 plugins
registered, abctl receives session events on user requests.

Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com>
Signed-off-by: Hai Huang <huang195@gmail.com>
@huang195
huang195 force-pushed the feat/three-binaries branch from ab11ed8 to ab70af7 Compare May 15, 2026 00:02
@huang195

Copy link
Copy Markdown
Member Author

Pushed ab70af7 adding binary-size optimization across all three Dockerfiles.

Changes per Dockerfile:

  • apk add includes binutils (for strip).
  • Go build line gains -ldflags="-s -w" — drops the symbol table and DWARF debug info from the authbridge binary. Go's runtime keeps pclntab separately, so panic stack traces still surface function names.
  • New spiffe-stripper build stage: pulls the upstream ghcr.io/spiffe/spiffe-helper:0.11.0 binary and runs strip on it. Runtime stage copies from spiffe-stripper instead of spiffe-source.
  • Envoy itself is left alone — envoyproxy/envoy:v1.37.1 already ships a stripped binary; running strip on it produces zero bytes of savings.

Measured (locally built and compared):

Image Before After Reduction
authbridge (proxy combined) 49 MB 38.1 MB -22% (-10.9 MB)
authbridge-lite 49 MB 38.1 MB -22% (-10.9 MB)
authbridge-envoy 161 MB 145 MB -10% (-16 MB)

The proxy variants get the biggest relative win because spiffe-helper + the Go binary make up most of their content. The envoy variant saves the same absolute amount on its own contents, but the percentage is smaller because Envoy itself dominates (~88 MB, unchangeable without rebuilding from source).

CI build time impact: apk add binutils and the strip step add ~1–2 s per image. Negligible.

@esnible esnible 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.

Solid refactor. Splitting the unified cmd/authbridge/ into three mode-specific binaries (authbridge-proxy, authbridge-envoy, authbridge-lite) eliminates the runtime --mode switch in favor of build-time selection — each main.go is now flat and unambiguous. This also fixes the silent-wrong-binary issue from #409 where Dockerfile.proxy was building the lite (parser-less) binary. Listener consolidation into authlib/listener/{extauthz,extproc} is consistent with the existing forwardproxy/reverseproxy layout. CI matrix correctly builds all three images plus proxy-init. Waypoint preservation in authlib without a binary is an explicit deferral and well-documented.

Areas reviewed: Go (3 main.go + authlib listener moves), Dockerfiles, shell entrypoints, GitHub Actions, Go modules, docs.

CI status: all 19 checks passing.

Commits: 1, signed-off, refactor(cmd): prefix matches recent main-branch convention. Assisted-By: trailer used per kagenti AI-attribution policy.

One small suggestion below about a Go 1.24/1.25 doc-vs-code mismatch — non-blocking.

Assisted-By: Claude Code

Comment thread CLAUDE.md Outdated
**Library:** `authbridge/authlib/`
**Language:** Go 1.24
**Library:** `authbridge/authlib/` (shared)
**Language:** Go 1.25

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.

suggestionLanguage: **Go 1.25** but the actual go.mod files all declare go 1.24.0 (toolchain go1.24.5), go.work declares go 1.24.2, and the Dockerfiles still use golang:1.24-alpine. The PR description also claims the bump happened ("go.mod files bump to Go 1.25", "Dockerfile golang base bumps from 1.24-alpine to 1.25-alpine") but I don't see that in the diff.

CI passes fine against the 1.24.5 toolchain — only the docs are out of sync. Either revert this line (and the matching one in authbridge/CLAUDE.md) back to Go 1.24, or actually do the 1.25 bump in go.mod + Dockerfiles. Non-blocking, but worth fixing so future readers aren't misled.

Comment thread authbridge/CLAUDE.md Outdated
- gRPC ext-proc using `envoyproxy/go-control-plane` types (in cmd/authbridge)
- JWT validation with `lestrrat-go/jwx/v2` (in authlib/validation)
### Go (authlib, cmd/authbridge-{proxy,envoy,lite}, demo-app)
- Go 1.25

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.

suggestion — same Go 1.24 → 1.25 doc claim as the root CLAUDE.md comment. Code is on 1.24.5 (toolchain) / go 1.24.0 in every module; Dockerfile base is golang:1.24-alpine. Either drop this back to Go 1.24 or land the bump for real.

Picked up reviewer feedback on PR rossoctl#411: I bumped the docs to 'Go 1.25'
during the earlier version-churn detour but reverted the code back to
1.24 without re-syncing the docs. Code is on go 1.24.0 across every
module, go.work declares go 1.24.2, and Dockerfile builders use
golang:1.24-alpine. Restore the doc claims to match.

Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com>
Signed-off-by: Hai Huang <huang195@gmail.com>
@huang195
huang195 merged commit 3ede093 into rossoctl:main May 15, 2026
19 checks passed
@huang195
huang195 deleted the feat/three-binaries branch May 15, 2026 00:39
huang195 added a commit to huang195/kagenti-extensions that referenced this pull request May 15, 2026
Follow-up to the dead-label fix in the previous commit. Repo-wide
sweep for other stale references to the pre-rossoctl#411 multi-sidecar
architecture, with two distinct treatments:

Fixed in place (still-supported paths drifted to dead names):

* local-build-and-test.sh — Dockerfile paths
  cmd/authbridge/Dockerfile.proxy and cmd/authbridge/Dockerfile.envoy
  no longer exist. Update to the post-rossoctl#411 cmd/authbridge-{proxy,envoy,
  lite}/Dockerfile paths and add a build step for the third image
  (authbridge-lite). Inventory list at the end of the script
  expanded accordingly.
* authbridge/CLAUDE.md — fix the prose at line 132 that incorrectly
  told future readers the kagenti.io/client-registration-inject:
  "true" label still works (it doesn't — operator's SkipReason
  honors it and the legacy sidecar that the label deferred to is
  gone). Fix the runtime-resources table to reflect operator-managed
  registration and the bundled spiffe-helper.
* README.md (top-level) — image inventory had authbridge-unified +
  separate client-registration / spiffe-helper images. Replace with
  the post-rossoctl#411 set: authbridge / authbridge-envoy / authbridge-lite
  / proxy-init, with a note explaining the bundling and that older
  release tags still publish the legacy shape.
* authbridge/README.md — image / mode tables fully rewritten to the
  post-rossoctl#411 set. Default mode is now proxy-sidecar (was envoy-sidecar
  in the old text).
* authbridge/demos/webhook/README.md — overview prose, prerequisites
  image list, "Enabling Combined Sidecar Mode" section (the feature
  gate is gone), debugging-logs section, image-pull-error
  troubleshooting block. The `combinedSidecar`, `envoyProxy: false`,
  `spiffeHelper: false` per-sidecar feature gates are all retired;
  rewrite the section to document the post-rossoctl#411 mode-resolution
  chain (CR → namespace ConfigMap → annotation → cluster default).
* authbridge/demos/weather-agent/demo-ui.md — "Key differences" table
  flipped: proxy-sidecar is now the default; both rows now name the
  combined images instead of the dead authbridge-light/envoy split.
* authbridge/demos/README.md — index page note about
  authbridge-unified replaced with the post-rossoctl#411 image set; flag the
  Single-Target / Multi-Target rows as currently broken with an
  inline ⚠️ warning paragraph.

Marked broken-needs-migration (no in-place fix without testing):

* authbridge/authproxy/k8s/auth-proxy-deployment.yaml,
  authbridge/demos/{single,multi}-target/k8s/authbridge-deployment.yaml,
  authbridge/demos/{single,multi}-target/k8s/authbridge-deployment-no-spiffe.yaml
  use the pre-rossoctl#411 multi-sidecar pattern (envoy-proxy +
  authbridge-light + client-registration + standalone spiffe-helper
  containers) with images that no longer publish. Rewriting them to
  the combined-sidecar shape is real work that needs each demo
  manually verified — out of scope for a stale-references cleanup.
  Add an ⚠️ broken-after-rossoctl#411 header to each YAML naming the dead
  images so any apply attempt produces a useful explanation
  alongside the inevitable ImagePullBackOff. Mirror the warning at
  the top of demos/{single,multi}-target/demo.md.

* LOCAL_TESTING_GUIDE.md (760 lines, deeply baked into the legacy
  shape) — top-of-file deprecation banner pointing at the working
  demos. The `local-build-and-test.sh` reference in §1 still works
  because we updated the script; the rest needs re-author.

Verified: bash syntax on local-build-and-test.sh; python3 yaml
parse on each touched K8s manifest; repo-wide grep for the dead
strings now matches only inside warning blocks ("no longer", "BROKEN",
"don't set it", etc.).

Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com>
Signed-off-by: Hai Huang <huang195@gmail.com>
huang195 added a commit to huang195/kagenti-extensions that referenced this pull request May 15, 2026
Surgical updates to working demos so their prose matches what the
operator actually injects post-rossoctl#411 / kagenti-operator#361 (one
combined AuthBridge sidecar, container name depends on resolved mode).

Changes:

* weather-agent/demo-ui.md
  - Architecture diagram: collapse 4-box agent-pod (agent +
    spiffe-helper + client-registration + envoy-proxy) into 2-box
    (agent + AuthBridge sidecar). Note that container name is
    mode-dependent (authbridge-proxy / envoy-proxy), spiffe-helper
    is bundled, and registration is operator-managed out of band.
  - "Verify pod" section: 4/4 → 2/2; expected `kubectl exec` output
    `agent kagenti-client-registration envoy-proxy spiffe-helper`
    becomes either `agent authbridge-proxy` (default) or
    `agent envoy-proxy` (envoy-sidecar).
  - "Check client registration" section: replace the
    `-c kagenti-client-registration` log inspection with a
    Secret-name-based check + a pointer at the kagenti-operator's
    controller-manager logs for the actual reconciler activity.
  - "Agent Pod Not Starting" troubleshooting: drop the
    `kagenti-client-registration` / `spiffe-helper` -c branches;
    add a kagenti-controller-manager fallback for stuck registration.
  - "Proxy-Sidecar Mode" section: rewrite as "Switching modes" —
    cluster default is now proxy-sidecar (was envoy-sidecar in the
    old prose); document the four-layer resolution chain
    (CR → namespace ConfigMap → annotation → cluster default) and
    show the canonical `kubectl patch agentruntime ... authBridgeMode`
    surface. Verification block shows expected container names per
    mode. Switching back drops the override on the AgentRuntime CR.
  - Inbound-troubleshooting reference: generalize "check envoy-proxy
    logs" to mention both authbridge-proxy and envoy-proxy.

* weather-agent/demo-ui-advanced.md
  - Drop two `combinedSidecar` references (the feature gate is gone
    after rossoctl#411); replace `4/4 (or combined sidecar variant)` with
    a clean `2/2`.
  - Hard-coded `-c envoy-proxy` in two log-inspection blocks: the
    advanced demo runs in envoy-sidecar mode by design, so the
    primary commands stay on `-c authbridge-proxy` for
    proxy-sidecar parity, with an inline note that envoy-sidecar
    uses `envoy-proxy`.

* weather-agent/k8s/configmaps-advanced.yaml
  - One stale comment referenced an `envoy-with-processor` build
    that no longer ships. Generalize to "AuthBridge ext_proc /
    forward-proxy" since the same observation applies to both
    modes after rossoctl#411.

* webhook/README.md
  - Architecture diagram redrawn for the combined-sidecar shape:
    one box for the AuthBridge sidecar with explicit per-mode
    container names. Out-of-band note added about
    operator-managed Keycloak client registration and the
    `kagenti-keycloak-client-credentials-<hash>` Secret.

* webhook/k8s/agent-deployment-webhook.yaml +
  webhook/k8s/agent-deployment-webhook-no-spiffe.yaml
  - Top-of-file "containers injected" lists were the old multi-
    sidecar shape (proxy-init + spiffe-helper +
    kagenti-client-registration + envoy-proxy). Rewrite to the
    post-rossoctl#411 shape (one combined sidecar, container name
    depends on mode, spiffe-helper bundled, registration
    operator-managed). The no-spiffe variant explicitly notes
    that the bundled spiffe-helper stays inactive when
    SPIRE_ENABLED=false.

No structural document changes; the demo flows themselves still
work end-to-end. Container-name updates throughout match the
operator's `AuthBridgeProxyContainerName = "authbridge-proxy"` /
`EnvoyProxyContainerName = "envoy-proxy"` constants.

Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com>
Signed-off-by: Hai Huang <huang195@gmail.com>
huang195 added a commit to huang195/kagenti-extensions that referenced this pull request May 15, 2026
Replace the two broken-after-rossoctl#411 standalone demos
(`single-target/`, `multi-target/`) with a single configuration-only
reference at `demos/token-exchange-routes/`. Both old demos used the
pre-rossoctl#411 multi-sidecar pattern (envoy-proxy + authbridge-light +
client-registration + standalone spiffe-helper) with images that no
longer publish; rewriting their YAMLs to the combined-sidecar shape
is real per-demo work that needs runtime testing. The route-config
content is the part that's still useful and isn't covered well by
other demos, so extract that.

New `demos/token-exchange-routes/README.md` covers:
- How AuthBridge's outbound `token-exchange` plugin matches the
  request `Host` header against `authproxy-routes` entries and
  performs RFC 8693 exchange.
- ConfigMap shape: per-route `host` / `target_audience` /
  `token_scopes` fields, with `kubectl create configmap` example.
- Single-target example (one route entry, weather-tool style).
- Multi-target example (three routes; the existing
  `routes.yaml` is moved into this directory unchanged as a
  worked example).
- Mixing exchange and passthrough (default policy);
  tightening to `default_policy: exchange` for tool-only
  namespaces.
- Glob pattern semantics — `filepath.Match` quirks around `**`,
  short-name matching, etc.
- Troubleshooting: `Host` mismatches, missing scopes on the
  agent's own Keycloak client, audience errors at the target,
  routes-not-reloaded.
- Cross-references to `weather-agent/demo-ui-advanced.md` and
  `webhook/README.md` for the deployment side.

Removed:
- `demos/single-target/` (entire directory) — covered by webhook +
  weather-agent demos plus the new routes reference; manual
  multi-sidecar deployment YAMLs were the broken bit.
- `demos/multi-target/{demo.md,run-demo-commands.sh,teardown-demo.sh,k8s/}`
  — the script-driven flow tied to the dead `agent` Deployment in
  the `authbridge` namespace; not worth migrating.

Renamed:
- `demos/multi-target/` → `demos/token-exchange-routes/`
  (`git mv` preserves history on `routes.yaml`).

Cross-references updated everywhere:
- `demos/README.md` table: drop the strikethrough rows + warning
  paragraph; add Token-Exchange Routes / MCP Parser / abctl
  Walkthrough as Reference-tier entries; the recommended-path
  step 3 points at the new routes guide.
- `demos/github-issue/{demo.md,demo-ui.md,demo-manual.md}`,
  `demos/weather-agent/demo-ui.md` — "Multi-Target Demo" links
  retargeted to `../token-exchange-routes/README.md` with updated
  link labels.
- `authbridge/README.md` overview link bullet + the demos list at
  the bottom collapsed to one Token-Exchange Routes entry.
- `authbridge/CLAUDE.md` — directory tree + demo descriptions +
  Keycloak setup-script table updated; gotcha rossoctl#6 (hardcoded SPIFFE
  ID in `single-target/setup_keycloak.py`) removed since the file
  is gone, remaining gotchas renumbered.
- `CLAUDE.md` (top-level) — directory listing line + manual-
  deployment learning-path bullet retargeted at the new routes
  guide.
- `demos/webhook/setup_keycloak.py` — comment that pointed at
  `single-target/k8s/authbridge-deployment.yaml` for the
  `envoy-config` ConfigMap retargeted at the kagenti-system
  release namespace.

Existing single/multi-target sweep banners from earlier in this PR
(broken-after-rossoctl#411 YAML headers) are deleted with the YAMLs.

Net diff: -1,500 lines (the two broken demos), +210 lines (the new
consolidated reference + cross-ref updates). Repo-wide grep for
`single-target/` and `multi-target/` now matches only on prose
that uses those words descriptively (e.g. "single-target route
pattern"), not as path components.

Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com>
Signed-off-by: Hai Huang <huang195@gmail.com>
huang195 added a commit to huang195/kagenti-extensions that referenced this pull request May 15, 2026
The github-issue demo (the recommended-path "intermediate" demo) was
written for the pre-rossoctl#411 multi-sidecar pattern: four containers per
agent pod (`agent` + `spiffe-helper` + `kagenti-client-registration`
+ `envoy-proxy`), all `kubectl exec/logs -c <sidecar>` blocks
targeting names that no longer exist, and a `combinedSidecar`
feature gate that was removed. Anyone following the demo today
hits container-not-found errors at every verification step.

Updates across all four files:

* `demo.md` (index) — architecture component list rewritten:
  two-container pod (agent + AuthBridge sidecar; container name
  depends on resolved mode), spiffe-helper bundled inside, client
  registration operator-managed.

* `k8s/git-issue-agent-deployment.yaml` — top-of-file injection
  comment rewritten to describe the post-rossoctl#411 shape: one combined
  sidecar with mode-dependent container name; proxy-init only in
  envoy-sidecar mode; operator-managed registration via the
  `kagenti-keycloak-client-credentials-<hash>` Secret mounted at
  `/shared/`.

* `demo-manual.md` — full rewrite of the architecture diagram and
  every verification block:
  - Agent pod ASCII diagram: 3+1 boxes collapsed into 1+1, with
    explicit per-mode container names and operator-managed
    registration callout.
  - "Verify injected containers" step: expected output flipped
    from `agent spiffe-helper kagenti-client-registration envoy-proxy`
    to `agent authbridge-proxy` (or `agent envoy-proxy` for
    envoy-sidecar). Pod ready count `4/4` → `2/2`.
  - "Check client registration" step: replaced the `-c
    kagenti-client-registration` log inspection with a
    Secret-name-based mount check + a kagenti-controller-manager
    log filter for the actual reconciler activity.
  - All `kubectl exec/logs -c envoy-proxy` blocks: rewritten to
    auto-detect the sidecar container name via a `$SIDECAR` shell
    variable that greps for `authbridge-proxy|envoy-proxy`.
  - "Agent Pod Not Starting (4/4 containers)" troubleshooting:
    rewritten for 1/2 / 0/2 with the operator log fallback added
    for stuck-on-shared-secret cases.

* `demo-ui.md` — same treatment as demo-manual.md, plus:
  - Architecture diagram parallel update.
  - "Sidecar Modes" section that previously documented two
    branches (legacy `combinedSidecar: false` vs combined
    `combinedSidecar: true`) collapsed into a single description
    of the post-rossoctl#411 cluster default. The link to the
    `combinedSidecar` feature-gate doc removed (the gate is gone).
  - "Agent card not available" troubleshooting block: log
    inspection rewritten to use the `$SIDECAR` auto-detect.

Net effect: every command in the demo now works against either
proxy-sidecar (cluster default) or envoy-sidecar mode without
manual fixup, and every architecture description matches what the
operator actually injects post-rossoctl#411.

Verified: `grep -n` for `kagenti-client-registration` returns zero
hits across all four files; remaining `envoy-proxy` matches are
all in the per-mode comments and shell auto-detect blocks (i.e.,
correctly describing envoy-sidecar mode), not stale references.

Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com>
Signed-off-by: Hai Huang <huang195@gmail.com>
huang195 added a commit to huang195/kagenti-extensions that referenced this pull request May 16, 2026
Combined cleanup that eliminates the last remnants of the pre-rossoctl#411
multi-sidecar architecture from the repo. Three coordinated moves:

1. Delete the webhook demo

The webhook demo was a synthetic-workload demonstration of "the
webhook injects sidecars" — but post-rossoctl#411, webhook injection is the
only path; every demo uses it implicitly. Its USP is gone, and its
images (auth-proxy:latest, demo-app:latest) were dropped from CI long
ago — anyone running it today hits ImagePullBackOff unless they
rebuild locally. The same coverage (inbound validation + outbound
token exchange) is provided by the weather-agent advanced and
github-issue demos, which use real workloads. Drop:

- authbridge/demos/webhook/ (entire dir): README.md, k8s/, setup_keycloak.py

2. Cascade the auth-proxy + demo-app source

With the webhook demo gone, nothing else references the auth-proxy
or demo-app images, so the source can go too:

- authbridge/authproxy/main.go + Dockerfile (auth-proxy app source)
- authbridge/authproxy/k8s/auth-proxy-deployment.yaml (already broken
  standalone deployment)
- authbridge/authproxy/quickstart/ (entire subtree — README.md,
  setup_keycloak.py, requirements.txt, k8s/demo-app-deployment.yaml,
  demo-app/main.go + Dockerfile)
- authbridge/authproxy/go.mod + go.sum (no Go code remains)
- authbridge/authproxy/Makefile build/deploy/test targets that
  reference any of the above

3. Rename authproxy/ → proxy-init/

What's left in authbridge/authproxy/ after the cascade is exactly
the iptables init container and nothing else (init-iptables.sh +
Dockerfile.init + a trimmed Makefile + a rewritten README focused
on just the init container's role). The directory name authproxy
no longer matches what's inside, and the pre-commit hooks
go-fmt-authproxy / go-vet-authproxy were already orphaned with no
.go files to scan. Rename to proxy-init/ — matches the image name
and the container name the operator injects.

Cross-reference sweep across 14 supporting files:

* `local-build-and-test.sh` — path updated.
* `Makefile` (root) — fmt now iterates over the live Go modules;
  build-images target replaced with build-proxy-init.
* `.pre-commit-config.yaml` — drop the orphaned
  go-fmt-authproxy / go-vet-authproxy hooks.
* `.github/workflows/ci.yaml` — drop the dedicated `go-ci` job
  (no Go module to test); update the pre-commit job's
  go-version-file to reference authlib/go.mod; rewrite the
  GOWORK="off" comment that named the deleted authproxy module.
* `.github/workflows/build.yaml` — proxy-init context path bumped.
* `.github/workflows/security-scans.yaml` — drop the
  authbridge/proxy-init/quickstart skip-dir entry (path is gone).
* `.github/dependabot.yml` — rewrite. Drop entries for the deleted
  authproxy/quickstart/demo-app docker image, the now-Go-less
  authproxy go.mod, the never-existed authproxy/client-registration
  pip + docker entries. Add the four authlib + cmd/* go.mod
  entries that were missing entirely.
* `authbridge/go.work` — drop ./authproxy from the workspace.
* `authbridge/CLAUDE.md` — directory tree, demo descriptions,
  Keycloak setup-script table, build/deploy section, and the
  envoy-config + required-ConfigMaps sections all rewritten to
  reference the kagenti Helm chart's templates instead of the
  deleted demos/webhook/k8s/configmaps-webhook.yaml. Gotcha rossoctl#5
  (virtualenv in deleted quickstart) removed; remaining gotchas
  renumbered.
* `CLAUDE.md` (root) — directory tree updated; ci.yaml description
  no longer mentions authproxy as a separate Go target;
  manual-deployment learning-path bullet retargeted at the
  routes-config doc.
* `authbridge/README.md` — the "AuthProxy" link bullets that
  described an Envoy + ext_proc binary (which doesn't exist
  anymore — that's authbridge-envoy now) replaced with bullets
  describing each cmd/* binary plus proxy-init.
* `README.md` (root) — same overview rewrite; broken
  ./authbridge/client-registration/ link removed.
* `LOCAL_TESTING_GUIDE.md` — Webhook Demo bullet retargeted at the
  token-exchange-routes guide; deprecation banner alternatives
  list updated to point at github-issue instead of the deleted
  webhook demo.
* `authbridge/demos/README.md` — Webhook row + description block
  removed from the demos table.
* `authbridge/demos/token-exchange-routes/README.md` — two
  broken `../webhook/` links retargeted at github-issue.
* `authbridge/demos/weather-agent/k8s/weather-tool-advanced.yaml`
  — the comment line that pointed at the deleted webhook README
  for the type-label rule retargeted at the operator's webhook
  source.

Net diff: 23 files modified, 14 deleted, 1 dir renamed (1 file moved
via git mv). About -1,800 LOC of unmaintained, broken-image-dependent
content; +120 LOC of corrected prose and the trimmed proxy-init
Makefile/README. End-state directory layout: each subdirectory under
authbridge/ has a name that matches what's inside, no orphaned hooks,
no broken cross-references, no dead-image references.

Verified: `bash -n local-build-and-test.sh`; `kubectl apply
--dry-run=client` on the surviving demo YAMLs; `helm template` on
the kagenti chart still renders (confirms our path changes don't
break anyone consuming the chart); repo-wide grep for
`authbridge/authproxy` returns zero hits in tracked content;
broken-link grep on demos/webhook/ matches only inside the
LOCAL_TESTING_GUIDE.md deprecation banner that was already flagged
as stale earlier in this PR.

Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com>
Signed-off-by: Hai Huang <huang195@gmail.com>
huang195 added a commit to huang195/kagenti-extensions that referenced this pull request May 16, 2026
Combined cleanup that eliminates the last remnants of the pre-rossoctl#411
multi-sidecar architecture from the repo. Three coordinated moves:

1. Delete the webhook demo

The webhook demo was a synthetic-workload demonstration of "the
webhook injects sidecars" — but post-rossoctl#411, webhook injection is the
only path; every demo uses it implicitly. Its USP is gone, and its
images (auth-proxy:latest, demo-app:latest) were dropped from CI long
ago — anyone running it today hits ImagePullBackOff unless they
rebuild locally. The same coverage (inbound validation + outbound
token exchange) is provided by the weather-agent advanced and
github-issue demos, which use real workloads. Drop:

- authbridge/demos/webhook/ (entire dir): README.md, k8s/, setup_keycloak.py

2. Cascade the auth-proxy + demo-app source

With the webhook demo gone, nothing else references the auth-proxy
or demo-app images, so the source can go too:

- authbridge/authproxy/main.go + Dockerfile (auth-proxy app source)
- authbridge/authproxy/k8s/auth-proxy-deployment.yaml (already broken
  standalone deployment)
- authbridge/authproxy/quickstart/ (entire subtree — README.md,
  setup_keycloak.py, requirements.txt, k8s/demo-app-deployment.yaml,
  demo-app/main.go + Dockerfile)
- authbridge/authproxy/go.mod + go.sum (no Go code remains)
- authbridge/authproxy/Makefile build/deploy/test targets that
  reference any of the above

3. Rename authproxy/ → proxy-init/

What's left in authbridge/authproxy/ after the cascade is exactly
the iptables init container and nothing else (init-iptables.sh +
Dockerfile.init + a trimmed Makefile + a rewritten README focused
on just the init container's role). The directory name authproxy
no longer matches what's inside, and the pre-commit hooks
go-fmt-authproxy / go-vet-authproxy were already orphaned with no
.go files to scan. Rename to proxy-init/ — matches the image name
and the container name the operator injects.

Cross-reference sweep across 14 supporting files:

* `local-build-and-test.sh` — path updated.
* `Makefile` (root) — fmt now iterates over the live Go modules;
  build-images target replaced with build-proxy-init.
* `.pre-commit-config.yaml` — drop the orphaned
  go-fmt-authproxy / go-vet-authproxy hooks.
* `.github/workflows/ci.yaml` — drop the dedicated `go-ci` job
  (no Go module to test); update the pre-commit job's
  go-version-file to reference authlib/go.mod; rewrite the
  GOWORK="off" comment that named the deleted authproxy module.
* `.github/workflows/build.yaml` — proxy-init context path bumped.
* `.github/workflows/security-scans.yaml` — drop the
  authbridge/proxy-init/quickstart skip-dir entry (path is gone).
* `.github/dependabot.yml` — rewrite. Drop entries for the deleted
  authproxy/quickstart/demo-app docker image, the now-Go-less
  authproxy go.mod, the never-existed authproxy/client-registration
  pip + docker entries. Add the four authlib + cmd/* go.mod
  entries that were missing entirely.
* `authbridge/go.work` — drop ./authproxy from the workspace.
* `authbridge/CLAUDE.md` — directory tree, demo descriptions,
  Keycloak setup-script table, build/deploy section, and the
  envoy-config + required-ConfigMaps sections all rewritten to
  reference the kagenti Helm chart's templates instead of the
  deleted demos/webhook/k8s/configmaps-webhook.yaml. Gotcha rossoctl#5
  (virtualenv in deleted quickstart) removed; remaining gotchas
  renumbered.
* `CLAUDE.md` (root) — directory tree updated; ci.yaml description
  no longer mentions authproxy as a separate Go target;
  manual-deployment learning-path bullet retargeted at the
  routes-config doc.
* `authbridge/README.md` — the "AuthProxy" link bullets that
  described an Envoy + ext_proc binary (which doesn't exist
  anymore — that's authbridge-envoy now) replaced with bullets
  describing each cmd/* binary plus proxy-init.
* `README.md` (root) — same overview rewrite; broken
  ./authbridge/client-registration/ link removed.
* `LOCAL_TESTING_GUIDE.md` — Webhook Demo bullet retargeted at the
  token-exchange-routes guide; deprecation banner alternatives
  list updated to point at github-issue instead of the deleted
  webhook demo.
* `authbridge/demos/README.md` — Webhook row + description block
  removed from the demos table.
* `authbridge/demos/token-exchange-routes/README.md` — two
  broken `../webhook/` links retargeted at github-issue.
* `authbridge/demos/weather-agent/k8s/weather-tool-advanced.yaml`
  — the comment line that pointed at the deleted webhook README
  for the type-label rule retargeted at the operator's webhook
  source.

Net diff: 23 files modified, 14 deleted, 1 dir renamed (1 file moved
via git mv). About -1,800 LOC of unmaintained, broken-image-dependent
content; +120 LOC of corrected prose and the trimmed proxy-init
Makefile/README. End-state directory layout: each subdirectory under
authbridge/ has a name that matches what's inside, no orphaned hooks,
no broken cross-references, no dead-image references.

Verified: `bash -n local-build-and-test.sh`; `kubectl apply
--dry-run=client` on the surviving demo YAMLs; `helm template` on
the kagenti chart still renders (confirms our path changes don't
break anyone consuming the chart); repo-wide grep for
`authbridge/authproxy` returns zero hits in tracked content;
broken-link grep on demos/webhook/ matches only inside the
LOCAL_TESTING_GUIDE.md deprecation banner that was already flagged
as stale earlier in this PR.

Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com>
Signed-off-by: Hai Huang <huang195@gmail.com>
huang195 added a commit to huang195/kagenti-extensions that referenced this pull request May 16, 2026
…DME sweep

Four small followups missed in the earlier sweep. All in scope of
the post-rossoctl#411 cleanup; they survived because previous edits to the
same files only touched the deployment-modes table + demos list,
not the prose / diagrams / component-doc list.

* `authbridge/README.md` line 3 — opening paragraph linked to two
  deleted/renamed paths: `[client registration](./client-registration/)`
  (no such directory in the repo) and `[token exchange](./authproxy/)`
  (renamed to `proxy-init/` in commit 0416172, and `proxy-init/`
  is just iptables — not a "token exchange" component anyway).
  Rewrite the paragraph to point at `authlib/` + `cmd/` for the
  actual code, with an explicit note that registration is now
  operator-managed.

* `authbridge/README.md` ASCII architecture diagram — the box
  labeled `client-registration (registers Workload with Keycloak)`
  is gone (operator-managed), so drop that box. The "AuthProxy
  Sidecar" header was rewritten to "AuthBridge Sidecar (combined
  image)" with the per-mode container-name disambiguation
  (`authbridge-proxy` / `envoy-proxy`) we already established
  elsewhere. Spiffe-helper is also no longer a separate box —
  bundled inside the combined image, gated by `SPIRE_ENABLED`,
  noted inline. Add an out-of-band footer naming the operator's
  ClientRegistrationReconciler + the
  `kagenti-keycloak-client-credentials-<hash>` Secret it produces.

* `authbridge/README.md` Mermaid architecture diagram — same
  treatment: collapse SpiffeHelper + ClientReg + Sidecar (which
  was three sub-nodes — auth-proxy + envoy-proxy + ext-proc) into
  one Sidecar node with the per-mode name. Move ClientRegistration
  into a new `Operator (kagenti-system)` subgraph so the diagram
  shows it living outside the workload pod. Renumber the
  request-flow arrows from 1-11 to 1-9 reflecting the simplified
  shape.

* `authbridge/README.md` Workload Pod table — drop the
  `client-registration` row, and split the single `AuthProxy
  Sidecar` row into two per-mode rows (`authbridge-proxy` and
  `envoy-proxy`) with a `Mode` column. Add a brief lead-in
  paragraph explaining the post-rossoctl#411 shape.

* `authbridge/README.md` Component Documentation links — both
  `[AuthProxy](authproxy/README.md)` and
  `[Client Registration](client-registration/README.md)` 404 now.
  Replace with one bullet per mode-specific cmd/* binary plus
  proxy-init plus authlib plus a pointer at the `docs/` directory
  that holds the framework / plugin author references. Add a
  trailing note that registration is operator-managed (the
  `Client Registration` link's purpose).

* `CLAUDE.md` lines 265-266 — the "Routes config reference" line
  appeared twice (once bare, once with the parenthetical). Drop
  the bare duplicate; keep the more informative one.

Verified: every link in authbridge/README.md resolves; repo-wide
grep confirms the only remaining `client-registration` mentions
in this file are descriptive prose about the post-rossoctl#411 migration
("standalone client-registration / spiffe-helper sidecars are
gone"), not paths or component references.

Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com>
Signed-off-by: Hai Huang <huang195@gmail.com>
huang195 added a commit that referenced this pull request May 16, 2026
The advanced weather demo's two pod templates carried
`kagenti.io/client-registration-inject: "true"`, which after PR #411
silently disables registration:

* The operator's ClientRegistrationReconciler treats this label as a
  signal to skip — `SkipReason` in
  kagenti-operator/internal/clientreg/names.go:58 returns "label is
  true (legacy webhook client-registration sidecar; operator-managed
  registration disabled for this workload)".
* The legacy in-pod kagenti-client-registration sidecar that the
  label was supposed to defer to was removed in #411.

Net effect: setting this label today produces a workload with NO
Keycloak client registered at all, and `setup_keycloak_weather_advanced.py
--wait-tool-client` correctly times out waiting for a SPIFFE-shaped
client (`spiffe://localtest.me/ns/<ns>/sa/<sa>`) that nobody will ever
create. This was hiding behind the kagenti repo's MLflow e2e
failures upstream — once those were fixed, the AuthBridge weather
e2e exposed the latent bug.

Drop the label from both pod templates:
* k8s/weather-tool-advanced.yaml
* k8s/weather-service-advanced.yaml

Plus refresh the two doc references that were directing readers to
set the label:
* demos/weather-agent/demo-ui-advanced.md — replace the bullet that
  recommended the label with one explaining operator-managed
  registration is now the only path.
* demos/webhook/README.md — rewrite the "client registration" bullet
  to call out the label as removed and explain why setting it today
  silently breaks registration.

Verified: `kubectl apply --dry-run=client -f` on both YAMLs renders
clean. Repo grep for the label only matches the two doc references
above (both now phrased as "don't set it").

Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com>
Signed-off-by: Hai Huang <huang195@gmail.com>
huang195 added a commit that referenced this pull request May 16, 2026
…gistration-inject

fix: sweep post-#411 stale references (dead labels, dead images, dead docs)
huang195 added a commit to huang195/kagenti-extensions that referenced this pull request May 16, 2026
…er name

The `pick_log_container` helper in deploy_and_verify_advanced.sh
only knew two AuthBridge sidecar container names: `envoy-proxy`
(envoy-sidecar mode) and `authbridge` (the pre-split combined-mode
name from before rossoctl#411). After rossoctl#411 + kagenti-operator#361 the
cluster default became proxy-sidecar, whose container is named
`authbridge-proxy` — the script `die()`s on every CI run because
neither of its two known names matches.

Reproduced on kagenti#1592 just now. The pod actually had two
containers — `mcp` and `authbridge-proxy` — i.e. the webhook had
injected fine and the demo flow was healthy. The script just
couldn't tell which container to read logs from:

  ERROR: pod weather-tool-advanced-... has neither envoy-proxy
         nor authbridge container (mcp
         authbridge-proxy)

(The error message itself was misleading — the pod's container
list `mcp\nauthbridge-proxy` got split across two log lines, so
casual readers saw "(mcp" and assumed no sidecar was injected.)

Fix:

* Replace the two-branch if-elif with a small fallthrough loop
  over `authbridge-proxy / envoy-proxy / authbridge` so the
  cluster default's container name is recognized first, the
  envoy-sidecar mode's name still works, and the legacy combined
  name is kept for older clusters / replays.

* Wrap `$names` in `$(echo $names)` inside the die message so the
  pod's container list renders on a single line, making the
  diagnostic accurate ("expected one of …; got: mcp authbridge-proxy")
  rather than visually truncated.

Verified: bash -n on the script; repo grep finds no other places
with the same restricted-name pick.

Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com>
Signed-off-by: Hai Huang <huang195@gmail.com>
mrsabath added a commit to mrsabath/kagenti-extensions that referenced this pull request Jun 3, 2026
Hai is right — on kagenti main, AuthBridge ships as a single combined
sidecar image (kagenti-extensions#411). The weather-service pod is 2/2
regardless of SPIRE: spiffe-helper is bundled inside the combined image
and activated per workload via SPIRE_ENABLED, not as a separate
container. The deployment guide explicitly lists "1 combined sidecar"
for both proxy-sidecar and envoy-sidecar modes
(docs/authbridge/deployment-guide.md and charts/kagenti/values.yaml).

The 3/3 separate-spiffe-helper layout I introduced in 8dacc17 described
the pre-rossoctl#411 / v0.6 model — wrong for main.

Revert the container-count claim to 2/2 in both "Check pod status" and
"Verify injected containers" sections, and update the explanatory note
to match the combined-sidecar architecture. Container names returned by
kubectl ... containers[*].name are 'agent authbridge-proxy' (proxy mode)
or 'agent envoy-proxy' (envoy mode) regardless of SPIRE.

Addresses huang195's review on PR rossoctl#439.

Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com>
Signed-off-by: Mariusz Sabath <mrsabath@gmail.com>
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