Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

v1.4-alpha.3: canonicalization id + A2A verification context#35

Open
jaschadub wants to merge 1 commit into
main from
feature/v1.4-alpha.3-canonicalization-a2a
Open

v1.4-alpha.3: canonicalization id + A2A verification context #35
jaschadub wants to merge 1 commit into
main from
feature/v1.4-alpha.3-canonicalization-a2a

Conversation

@jaschadub

@jaschadub jaschadub commented May 16, 2026

Copy link
Copy Markdown
Contributor

Summary

Items 4 + 5 of the v1.4 roadmap, shipped together across all four SDKs (Rust, JavaScript, Python, Go). Wire-compatible with v1.3 / v1.4 alpha.1 / v1.4 alpha.2; all additions are additive optional fields and parameters.

This is the SchemaPin side of the cross-protocol integration with AgentPin v0.3's AllowedDomains typed wrapper — the AgentPin v0.3.0 release (2026年05月14日) was explicitly tagged as "unblocking SchemaPin v1.4.0 A2aVerificationContext," and this PR closes that loop.

What ships

Item 4 — Canonicalization Algorithm Identifier

Optional canonicalization field on .schemapin.sig (and matching parameter on the verifier APIs). Forward-compatibility hook so a future v2.x can swap canonicalization without breaking v1.x signatures.

  • Current and only supported value: "schemapin-v1". Absence is equivalent.
  • Any other value → hard failure with the new CANONICALIZATION_UNSUPPORTED / canonicalization_unsupported error code, before any cryptographic work.
  • Sign-time: SignOptions.canonicalization / SignOptions::with_canonicalization() (Rust builder).
  • Verifier: verify_schema_offline_with_canonicalization (Rust) / optional param on verifySchemaOffline (JS, Python) / VerifySchemaOfflineWithCanonicalization (Go).

Item 5 — A2A Verification Context

A2aVerificationContext + verify_schema_for_a2a wrap the standard 7-step flow with:

  1. Delegation-depth cap — reject delegation_depth > 3 (mirrors AgentPin's max_delegation_depth).
  2. Standard verification. If it fails, return that unchanged — A2A scope is NOT a remedy for cryptographic failure.
  3. Scope check — when trusted_domains is non-empty, reject when the provider domain isn't allowed by it (wildcard-aware *.suffix matching from AgentPin spec §5.5).

Both rejections surface as A2A_SCOPE_VIOLATION. trusted_domains uses the AgentPin convention: an empty list means unrestricted (all domains trusted), not "deny-all".

AllowedDomains helpers (is_unrestricted / allows / intersect) are re-implemented locally in each SDK rather than via a hard dep on the AgentPin SDK — keeps SchemaPin self-contained and avoids a circular trust-stack dependency. Wire shapes are byte-identical so callers linking both packages can pass agentpin.AllowedDomains.intersect() results directly into trusted_domains.

Spec + CHANGELOG

  • TECHNICAL_SPECIFICATION.md header bumped from v1.2 to v1.4 (alpha.3) with new §19 (Canonicalization Algorithm Identifier) and §20 (A2A Verification Context).
  • CHANGELOG.md: new [1.4.0-alpha.3] entry above the alpha.2 entry, documenting all five components.

Version bumps

All four SDKs to 1.4.0-alpha.3 (Python uses 1.4.0a3 per PEP 440):

  • rust/Cargo.toml
  • javascript/package.json
  • python/pyproject.toml + python/setup.cfg + python/schemapin/__init__.py
  • go/internal/version/version.go

Test plan

  • Rust: 133 lib tests pass; cargo clippy -- -D warnings clean; cargo fmt --check clean.
  • JavaScript: 180 tests pass (19 new A2A + canonicalization tests).
  • Python: 201 tests pass (19 new A2A + canonicalization tests).
  • Go: all packages green; go vet ./... clean; gofmt -l . empty after the bundled cleanup.
  • Implementation correctness: verify_schema_for_a2a uses allows(trusted, domain) directly (NOT allows(intersect(trusted, [domain]))) so the disjoint-allow-list edge case from AgentPin spec §4.11.4 doesn't silently bypass the scope check. There's a dedicated unit test for this in each SDK.

What's NOT in this PR

Items 6 (A2A trust bundle distribution), 7 (scan-aware signatures), 8 (cross-agent schema cache) of the v1.4 roadmap. Per the scope doc at docs/superpowers/specs/2026-05-15-v1.4-remaining-items.md (gitignored, local only), those bundle into 1.4.0-alpha.4 (items 6 + 7) and 1.4.0 final (item 8 + polish).

Bundled cleanup

Pre-existing gofmt drift on go/pkg/bundle/bundle.go, go/pkg/revocation/revocation.go, go/pkg/skill/skill.go, and go/pkg/skill/skill_test.go is fixed in this PR (got picked up by gofmt -w . during pre-commit verification). Whitespace-only — no behaviour change.

Items 4 + 5 from the v1.4 roadmap, shipped together across all four
SDKs (Rust, JavaScript, Python, Go). All additions are additive optional
fields / parameters; v1.3 verifiers and existing v1.4 alpha.1/alpha.2
signatures are unaffected.
Item 4 — Canonicalization Algorithm Identifier
==============================================
Optional "canonicalization" field on .schemapin.sig naming the
algorithm used to produce the signing input. Forward-compatibility
hook so a future v2.x can swap canonicalization without breaking v1.x
signatures.
* Current and only supported value: "schemapin-v1" (the algorithm in
 §4 of the spec).
* Absence is equivalent to "schemapin-v1" (v1.3 backward compatibility).
* Any other value is a hard failure surfacing as the new
 CANONICALIZATION_UNSUPPORTED / canonicalization_unsupported error
 code. The check executes before any cryptographic work.
Sign-time API:
* Rust: SignOptions::with_canonicalization(algorithm).
* JavaScript: SignOptions { canonicalization } on signSkillWithOptions.
* Python: SignOptions(canonicalization=...).
* Go: SignOptions{ Canonicalization: ... }.
Verifier API:
* Rust: verify_schema_offline_with_canonicalization(...).
* JavaScript: optional `canonicalization` parameter on
 verifySchemaOffline.
* Python: optional `canonicalization` keyword arg on
 verify_schema_offline.
* Go: VerifySchemaOfflineWithCanonicalization(...).
* Skill flow: VerifySkillOffline-family functions now check
 sig.canonicalization automatically.
Item 5 — A2A Verification Context
=================================
A2aVerificationContext and verify_schema_for_a2a wrap the standard
7-step verification flow with an A2A scope check that closes the
cross-protocol loop with AgentPin v0.3 AllowedDomains (AgentPin
spec §4.11).
A2aVerificationContext fields:
* caller_agent_id (URN-style, matching AgentPin; informational)
* delegation_depth (u8; 0 = direct caller)
* originating_domain (informational)
* trusted_domains (string list; empty = unrestricted per AgentPin
 convention)
Verification algorithm:
1. Reject when delegation_depth > A2A_MAX_DELEGATION_DEPTH (= 3 to
 match AgentPin's max_delegation_depth cap; must move in lockstep
 with AgentPin if ever bumped).
2. Run the standard 7-step verification (with the §19
 canonicalization check). If it fails, return that result
 unchanged — A2A scope is not a remedy for cryptographic failure.
3. When trusted_domains is non-empty, reject when the provider
 domain is not allowed by it (wildcard-aware via *.suffix
 matching from AgentPin spec §5.5).
Both rejections surface as the new A2A_SCOPE_VIOLATION error code.
AllowedDomains helpers (is_unrestricted / allows / intersect) are
re-implemented locally in each SDK rather than via a dependency on
the AgentPin SDK — keeps SchemaPin self-contained for tool-integrity-
only deployments and avoids a circular trust-stack dependency. The
wire and in-memory shapes are byte-identical to AgentPin's so
callers linking both packages can pass agentpin's intersect()
results directly into trusted_domains.
Important implementation detail: verify_schema_for_a2a uses
allows(trusted_domains, domain) DIRECTLY, not
allows(intersect(trusted_domains, [domain])). The intersection
helper has a documented edge case (AgentPin spec §4.11.4) where two
non-empty disjoint allow-lists intersect to [] which the convention
treats as unrestricted — using intersect here would silently bypass
the scope check.
Spec and CHANGELOG
==================
* TECHNICAL_SPECIFICATION.md bumped from v1.2 header to v1.4
 (alpha.3) with a top-of-doc summary; new §19 (Canonicalization
 Algorithm Identifier) and §20 (A2A Verification Context).
* CHANGELOG.md: new [1.4.0-alpha.3] entry above the alpha.2 entry.
* All four SDKs bumped to 1.4.0-alpha.3 (Python: 1.4.0a3 per PEP 440).
Test counts
===========
* Rust: 133 lib tests pass; cargo clippy -- -D warnings clean;
 cargo fmt clean.
* JavaScript: 180 tests pass (19 new A2A + canonicalization tests).
* Python: 201 tests pass (19 new A2A + canonicalization tests).
* Go: all packages green; go vet clean; gofmt -l empty.
Also includes pre-existing gofmt drift fixes on go/pkg/bundle/bundle.go,
go/pkg/revocation/revocation.go, go/pkg/skill/skill.go, and
go/pkg/skill/skill_test.go that surfaced when running gofmt -l
during pre-commit verification.
Items 6–8 of the v1.4 roadmap (A2A trust bundle distribution,
scan-aware signatures, cross-agent schema cache) follow in
1.4.0-alpha.4 and 1.4.0 final per the local scope doc at
docs/superpowers/specs/2026-05-15-v1.4-remaining-items.md.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

No reviews

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

1 participant

AltStyle によって変換されたページ (->オリジナル) /