Skip to content

feat(a2a-trust-header): Week 3 dual-provider consumer verifier + canonical schema#6

Open
aeoess wants to merge 6 commits into
ScopeBlind:mainfrom
aeoess:feat/a2a-trust-header-week3-consumer-test
Open

feat(a2a-trust-header): Week 3 dual-provider consumer verifier + canonical schema#6
aeoess wants to merge 6 commits into
ScopeBlind:mainfrom
aeoess:feat/a2a-trust-header-week3-consumer-test

Conversation

@aeoess
Copy link
Copy Markdown
Contributor

@aeoess aeoess commented Apr 21, 2026

Summary

Week 3 of the Week 1 (schema lock) → Week 2 (APS fixtures, PR #2) → Week 3 arc for the A2A x-agent-trust header under a2aproject/A2A#1742.

This PR turns the Week 1 schema lock into runnable artifacts and adds MolTrust-shaped placeholder fixtures so the consumer verifier can exercise both provider shapes end-to-end before MolTrust ships their half.

What landed

  • Canonical JSON Schema (a2a-trust-header/schema/a2a-trust-header.schema.json): Draft 2020-12. 5 required fields: trust_level / attestation_count / last_verified / evidence_bundle / delegation_chain_root. delegation_chain_root is pattern-constrained to the self-describing sha256:<hex> OR uri:https?://… form. additionalProperties: true so providers can emit vendor-specific sibling fields without coupling the canonical contract.
  • Dual-provider consumer verifier (a2a-trust-header/consumer-verify.ts): discovers every fixture at the top of a2a-trust-header/ and under moltrust-placeholder/, classifies each by issuer (APS / MolTrust / unknown), derives the canonical composite view (direct for MolTrust-shape, synthesized for APS-shape), schema-validates via ajv + ajv-formats, and verifies every Ed25519 signature via @noble/ed25519 (no APS SDK dependency for signature verification, so MolTrust-side consumers can run it as-is). Emits per-fixture compliance rows and aggregate summary. Exit codes: 0 all-pass, 1 signature/chain-root failure, 2 schema failure.
  • 3 MolTrust-shaped placeholder fixtures (a2a-trust-header/moltrust-placeholder/): trust-trajectory-decay.json (4→3→2), attestation-accumulation.json (2→7→15), shared-happy-path-moltrust.json (re-signs the APS happy-path chain under the MolTrust placeholder key). All marked _placeholder: true / _replace_with_real_moltrust_emission: true. Signed with a deterministic test seed (tail 0xAA), public half embedded for round-trip verification. Generator committed so MolTrust can see exactly how the shape was constructed.
  • README Week 3 section covering the canonical schema, consumer-verifier contract + usage + exit codes, MolTrust placeholder catalog with clear replacement workflow, and shared Ed25519 / JCS conventions. Week 2 content preserved verbatim.

Week 2 → Week 3 diff

Week 2 Week 3
Fixtures 6 APS 6 APS + 3 MolTrust placeholder
Schema informal in #1742 thread schema/a2a-trust-header.schema.json, Draft 2020-12
Verifier APS-only round-trip (verify.ts) dual-provider consumer (consumer-verify.ts) + Week 2 round-trip
APS SDK coupling required for verification only for canonicalization; @noble/ed25519 for signatures
Portability verify.ts imported APS SDK via laptop-local absolute path npm-resolved

The Week 2 verify.ts absolute-path import (/Users/tima/agent-passport-system/src/index.js) was replaced with a portable import 'agent-passport-system' so any consumer, including MolTrust and CI, can run it. Week 2 round-trip is byte-identical otherwise: 6/6 fixtures still pass.

MolTrust placeholder replacement workflow

When MolTrust ships Week 3 on their side:

  1. Replace each fixture under moltrust-placeholder/ with their real emission. Keep filenames so the consumer verifier picks them up automatically.
  2. Drop the _placeholder / _replace_with_real_moltrust_emission fields.
  3. Replace moltrust_signing_key with production kid + pubkey and re-sign every emission under that key.
  4. Re-run npx tsx consumer-verify.ts. All 9 fixtures (6 APS + 3 MolTrust real) must pass schema + signature + chain-root checks, exit 0.

The consumer verifier does not implement MolTrust import weighting (0.3 weight, 45-day half-life, POST /identity/resolve before import) — that is a downstream policy decision. What this PR guarantees is the preconditions weighting sits on top of: every 5-field composite is schema-conformant, cryptographically verifiable, and chain-root consistent.

Verification output

$ npx tsx a2a-trust-header/verify.ts
6/6 fixtures round-trip through APS verifier.
(exit 0)

$ npx tsx a2a-trust-header/consumer-verify.ts
Consumer verify: aggregate
  APS fixtures:       6 / 6 pass
  MolTrust fixtures:  3 / 3 pass (placeholder)
  Unknown issuer:     0
  Schema failures:    0
  Signature failures: 0
  Chain-root drift:   0
(exit 0)

Not touched

  • None of the 6 Week 2 fixture JSON files (happy-path.json, drift-explicit-flag.json, revocation-mid-chain.json, shared-card-crossorg.json, trust-level-ascending.json, trust-level-descending.json), _keys.json, or generate.ts. Locked at the hashes committed in PR feat(a2a-trust-header): APS Week 2 fixture set per A2A#1742 #2.

Refs

aeoess added 6 commits April 21, 2026 10:47
Draft 2020-12 schema at schema/a2a-trust-header.schema.json lock of the
Week 1 agreement with MolTrust for A2A#1742 x-agent-trust header:
trust_level / attestation_count / last_verified / evidence_bundle /
delegation_chain_root, all required. delegation_chain_root is
pattern-constrained to sha256:<hex> OR uri:https://... per the
self-describing form agreed in #1742. additionalProperties: true so
providers can emit vendor-specific sibling fields without coupling
the canonical contract.

Refs: a2aproject/A2A#1742
Private workspace package. Deps:
  - agent-passport-system ^2.0.0 (canonicalizeJCS helper, SDK verifier)
  - @noble/ed25519 ^2.0.0 (verifier uses this instead of APS SDK so
    MolTrust-shaped fixtures verify without a hard APS-SDK dependency)
  - ajv ^8.0.0 + ajv-formats ^3.0.0 (canonical schema validation,
    including format: date-time on last_verified)

.gitignore: node_modules/
Week 2 verify.ts imported canonicalizeJCS + verify from the absolute
path /Users/tima/agent-passport-system/src/index.js, which broke for
any consumer running outside Tima's laptop, including MolTrust and CI.

Replace with npm-resolved 'agent-passport-system' import. Behavior is
otherwise identical: same named imports, same verifier logic, same
6/6 fixture round-trip on disk-identical fixtures.

Also replace the absolute DIR constant with a module-relative path
derived via fileURLToPath(import.meta.url) + dirname so the verifier
is fully portable.

Refs: a2aproject/A2A#1742
Synthetic MolTrust-shaped emissions MolTrust replaces with their real
fixtures when they ship Week 3 on their side. Every fixture:
  - carries the canonical 5-field composite header directly on
    header_value (trust_level / attestation_count / last_verified /
    evidence_bundle / delegation_chain_root)
  - is marked _placeholder: true and
    _replace_with_real_moltrust_emission: true
  - is Ed25519-signed with a deterministic test seed (tail 0xAA,
    documented in generate-placeholder.ts); public half embedded on
    every fixture for round-trip verification
  - uses RFC 8785 JCS canonicalization (same as APS) so both
    providers share canonicalization conventions

Fixtures:
  1. trust-trajectory-decay.json       trust_level 4 -> 3 -> 2
  2. attestation-accumulation.json     attestation_count 2 -> 7 -> 15
  3. shared-happy-path-moltrust.json   same chain + root as APS
                                       happy-path.json, re-signed

The generator is committed so MolTrust can see exactly how the shape
was constructed. Replacement workflow documented in README.md.

Refs: a2aproject/A2A#1742
consumer-verify.ts validates BOTH APS and MolTrust-shaped fixtures
against the canonical 5-field composite schema locked in Week 1.

Discovers every *.json at the top of a2a-trust-header/ (excluding
_keys.json, package*.json, tsconfig.json, anything prefixed with _)
and under moltrust-placeholder/. For each fixture:

  1. Classify issuer (aps | moltrust | unknown) by inspecting
     header_value.issuer / did / attestation kid prefixes /
     agent_card trust signals.
  2. Derive canonical composite view. MolTrust fixtures carry the
     5 fields directly on header_value (derivation=direct). APS
     fixtures reduce attestations[] into the 5-field composite
     (derivation=aps-synthesized).
  3. Schema-validate the composite via ajv (Draft 2020-12), with
     ajv-formats so format: date-time actually fires at runtime.
  4. Verify every Ed25519 signature encountered (delegation links,
     attestations, agent_card trust signals, deny receipts, MolTrust
     inline emission signature, trajectory entries). Uses
     @noble/ed25519 verifyAsync so MolTrust-side consumers do not need
     the APS SDK for signature verification.
  5. Recompute delegation_chain_root from inline chains. Mismatch is
     reported but not a failure when fixture declares
     format_variant: true (Week 2 drift case).

Exit codes:
  0 = all fixtures pass
  1 = any signature or chain-root failure
  2 = any schema failure

First run: 6/6 APS pass, 3/3 MolTrust placeholder pass, exit 0.

Refs: a2aproject/A2A#1742
Adds Week 3 section covering:
  - canonical 5-field composite schema (location, field contracts,
    self-describing delegation_chain_root, additionalProperties: true)
  - composite view derivation (direct for MolTrust, aps-synthesized
    for APS) so the same schema covers both provider shapes
  - consumer verifier contract, usage, output row shape, exit codes
  - MolTrust placeholder fixture catalog with a clear replacement
    workflow MolTrust follows when they ship Week 3 on their side
  - placeholder signing-key disclosure (deterministic test seed,
    replace before production)
  - Ed25519 / JCS canonicalization conventions shared across providers

Week 2 content preserved verbatim under a new "Week 2" heading.

Refs: a2aproject/A2A#1742
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