Skip to content

Commit 0f45009

Browse files
authored
Merge pull request #42 from ThirdKeyAI/docs/v1.4-a2a-context-and-api-reference
docs: document v1.4 A2A context + complete docs site nav
2 parents 806c385 + 230b742 commit 0f45009

6 files changed

Lines changed: 204 additions & 2 deletions

File tree

docs/a2a-context.md

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
# A2A Verification Context
2+
3+
> **Status:** v1.4.0-alpha.3 — implemented in **Rust, Python, JavaScript, and Go**. Mirrors the AgentPin v0.3 `AllowedDomains` convention so the two trust stacks compose.
4+
5+
When agents collaborate over A2A (Agent-to-Agent), a tool schema verified by one agent crosses a trust boundary into another. The standard offline verification answers *"is this schema authentically signed by its provider?"* — but in an A2A flow you also need to answer *"is this provider's domain one the calling agent is allowed to trust?"*
6+
7+
`verify_schema_for_a2a` runs the standard verification and adds two A2A-aware checks:
8+
9+
1. **Delegation-depth cap** — reject when `delegation_depth` exceeds `A2A_MAX_DELEGATION_DEPTH` (3), matching AgentPin's `max_delegation_depth`.
10+
2. **Scope check** — reject when the tool provider's domain is not allowed by the caller's trusted-domains allow-list.
11+
12+
The cryptographic outcome is unchanged — A2A context only adds a *policy* gate. A failure surfaces as the `A2A_SCOPE_VIOLATION` error code.
13+
14+
---
15+
16+
## AllowedDomains convention
17+
18+
The `trusted_domains` allow-list follows AgentPin v0.3's `AllowedDomains` semantics exactly:
19+
20+
- **An empty list means *unrestricted*** (all domains trusted) — not "deny-all". This matches v1.3 behaviour where an omitted allow-list permitted all domains.
21+
- A non-empty list allows a domain when it matches an entry literally, or via a leading `*.` wildcard (`*.client.com` matches `api.client.com` but not `client.com` itself).
22+
- Intersection follows AgentPin spec §4.11.4: `unrestricted ∩ X = X`.
23+
24+
SchemaPin re-implements these helpers (`is_unrestricted` / `allows` / `intersect`) locally rather than depending on the AgentPin package, keeping the tool-integrity library self-contained. The wire and in-memory shapes are identical, so callers who *do* link AgentPin can pass `agentpin.AllowedDomains.intersect(...)` results straight into `trusted_domains`.
25+
26+
See [Technical specification §20](https://github.com/ThirdKeyAI/SchemaPin/blob/main/TECHNICAL_SPECIFICATION.md) for the normative definition.
27+
28+
---
29+
30+
## `A2aVerificationContext`
31+
32+
| Field | Meaning |
33+
|-------|---------|
34+
| `caller_agent_id` | Caller's agent identity (URN-style, matching AgentPin). Informational. |
35+
| `delegation_depth` | Depth in the A2A delegation chain; `0` = direct caller. Rejected above 3. |
36+
| `originating_domain` | Originating domain of the A2A request. Informational. |
37+
| `trusted_domains` | Caller-trusted domains. **Empty = unrestricted.** |
38+
39+
(Field names are camel/Pascal-cased per language — e.g. `delegationDepth` in JS, `DelegationDepth` in Go.)
40+
41+
---
42+
43+
## Usage
44+
45+
### Rust
46+
47+
```rust
48+
use schemapin::A2aVerificationContext;
49+
use schemapin::verification::verify_schema_for_a2a;
50+
use schemapin::pinning::KeyPinStore;
51+
52+
let context = A2aVerificationContext {
53+
caller_agent_id: "urn:agent:coordinator".to_string(),
54+
delegation_depth: 1,
55+
originating_domain: "coordinator.example".to_string(),
56+
trusted_domains: vec!["*.thirdkey.ai".to_string()],
57+
};
58+
59+
let result = verify_schema_for_a2a(
60+
&schema,
61+
&signature_b64,
62+
"api.thirdkey.ai", // tool provider domain
63+
"calculate_sum", // tool_id
64+
&discovery,
65+
None, // revocation
66+
&mut KeyPinStore::new(),
67+
&context,
68+
None, // canonicalization (default schemapin-v1)
69+
);
70+
assert!(result.valid);
71+
```
72+
73+
Use `A2aVerificationContext::unrestricted("urn:agent:...")` to verify with no domain restriction.
74+
75+
### Python
76+
77+
```python
78+
from schemapin.a2a import A2aVerificationContext
79+
from schemapin.verification import verify_schema_for_a2a, KeyPinStore
80+
81+
context = A2aVerificationContext(
82+
caller_agent_id="urn:agent:coordinator",
83+
delegation_depth=1,
84+
originating_domain="coordinator.example",
85+
trusted_domains=["*.thirdkey.ai"],
86+
)
87+
88+
result = verify_schema_for_a2a(
89+
schema, signature_b64, "api.thirdkey.ai", "calculate_sum",
90+
discovery, None, KeyPinStore(), context,
91+
)
92+
assert result.valid
93+
```
94+
95+
### JavaScript
96+
97+
```javascript
98+
import { A2aVerificationContext } from "schemapin";
99+
import { verifySchemaForA2a, KeyPinStore } from "schemapin";
100+
101+
const context = new A2aVerificationContext({
102+
callerAgentId: "urn:agent:coordinator",
103+
delegationDepth: 1,
104+
originatingDomain: "coordinator.example",
105+
trustedDomains: ["*.thirdkey.ai"],
106+
});
107+
108+
const result = verifySchemaForA2a(
109+
schema, signatureB64, "api.thirdkey.ai", "calculate_sum",
110+
discovery, null, new KeyPinStore(), context,
111+
);
112+
```
113+
114+
### Go
115+
116+
```go
117+
ctx := &verification.A2AVerificationContext{
118+
CallerAgentID: "urn:agent:coordinator",
119+
DelegationDepth: 1,
120+
OriginatingDomain: "coordinator.example",
121+
TrustedDomains: []string{"*.thirdkey.ai"},
122+
}
123+
124+
result := verification.VerifySchemaForA2A(
125+
schema, signatureB64, "api.thirdkey.ai", "calculate_sum",
126+
discovery, nil, pinStore, ctx,
127+
)
128+
```
129+
130+
---
131+
132+
## Failure modes
133+
134+
| Condition | Result |
135+
|-----------|--------|
136+
| `delegation_depth > 3` | `A2A_SCOPE_VIOLATION` (checked before any crypto) |
137+
| Provider domain not in a non-empty `trusted_domains` | `A2A_SCOPE_VIOLATION` |
138+
| Standard verification fails (bad signature, revoked key, pin mismatch, …) | the underlying error, unchanged |
139+
140+
A2A context never makes a cryptographically invalid schema pass — it can only add a restriction.
141+
142+
---
143+
144+
## Related
145+
146+
- [Trust Bundle Distribution](trust-bundle-distribution.md) — sign and exchange trust bundles between agents over A2A.

docs/api-reference.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,3 +409,47 @@ check_revocation(doc, some_fingerprint) # raises if revoked
409409
| Rust | `detect_tampered_files(current, original)` | `TamperResult` |
410410

411411
See [Skill Signing](skill-signing.md) for detailed usage.
412+
413+
---
414+
415+
## v1.4 Features
416+
417+
All v1.4 additions are optional fields/parameters — v1.3 clients are unaffected. Each feature has a dedicated page with full per-language examples; this section is the at-a-glance index.
418+
419+
### Signature Expiration — alpha.1
420+
421+
Optional `expires_at` on signatures; expired signatures degrade to a warning rather than failing. See [Signature Expiration](signature-expiration.md).
422+
423+
### DNS TXT Cross-Verification — alpha.1
424+
425+
Second-channel `_schemapin.{domain}` TXT lookup cross-checks the discovery key fingerprint. See [DNS TXT Cross-Verification](dns-txt.md).
426+
427+
### Schema Version Binding — alpha.2
428+
429+
Optional `schema_version` + `previous_hash` lineage chain, with opt-in `verify_chain` (`verifyChain` / `VerifyChain`). See [Schema Version Binding](schema-version-binding.md).
430+
431+
### Canonicalization Algorithm Identifier — alpha.3
432+
433+
Optional `canonicalization` field (`"schemapin-v1"`); unknown algorithms are a hard `CANONICALIZATION_UNSUPPORTED` failure. Verifier functions take an optional `canonicalization` argument.
434+
435+
### A2A Verification Context — alpha.3
436+
437+
| Language | Function |
438+
|----------|----------|
439+
| Python | `verify_schema_for_a2a(schema, sig, domain, tool_id, discovery, revocation, pin_store, context, canonicalization=None)` |
440+
| JavaScript | `verifySchemaForA2a(schema, sig, domain, toolId, discovery, revocation, pinStore, context)` |
441+
| Go | `verification.VerifySchemaForA2A(schema, sig, domain, toolID, discovery, revocation, pinStore, ctx)` |
442+
| Rust | `verify_schema_for_a2a(schema, sig, domain, tool_id, discovery, revocation, pin_store, context, canonicalization)` |
443+
444+
Scopes verification to caller-trusted domains; failure is `A2A_SCOPE_VIOLATION`. See [A2A Verification Context](a2a-context.md).
445+
446+
### Trust Bundle Distribution — alpha.4
447+
448+
| Operation | Python / JS / Go / Rust |
449+
|-----------|--------------------------|
450+
| Sign | `sign_trust_bundle` / `signTrustBundle` / `SignTrustBundle` / `sign_trust_bundle` |
451+
| Verify | `verify_trust_bundle` / `verifyTrustBundle` / `VerifyTrustBundle` / `verify_trust_bundle` |
452+
| Merge | `merge_trust_bundles` / `mergeTrustBundles` / `MergeTrustBundles` / `merge_trust_bundles` |
453+
| JSON-RPC | `build_trust_bundle_request` / `build_trust_bundle_response` / `parse_trust_bundle_response` (+ camel/Pascal variants) |
454+
455+
Sign and exchange trust bundles between agents; new error codes `BUNDLE_UNSIGNED` / `BUNDLE_EXPIRED`. See [Trust Bundle Distribution](trust-bundle-distribution.md).

docs/getting-started.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,10 @@ const result = verifySkillOffline('./my-skill/', discoveryData, sig, null, pinSt
361361
- [Skill Signing](skill-signing.md) — SkillSigner deep dive
362362
- [Trust Bundles](trust-bundles.md) — Offline and air-gapped verification
363363
- [Revocation](revocation.md) — Rotate keys and serve signed revocation documents
364-
- [Signature Expiration](signature-expiration.md) — v1.4-alpha (Rust): `expires_at` and degraded-not-failed verification
365-
- [DNS TXT Cross-Verification](dns-txt.md) — v1.4-alpha (Rust): second-channel `_schemapin.{domain}` lookups
364+
- [Signature Expiration](signature-expiration.md) — v1.4-alpha (all 4 languages): `expires_at` and degraded-not-failed verification
365+
- [DNS TXT Cross-Verification](dns-txt.md) — v1.4-alpha (all 4 languages): second-channel `_schemapin.{domain}` lookups
366+
- [Schema Version Binding](schema-version-binding.md) — v1.4-alpha (all 4 languages): `schema_version` + `previous_hash` lineage chain
367+
- [A2A Verification Context](a2a-context.md) — v1.4-alpha (all 4 languages): scope verification to caller-trusted domains
368+
- [Trust Bundle Distribution](trust-bundle-distribution.md) — v1.4-alpha (all 4 languages): sign, verify, and merge trust bundles for A2A
366369
- [Deployment](deployment.md) — Serve `.well-known` endpoints in production
367370
- [Troubleshooting](troubleshooting.md) — Common issues and solutions

docs/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ All four implementations use identical crypto (ECDSA P-256 + SHA-256) — cross-
8080
| [Signature Expiration](signature-expiration.md) | `expires_at` field for degraded-not-failed verification (v1.4-alpha, all 4 languages) |
8181
| [DNS TXT Cross-Verification](dns-txt.md) | Second-channel `_schemapin.{domain}` lookups (v1.4-alpha, all 4 languages) |
8282
| [Schema Version Binding](schema-version-binding.md) | `schema_version` + `previous_hash` lineage chain to defend against rug-pull substitutions (v1.4-alpha, all 4 languages) |
83+
| [A2A Verification Context](a2a-context.md) | Scope schema verification to caller-trusted domains across A2A boundaries (v1.4-alpha, all 4 languages) |
8384
| [Trust Bundle Distribution](trust-bundle-distribution.md) | Sign, verify, and merge trust bundles for safe A2A exchange (v1.4-alpha, all 4 languages) |
8485
| [Deployment](deployment.md) | Serve `.well-known` endpoints in production |
8586
| [Troubleshooting](troubleshooting.md) | Common issues and solutions |

docs/trust-bundles.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
SchemaPin v1.2 introduced trust bundles and pluggable discovery resolvers for environments where HTTP-based `.well-known` discovery is unavailable or impractical.
44

5+
> **v1.4:** trust bundles can now be **signed by a bundle authority** and exchanged between agents over A2A. See [Trust Bundle Distribution](trust-bundle-distribution.md).
6+
57
---
68

79
## When to Use Offline Verification

zensical.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ nav = [
1010
{"API Reference" = "api-reference.md"},
1111
{"Skill Signing" = "skill-signing.md"},
1212
{"Trust Bundles" = "trust-bundles.md"},
13+
{"Revocation" = "revocation.md"},
14+
{"Signature Expiration" = "signature-expiration.md"},
15+
{"DNS TXT Cross-Verification" = "dns-txt.md"},
16+
{"Schema Version Binding" = "schema-version-binding.md"},
17+
{"A2A Verification Context" = "a2a-context.md"},
18+
{"Trust Bundle Distribution" = "trust-bundle-distribution.md"},
1319
{"Deployment" = "deployment.md"},
1420
{"Troubleshooting" = "troubleshooting.md"},
1521
{"schemapin.org" = "https://schemapin.org"},

0 commit comments

Comments
 (0)