vitnify 0.2.1__tar.gz → 0.2.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {vitnify-0.2.1/src/vitnify.egg-info → vitnify-0.2.2}/PKG-INFO +1 -1
- {vitnify-0.2.1 → vitnify-0.2.2}/pyproject.toml +1 -1
- {vitnify-0.2.1 → vitnify-0.2.2}/src/vitnify/certificate.py +8 -0
- {vitnify-0.2.1 → vitnify-0.2.2/src/vitnify.egg-info}/PKG-INFO +1 -1
- {vitnify-0.2.1 → vitnify-0.2.2}/tests/test_receipt_v2.py +21 -0
- {vitnify-0.2.1 → vitnify-0.2.2}/LICENSE +0 -0
- {vitnify-0.2.1 → vitnify-0.2.2}/NOTICE +0 -0
- {vitnify-0.2.1 → vitnify-0.2.2}/README.md +0 -0
- {vitnify-0.2.1 → vitnify-0.2.2}/setup.cfg +0 -0
- {vitnify-0.2.1 → vitnify-0.2.2}/src/vitnify/__init__.py +0 -0
- {vitnify-0.2.1 → vitnify-0.2.2}/src/vitnify/_vendor/__init__.py +0 -0
- {vitnify-0.2.1 → vitnify-0.2.2}/src/vitnify/_vendor/pck/__init__.py +0 -0
- {vitnify-0.2.1 → vitnify-0.2.2}/src/vitnify/_vendor/pck/cas.py +0 -0
- {vitnify-0.2.1 → vitnify-0.2.2}/src/vitnify/capability.py +0 -0
- {vitnify-0.2.1 → vitnify-0.2.2}/src/vitnify/deterministic_llm.py +0 -0
- {vitnify-0.2.1 → vitnify-0.2.2}/src/vitnify/engine.py +0 -0
- {vitnify-0.2.1 → vitnify-0.2.2}/src/vitnify/events.py +0 -0
- {vitnify-0.2.1 → vitnify-0.2.2}/src/vitnify/langgraph_adapter.py +0 -0
- {vitnify-0.2.1 → vitnify-0.2.2}/src/vitnify/mcp_adapter.py +0 -0
- {vitnify-0.2.1 → vitnify-0.2.2}/src/vitnify/react.py +0 -0
- {vitnify-0.2.1 → vitnify-0.2.2}/src/vitnify/replayer.py +0 -0
- {vitnify-0.2.1 → vitnify-0.2.2}/src/vitnify/viewer.py +0 -0
- {vitnify-0.2.1 → vitnify-0.2.2}/src/vitnify.egg-info/SOURCES.txt +0 -0
- {vitnify-0.2.1 → vitnify-0.2.2}/src/vitnify.egg-info/dependency_links.txt +0 -0
- {vitnify-0.2.1 → vitnify-0.2.2}/src/vitnify.egg-info/requires.txt +0 -0
- {vitnify-0.2.1 → vitnify-0.2.2}/src/vitnify.egg-info/top_level.txt +0 -0
- {vitnify-0.2.1 → vitnify-0.2.2}/tests/test_adapters.py +0 -0
- {vitnify-0.2.1 → vitnify-0.2.2}/tests/test_attack_matrix.py +0 -0
- {vitnify-0.2.1 → vitnify-0.2.2}/tests/test_capability.py +0 -0
- {vitnify-0.2.1 → vitnify-0.2.2}/tests/test_certificate.py +0 -0
- {vitnify-0.2.1 → vitnify-0.2.2}/tests/test_ed25519.py +0 -0
- {vitnify-0.2.1 → vitnify-0.2.2}/tests/test_events.py +0 -0
- {vitnify-0.2.1 → vitnify-0.2.2}/tests/test_l2_recompute.py +0 -0
- {vitnify-0.2.1 → vitnify-0.2.2}/tests/test_verification.py +0 -0
- {vitnify-0.2.1 → vitnify-0.2.2}/tests/test_verify_hardening.py +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "vitnify"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.2"
|
|
8
8
|
description = "Execution receipts for AI agents: contain, deterministically reconstruct, and cryptographically certify a run."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -195,6 +195,14 @@ def verify_certificate(cert: ExecutionCertificate, log: EventLog, key: bytes | N
|
|
|
195
195
|
and str(e.payload.get("decision", "")).lower() == "allow"
|
|
196
196
|
)
|
|
197
197
|
|
|
198
|
+
# A verified receipt must carry NO data field its version does not sign. The v1
|
|
199
|
+
# body binds none of the v2 issuance fields, so a v1 receipt with issued_at /
|
|
200
|
+
# nonce / run_id set is carrying an unsigned, forgeable value (e.g. a backdated
|
|
201
|
+
# issued_at) -- reject it, so ok=True never blesses data outside the signature.
|
|
202
|
+
checks["fields_match_version"] = not (
|
|
203
|
+
cert.v == "vitnify-receipt v1"
|
|
204
|
+
and any(x is not None for x in (cert.issued_at, cert.nonce, cert.run_id)))
|
|
205
|
+
|
|
198
206
|
# Optional signer pinning -- an embedded key proves continuity, not authority.
|
|
199
207
|
# When an allow-list is supplied, the signer must be ed25519 and on the list.
|
|
200
208
|
if pinned_pubkeys is not None:
|
|
@@ -109,3 +109,24 @@ def test_f9_session_llm_records_provider():
|
|
|
109
109
|
ev = next(e for e in s.log.events if e.kind == Kind.LLM_CALL.value)
|
|
110
110
|
assert ev.payload["provider"] == {
|
|
111
111
|
"provider": "openai", "model_version": "gpt-x", "response_id": "resp_1"}
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def test_f10_v1_receipt_carrying_v2_fields_is_rejected():
|
|
115
|
+
# F10: v1 does not sign issued_at/nonce/run_id, so a v1 receipt that CARRIES them
|
|
116
|
+
# is carrying unsigned, forgeable data (e.g. a backdated timestamp) -- it must not
|
|
117
|
+
# verify, or ok=True would bless a value outside the signature.
|
|
118
|
+
from vitnify.certificate import ExecutionCertificate, _canon, _digest32
|
|
119
|
+
from vitnify._vendor.pck.cas import MerkleCAS
|
|
120
|
+
priv, pub = gen_ed25519()
|
|
121
|
+
log = _run(); cas = MerkleCAS(log.chunks())
|
|
122
|
+
b1 = {"v": "vitnify-receipt v1", "program_hash": "p", "capabilities": ["read_docs"],
|
|
123
|
+
"event_root": cas.root, "n_events": len(log), "head_hash": log.head(),
|
|
124
|
+
"model_digests": log.model_digests()}
|
|
125
|
+
sig = priv.sign(bytes.fromhex(_digest32(_canon(b1).encode()))).hex()
|
|
126
|
+
cert = ExecutionCertificate("p", ["read_docs"], cas.root, len(log), log.head(),
|
|
127
|
+
model_digests=log.model_digests())
|
|
128
|
+
cert.v, cert.sig, cert.sig_alg, cert.pubkey = "vitnify-receipt v1", sig, "ed25519", pub
|
|
129
|
+
assert verify_certificate(cert, log)["ok"] is True # genuine v1 still verifies
|
|
130
|
+
cert.issued_at = "2019-01-01T00:00:00Z" # forge a backdated timestamp
|
|
131
|
+
r = verify_certificate(cert, log)
|
|
132
|
+
assert r["fields_match_version"] is False and r["ok"] is False
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|