Dependency-free path_proof package under a dedicated module. Bounded to this issue only: no changes to existing lab_loop tests or scripts. Deliverables: 1. path_proof/ package (receipt.py, keys.py, __init__.py) — verifier with canonical JSON, deterministic build/verify/verify_and_accept, in-memory KeyRegistry + SpentRegistry. No I/O, no wall clock, no randomness. 2. Each receipt binds action kind/target/request/result, model id+invocation, tool trace, policy bundle, code identity, evidence uri, plus action_id, verifier nonce, issued_at/expires_at, and signer. 3. Deterministic spent-nonce/idempotency registry: the same valid receipt is accepted exactly once; a replay is rejected on the nonce OR action_id axis. 4. Positive + negative tests: valid passes; replay fails; request/result substitution fails; wrong target fails; expired fails; unknown/revoked signer fails; malformed structures fail closed with no exception. Every negative case asserts rejection AND a specific reason. 5. docs/path-proof-threat-boundary.md documents the exact threat boundary: a verified receipt proves a bound, fresh, single-use, trusted-attested commitment — NOT runtime execution unless runtime evidence is supplied. Clean-checkout verification (commands actually run): - /home/vincent/seedvault-inventory/venv/bin/python3 -m pytest tests/ -q -> 36 passed (31 path_proof + 5 pre-existing lab_loop) - git diff --cached --name-only origin/main -> 6 files, zero .pyc - __pycache__ gitignored; clean checkout stays clean after tests Closes #28 Refs: #3 (Vincent path-proof critique), #19/PR #42 (canon validator r2) [HANDOFF] from=vincent to=timmy
53 lines
1.6 KiB
Python
53 lines
1.6 KiB
Python
"""
|
|
Path Proof receipt replay/forgery gate.
|
|
|
|
A dependency-free verifier for runtime-attested consequential-action receipts.
|
|
See ``docs/path-proof-receipt.md`` for the threat model and field rationale.
|
|
|
|
Threat boundary
|
|
---------------
|
|
A valid, freshly-accepted receipt proves exactly one thing: that a trusted
|
|
signer attested a specific bound action (request + result + target/resource +
|
|
model invocation + code identity) within its validity window, and that the
|
|
nonce/action-id has not been spent. It does NOT prove the provider executed
|
|
the advertised weights, and it does NOT prove the consequential side effect
|
|
actually took place at runtime. Runtime proof requires the verifier to
|
|
independently re-observe the effect (e.g. read Gitea state back and compare
|
|
``result_sha256``). Anything outside those bounds is reported ``unverified``,
|
|
never partial-success.
|
|
|
|
Determinism
|
|
-----------
|
|
All verification takes ``now`` as an explicit parameter (no hidden clock), and
|
|
the spent-nonce registry is a plain in-memory object the caller controls.
|
|
There is no I/O, no randomness, and no network in this module.
|
|
"""
|
|
|
|
from . import keys
|
|
from .keys import SignerKey
|
|
from .receipt import (
|
|
SPEND_KIND_NONCE,
|
|
SPEND_KIND_ACTION_ID,
|
|
SpendRecord,
|
|
SpentRegistry,
|
|
canonical_json,
|
|
build_receipt,
|
|
receipt_payload,
|
|
verify_receipt,
|
|
verify_and_accept,
|
|
)
|
|
|
|
__all__ = [
|
|
"SPEND_KIND_NONCE",
|
|
"SPEND_KIND_ACTION_ID",
|
|
"SignerKey",
|
|
"SpendRecord",
|
|
"SpentRegistry",
|
|
"canonical_json",
|
|
"build_receipt",
|
|
"receipt_payload",
|
|
"verify_receipt",
|
|
"verify_and_accept",
|
|
"keys",
|
|
]
|