Skip to content

release(v0.39.2): SEP-2787 v2 envelope with full wire round-trip, audit-event schema 1.0, Qi survey mapping#151

Merged
vaaraio merged 1 commit into
mainfrom
release/v0.39.2
May 27, 2026
Merged

release(v0.39.2): SEP-2787 v2 envelope with full wire round-trip, audit-event schema 1.0, Qi survey mapping#151
vaaraio merged 1 commit into
mainfrom
release/v0.39.2

Conversation

@vaaraio
Copy link
Copy Markdown
Owner

@vaaraio vaaraio commented May 27, 2026

Summary

SEP-2787 reference implementation lands the v2 envelope shape with
full wire round-trip. Two doc artefacts and one new public API
(parse_attestation) ship in the same release.

The four mechanical alignments Vaara committed to in
modelcontextprotocol/modelcontextprotocol#2787 after the
trust-surface grouping was incorporated into the SEP draft on
soup-oss commit dd030d5b:

  1. toolCalls lives under payloadDerived, not plannerDeclared.
    Tool bindings (name, server fingerprint, args commitment) are
    facts derived from the request payload, not planner declarations.
  2. argsProjection serialises with a JSON-stringified projection
    field carrying the JCS-canonical encoding of the projection
    object. The digest is taken over those bytes.
  3. The v1 kind-discriminated union is dropped. ArgsRef and
    ArgsProjection self-discriminate by which fields are present.
  4. Commitment-only audit composes on ArgsProjection as a
    hash-only-identity projection of the form {"digest": "sha256:..."}. No separate ArgsDigest ships.

Wire round-trip

parse_attestation(d) is the inverse of Attestation.to_dict(). It
reconstructs the Python dataclass tree from a wire JSON dict so a
third-party consumer of the published v0 test vectors can parse,
verify, and re-emit envelopes byte-identically. Field-presence
validation and alg allowlisting happen on the boundary. 13 new tests
in tests/test_attestation_sep2787_wire.py cover emit -> JCS bytes -> parse -> verify across HS256, ES256, RS256 for both ArgsRef and
ArgsProjection, plus parse rejection on missing-field and
unsupported-alg inputs and a byte-identical re-emit check.

Docs

  • docs/audit_event_schema.md: AUDIT-EVENT-SCHEMA-1.0, the versioned
    wire/storage contract for Vaara audit events. Versioned
    independently of the Python package so third-party consumers can
    pin to a schema version without coupling to a runtime version.
  • docs/qi_survey_mapping.md: Vaara surface coverage against the
    taxonomy in Qi et al., Towards Trustworthy Agentic AI
    (arXiv:2605.23989, 2026-05-17).
  • docs/sep2787-overt-mapping.md field table updated to v2.

SEP-2787 reference implementation tags

  • sep2787-ref-v2 (this release): v2 envelope shape with full wire
    round-trip.
  • sep2787-ref-v1 (preserved at a61e87c): camelCase envelope.
  • sep2787-ref-v0 (preserved at 3d7af54): snake_case envelope.

The v0 test vectors at vaaraio/modelcontextprotocol#2789 will be
regenerated against the v2 shape in a follow-up push to the
sep2787-v0-test-vectors branch, with a confirming comment under
the SEP draft at modelcontextprotocol/modelcontextprotocol#2787.

Test plan

  • ruff check on changed Python paths
  • pytest tests/test_attestation_sep2787*.py (47 tests pass:
    34 prior + 13 new wire tests)
  • Full pytest suite in CI
  • Tag v0.39.2 triggers Release workflow; PyPI + npm publish
  • gh release view v0.39.2 shows artefacts + Sigstore signatures
  • pip install vaara==0.39.2 and npm view @vaara/client@0.39.2
  • Co-tag sep2787-ref-v2 lands on the same release commit

Summary by CodeRabbit

Release Notes – v0.39.2

  • New Features

    • SEP-2787 v2 envelope support with restructured trust-surface blocks and updated field mapping.
    • Added parse_attestation() function for round-trip attestation parsing and verification.
  • Documentation

    • New "Audit Event Schema v1.0" documentation page.
    • New mapping guide correlating Vaara governance mechanisms to agentic-AI trustworthiness survey categories.
    • Updated SEP-2787 compliance documentation covering both OVERT 1.0 and v2 envelope formats.

Review Change Stack

…it-event schema 1.0, Qi survey mapping

The four mechanical alignments Vaara committed to in
modelcontextprotocol/modelcontextprotocol#2787 after the trust-surface
grouping was incorporated into the SEP draft on soup-oss commit
dd030d5b ship as the v2 envelope shape:

1. toolCalls lives under payloadDerived, not plannerDeclared. Tool
   bindings (name, server fingerprint, args commitment) are facts
   derived from the request payload, not planner declarations.
2. argsProjection serialises with a JSON-stringified projection field
   carrying the JCS-canonical encoding of the projection object. The
   digest is taken over those bytes.
3. The v1 kind-discriminated union is dropped. ArgsRef and
   ArgsProjection self-discriminate by which fields are present.
4. Commitment-only audit composes on ArgsProjection as a
   hash-only-identity projection of the form {"digest": "sha256:..."}.
   No separate ArgsDigest type ships in the spec.

parse_attestation(d) is the new wire-decode entrypoint: inverse of
Attestation.to_dict(). 13 new tests cover emit -> JCS bytes -> parse
-> verify across HS256, ES256, RS256 for both ArgsRef and
ArgsProjection, plus parse rejection on missing-field and
unsupported-alg inputs and a byte-identical re-emit check.

Two doc artefacts ship in the same release:

- docs/audit_event_schema.md: AUDIT-EVENT-SCHEMA-1.0, versioned
  wire/storage contract for the audit events Vaara emits. Independent
  of code version so third-party consumers can pin without coupling
  to a Python runtime version.
- docs/qi_survey_mapping.md: Vaara surface coverage against the
  taxonomy in Qi et al., Towards Trustworthy Agentic AI
  (arXiv:2605.23989, 2026-05-17). Direct, partial, and out-of-scope
  rows by Perceive / Plan / Act / Reflect / Learn / Multi-agent /
  Long-horizon stage under both top-level dimensions.

SEP-2787 reference implementation tag sep2787-ref-v2 lands on this
release commit alongside v0.39.2 for cross-repo provenance. The v0.40
slot stays reserved for the deployment-shape scope (HTTP transport,
multi-tenancy schema, hot-reload extended, fan-out) per
project_v040_roadmap_opa_frame_20260527.md.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 27, 2026

📝 Walkthrough

Walkthrough

Version 0.39.2 introduces SEP-2787 v2 attestation envelope specification. The core change refactors the args commitment model from a single ArgsDigest type to two discriminated variants (ArgsRef and ArgsProjection), moves tool-call bindings from PlannerDeclared into a new PayloadDerived trust-surface block, and updates signing and verification accordingly. Includes new audit event schema and Qi survey mapping documentation.

Changes

SEP-2787 v2 Attestation Envelope Release

Layer / File(s) Summary
Release metadata and documentation
CHANGELOG.md, COMPLIANCE.md, pyproject.toml, clients/ts/package.json, src/vaara/__init__.py, docs/audit_event_schema.md, docs/qi_survey_mapping.md, docs/sep2787-overt-mapping.md
Version bumped to 0.39.2 across package manifests and client. Changelog and compliance documentation added for SEP-2787 v2 envelope (signing modes, trust-surface blocks, parse_attestation round-trip). Two new documentation pages introduced: audit event schema (v1.0) defining wire/storage contracts for audit trails and events, and Qi et al. survey mapping documenting how Vaara governance mechanisms address agentic-AI trustworthiness risks. SEP-2787/OVERT mapping updated to describe v2 envelope structure and revised field mappings.
SEP-2787 v2 data model and types
src/vaara/attestation/_sep2787_types.py
ArgsDigest removed; ArgsRef and ArgsProjection introduced as self-discriminating commitment variants (no kind field). ArgsProjection.projection now stores JCS-canonical JSON string with computed projection_digest. Tool-call bindings moved from PlannerDeclared to new PayloadDerived block. Attestation.payload_derived now typed as PayloadDerived instead of raw args tuple. Serialization updated to emit payloadDerived with toolCalls and args without kind discriminator. Complete JSON parsing helpers added (args_from_dict, tool_call_from_dict, planner_from_dict, issuer_from_dict, payload_from_dict, attestation_from_dict) with field validation and ref vs projection discriminator logic.
Args commitment canonicalization
src/vaara/attestation/_sep2787_canonical.py
make_args_digest refactored to return ArgsProjection with hash-only-identity format {"digest":"sha256:<hex>"} embedded, JCS-canonicalized, and represented as UTF-8 string in projection field. make_args_projection updated to JCS-canonicalize input dict, set projection to UTF-8 decoded canonical bytes, and compute projection_digest from SHA-256 of those bytes.
Emission with PayloadDerived
src/vaara/attestation/_sep2787_emit.py
emit_attestation signature updated to accept explicit payload_derived: PayloadDerived instead of deriving from planner tool-calls. _signing_payload updated to use payload_to_dict(payload_derived) for envelope construction. Input validation added to ensure payload_derived.tool_calls is non-empty.
Verification of v2 commitments
src/vaara/attestation/_sep2787_verifier.py
Verifier updated to handle hash-only-identity projections by parsing {"digest":"sha256:<hex>"} carriers and verifying embedded digest against canonical runtime arguments. verify_args_commitment reworked to distinguish identity vs redacted projections and validate projection_digest against SHA-256 of projection bytes. ArgsDigest verification branch removed. ArgsCommitmentResult.projection_match documentation clarified for identity projections only.
Public API exports
src/vaara/attestation/__init__.py, src/vaara/attestation/sep2787.py
attestation/__init__.py docstring expanded to describe OVERT 1.0 and SEP-2787 v2 coexistence. New re-exports added: PayloadDerived and sep2787_parse_attestation (alias for parse_attestation). sep2787.py documentation updated for v2 shape. ArgsDigest removed from exports; attestation_from_dict aliased and re-exported as parse_attestation.
Core test suite refactoring
tests/test_attestation_sep2787.py
Refactored with new helpers: _planner() (parameterless), _payload(args) (builds PayloadDerived), _emit(**overrides) (creates Attestation). Round-trip tests for HS256/ES256/RS256 added with signature and verification assertions. Tampering tests rewritten to cover IssuerAsserted and PayloadDerived modifications. Canonical JSON assertions expanded for key-sorting and unicode handling. TTL expiration and clock-skew tolerance tested via now parameter overrides.
Comprehensive v2 envelope tests
tests/test_attestation_sep2787_shape.py, tests/test_attestation_sep2787_step5.py, tests/test_attestation_sep2787_wire.py
test_attestation_sep2787_shape.py validates deterministic make_args_digest, serialization schema (toolCalls under payloadDerived, no kind field), projection JSON round-tripping, and emit_attestation rejection of invalid inputs. test_attestation_sep2787_step5.py covers digest-only, ArgsRef, and ArgsProjection commitment verification with resolver handling and projection identity/redaction distinction. test_attestation_sep2787_wire.py exercises wire round-trip (emit → to_dict → canonical_json → parse → verify) with HS256/ES256/RS256, negative parsing tests for malformed envelopes, and byte-identical round-trip property.

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly Related PRs

  • vaaraio/vaara#139: Primary PR refactoring SEP-2787 from proposed (v1) to v2 envelope shape, including the same core module changes (_sep2787_types.py, _sep2787_canonical.py, _sep2787_emit.py) that remove ArgsDigest and introduce PayloadDerived/revised projections.
  • vaaraio/vaara#150: Parallel serialization boundary updates in the same core code paths around plannerDeclared/payloadDerived and projectionDigest representation, extending v2 envelope and commitment model changes.

Poem

🐰 A v2 envelope hops into view,
With PayloadDerived shining fresh and new,
No more ArgsDigest in the way,
Wire round-trips celebrate the day!
Tests bloom like carrots, green and bright,
SEP-2787 v2 takes flight! 🚀

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 15.19% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the three main changes: SEP-2787 v2 envelope with wire round-trip support, audit-event schema 1.0, and Qi survey mapping.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch release/v0.39.2

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/vaara/attestation/_sep2787_types.py (1)

203-221: 💤 Low value

Consider validating canonicalization value in args_from_dict.

The ArgsRef type restricts canonicalization to Literal["jcs"], but args_from_dict accepts any value from the wire without validation. A malformed envelope with "canonicalization": "cbor" would create an ArgsRef instance that violates the type constraint.

🛡️ Proposed validation
 def args_from_dict(d: dict[str, Any]) -> ArgsCommitment:
     if "ref" in d:
         if "digest" not in d:
             raise AttestationError("ArgsRef missing 'digest'")
+        canon = d.get("canonicalization", "jcs")
+        if canon != "jcs":
+            raise AttestationError(f"unsupported canonicalization {canon!r}")
         return ArgsRef(
             ref=d["ref"],
             digest=d["digest"],
-            canonicalization=d.get("canonicalization", "jcs"),
+            canonicalization=canon,
         )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/vaara/attestation/_sep2787_types.py` around lines 203 - 221, The
args_from_dict function currently accepts any canonicalization value from the
input and then constructs an ArgsRef (which expects Literal["jcs"]); update
args_from_dict to validate the canonicalization field when creating an ArgsRef:
read canonicalization = d.get("canonicalization", "jcs") and if canonicalization
!= "jcs" raise AttestationError (e.g. "unsupported canonicalization: {value}")
before returning ArgsRef(ref=..., digest=..., canonicalization=canonicalization)
so only the allowed "jcs" value is accepted.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/vaara/attestation/_sep2787_types.py`:
- Around line 203-221: The args_from_dict function currently accepts any
canonicalization value from the input and then constructs an ArgsRef (which
expects Literal["jcs"]); update args_from_dict to validate the canonicalization
field when creating an ArgsRef: read canonicalization =
d.get("canonicalization", "jcs") and if canonicalization != "jcs" raise
AttestationError (e.g. "unsupported canonicalization: {value}") before returning
ArgsRef(ref=..., digest=..., canonicalization=canonicalization) so only the
allowed "jcs" value is accepted.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c907bff3-3e3f-40f7-9041-16f019549e46

📥 Commits

Reviewing files that changed from the base of the PR and between a61e87c and 81d27c6.

📒 Files selected for processing (18)
  • CHANGELOG.md
  • COMPLIANCE.md
  • clients/ts/package.json
  • docs/audit_event_schema.md
  • docs/qi_survey_mapping.md
  • docs/sep2787-overt-mapping.md
  • pyproject.toml
  • src/vaara/__init__.py
  • src/vaara/attestation/__init__.py
  • src/vaara/attestation/_sep2787_canonical.py
  • src/vaara/attestation/_sep2787_emit.py
  • src/vaara/attestation/_sep2787_types.py
  • src/vaara/attestation/_sep2787_verifier.py
  • src/vaara/attestation/sep2787.py
  • tests/test_attestation_sep2787.py
  • tests/test_attestation_sep2787_shape.py
  • tests/test_attestation_sep2787_step5.py
  • tests/test_attestation_sep2787_wire.py

@vaaraio vaaraio merged commit 5ea7cd3 into main May 27, 2026
12 checks passed
@vaaraio vaaraio deleted the release/v0.39.2 branch May 27, 2026 19:28
vaaraio added a commit to vaaraio/modelcontextprotocol that referenced this pull request May 27, 2026
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.
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