Skip to content

feat(a2a-contract): freeze runtime tenant-registration contract (v1.3.0) - #204

Open
claude[bot] wants to merge 3 commits into
mainfrom
feat/a2a-tenant-registration-contract
Open

feat(a2a-contract): freeze runtime tenant-registration contract (v1.3.0)#204
claude[bot] wants to merge 3 commits into
mainfrom
feat/a2a-tenant-registration-contract

Conversation

@claude

@claude claude Bot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Frozen A2A contract v1.3.0 — runtime tenant registration (Slice 4 gate)

Additive MINOR bump within the frozen A2A contract v1 for the runtime-registration topology decided in #203. This is the first slice and it GATES all implementation (Slice 1 migration, orchestrator handlers, Slice 3 server reader, tests, docs). Contract + generated client only — no server, migration, or handlers.

What changes (the move, from #203)

The shared A2A server stops learning its tenants at git/build time from the static a2a.tenants[] values ConfigMap (+ initContainer repo clone). Instead:

  1. HTTP-to-orchestrator — the A2A server stays stateless/DB-free and fetches the tenant set over HTTP; the orchestrator owns the registry DB.
  2. Card-as-data — the consumer pushes its projected Agent Card at registration; the server validates and stores it. The card projection output is byte-identical to today — only its delivery changes.
  3. Self-registration authz — authenticated by the OIDC caller-repo claim (the same auth.callerClaim the A2A server validates today); a registration whose tenant/repo ≠ the authenticated identity is rejected 403 and never written.

Frozen surface

  • schema/tenant-registration.schema.json
    • RegisteredTenant — the canonical a2a_tenants record (tenant unique key, repo, ref, entryRole, servingRoles[], external, provider, card, enabled, createdAt, updatedAt), frozen once so the DB migration and the server reader target one shape.
    • RegisterTenantRequest / RegisterTenantResponse — self-registration payload + upsert result.
    • TenantListGET /a2a/tenants response, marked x-pagination: exempt (bounded whole-set config read the A2A server resolves atomically).
    • card reuses agent-card.schema.json by reference (not redefined); a pushed card MUST additionally satisfy fuze-profile.schema.json.
  • tenant-registration.md — NORMATIVE: POST /a2a/tenants/register, GET /a2a/tenants (+ /{tenant}), idempotent-upsert semantics (201 create / 200 update, keyed on tenant), the OIDC self-registration security rule, the two-schema card-validation rule.
  • Generated clientclient/fuze_a2a_client/registration_models.py (via regenerate.sh, which now bundles the cross-file card ref for single-file codegen), exported from fuze_a2a_client. Package + VERSION bumped 1.0.0 → 1.3.0 (first bump since freeze that changes the generated surface).
  • examples/registration/fuzeplan.tenant-registration.json — worked fixture.
  • CHANGELOG + README updated.

Backward compatibility

Purely additive. values-interface.schema.json and the static a2a.tenants[] topology are unchanged and still valid; agent-card/fuze-profile/a2a-wire schemas, card-projection.md, binding.md, state-mapping.md, authz.md are untouched; wire_models/card_models are byte-identical after regeneration; both topologies serve byte-identical cards. A v1 consumer that does not use runtime registration is unaffected.

Validation

  • tenant-registration.schema.json valid Draft 2020-12; example validates end-to-end (cross-file card ref resolves); negatives rejected (additionalProperties:false, required fields).
  • Generated Pydantic models import and round-trip the example.
  • A2A conformance suite green (68 passed, 22 deselected).

Identifier / pagination standards

  • RegisterTenantRequest is x-client-assigned-id: allowedtenant is the natural registry key (must equal the card's AgentInterface.tenant and be derivable from the authenticated repo), no server-minted surrogate; additionalProperties:false throughout.
  • GET /a2a/tenants is x-pagination: exempt with a stated reason.

Out of scope — NOT in this PR (fan out AFTER freeze)

Slice 1 DB migration (a2a_tenants), the orchestrator POST /a2a/tenants/register + GET /a2a/tenants handlers, the Slice 3 stateless A2A server reader, acceptance/conformance tests for the live endpoints, and any chart/Argo wiring. This PR is the gate they build on.

Refs #203.


Generated by Claude Code

Additive MINOR bump within the frozen A2A contract v1 for the runtime
tenant-registration topology (#203): consumers self-register
into a DB registry owned by the orchestrator and push their projected Agent Card
as data; the stateless A2A server resolves the tenant set over HTTP instead of
from the static a2a.tenants[] values ConfigMap.

Frozen surface (interface only — no server, migration or handlers):
- schema/tenant-registration.schema.json: RegisteredTenant (the a2a_tenants
  record), RegisterTenantRequest/Response, TenantList. The `card` field reuses
  agent-card.schema.json by reference (byte-identical projected card, not
  redefined); a pushed card must additionally satisfy fuze-profile.schema.json.
- tenant-registration.md: NORMATIVE spec for POST /a2a/tenants/register and
  GET /a2a/tenants[/{tenant}] — idempotent upsert keyed on `tenant`, the OIDC
  caller-repo self-registration rule (tenant/repo != authenticated identity =>
  403, never written), and the two-schema card-validation rule.
- Generated client: registration_models.py + fuze_a2a_client exports; package
  and VERSION bumped to 1.3.0; CHANGELOG + README updated.

Purely additive: values-interface.schema.json and the static a2a.tenants[]
topology are unchanged; wire_models/card_models are byte-identical after regen;
the two topologies serve byte-identical cards. Conformance suite green (68 passed).

GET /a2a/tenants is x-pagination: exempt (bounded whole-set config read).
RegisterTenantRequest is x-client-assigned-id: allowed (`tenant` is the natural key).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SVW8cHupvBPDfiuB9jdXsF
@claude
claude Bot requested a review from izzywdev as a code owner August 27, 2026 04:44

Copy link
Copy Markdown
Owner

dependency-check is failing on a pre-existing CVE unrelated to this PR — standing down on it here.

pip-audit flags 3 vulnerabilities in chromadb 1.1.1 (CVE-2026-45830, -45831, -45833), pulled in via services/orchestrator/requirements.txt (chromadb>=0.5.0,<2.0.0). This PR adds only the frozen v1.3.0 A2A contract (JSON schemas + docs) and a datamodel-codegen'd fuze_a2a_client — it does not touch chromadb or any orchestrator dependency, so the failure reproduces independently of this change.

I'm not porting a fix here: bumping chromadb to a patched release is a dependency/security change owned by the security workstream, and folding it into a frozen-contract PR would widen the PR beyond its slice. Flagging it separately for CVE triage (the constrained range <2.0.0 should admit a patched chromadb).

Every other check is green; this contract slice is otherwise ready for human review.


Generated by Claude Code

…ackage

The orchestrator connects to the FuzeInfra-provisioned ChromaDB via
chromadb.HttpClient (services/orchestrator/rag_integration.py) — it never
embeds a ChromaDB server. Pinning the full `chromadb` package dragged in the
vulnerable server surface (CVE-2026-45830/45831/45833 in 1.1.1), failing
dependency-check and backend-security-scan. The thin `chromadb-client` package
provides chromadb.HttpClient + chromadb.config.Settings (API-identical for our
usage) and pip-audit reports no known vulnerabilities. Server provisioning stays
FuzeInfra's; the product repo carries the client only.

Co-authored-by: Israel Weinberg <99821070+izzywdev@users.noreply.github.com>

Copy link
Copy Markdown
Owner

Update — fixed properly (not suppressed). Pushed 44394d3: services/orchestrator/requirements.txt now depends on chromadb-client instead of the full chromadb package.

The orchestrator only ever connects via chromadb.HttpClient to the FuzeInfra-provisioned ChromaDB (rag_integration.py) — it never embeds a server — so the full package was needlessly dragging in the vulnerable server surface (CVE-2026-45830/45831/45833). Validated locally: chromadb-client>=0.5.0,<2.0.0 (resolves 1.5.9) provides chromadb.HttpClient + chromadb.config.Settings (API-identical for our usage), and pip-audit reports no known vulnerabilities. No --ignore-vuln, no assertion weakened — the server surface is simply gone from the product repo, where server provisioning is FuzeInfra's job. This should clear both dependency-check and backend-security-scan.


Generated by Claude Code

The chromadb-client swap could not clear the CVE: crewai (used by
agent_manager.py and claude_code_wrapper.py) declares chromadb~=1.1.0 as a
core dependency, so the full chromadb 1.1.1 is installed transitively no matter
what the orchestrator's own line says — and shipping chromadb-client alongside it
would clash on the chromadb module namespace. Every chromadb release
(1.1.1 through 1.5.9) is flagged for CVE-2026-45830/45831/45833 with no fixed
version, so there is no dependency-level fix. Restoring the original line; the
chromadb/crewai remediation is a separate security decision, pre-existing and
independent of this contract PR.

Co-authored-by: Israel Weinberg <99821070+izzywdev@users.noreply.github.com>

Copy link
Copy Markdown
Owner

Correction — the chromadb-client swap did not work, and I reverted it (535e184). Root cause, verified:

  • crewai hard-pins it. crewai==1.15.17 declares Requires-Dist: chromadb~=1.1.0 as a core dependency, and crewai is used by agent_manager.py / claude_code_wrapper.py. So the full chromadb 1.1.1 is installed transitively regardless of the orchestrator's own requirement line, and shipping chromadb-client beside it would clash on the chromadb module namespace.
  • No chromadb release is clean. pip-audit flags CVE-2026-45830/45831/45833 on every version from 1.1.1 through the latest 1.5.9, with no fixed version published. A version bump cannot clear it.

So there is no dependency-level fix for this check. It is pre-existing (fails on main for the same reason) and unrelated to this PR's contract diff, which is clean and green on every non-chromadb check.

Two real remediation paths, both a separate security decision (not this contract PR's to make):

  1. Documented --ignore-vuln for the three CVEs in the scan jobs — matching this repo's existing precedent for the unfixable PYSEC-2026-311 — with a tracking issue.
  2. Remove/replace crewai's embedded chromadb (the architecturally-aligned fix: the product repo shouldn't carry an embedded vector-store server at all). That's a refactor of the crewai usage, not a dependency tweak.

Generated by Claude Code

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.

2 participants