Metadata-Version: 2.4
Name: pramiti-mcp-verify
Version: 0.3.0
Summary: Standalone offline verifier for SEP-2828 signed execution records, Pramiti settlement packs and IETF draft-sharif-agent-audit-trail sessions
Author-email: "Pramiti Labs, Inc." <hello@getpramiti.com>
License-Expression: MIT
Project-URL: Homepage, https://getpramiti.com
Project-URL: Repository, https://github.com/pramiti-labs/epistom
Keywords: mcp,sep-2828,attestation,audit,verifier,pramiti
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Security
Classifier: Topic :: Software Development :: Libraries
Requires-Python: <3.14,>=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: cryptography>=42.0
Requires-Dist: rfc8785>=0.1.4
Dynamic: license-file

# pramiti-mcp-verify

Standalone, offline verifier for **SEP-2828 signed execution records** — the
paired decision/outcome records a governing MCP server or proxy emits for
every tool call ([modelcontextprotocol#2828](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2828)).

Verifies, with no vendor dependency (`rfc8785` + `cryptography` only):

1. **Signatures** — detached ES256/RS256/HS256 over the JCS-canonical record
   body excluding `signature` (ES256 as raw `r||s` in 128 lowercase hex chars;
   RS256 as RSA PKCS#1 v1.5 SHA-256, lowercase hex of the raw signature).
2. **Instance binding** — `backLink.attestationDigest` recomputation against
   the SEP-2787 attestation, or against a named, versioned fallback
   projection (`tools_call_params_plus_meta_authorization_binding_v1`,
   `praxom_payload_hash_binding_v1`).
3. **Pairing** — Check A (shared `backLink`) + Check B (the outcome's
   `decisionDigest` over the FULL signed decision record).
4. **Consistency** — enum validity; a `block` decision paired with an
   `executed` outcome is rejected as a contradiction.
5. **Result commitments** — `ArgsProjection` self-consistency
   (`projectionDigest` over the projection bytes).

## Usage

```bash
# Verify a Praxom export bundle (POST /attestations/export, format=sep2828)
pramiti-mcp-verify bundle.json --pubkey es256_public.pem

# Verify a Praxom SETTLEMENT PACK (GET /action-budgets/{id}/settlement-pack, 0.2.0):
# dispatched on spec == "pramiti-settlement-pack" — the manifest signature, the
# recomputed records digest, the segment count AND every entry must hold
pramiti-mcp-verify settlement-pack.json --pubkey es256_public.pem

# Verify an IETF draft-sharif-agent-audit-trail-02 session (POST /attestations/export,
# format=aat → JSONL; 0.3.0). `check` is the documented subcommand spelling; a .jsonl
# file, --aat, or an AAT-shaped first line dispatches to the draft's chain procedure:
# genesis nulls, prev_hash over each complete previous record, signatures, the
# pre-execution rule, nonce uniqueness, the close record's session hash.
pramiti-mcp-verify check agent-audit-trail.jsonl --pubkey es256_public.pem

# Run a record_conformance_v0-layout vector suite against this implementation
pramiti-mcp-verify --vectors tests/vectors/sep2828/record_conformance_v0
# Verify a Praxom signed policy bundle (POST /api/v1/praxom/policy-bundles/export)
pramiti-mcp-verify policy_bundle.json --ed25519-pubkey exporter_ed25519.pub

# Run the record_conformance_v0 suite shipped in this package (includes RS256)
pramiti-mcp-verify --vectors
```

Exit code `0` when every record verifies, `1` otherwise; a JSON summary is
printed to stdout either way.

Absence is treated as tampering: an entry missing its `backLinkPreimage`,
its **outcome record**, or the `resultCommitment` of an `executed`/`errored`
outcome fails by default. The explicit opt-outs are
`--allow-missing-backlink-preimage` (records bound via an external SEP-2787
attestation), `--allow-decision-only` (a held `escalate` awaiting human
oversight — the only decision SEP-2828 permits without an outcome record; a
decision-only `allow`/`block` fails regardless), and
`--allow-uncommitted-result` (emitters that never bind the result payload —
only a `refused` outcome legitimately carries no `resultCommitment`, and a
present-but-inconsistent commitment fails regardless). Every skip is visibly
marked in the JSON summary, never silent.

Accepted bundle shapes: the Praxom export bundle
(`{"spec": "SEP-2828", "records": [...]}`), a bare
`{"decision": ..., "outcome": ...}` pair, or a list of pairs.

A document whose `format` is `praxom.policy_bundle/v1` is checked as a
**signed policy bundle** instead: the `digest` (SHA-256 over the RFC 8785
canonical bundle without `digest` and `signature`) and the signature over the
canonical bundle including its `alg` / `key_id` / `key_class` labels —
Ed25519 against the exporting deployment's base64url raw public key
(`--ed25519-pubkey`), HS256 only with the shared secret (`--hs256-secret`).
A failure names its reason: `unknown_format`, `unsigned`, `digest_mismatch`,
`unsupported_alg`, `unknown_key_class`, `key_required` or
`signature_invalid`.

`ok: true` means the document is unaltered and signed by the holder of the key
**you supplied** — integrity, not provenance. It is also profile-blind: the
product additionally refuses, under its production profile, an HS256 bundle, a
bundle whose `key_class` is `dev`, and any Ed25519 bundle whose `key_id` is not
among that deployment's configured trusted exporters. A bundle can therefore
verify here and still be refused on import, by design. This tool does not import
anything.

## Not the flight-recorder verifier

`pramiti-fr verify` checks the vendor-embedded **flight-recorder** store.
`pramiti-mcp-verify` (this tool) checks **SEP-2828 wire records** from an
enterprise proxy. Different stores, different audiences, deliberately
separate CLIs.
