Skip to content

controller: add A2AAgentRegistration CRD and reconciler - #3

Merged
Aman-Cool merged 12 commits into
mainfrom
a2a-crd-controller
Jul 4, 2026
Merged

controller: add A2AAgentRegistration CRD and reconciler#3
Aman-Cool merged 12 commits into
mainfrom
a2a-crd-controller

Conversation

@Aman-Cool

Copy link
Copy Markdown
Owner

Part of the A2A workshop (design: Kuadrant#1114, upstream issue: Kuadrant#766) ; this is Tasks 3-5 plus the minimal slice of Task 6 from the implementation plan — the CRD, the reconciler, and the config-writer plumbing it needs. Data-plane consumption of the a2aAgents config (MCPServersConfig field, loadConfig, broker observer) is deliberately NOT here.., that's Tasks 7/8, so the broker ignores the new config section until then.

The A2AAgentRegistration CRD mirrors MCPServerRegistration's machinery without cargo-culting its field set: agentPrefix (required, the /a2a/{prefix} routing key), targetRef, optional agentCardURL override, broker-only credentialRef, and state. Both agentPrefix and targetRef are immutable via CEL — retargeting a registration would leave the previous agent's config behind, so replacing an agent means replacing the registration (this also retires the TODO MCPServerRegistration carries about unhandled targetRef changes).

The reconciler follows the sibling controller's flow — finalizer-guarded config-first deletion, gateway/extension discovery with listener-attachment filtering, per-namespace config fan-out, the status no-op guard — with one deliberate strengthening: cross-namespace targetRef requires a ReferenceGrant in the route's namespace (from: A2AAgentRegistration, to: HTTPRoute), the same consent model MCPGatewayExtension uses and the boundary maleck13 called for on Kuadrant#1139. The controller watches ReferenceGrants (backed by a target-namespace index), and revoking a grant withdraws the previously written config rather than just flipping status.., consent withdrawn means exposure withdrawn. Everywhere else config stays last-known-good on failure, mirroring MCP, so transient errors never rip a live agent out of the data plane — the semantics are documented on the failure path.

Also here: the shared HTTPRoute gateway/endpoint helpers extracted to free functions so both registration controllers use them, config UpsertA2AAgent/RemoveA2AAgent with the same retry-on-conflict + skip-unchanged-write discipline, reference doc, sample, and the controller CLAUDE.md section.

Verification so far: 56/56 controller integration specs (envtest, --race) covering finalizer, happy path, deletion, disabled state, missing route, credentialRef paths incl. the required-label rejection, cross-namespace with and without a grant, grant revocation withdrawing config, and the CEL immutability rules ; kube-api-linter 0 issues ; generate-all idempotent. The earlier commits were verified end-to-end on a live Kind cluster (Ready=True, a2aAgents in the config Secret, deletion scrubbing) — the ReferenceGrant gate and immutability commits still need that live pass, which is the remaining item before this leaves draft. Findings from that run land here.

Aman-Cool added 6 commits July 2, 2026 12:11
Signed-off-by: Aman-Cool <aman017102007@gmail.com>
…nctions

Signed-off-by: Aman-Cool <aman017102007@gmail.com>
Signed-off-by: Aman-Cool <aman017102007@gmail.com>
Signed-off-by: Aman-Cool <aman017102007@gmail.com>
Signed-off-by: Aman-Cool <aman017102007@gmail.com>
Signed-off-by: Aman-Cool <aman017102007@gmail.com>
@Aman-Cool
Aman-Cool marked this pull request as ready for review July 4, 2026 10:08
@Aman-Cool

Copy link
Copy Markdown
Owner Author

Live verification done on Kind (Istio 1.27) against the tip... the fixed install-crd target applies the CRD, all three CEL rules reject mutations with the right messages (including targetRef.namespace; the retarget vector), same-namespace registration goes Ready with the derived config in the Secret, and the cross-namespace lifecycle works end to end: no grant -> NotReady with zero config written, grant created -> the ReferenceGrant watch flips it Ready within seconds, grant revoked -> the config is withdrawn from the Secret, not just the status; and deletion scrubs everything. The CI round also earned its keep: it caught the CRD missing from the explicit install lists (real crash in a fresh cluster), a stale OLM bundle, and the dupl hit that's now a shared generic writer core. Marking ready as e2e goes green after #4.

… receivers

Signed-off-by: Aman-Cool <aman017102007@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant