Skip to content

feat: @peac/mappings-a2a for A2A evidence carrier#416

Merged
jithinraj merged 16 commits intomainfrom
feat/mappings-a2a
Feb 23, 2026
Merged

feat: @peac/mappings-a2a for A2A evidence carrier#416
jithinraj merged 16 commits intomainfrom
feat/mappings-a2a

Conversation

@jithinraj
Copy link
Member

Summary

  • New @peac/mappings-a2a package: Agent-to-Agent Protocol (A2A) v0.3.0 integration for PEAC evidence carriers
  • Minimal A2A types from spec v0.3.0 (no @a2a-js/sdk dependency per DD-126)
  • Attach/extract functions for metadata, TaskStatus, Message, and Artifact
  • Sync + async extraction paths (DD-129 receipt_ref consistency check)
  • SSRF-hardened agent discovery (Polish C: scheme allowlist, private IP rejection, 256KB cap)
  • 62 tests across 5 test files

Key Design

A2A Metadata Layout (DD-128)

Extension URI as metadata key, nested carrier payload as value:

{
  "metadata": {
    "https://www.peacprotocol.org/ext/traceability/v1": {
      "carriers": [{ "receipt_ref": "sha256:...", "receipt_jws": "eyJ..." }],
      "meta": { "transport": "a2a", "format": "embed", "max_size": 65536 }
    }
  }
}

DD-129 Async Extraction

  • extractReceiptFromMetadata() (sync): structural validation only (schema check)
  • extractReceiptFromMetadataAsync() (async): + verifyReceiptRefConsistency() check

SSRF Hardening (Polish C)

  1. Scheme allowlist: HTTPS only; HTTP for localhost with allowInsecureLocalhost
  2. Private IP rejection (RFC 1918, RFC 4193, loopback, link-local)
  3. Response size cap: 256 KB
  4. Content-Type check: application/json or application/*+json
  5. Redirect rejection: redirect: "error"
  6. Timeout: 5 seconds

Test plan

  • Round-trip: attach -> extract returns identical carrier (11 attach tests)
  • Schema validation at extraction (DD-131): invalid carriers skipped (19 extract tests)
  • Async DD-129 consistency: tampered carriers detected (4 async tests)
  • SSRF: private IPs rejected, HTTP blocked, oversized responses rejected (9 discovery tests)
  • Header round-trip: build -> parse (8 header tests)
  • CarrierAdapter: validateConstraints passes/fails correctly (8 carrier tests)
  • pnpm build (78/78), pnpm test (4308), lint, typecheck, guards all pass

Stacked on: PR #414 (feat/evidence-carrier-types)

Ship PeacEvidenceCarrier types (Layer 0, zero runtime) and Zod schemas
with shared computeReceiptRef() helper (Layer 1). Includes carrier
conformance fixtures (5 valid, 3 invalid) and verifyReceiptRefConsistency()
for DD-129 async extraction enforcement.

- kernel: PeacEvidenceCarrier, CarrierAdapter<T,U>, CarrierMeta types
- kernel: PEAC_RECEIPT_HEADER canonical constant (DD-127)
- schema: ReceiptRefSchema, CompactJwsSchema, PeacEvidenceCarrierSchema
- schema: computeReceiptRef() with WebCrypto runtime guard
- schema: validateCarrierConstraints() transport-aware validation
- schema: verifyReceiptRefConsistency() for tamper detection
- schema: CARRIER_TRANSPORT_LIMITS per-transport size constants
- conformance: 8 carrier fixtures in specs/conformance/fixtures/carrier/
- conformance: carrier category registered in manifest and tracking
…-128)

New mapping package for Agent-to-Agent Protocol (A2A) v0.3.0 integration.
Maps PEAC evidence carriers to A2A metadata using the PEAC extension URI
as the metadata key with nested carrier payload.

- types: minimal A2A types from spec v0.3.0 (no @a2a-js/sdk dependency)
- attach: attachReceiptToMetadata/TaskStatus/Message/Artifact
- extract: sync (structural, DD-131) + async (receipt_ref consistency, DD-129)
- carrier: A2ACarrierAdapter implementing CarrierAdapter interface
- header: parseA2AExtensionsHeader/buildA2AExtensionsHeader (DD-86)
- discovery: discoverAgentCard with SSRF hardening (scheme allowlist,
  private IP rejection, 256KB cap, content-type check, redirect rejection)
- 62 tests across 5 test files
* feat: discovery profile spec and 3-step algorithm (DD-110)

Discovery Profile (docs/specs/DISCOVERY-PROFILE.md):
- 3-step discovery algorithm: Agent Card -> well-known -> header probe
- SSRF protection requirements per Polish C
- PeacDiscoveryResult type with source attribution
- Caching recommendations and security considerations

Discovery code (@peac/mappings-a2a):
- discoverPeacCapabilities(): implements 3-step algorithm
- discoverPeacWellKnown(): /.well-known/peac.json discovery
- discoverPeacViaHeaderProbe(): HEAD request with PEAC-Receipt check
- PeacDiscoveryResult, PeacDiscoverySource types
- 8 new tests (24 total discovery tests)

* feat: strict discovery surface contract with shared JWKS resolver

Enforce the canonical 3-step JWKS resolution algorithm:
iss -> peac-issuer.json -> jwks_uri -> JWKS

- Add shared jwks-resolver.ts: single cache, strict discovery, 6 new
  kernel error codes (E_VERIFY_ISSUER_CONFIG_MISSING, _INVALID,
  _MISMATCH, JWKS_URI_INVALID, INSECURE_SCHEME_BLOCKED, JWKS_INVALID)
- Rewrite verify.ts to delegate to jwks-resolver (remove legacy
  fallback paths, local JWK/JWKS types, parallel cache)
- Rewrite verifier-core.ts to delegate to jwks-resolver (remove
  private fetchIssuerConfig, private cache, direct SSRF fetch)
- Add discovery surface drift guard to guard.sh (scoped to
  packages/protocol/src/*.ts production code)
- Update PEAC-ISSUER.md: strict key discovery section, new error table
- Update PEAC-TXT.md: peac.txt MUST NOT be used for key discovery
- Update docs/receipts.md and docs/ARCHITECTURE.md references
- Add 19 tests covering all error codes, caching, and no-fallback

* fix: discovery SSRF hardening and AGENTS.md A2A v0.3.0 alignment

Discovery (P0-2, P0-3, P1-A, P1-C):
- Add resolveHostname option for portable DNS rebinding defense
- Replace blanket proxy bypass claim with accurate proxy policy
- Add userinfo rejection (user:pass@host URLs blocked)
- Add RFC 8174 reference alongside RFC 2119 in normative keywords
- Spec sections 4.1, 4.7, 4.8 updated to match implementation
- 4 new tests: userinfo rejection, DNS rebinding (2), public IP pass

AGENTS.md (P1-B):
- Update A2A Agent Card example to v0.3.0 capabilities.extensions[]
- Fix discovery path to /.well-known/agent-card.json (v0.3.0 canonical)
- Update JWKS path to /.well-known/peac-issuer.json

* fix: JWKS resolver spec alignment and formatter corrections

Post-commit formatter corrections for JWKS resolver changes:
- PEAC-ISSUER.md: canonicalize issuer to origin, stricter jwks_uri validation
- guard.sh: updated discovery surface drift patterns
- Protocol test and implementation alignment

* fix: JWKS resolver improvements (issuer normalization, error taxonomy, LRU cache, drift gate)
DISCOVERY-PROFILE.md:
- Add RFC 8174 reference alongside RFC 2119 (P1-A)
- Rewrite section 4.1: portable two-level DNS rebinding defense
  with optional resolveHostname callback (P0-3)
- Rewrite section 4.7: accurate proxy policy covering Node.js
  --use-env-proxy and http.setGlobalProxyFromEnv() (P0-2)
- Add section 4.8: userinfo rejection requirement (P1-C)
- Add conformance items 6 (userinfo) and 7 (DNS resolution)

PEAC-ISSUER.md:
- Tighten verifier conformance: explicit MUST NOT assume JWKS
  location without resolving issuer config (section 13.2)
Clarifies that GitHub's bidi Unicode warning banner is heuristic;
the repo runs a fail-closed Trojan Source scan on every CI run and
local guard.sh invocation as the authoritative check.
PEAC-ISSUER.md:
- Add RFC 8174 to keyword clause and references section
- Add RFC 2119 to references section (was cited but not listed)
- Add language tags to fenced code blocks (pseudocode -> text)

PEAC-TXT.md:
- Add RFC 8174 to keyword clause and references section
- Add cross-reference to PEAC-ISSUER.md in references
- Add section 9.4 error codes table (9 error codes with HTTP mappings)
- Add language tags to fenced code blocks

AGENTS.md:
- Fix Key Directory to reference normative discovery chain
  (peac-issuer.json -> jwks_uri) instead of direct JWKS URL
- Add ES256 alongside EdDSA in supported algorithms
- Add Specification column with cross-references to spec docs

.github/SECURITY.md:
- Add 0.11.x to supported versions table
- Update algorithms: EdDSA (recommended) + ES256
- Update key rotation description to match JWKS kid model
- Bump specs/kernel/registries.json from 0.9.19 to 0.10.0
- Add stripe to payment_rails, a2a and ucp to agent_protocols
- Update docs/README_LONG.md: ten pillars, A2A mapping status,
  ES256 algorithm support, mcp-server/middleware/capture-node
  packages, layer map with L3.5/L5/L6, pnpm >= 9
…lish infra

- Discovery Profile: rename jwks_uri to issuer_config_url to prevent
  a second key-discovery path that bypasses the normative issuer chain
  (peac-issuer.json -> jwks_uri -> JWKS)
- JWKS resolver: return E_VERIFY_ISSUER_CONFIG_INVALID (not
  E_VERIFY_INSECURE_SCHEME_BLOCKED) for malformed/non-hierarchical
  issuer URLs
- Publish infra: add @peac/mappings-a2a to check-publish-list.sh
  expected packages and publish-manifest.json pendingTrustedPublishing
- Fix package count consistency in check-publish-list.sh (17 untested)
Per BCP 14, specs citing RFC 2119 keywords should also cite RFC 8174
to clarify that keywords are normative only when capitalized. Updated:
AGENT-IDENTITY, ATTRIBUTION, DISPUTE, INTERACTION-EVIDENCE,
PROTOCOL-BEHAVIOR, SCHEMA-NORMALIZATION.
@jithinraj jithinraj changed the title feat: @peac/mappings-a2a for A2A evidence carrier (DD-126, DD-128) feat: @peac/mappings-a2a for A2A evidence carrier Feb 23, 2026
@jithinraj jithinraj changed the base branch from feat/evidence-carrier-types to main February 23, 2026 18:45
@jithinraj jithinraj closed this Feb 23, 2026
@jithinraj jithinraj reopened this Feb 23, 2026
New error codes added in this branch (JWKS resolver, issuer config,
insecure scheme) were missing from the generated TypeScript file.
@jithinraj jithinraj merged commit b94f68a into main Feb 23, 2026
8 checks passed
@jithinraj jithinraj deleted the feat/mappings-a2a branch February 24, 2026 21:52
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