Skip to content

SEP-2787 proposed-shape test vectors (v0)#2789

Open
vaaraio wants to merge 8 commits into
modelcontextprotocol:mainfrom
vaaraio:sep2787-v0-test-vectors
Open

SEP-2787 proposed-shape test vectors (v0)#2789
vaaraio wants to merge 8 commits into
modelcontextprotocol:mainfrom
vaaraio:sep2787-v0-test-vectors

Conversation

@vaaraio

@vaaraio vaaraio commented May 26, 2026

Copy link
Copy Markdown

Status: proposed-shape, not conformance for current SEP-2787 draft.

These vectors target the revised envelope shape proposed in the four-proposal comment on #2787: planner_declared / issuer_asserted / payload_derived trust-surface blocks, explicit args-commitment kinds (digest / ref / projection), JCS canonicalisation, IEEE-754 float rejection at the canonicalisation boundary.

The SEP text in #2787 still describes a flatter v1 shape (top-level iss / sub / intent, toolCalls[*].args as a string, sorted-key no-whitespace canonicalisation, optional ack). A second implementer reading the SEP as-is would correctly implement v1 and fail these fixtures.

Treat as provisional until the SEP text adopts matching schema and canonicalisation rules. Sibling v1-current vector set against the SEP text as written is on offer if useful.


Adds test-vectors/sep-2787/v0/ per the conformance-surface discussion in #2787. Depends on #2787.

The bundle splits into two directories per the reviewer's distinction in the thread.

normative/ covers signed-envelope round-trips across HS256/ES256/RS256, the three args-commitment shapes (digest, ref, projection), tampering rejection on the planner_declared and issuer_asserted blocks, and IEEE-754 float rejection at the canonicalisation boundary. Nine cases. Pass/fail against the SEP-2787 wire format today.

verifier-policy/ covers TTL expiry past iat + exp + skew, unsupported-alg rejection (HS512), schema rejection of unknown args-commitment kinds, and HS256-against-ES256-verifier alg-mismatch. Four cases. Become normative once the SEP names skew tolerance, alg whitelist, schema, and verifier alg-acceptance.

_check_independent.py reads the fixtures from disk and walks the conformance dimensions with no reference to any implementation. Imports stdlib plus cryptography and rfc8785 only. Output is tagged NORMATIVE vs POLICY per bucket. Local run reports 6/6 normative positive, 3/3 normative negative, 4/4 policy matching default policy.

Provenance

Apache-2.0. Derived from tests/test_attestation_sep2787.py at vaaraio/vaara@3d7af54 (tag sep2787-ref-v0, merged via vaaraio/vaara#139). SEP maintainers own the final normative artifact location, including whether this lives here, at a sibling path, or in a separate repo.

Acceptance gate

One independent implementation reads these fixtures and produces the same canonical bytes and signature verification results for every NORMATIVE case.

Per the conformance-surface discussion in modelcontextprotocol#2787. Adds
test-vectors/sep-2787/v0/ with 13 cases split into the two buckets
the reviewer named in the thread.

normative/ covers signed-envelope round-trips across HS256/ES256/RS256,
the three args-commitment shapes (digest, ref, projection), tampering
rejection on the planner_declared and issuer_asserted blocks, and
IEEE-754 float rejection at the canonicalisation boundary. Nine cases,
pass/fail against the SEP-2787 wire format today.

verifier-policy/ covers TTL expiry past iat + exp + skew,
unsupported-alg rejection (HS512), schema rejection of unknown
args-commitment kinds, and HS256-against-ES256-verifier alg-mismatch.
Four cases that become normative once the SEP names skew tolerance,
alg whitelist, schema, and verifier alg-acceptance.

_check_independent.py reads the fixtures from disk and walks the
conformance dimensions with no reference to any implementation.
Imports stdlib plus cryptography and rfc8785 only. Output is tagged
NORMATIVE vs POLICY per bucket.

Apache-2.0. Derived from tests/test_attestation_sep2787.py at commit
3d7af54 of vaaraio/vaara (branch feat/sep2787-reference-impl). SEP
maintainers own the final normative artifact location.
@vaaraio vaaraio mentioned this pull request May 26, 2026
9 tasks
@Rul1an

Rul1an commented May 26, 2026

Copy link
Copy Markdown

This is useful as a fixture PR. One alignment point before these get treated as conformance vectors for #2787:

As far as I can tell, these vectors target the proposed revised envelope shape: planner_declared, issuer_asserted, payload_derived, explicit args commitment kinds, JCS canonicalization, and float rejection.

The SEP text in #2787 still defines the flatter v1 shape: top-level iss / sub / intent, toolCalls[*].args as a string, sorted-key/no-whitespace canonicalization, and optional ack.

So I would mark this vector set as provisional until the SEP text lands the matching schema and canonicalization rules, or name it clearly as proposed-shape vectors rather than conformance for the current draft.

Otherwise a second implementation could correctly implement the SEP text as written and fail these fixtures.

@vaaraio vaaraio changed the title Add SEP-2787 v0 test vectors SEP-2787 proposed-shape test vectors (v0) May 26, 2026
@vaaraio

vaaraio commented May 26, 2026

Copy link
Copy Markdown
Author

Fair catch and accurate read. Renaming the set as proposed-shape rather than conformance for the current draft. README and PR body updated to call out the divergence between the SEP text as written (flat iss / sub / intent, toolCalls[*].args as string, sorted-key canonicalisation) and the revised shape these vectors target (the four-proposal bundle from #issuecomment-4544033186).

If useful, I can add a sibling v1-current vector set against the SEP text as written so conformance works for both surfaces until the SEP shape settles. Say the word.

Henri Sirkkavaara and others added 4 commits May 27, 2026 19:54
Rename snake_case keys in proposed-shape envelope to camelCase, matching MCP
convention adopted by soup-oss/modelcontextprotocol@48c739b1 in PR modelcontextprotocol#2787.

issuer_asserted -> issuerAsserted
planner_declared -> plannerDeclared
payload_derived -> payloadDerived
tool_calls -> toolCalls
server_fingerprint -> serverFingerprint
secret_version -> secretVersion
exp_seconds -> expSeconds
requested_capability -> requestedCapability
projection_digest -> projectionDigest

RFC 8785 JCS sorts keys alphabetically, so canonical bytes are recomputed
across all 13 fixtures. HS256 and RS256 signatures regenerated deterministically.
ES256 case is randomised; a fresh signature is stored.

Independent walker passes 6/6 normative positive, 3/3 normative negative,
4/4 verifier-policy negative.
Walker:
- drop the kind-discriminated args handler; ArgsRef and ArgsProjection
  self-discriminate by present fields
- tampered-case logic checks that the recanonicalised present body
  fails signature verification (canonical_signing_input.bin remains
  the pre-tamper canonical that the signature was computed over)
- case 10 uses wall clock for TTL evaluation; expected.json no longer
  carries verify_at_epoch
- case 12 renamed to args-commitment-missing-discriminator; flag
  toolCalls whose args carries neither ref nor projection

README:
- drop the proposed-shape framing; SEP text adopted trust-surface
  enveloping
- describe the v2 args union without the kind discriminator
- spell out the canonical_signing_input.bin convention for tampered
  cases so independent implementers do not re-trip the same surprise

MANIFEST:
- refresh bucket list to match the v2 case directories
- provenance points at vaaraio/vaara@5ea7cd3, tag sep2787-ref-v2,
  merged via vaaraio/vaara#151

Walker smoke test: 6/6 normative positive + 3/3 normative negative
+ 4/4 verifier-policy negative.
@vaaraio

vaaraio commented May 28, 2026

Copy link
Copy Markdown
Author

v0.40.0 shipped on vaaraio/vaara@1ac1d75; vaaraio/vaara#154 lands the streamable-HTTP proxy that emits the v2 envelope this PR targets.

@Rul1an

Rul1an commented May 28, 2026

Copy link
Copy Markdown

The v2 envelope changes are a clear improvement. Self-discriminating args without the kind enum is cleaner, and the canonical_signing_input.bin convention for tampered cases is exactly the right primitive for independent implementers.

One fixture-determinism point on case 10: I would keep an explicit verify_at_epoch or equivalent verifier time in expected.json.

Using wall clock in _check_independent.py makes the policy case depend on when the walker runs. It happens to reject now because the pinned iat is already in the past, but test vectors are more useful if a second implementation can replay the exact verifier inputs without ambient time. Concretely: a second implementation that runs the walker in 2027 should get identical pass/fail to one that runs it tomorrow. With wall clock, that's not guaranteed for case 10.

So the case can still be "TTL expired past skew," but the expiry decision should be driven by fixture data rather than datetime.now(). That keeps the vector set boring and reproducible, which is exactly what we want for independent implementations.

Replace datetime.now() in the case-10 walker branch with an explicit
verify_at_epoch field read from expected.json. A second implementation
replaying the fixtures gets identical pass/fail regardless of when the
walker runs, which is the determinism guarantee the vector set is
supposed to provide. Per review feedback on modelcontextprotocol#2789.
@vaaraio

vaaraio commented May 28, 2026

Copy link
Copy Markdown
Author

Pushed 2147293: case 10's expected.json now carries verify_at_epoch (1577923200, i.e. 2020-01-02T00:00:00Z, comfortably past iat+exp+skew with the 2020-01-01 iat). The walker reads that field instead of datetime.now(), so case 10 is replay-deterministic. Walker still reports PASS across all 13 cases. README updated to document the convention for time-sensitive policy fixtures.

@vaaraio

vaaraio commented May 29, 2026

Copy link
Copy Markdown
Author

Vaara v0.42.0 ships the post-execution complement to these vectors: the execution receipt layer (vaara.attestation.receipt), which takes the attestation wire bytes as backLink input and records what actually executed. Reference implementation at vaaraio/vaara@4608c36, conformance vectors at tests/vectors/execution_receipt_v0/.

@chopmob-cloud

This comment was marked as spam.

@localden localden added SEP draft SEP proposal with a sponsor. labels Jun 8, 2026
@localden localden added proposal SEP proposal without a sponsor. and removed draft SEP proposal with a sponsor. labels Jun 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

proposal SEP proposal without a sponsor. SEP

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

4 participants