Skip to content

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

Closed
vaaraio wants to merge 9 commits into
modelcontextprotocol:mainfrom
vaaraio:sep2787-v0-test-vectors
Closed

SEP-2787 proposed-shape test vectors (v0)#2789
vaaraio wants to merge 9 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, a top-level alg downgrade to "none" caught by recanonicalisation, and IEEE-754 float rejection at the canonicalisation boundary. Ten 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, 4/4 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

This comment was marked as spam.

@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

This comment was marked as spam.

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
A legitimately HS256-signed body presented with its top-level alg
re-labelled "none" while still carrying the HS256 MAC. alg is part of
the signed body, so recanonicalising and re-verifying the present body
fails on the path the walker already runs for tampered cases. It lands
as case 14 with no change to _check_independent.py. A conformant
verifier MUST NOT treat the envelope as unsigned-and-accepted.

MANIFEST and README updated. Walker reports 4/4 normative negative.
@localden localden closed this Jun 30, 2026
@localden

Copy link
Copy Markdown
Contributor

Closing as it's unclear what this SEP does or why, and it introduces a large number of files rather than start with a normative proposal. Recommend starting a discussion in the contributor Discord as a starting point if you have a large-scale proposal.

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