Verification¶
The core verification engine and FastAPI router. See Tutorial: Server-side verification for usage examples.
Public API¶
For gateway and runtime-session binding, call the package-root export rather than the private _verify module:
verify_manifest() is the supported high-level entry point. VerificationContext.trusted_keys maps an issuer key_id (the SHA-256 hex of the public key bytes) to its base64url-encoded Ed25519 public key, the form returned by Ed25519KeyPair.public_b64url(). A consumer that holds raw public key bytes must base64url-encode them before populating trusted_keys. Signers and verifiers share agent_manifest.signing_pre_image() for the exact RFC 8785 canonical byte sequence, including the hitl_record.approvals normalization, so a relying party never reconstructs the pre-image itself.
Core function¶
verify_manifest ¶
verify_manifest(manifest: Union[dict[str, Any], bytes], context: VerificationContext, revocation_store: 'RevocationStore', *, _envelope: Optional[CoseVerification] = None) -> VerificationResult
Core verification engine - hosting-model agnostic and fail-closed.
Checks version compatibility, signature, expiry, revocation, artifact hashes, delegation chain, and HITL. Returns a VerificationResult with per-field status and mismatch details.
Accepts either envelope, selected by what it is given (ADR-0011):
- A
dictis a version 0.1 manifest carrying a detachedsignatureblock, verified over the RFC 8785 pre-image exactly as it always has been. bytesare a version 0.2 COSE envelope (COSE_Sign1orCOSE_Sign). The signature is checked over the payload as received, and receipts, attestation, and approvals are read from the unprotected header after the signature is settled.
Fail-closed semantics (spec 5.3 - VALID requires a valid signature):
- A manifest with an unsupported (or missing)
versionreturnsINCOMPATIBLE_VERSIONwithout further processing (spec 2.4). - A manifest without a
signatureblock returnsSIGNATURE_MISSING. - A signed manifest verified without any
trusted_keysin the context returnsUNVERIFIABLE- neverVALID. - A delegation chain that cannot be verified (no
delegation_public_keys) is markedUNVERIFIABLEand the overall result isUNVERIFIABLE(spec 3.4.1 / 5.2). - A delegation chain that verifies signatures and scope narrowing but carries a non-empty
scope_grant.constraints(a Cedar statement this verifier does not parse or evaluate) is also markedUNVERIFIABLE, notVALID(spec 3.4.1 / 5.2). enforce_hitl=Truewith nohitl_recordin the manifest is a failure (HitlResult.MISSINGand a non-VALID overall result).- An approval is never
APPROVEDunless its own signature verifies with a trusted approver key and binds the current manifest ID and scope.
The _envelope parameter is internal: it carries an already-appraised COSE envelope into the shared pipeline and is not part of the public API.
Context¶
VerificationContext ¶
Bases: BaseModel
Runtime artifact hashes and keys provided by the trusted component.
Results¶
VerificationResult ¶
Bases: BaseModel
OverallResult ¶
Bases: str, Enum
FieldsVerified ¶
Bases: BaseModel
FieldResult ¶
Bases: str, Enum
DelegationResult ¶
Bases: str, Enum
HitlResult ¶
Bases: str, Enum
MismatchDetail ¶
Bases: BaseModel
EvidencePack is an optional reference (trace id, signer, hash, and URI) to an externally retained evidence pack that a verifier can record alongside a result.
EvidencePack ¶
Bases: BaseModel
TRACE envelopes and evidence packs¶
EvidencePack above is only a reference to a pack. To appraise the pack itself, and the per-tool-call TRACE envelopes inside it, use:
A TRACE envelope (spec §6.3.2) is signed by a TEE-sealed key over the RFC 8785 canonical form of every field except signature. The envelope carries no algorithm or key id of its own, so the caller supplies both; trusted_keys uses the same key_id → base64url public key mapping as VerificationContext. An evidence pack (spec §5.2.1) instead carries a detached pack_signature object in the form of §3.6, so hybrid signatures work there but not on envelopes.
Read admissible, not just status. A TRACE reporting manifest_verification_result: MISMATCH or EXPIRED can have a perfectly valid signature — the runtime honestly recorded a bad state — but spec §6.3.2 says it "MUST NOT be accepted as evidence of a valid tool call for regulatory reporting purposes". verify_trace_envelope() returns status=VERIFIED with admissible=False in that case.
Passing manifest= additionally enforces the §6.3.2 hash-conflict rule (SCHEMA F-21): if the envelope's policy_hash differs from the manifest's artifacts.policy_bundle.hash, the envelope must declare MISMATCH. One that claims VALID over a conflicting hash is a spec violation and fails.
Verification is fail-closed: a missing key, an unknown algorithm, or a build without the [pq] extra yields UNVERIFIABLE, never VERIFIED.
verify_trace_envelope ¶
verify_trace_envelope(envelope: dict[str, Any], *, trusted_keys: Optional[dict[str, str]] = None, key_id: Optional[str] = None, algorithm: str = 'Ed25519', manifest: Optional[dict[str, Any]] = None) -> TraceVerificationResult
Verify one TRACE envelope's signature and manifest binding (spec 6.3.2).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
envelope | dict[str, Any] | The TRACE envelope dict. | required |
trusted_keys | Optional[dict[str, str]] | key_id (sha256 hex of raw public key bytes) -> base64url public key. The envelope carries no key id of its own. | None |
key_id | Optional[str] | Which trusted key signed this envelope. Optional when exactly one key is trusted. | None |
algorithm | str |
| 'Ed25519' |
manifest | Optional[dict[str, Any]] | When supplied, enforces the spec 6.3.2 hash-conflict rule (SCHEMA F-21) against | None |
Returns:
| Name | Type | Description |
|---|---|---|
A | TraceVerificationResult | class: |
TraceVerificationResult | the envelope as evidence -- a verified signature alone is not enough. |
verify_evidence_pack ¶
verify_evidence_pack(pack: dict[str, Any], *, trusted_keys: Optional[dict[str, str]] = None, expected_pack_hash: Optional[str] = None, trace_key_id: Optional[str] = None, trace_algorithm: str = 'Ed25519', verify_envelopes: bool = True) -> EvidencePackVerificationResult
Verify an evidence pack's pack_signature and its TRACE envelopes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
pack | dict[str, Any] | The evidence pack document (spec 5.2.1). | required |
trusted_keys | Optional[dict[str, str]] | key_id -> base64url public key, covering both the pack's TEE-sealed key and the envelope signing key. | None |
expected_pack_hash | Optional[str] | When supplied (e.g. the | None |
trace_key_id | Optional[str] | Key id for the envelopes inside the pack. | None |
trace_algorithm | str | Envelope signature algorithm. | 'Ed25519' |
verify_envelopes | bool | Set False to appraise only the pack signature. | True |
Returns:
| Name | Type | Description |
|---|---|---|
An | EvidencePackVerificationResult | class: |
EvidencePackVerificationResult | only when the pack signature verifies, any supplied | |
EvidencePackVerificationResult | matches, and (when checked) every envelope is admissible. |
TraceVerificationResult dataclass ¶
Appraisal of one TRACE envelope.
admissible is the question a relying party actually asks: may this record be used as evidence of a valid tool call? That needs a verified signature and a manifest_verification_result outside :data:INADMISSIBLE_RESULTS. A perfectly-signed envelope reporting MISMATCH is authentic and inadmissible at the same time -- the signature proves the runtime honestly recorded that the policy hash did not match, which is exactly the case spec 6.3.2 excludes from reporting.
EvidencePackVerificationResult dataclass ¶
Appraisal of an evidence pack and, optionally, the TRACEs inside it.
TraceStatus ¶
Bases: str, Enum
Outcome of appraising a TRACE envelope or evidence pack.
compute_pack_hash() returns the spec §5.2.1 pack_hash — the SHA-256 of the pack's canonical bytes excluding pack_signature. trace_signing_pre_image() and evidence_pack_pre_image() are the shared pre-image functions; producers and verifiers MUST both use them so the byte sequences match.
compute_pack_hash ¶
Return "sha256:<64-hex>" over the pack's canonical bytes (spec 5.2.1).
trace_signing_pre_image ¶
Return the RFC 8785 canonical bytes a TRACE signature covers.
Every field except signature itself. Both producers and verifiers MUST call this so the byte sequences are identical.
evidence_pack_pre_image ¶
Return the RFC 8785 canonical bytes pack_signature covers.
Every field except pack_signature, which spec 5.2.1 appends to the document after hashing and signing.
Revocation¶
RevocationStore is the revocation lookup a verifier consults during verify_manifest(); the default is in-memory, and production deployments back it with a persistent store. RevocationRecord is a single revocation entry: which manifest was revoked, when, why, and by whom.
RevocationStore ¶
In-memory revocation store. Production should use a persistent backend.
RevocationRecord ¶
Bases: BaseModel
FastAPI router¶
create_router ¶
create_router(manifest_store: dict[str, dict[str, Any]], revocation_store: RevocationStore, cose_context: Optional[VerificationContext] = None) -> Any
Return a FastAPI APIRouter with /verify and /revocation-status endpoints.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
manifest_store | dict[str, dict[str, Any]] | Dict mapping manifest_id -> manifest dict. | required |
revocation_store | RevocationStore | Revocation store instance. | required |
cose_context | Optional[VerificationContext] | Trust configuration for | None |