betterwithage commited on
Commit
4061178
·
verified ·
1 Parent(s): 44d2c74

chore(sync): mirror backend .py + Dockerfile to Space (hf-sync-backend)

Browse files

Automated backend sync from szl-holdings/a11oy main via hf-sync-backend.
Updated (differed from the Space): a11oy_forge_family.py, ayllu/model_binding.py, model_release/receipt-agent/reconciliation/reconcile_artifact_binding.py
Deleted (gone from the repo + Dockerfile COPY set): (none)

Keeps the Space-built backend (serve.py + the Dockerfile-COPY'd .py
modules) identical to GitHub main so the Space never rebuilds from a
stale backend, new endpoints don't 404 there, and orphaned modules
removed from the repo don't linger in the Space tree.

a11oy_forge_family.py CHANGED
@@ -41,6 +41,7 @@ import json
41
  import os
42
  import time
43
  from datetime import datetime, timezone
 
44
 
45
  import httpx
46
  from cryptography.hazmat.primitives.serialization import load_der_public_key
@@ -50,6 +51,14 @@ _ROUTE = "/api/forge/family"
50
  _HF = "https://huggingface.co"
51
  _RECEIPT_FILES = ("owner_pubkey.json", "training_receipt.signed.json", "eval_receipt.signed.json")
52
  _CACHE_TTL_SECONDS = 300 # receipt BYTES only; verification always re-runs
 
 
 
 
 
 
 
 
53
 
54
  _MODELS = (
55
  {
@@ -57,6 +66,7 @@ _MODELS = (
57
  "displayName": "SZL-Forge-1.5B-ReceiptAgent",
58
  "hfRepo": "SZLHOLDINGS/SZL-Forge-1.5B-ReceiptAgent",
59
  "pinEnv": "A11OY_OWNER_KEYID",
 
60
  },
61
  {
62
  "model": "khipu",
@@ -66,8 +76,8 @@ _MODELS = (
66
  },
67
  )
68
 
69
- # repo -> {"at": epoch, "files": {name: bytes}}
70
- _byte_cache: dict = {}
71
 
72
 
73
  def _now_iso() -> str:
@@ -83,20 +93,67 @@ def _canonical(payload: dict) -> str:
83
  return json.dumps(payload, sort_keys=True, separators=(",", ":"), ensure_ascii=False)
84
 
85
 
86
- async def _fetch_receipt_bytes(client: httpx.AsyncClient, repo: str) -> dict:
87
- cached = _byte_cache.get(repo)
 
 
 
 
 
88
  if cached and (time.time() - cached["at"]) < _CACHE_TTL_SECONDS:
89
  return cached
90
  files = {}
91
  for name in _RECEIPT_FILES:
92
- resp = await client.get(f"{_HF}/{repo}/resolve/main/{name}")
93
  resp.raise_for_status()
94
  files[name] = resp.content
95
  entry = {"at": time.time(), "files": files}
96
- _byte_cache[repo] = entry
97
  return entry
98
 
99
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
  def _verify_one_receipt(receipt: dict, owner_spki_b64: str, owner_key_id: str, expected_kind_word: str) -> dict:
101
  """Run every check for one signed receipt. Returns {check_name: bool} + meta."""
102
  checks = {}
@@ -130,7 +187,12 @@ def _verify_one_receipt(receipt: dict, owner_spki_b64: str, owner_key_id: str, e
130
  }
131
 
132
 
133
- def _band_for_model(cfg: dict, raw_files: dict, fetched_at_epoch: float) -> dict:
 
 
 
 
 
134
  """Build one fully-verified wall band. Verification runs on every call."""
135
  owner = json.loads(raw_files["owner_pubkey.json"])
136
  training = json.loads(raw_files["training_receipt.signed.json"])
@@ -141,7 +203,7 @@ def _band_for_model(cfg: dict, raw_files: dict, fetched_at_epoch: float) -> dict
141
  owner_checks = {
142
  "ownerAlgoIsEd25519": owner.get("algo") == "ed25519",
143
  "ownerKeyIdDerivesFromSpki": (
144
- _sha256_hex(base64.b64decode(owner_spki_b64)) [:16] == owner_key_id
145
  if owner_spki_b64 else False
146
  ),
147
  }
@@ -168,6 +230,71 @@ def _band_for_model(cfg: dict, raw_files: dict, fetched_at_epoch: float) -> dict
168
 
169
  training_verified = owner_checks["ownerAlgoIsEd25519"] and owner_checks["ownerKeyIdDerivesFromSpki"] and training_result["allPassed"] and pin_ok
170
  eval_verified = owner_checks["ownerAlgoIsEd25519"] and owner_checks["ownerKeyIdDerivesFromSpki"] and eval_result["allPassed"] and chain_ok and pin_ok
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
171
  ep = eval_result["payload"]
172
  tp = training_result["payload"]
173
 
@@ -178,11 +305,26 @@ def _band_for_model(cfg: dict, raw_files: dict, fetched_at_epoch: float) -> dict
178
  "keyId": owner_key_id,
179
  "keyTrust": key_trust,
180
  "pinEnv": pin_env,
181
- "verified": training_verified and eval_verified,
 
182
  "status": (
183
  (["TRAINED_RECEIPT_VERIFIED"] if training_verified else ["TRAINING_RECEIPT_FAILED"])
184
  + (["EVAL_RECEIPT_VERIFIED"] if eval_verified else ["EVAL_RECEIPT_FAILED"])
 
 
 
 
 
 
 
 
 
 
 
 
 
185
  ),
 
186
  "checks": {
187
  "owner": owner_checks,
188
  "training": training_result["checks"],
@@ -215,8 +357,22 @@ async def _forge_family_handler():
215
  async with httpx.AsyncClient(timeout=10.0, follow_redirects=True) as client:
216
  for cfg in _MODELS:
217
  try:
218
- entry = await _fetch_receipt_bytes(client, cfg["hfRepo"])
219
- bands.append(_band_for_model(cfg, entry["files"], entry["at"]))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
220
  except Exception as band_error: # loud, honest, isolated per band
221
  bands.append({
222
  "model": cfg["model"],
 
41
  import os
42
  import time
43
  from datetime import datetime, timezone
44
+ from pathlib import Path
45
 
46
  import httpx
47
  from cryptography.hazmat.primitives.serialization import load_der_public_key
 
51
  _HF = "https://huggingface.co"
52
  _RECEIPT_FILES = ("owner_pubkey.json", "training_receipt.signed.json", "eval_receipt.signed.json")
53
  _CACHE_TTL_SECONDS = 300 # receipt BYTES only; verification always re-runs
54
+ _RECONCILIATION_STATE = "ARTIFACT_BYTES_RECONCILED_MEASURED_NOT_PROMOTED"
55
+ _RECONCILIATION_PATH = (
56
+ Path(__file__).resolve().parent
57
+ / "model_release"
58
+ / "receipt-agent"
59
+ / "reconciliation"
60
+ / "receipt-agent-artifact-reconciliation.v1.json"
61
+ )
62
 
63
  _MODELS = (
64
  {
 
66
  "displayName": "SZL-Forge-1.5B-ReceiptAgent",
67
  "hfRepo": "SZLHOLDINGS/SZL-Forge-1.5B-ReceiptAgent",
68
  "pinEnv": "A11OY_OWNER_KEYID",
69
+ "artifactReconciliation": True,
70
  },
71
  {
72
  "model": "khipu",
 
76
  },
77
  )
78
 
79
+ # (repo, immutable revision) -> {"at": epoch, "files": {name: bytes}}
80
+ _byte_cache: dict[tuple[str, str], dict] = {}
81
 
82
 
83
  def _now_iso() -> str:
 
93
  return json.dumps(payload, sort_keys=True, separators=(",", ":"), ensure_ascii=False)
94
 
95
 
96
+ async def _fetch_receipt_bytes(
97
+ client: httpx.AsyncClient,
98
+ repo: str,
99
+ revision: str,
100
+ ) -> dict:
101
+ cache_key = (repo, revision)
102
+ cached = _byte_cache.get(cache_key)
103
  if cached and (time.time() - cached["at"]) < _CACHE_TTL_SECONDS:
104
  return cached
105
  files = {}
106
  for name in _RECEIPT_FILES:
107
+ resp = await client.get(f"{_HF}/{repo}/resolve/{revision}/{name}")
108
  resp.raise_for_status()
109
  files[name] = resp.content
110
  entry = {"at": time.time(), "files": files}
111
+ _byte_cache[cache_key] = entry
112
  return entry
113
 
114
 
115
+ async def _fetch_public_head(client: httpx.AsyncClient, repo: str) -> str:
116
+ """Observe the current public head independently of cached receipt bytes."""
117
+ response = await client.get(f"{_HF}/api/models/{repo}")
118
+ response.raise_for_status()
119
+ payload = response.json()
120
+ revision = payload.get("sha") if isinstance(payload, dict) else None
121
+ if (
122
+ not isinstance(revision, str)
123
+ or len(revision) != 40
124
+ or any(character not in "0123456789abcdef" for character in revision)
125
+ ):
126
+ raise ValueError("Hugging Face model API did not return a lowercase hex head")
127
+ return revision
128
+
129
+
130
+ def _load_receipt_agent_reconciliation() -> dict:
131
+ """Load and self-verify the frozen, non-promoting reconciliation artifact."""
132
+ value = json.loads(_RECONCILIATION_PATH.read_text(encoding="utf-8"))
133
+ recorded = value.get("reconciliation_sha256")
134
+ unsigned = dict(value)
135
+ unsigned.pop("reconciliation_sha256", None)
136
+ computed = _sha256_hex(_canonical(unsigned).encode("utf-8"))
137
+ if recorded != computed:
138
+ raise ValueError("ReceiptAgent reconciliation self-digest mismatch")
139
+ if value.get("state") != _RECONCILIATION_STATE:
140
+ raise ValueError("ReceiptAgent reconciliation state mismatch")
141
+ if value.get("repository") != "SZLHOLDINGS/SZL-Forge-1.5B-ReceiptAgent":
142
+ raise ValueError("ReceiptAgent reconciliation repository mismatch")
143
+ if value.get("authorization") != {
144
+ "trained": False,
145
+ "uploaded": False,
146
+ "promoted": False,
147
+ "deployed": False,
148
+ }:
149
+ raise ValueError("ReceiptAgent reconciliation overstates authorization")
150
+ binding = value.get("exact_qualified_artifact_binding") or {}
151
+ head = value.get("current_public_head_equivalence") or {}
152
+ if binding.get("verified") is not True or head.get("verified") is not True:
153
+ raise ValueError("ReceiptAgent reconciliation is not fully verified")
154
+ return value
155
+
156
+
157
  def _verify_one_receipt(receipt: dict, owner_spki_b64: str, owner_key_id: str, expected_kind_word: str) -> dict:
158
  """Run every check for one signed receipt. Returns {check_name: bool} + meta."""
159
  checks = {}
 
187
  }
188
 
189
 
190
+ def _band_for_model(
191
+ cfg: dict,
192
+ raw_files: dict,
193
+ fetched_at_epoch: float,
194
+ public_head_revision: str | None = None,
195
+ ) -> dict:
196
  """Build one fully-verified wall band. Verification runs on every call."""
197
  owner = json.loads(raw_files["owner_pubkey.json"])
198
  training = json.loads(raw_files["training_receipt.signed.json"])
 
203
  owner_checks = {
204
  "ownerAlgoIsEd25519": owner.get("algo") == "ed25519",
205
  "ownerKeyIdDerivesFromSpki": (
206
+ _sha256_hex(base64.b64decode(owner_spki_b64))[:16] == owner_key_id
207
  if owner_spki_b64 else False
208
  ),
209
  }
 
230
 
231
  training_verified = owner_checks["ownerAlgoIsEd25519"] and owner_checks["ownerKeyIdDerivesFromSpki"] and training_result["allPassed"] and pin_ok
232
  eval_verified = owner_checks["ownerAlgoIsEd25519"] and owner_checks["ownerKeyIdDerivesFromSpki"] and eval_result["allPassed"] and chain_ok and pin_ok
233
+ receipt_signatures_verified = training_verified and eval_verified
234
+ verification_layers = {
235
+ "receiptSignatureValidity": {
236
+ "verified": receipt_signatures_verified,
237
+ "training": training_verified,
238
+ "evaluation": eval_verified,
239
+ "trustBoundary": {
240
+ "PINNED": "PINNED_OWNER_KEY",
241
+ "PIN_MISMATCH": "PIN_MISMATCH_FAIL_CLOSED",
242
+ "REPO_DECLARED": (
243
+ "REPOSITORY_DECLARED_KEY_NOT_INDEPENDENTLY_PINNED"
244
+ ),
245
+ }[key_trust],
246
+ },
247
+ "exactQualifiedArtifactBinding": {
248
+ "verified": None,
249
+ "state": "NOT_EVALUATED_FOR_THIS_PROFILE",
250
+ },
251
+ "currentPublicHeadEquivalence": {
252
+ "verified": None,
253
+ "state": "NOT_EVALUATED_FOR_THIS_PROFILE",
254
+ "observedHead": public_head_revision,
255
+ },
256
+ "promotion": {
257
+ "authorized": False,
258
+ "state": "NOT_PROMOTED",
259
+ },
260
+ }
261
+ profile_state = None
262
+ fully_verified = receipt_signatures_verified
263
+ if cfg.get("artifactReconciliation"):
264
+ reconciliation = _load_receipt_agent_reconciliation()
265
+ artifact_binding = reconciliation["exact_qualified_artifact_binding"]
266
+ frozen_head = reconciliation["public_head_revision"]
267
+ current_head_equivalent = public_head_revision == frozen_head
268
+ verification_layers["exactQualifiedArtifactBinding"] = {
269
+ "verified": artifact_binding["verified"] is True,
270
+ "state": _RECONCILIATION_STATE,
271
+ "qualifiedRevision": reconciliation["qualified_revision"],
272
+ "qualificationReceiptSha256": artifact_binding[
273
+ "qualification_receipt_sha256"
274
+ ],
275
+ "digestDomain": artifact_binding["digest_domain"],
276
+ }
277
+ verification_layers["currentPublicHeadEquivalence"] = {
278
+ "verified": current_head_equivalent,
279
+ "state": (
280
+ "INFERENCE_BEARING_BLOBS_EQUIVALENT_TO_QUALIFIED_REVISION"
281
+ if current_head_equivalent
282
+ else "PUBLIC_HEAD_CHANGED_RECONCILIATION_REQUIRED"
283
+ ),
284
+ "observedHead": public_head_revision,
285
+ "reconciledHead": frozen_head,
286
+ "failClosedOnHeadChange": True,
287
+ }
288
+ fully_verified = (
289
+ receipt_signatures_verified
290
+ and artifact_binding["verified"] is True
291
+ and current_head_equivalent
292
+ )
293
+ profile_state = (
294
+ _RECONCILIATION_STATE
295
+ if fully_verified
296
+ else "ARTIFACT_RECONCILIATION_FAILED_CLOSED"
297
+ )
298
  ep = eval_result["payload"]
299
  tp = training_result["payload"]
300
 
 
305
  "keyId": owner_key_id,
306
  "keyTrust": key_trust,
307
  "pinEnv": pin_env,
308
+ "verified": fully_verified,
309
+ "profileState": profile_state,
310
  "status": (
311
  (["TRAINED_RECEIPT_VERIFIED"] if training_verified else ["TRAINING_RECEIPT_FAILED"])
312
  + (["EVAL_RECEIPT_VERIFIED"] if eval_verified else ["EVAL_RECEIPT_FAILED"])
313
+ + (
314
+ [
315
+ "ARTIFACT_BYTES_RECONCILED_MEASURED",
316
+ "CURRENT_PUBLIC_HEAD_EQUIVALENT",
317
+ "NOT_PROMOTED",
318
+ ]
319
+ if cfg.get("artifactReconciliation") and fully_verified
320
+ else (
321
+ ["ARTIFACT_RECONCILIATION_FAILED_CLOSED", "NOT_PROMOTED"]
322
+ if cfg.get("artifactReconciliation")
323
+ else []
324
+ )
325
+ )
326
  ),
327
+ "verificationLayers": verification_layers,
328
  "checks": {
329
  "owner": owner_checks,
330
  "training": training_result["checks"],
 
357
  async with httpx.AsyncClient(timeout=10.0, follow_redirects=True) as client:
358
  for cfg in _MODELS:
359
  try:
360
+ public_head_revision = await _fetch_public_head(
361
+ client, cfg["hfRepo"]
362
+ )
363
+ entry = await _fetch_receipt_bytes(
364
+ client,
365
+ cfg["hfRepo"],
366
+ public_head_revision,
367
+ )
368
+ bands.append(
369
+ _band_for_model(
370
+ cfg,
371
+ entry["files"],
372
+ entry["at"],
373
+ public_head_revision,
374
+ )
375
+ )
376
  except Exception as band_error: # loud, honest, isolated per band
377
  bands.append({
378
  "model": cfg["model"],
ayllu/model_binding.py CHANGED
@@ -33,7 +33,7 @@ _ALL_COMPUTE_OPERATIONS = (
33
  )
34
 
35
  _PROFILE_STATES = {
36
- "ReceiptAgent-v1": "SIGNED_RECEIPTS_VALID_ARTIFACT_BINDING_CONFLICT",
37
  "BrainNavigator-v1": "SIGNED_RECEIPTS_VALID_ARTIFACT_BINDING_CONFLICT",
38
  "Operator-v1": "PLANNED_TOOL_CONTRACT_REQUIRED",
39
  "Sentinel-v1": "PLANNED_SECURITY_ADMISSION_REQUIRED",
 
33
  )
34
 
35
  _PROFILE_STATES = {
36
+ "ReceiptAgent-v1": "ARTIFACT_BYTES_RECONCILED_MEASURED_NOT_PROMOTED",
37
  "BrainNavigator-v1": "SIGNED_RECEIPTS_VALID_ARTIFACT_BINDING_CONFLICT",
38
  "Operator-v1": "PLANNED_TOOL_CONTRACT_REQUIRED",
39
  "Sentinel-v1": "PLANNED_SECURITY_ADMISSION_REQUIRED",
model_release/receipt-agent/reconciliation/reconcile_artifact_binding.py ADDED
@@ -0,0 +1,578 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Offline ReceiptAgent artifact-binding reconciliation.
3
+
4
+ The input fixture is a frozen observation captured from the public Hugging Face
5
+ Git repository. This program performs no network access and does not download,
6
+ train, upload, promote, or deploy a model. It separates three claims:
7
+
8
+ 1. the repository-declared Ed25519 receipt signatures verified during the
9
+ qualification run;
10
+ 2. the exact qualified weight/adapter byte binding, including the ReceiptAgent
11
+ signer's basename-plus-bytes digest domain; and
12
+ 3. equivalence of every inference-bearing Git blob at the observed public head
13
+ to the qualified revision.
14
+
15
+ Any inference-bearing drift, digest-domain mismatch, invalid qualification
16
+ self-digest, or promotion claim is a hard refusal.
17
+ """
18
+
19
+ from __future__ import annotations
20
+
21
+ import argparse
22
+ import base64
23
+ import hashlib
24
+ import json
25
+ from pathlib import Path
26
+ from typing import Any
27
+
28
+
29
+ SCHEMA_VERSION = "szl.receiptagent-artifact-reconciliation.v1"
30
+ FIXTURE_SCHEMA_VERSION = "szl.receiptagent-artifact-reconciliation-fixture.v1"
31
+ RECONCILED_STATE = "ARTIFACT_BYTES_RECONCILED_MEASURED_NOT_PROMOTED"
32
+ REPOSITORY = "SZLHOLDINGS/SZL-Forge-1.5B-ReceiptAgent"
33
+ QUALIFIED_REVISION = "fa73dc1bd8eeece727d0b5c1db52448ec0703e8b"
34
+ PUBLIC_HEAD_REVISION = "2e62cb5f8e6a17052da532305a467861094a2109"
35
+ HEX40 = set("0123456789abcdef")
36
+ HEX64 = HEX40
37
+ INFERENCE_BEARING_PATHS = frozenset(
38
+ {
39
+ "adapter/adapter_config.json",
40
+ "adapter/adapter_model.safetensors",
41
+ "chat_template.jinja",
42
+ "config.json",
43
+ "eval_receipt.signed.json",
44
+ "generation_config.json",
45
+ "model.safetensors",
46
+ "owner_pubkey.json",
47
+ "receiptagent.schema.json",
48
+ "tokenizer.json",
49
+ "tokenizer_config.json",
50
+ "training_receipt.signed.json",
51
+ }
52
+ )
53
+
54
+
55
+ class ReconciliationRefusal(RuntimeError):
56
+ """The frozen evidence cannot support artifact equivalence."""
57
+
58
+
59
+ def _require(condition: bool, message: str) -> None:
60
+ if not condition:
61
+ raise ReconciliationRefusal(message)
62
+
63
+
64
+ def _strict_keys(value: dict[str, Any], expected: set[str], label: str) -> None:
65
+ _require(set(value) == expected, f"{label} keys do not match the frozen contract")
66
+
67
+
68
+ def _is_hex(value: Any, length: int) -> bool:
69
+ return (
70
+ isinstance(value, str)
71
+ and len(value) == length
72
+ and all(character in HEX40 for character in value)
73
+ )
74
+
75
+
76
+ def canonical_bytes(value: Any) -> bytes:
77
+ return json.dumps(
78
+ value, sort_keys=True, separators=(",", ":"), ensure_ascii=False
79
+ ).encode("utf-8")
80
+
81
+
82
+ def sha256_bytes(value: bytes) -> str:
83
+ return hashlib.sha256(value).hexdigest()
84
+
85
+
86
+ def git_blob_sha1(value: bytes) -> str:
87
+ header = b"blob " + str(len(value)).encode("ascii") + b"\0"
88
+ return hashlib.sha1(header + value, usedforsecurity=False).hexdigest()
89
+
90
+
91
+ def git_object_sha1(kind: str, value: bytes) -> str:
92
+ _require(kind in {"commit", "tree"}, "unsupported Git object kind")
93
+ header = kind.encode("ascii") + b" " + str(len(value)).encode("ascii") + b"\0"
94
+ return hashlib.sha1(header + value, usedforsecurity=False).hexdigest()
95
+
96
+
97
+ def lfs_pointer_git_blob_sha1(raw_sha256: str, size: int) -> str:
98
+ pointer = (
99
+ "version https://git-lfs.github.com/spec/v1\n"
100
+ f"oid sha256:{raw_sha256}\n"
101
+ f"size {size}\n"
102
+ ).encode("ascii")
103
+ return git_blob_sha1(pointer)
104
+
105
+
106
+ def self_digest(value: dict[str, Any], field: str) -> str:
107
+ unsigned = dict(value)
108
+ unsigned.pop(field, None)
109
+ return sha256_bytes(canonical_bytes(unsigned))
110
+
111
+
112
+ def receipt_digest(value: dict[str, Any]) -> str:
113
+ return self_digest(value, "receipt_sha256")
114
+
115
+
116
+ def raw_and_receipt_digest(basename: str, content: bytes) -> tuple[str, str]:
117
+ """Return raw bytes and ReceiptAgent signer-domain digests.
118
+
119
+ The training signer used sha256(UTF8(basename) || raw_file_bytes) for each
120
+ directory containing a single safetensors artifact. It did not claim that
121
+ this digest was the raw LFS object SHA-256.
122
+ """
123
+
124
+ return (
125
+ sha256_bytes(content),
126
+ sha256_bytes(basename.encode("utf-8") + content),
127
+ )
128
+
129
+
130
+ def load_json(path: Path) -> dict[str, Any]:
131
+ value = json.loads(path.read_text(encoding="utf-8"))
132
+ _require(isinstance(value, dict), f"{path} must contain one JSON object")
133
+ return value
134
+
135
+
136
+ def _verify_digest_vector(vector: dict[str, Any]) -> None:
137
+ _strict_keys(
138
+ vector,
139
+ {
140
+ "basename",
141
+ "content_base64",
142
+ "bytes",
143
+ "raw_sha256",
144
+ "receipt_directory_sha256",
145
+ },
146
+ "digest_test_vector",
147
+ )
148
+ content = base64.b64decode(vector["content_base64"], validate=True)
149
+ _require(len(content) == vector["bytes"], "digest test-vector byte count mismatch")
150
+ raw_sha, receipt_sha = raw_and_receipt_digest(vector["basename"], content)
151
+ _require(raw_sha == vector["raw_sha256"], "raw digest domain test-vector mismatch")
152
+ _require(
153
+ receipt_sha == vector["receipt_directory_sha256"],
154
+ "basename-plus-bytes digest domain test-vector mismatch",
155
+ )
156
+ _require(raw_sha != receipt_sha, "digest domains must remain explicitly distinct")
157
+
158
+
159
+ def _verify_revision_git_evidence(
160
+ evidence: dict[str, Any],
161
+ *,
162
+ label: str,
163
+ expected_revision: str,
164
+ ) -> dict[str, str]:
165
+ _strict_keys(
166
+ evidence,
167
+ {"revision", "commit_object_base64", "trees"},
168
+ f"{label}_git_evidence",
169
+ )
170
+ _require(evidence["revision"] == expected_revision, f"{label} evidence revision mismatch")
171
+ commit_object = base64.b64decode(evidence["commit_object_base64"], validate=True)
172
+ _require(
173
+ git_object_sha1("commit", commit_object) == expected_revision,
174
+ f"{label} commit object identity mismatch",
175
+ )
176
+ commit_lines = commit_object.splitlines()
177
+ _require(
178
+ commit_lines
179
+ and commit_lines[0].startswith(b"tree ")
180
+ and len(commit_lines[0]) == 45,
181
+ f"{label} commit object lacks one root tree",
182
+ )
183
+ root_tree_sha1 = commit_lines[0][5:].decode("ascii")
184
+ _require(_is_hex(root_tree_sha1, 40), f"{label} root tree identity is invalid")
185
+
186
+ tree_records = evidence["trees"]
187
+ _require(isinstance(tree_records, list), f"{label} tree evidence must be a list")
188
+ trees_by_path: dict[str, dict[str, Any]] = {}
189
+ for tree in tree_records:
190
+ _strict_keys(tree, {"path", "tree_sha1", "entries"}, f"{label} tree")
191
+ path = tree["path"]
192
+ _require(
193
+ isinstance(path, str)
194
+ and (path == "" or (not path.startswith("/") and not path.endswith("/"))),
195
+ f"{label} tree path is invalid",
196
+ )
197
+ _require(path not in trees_by_path, f"{label} duplicate tree path: {path}")
198
+ _require(_is_hex(tree["tree_sha1"], 40), f"{label} tree identity is invalid: {path}")
199
+ entries = tree["entries"]
200
+ _require(isinstance(entries, list), f"{label} tree entries must be a list: {path}")
201
+ names: set[str] = set()
202
+ serialized = bytearray()
203
+ for entry in entries:
204
+ _strict_keys(
205
+ entry,
206
+ {"mode", "type", "object_sha1", "name"},
207
+ f"{label} tree entry",
208
+ )
209
+ name = entry["name"]
210
+ _require(
211
+ isinstance(name, str)
212
+ and name
213
+ and "/" not in name
214
+ and "\0" not in name,
215
+ f"{label} tree entry name is invalid",
216
+ )
217
+ _require(name not in names, f"{label} duplicate tree entry: {path}/{name}")
218
+ names.add(name)
219
+ is_tree = entry["type"] == "tree"
220
+ _require(
221
+ (is_tree and entry["mode"] == "040000")
222
+ or (entry["type"] == "blob" and entry["mode"] in {"100644", "100755"}),
223
+ f"{label} tree entry mode/type mismatch: {path}/{name}",
224
+ )
225
+ _require(
226
+ _is_hex(entry["object_sha1"], 40),
227
+ f"{label} tree entry identity is invalid: {path}/{name}",
228
+ )
229
+ object_mode = "40000" if is_tree else entry["mode"]
230
+ serialized.extend(object_mode.encode("ascii"))
231
+ serialized.extend(b" ")
232
+ serialized.extend(name.encode("utf-8"))
233
+ serialized.extend(b"\0")
234
+ serialized.extend(bytes.fromhex(entry["object_sha1"]))
235
+ _require(
236
+ git_object_sha1("tree", bytes(serialized)) == tree["tree_sha1"],
237
+ f"{label} tree object identity mismatch: {path or '<root>'}",
238
+ )
239
+ trees_by_path[path] = tree
240
+
241
+ root = trees_by_path.get("")
242
+ _require(root is not None, f"{label} root tree evidence is missing")
243
+ _require(
244
+ root["tree_sha1"] == root_tree_sha1,
245
+ f"{label} root tree does not bind to the commit object",
246
+ )
247
+
248
+ blobs: dict[str, str] = {}
249
+ visited_trees: set[str] = set()
250
+
251
+ def walk_tree(path: str, expected_tree_sha1: str) -> None:
252
+ tree = trees_by_path.get(path)
253
+ _require(tree is not None, f"{label} referenced tree evidence is missing: {path}")
254
+ _require(
255
+ tree["tree_sha1"] == expected_tree_sha1,
256
+ f"{label} referenced tree identity mismatch: {path}",
257
+ )
258
+ visited_trees.add(path)
259
+ for entry in tree["entries"]:
260
+ child_path = f"{path}/{entry['name']}" if path else entry["name"]
261
+ if entry["type"] == "tree":
262
+ walk_tree(child_path, entry["object_sha1"])
263
+ else:
264
+ _require(child_path not in blobs, f"{label} duplicate blob path: {child_path}")
265
+ blobs[child_path] = entry["object_sha1"]
266
+
267
+ walk_tree("", root_tree_sha1)
268
+ _require(
269
+ visited_trees == set(trees_by_path),
270
+ f"{label} tree evidence contains an unreachable tree",
271
+ )
272
+ return blobs
273
+
274
+
275
+ def reconcile(
276
+ fixture: dict[str, Any],
277
+ qualification_receipt: dict[str, Any],
278
+ ) -> dict[str, Any]:
279
+ _strict_keys(
280
+ fixture,
281
+ {
282
+ "schema_version",
283
+ "repository",
284
+ "observed_at",
285
+ "qualified_revision",
286
+ "public_head_revision",
287
+ "qualification_receipt",
288
+ "signature_evidence",
289
+ "digest_test_vectors",
290
+ "git_object_evidence",
291
+ "inference_bearing_blobs",
292
+ "public_head_delta",
293
+ "authorization",
294
+ "non_claims",
295
+ },
296
+ "fixture",
297
+ )
298
+ _require(
299
+ fixture["schema_version"] == FIXTURE_SCHEMA_VERSION,
300
+ "fixture schema version mismatch",
301
+ )
302
+ _require(fixture["repository"] == REPOSITORY, "repository mismatch")
303
+ _require(
304
+ fixture["qualified_revision"] == QUALIFIED_REVISION,
305
+ "qualified revision mismatch",
306
+ )
307
+ _require(
308
+ fixture["public_head_revision"] == PUBLIC_HEAD_REVISION,
309
+ "public-head revision mismatch",
310
+ )
311
+ _require(
312
+ qualification_receipt.get("schema_version")
313
+ == "szl.receipt-agent-public-candidate-qualification-receipt.v1",
314
+ "qualification receipt schema mismatch",
315
+ )
316
+ _require(
317
+ receipt_digest(qualification_receipt)
318
+ == qualification_receipt.get("receipt_sha256"),
319
+ "qualification receipt self-digest mismatch",
320
+ )
321
+ _require(
322
+ qualification_receipt.get("receipt_sha256")
323
+ == fixture["qualification_receipt"]["receipt_sha256"],
324
+ "fixture does not bind the qualification receipt",
325
+ )
326
+ _require(
327
+ qualification_receipt.get("result") == "PASS"
328
+ and qualification_receipt.get("maturity") == "MEASURED",
329
+ "qualification is not a measured pass",
330
+ )
331
+ _require(
332
+ qualification_receipt["candidate"]["repository"] == REPOSITORY
333
+ and qualification_receipt["candidate"]["revision"] == QUALIFIED_REVISION,
334
+ "qualification candidate identity mismatch",
335
+ )
336
+
337
+ signature_evidence = fixture["signature_evidence"]
338
+ _strict_keys(
339
+ signature_evidence,
340
+ {"training", "evaluation", "trust_boundary"},
341
+ "signature_evidence",
342
+ )
343
+ for kind in ("training", "evaluation"):
344
+ frozen = signature_evidence[kind]
345
+ receipt_value = qualification_receipt["candidate"][f"{kind}_receipt"]
346
+ _require(frozen["verified"] is True, f"{kind} signature is not verified")
347
+ _require(
348
+ frozen["verified"] == receipt_value["verified"]
349
+ and frozen["key_id"] == receipt_value["key_id"]
350
+ and frozen["canonical_sha256"] == receipt_value["canonical_sha256"],
351
+ f"{kind} signature evidence differs from the qualification receipt",
352
+ )
353
+ _require(
354
+ signature_evidence["trust_boundary"]
355
+ == "REPOSITORY_DECLARED_KEY_NOT_INDEPENDENTLY_PINNED",
356
+ "signature trust boundary was overstated",
357
+ )
358
+
359
+ vectors = fixture["digest_test_vectors"]
360
+ _require(len(vectors) == 2, "exactly two digest-domain vectors are required")
361
+ for vector in vectors:
362
+ _verify_digest_vector(vector)
363
+
364
+ git_evidence = fixture["git_object_evidence"]
365
+ _strict_keys(
366
+ git_evidence,
367
+ {"qualified", "public_head"},
368
+ "git_object_evidence",
369
+ )
370
+ qualified_tree_blobs = _verify_revision_git_evidence(
371
+ git_evidence["qualified"],
372
+ label="qualified",
373
+ expected_revision=QUALIFIED_REVISION,
374
+ )
375
+ public_head_tree_blobs = _verify_revision_git_evidence(
376
+ git_evidence["public_head"],
377
+ label="public-head",
378
+ expected_revision=PUBLIC_HEAD_REVISION,
379
+ )
380
+
381
+ entries = fixture["inference_bearing_blobs"]
382
+ _require(isinstance(entries, list), "inference-bearing blob inventory must be a list")
383
+ paths = {entry["path"] for entry in entries}
384
+ _require(paths == INFERENCE_BEARING_PATHS, "inference-bearing path set mismatch")
385
+ _require(len(paths) == len(entries), "duplicate inference-bearing path")
386
+ for entry in entries:
387
+ _strict_keys(
388
+ entry,
389
+ {
390
+ "path",
391
+ "qualified_git_blob_sha1",
392
+ "public_head_git_blob_sha1",
393
+ "inference_bearing",
394
+ },
395
+ f"inference blob {entry.get('path')}",
396
+ )
397
+ _require(entry["inference_bearing"] is True, "inference path mislabeled")
398
+ _require(
399
+ _is_hex(entry["qualified_git_blob_sha1"], 40)
400
+ and _is_hex(entry["public_head_git_blob_sha1"], 40),
401
+ f"invalid Git blob identity: {entry['path']}",
402
+ )
403
+ _require(
404
+ entry["qualified_git_blob_sha1"] == entry["public_head_git_blob_sha1"],
405
+ f"inference-bearing public-head drift: {entry['path']}",
406
+ )
407
+ _require(
408
+ qualified_tree_blobs.get(entry["path"])
409
+ == entry["qualified_git_blob_sha1"],
410
+ f"qualified path/blob is not bound to the declared revision: {entry['path']}",
411
+ )
412
+ _require(
413
+ public_head_tree_blobs.get(entry["path"])
414
+ == entry["public_head_git_blob_sha1"],
415
+ f"public-head path/blob is not bound to the declared revision: {entry['path']}",
416
+ )
417
+
418
+ candidate = qualification_receipt["candidate"]
419
+ fixture_binding = fixture["qualification_receipt"]["artifact_binding"]
420
+ _strict_keys(
421
+ fixture_binding,
422
+ {"model_file", "adapter_file", "digest_domain"},
423
+ "qualification_receipt.artifact_binding",
424
+ )
425
+ _require(
426
+ fixture_binding["digest_domain"]
427
+ == "SHA256_UTF8_BASENAME_CONCAT_RAW_FILE_BYTES",
428
+ "artifact digest domain mismatch",
429
+ )
430
+ entry_by_path = {entry["path"]: entry for entry in entries}
431
+ lfs_pointer_blobs: dict[str, str] = {}
432
+ for key in ("model_file", "adapter_file"):
433
+ frozen = fixture_binding[key]
434
+ measured = candidate[key]
435
+ _require(
436
+ frozen["path"] == measured["path"]
437
+ and frozen["bytes"] == measured["bytes"]
438
+ and frozen["raw_sha256"] == measured["sha256"]
439
+ and frozen["receipt_directory_sha256"]
440
+ == measured["receipt_directory_sha256"],
441
+ f"{key} differs from the measured qualification receipt",
442
+ )
443
+ _require(
444
+ frozen["raw_sha256"] != frozen["receipt_directory_sha256"],
445
+ f"{key} digest domains were collapsed",
446
+ )
447
+ _require(
448
+ _is_hex(frozen["raw_sha256"], 64),
449
+ f"{key} raw SHA-256 is invalid",
450
+ )
451
+ _require(
452
+ isinstance(frozen["bytes"], int)
453
+ and not isinstance(frozen["bytes"], bool)
454
+ and frozen["bytes"] > 0,
455
+ f"{key} byte count is invalid",
456
+ )
457
+ recorded_blob = entry_by_path.get(frozen["path"])
458
+ _require(
459
+ recorded_blob is not None,
460
+ f"{key} is absent from the frozen Git tree",
461
+ )
462
+ pointer_blob = lfs_pointer_git_blob_sha1(
463
+ frozen["raw_sha256"],
464
+ frozen["bytes"],
465
+ )
466
+ _require(
467
+ pointer_blob == recorded_blob["qualified_git_blob_sha1"],
468
+ f"{key} raw artifact claim does not bind to the frozen LFS pointer",
469
+ )
470
+ lfs_pointer_blobs[key] = pointer_blob
471
+
472
+ delta = fixture["public_head_delta"]
473
+ _require(
474
+ delta
475
+ == [
476
+ {
477
+ "path": "SZL_ESTATE_MANAGED.json",
478
+ "change": "ADDED",
479
+ "inference_bearing": False,
480
+ }
481
+ ],
482
+ "public-head delta is not the frozen metadata-only change",
483
+ )
484
+ _require(
485
+ set(public_head_tree_blobs) - set(qualified_tree_blobs)
486
+ == {"SZL_ESTATE_MANAGED.json"}
487
+ and set(qualified_tree_blobs) - set(public_head_tree_blobs) == set()
488
+ and all(
489
+ qualified_tree_blobs[path] == public_head_tree_blobs[path]
490
+ for path in qualified_tree_blobs
491
+ ),
492
+ "complete revision tree delta is not the frozen metadata-only addition",
493
+ )
494
+ _require(
495
+ fixture["authorization"]
496
+ == {
497
+ "trained": False,
498
+ "uploaded": False,
499
+ "promoted": False,
500
+ "deployed": False,
501
+ },
502
+ "reconciliation cannot authorize training, upload, promotion, or deployment",
503
+ )
504
+
505
+ result: dict[str, Any] = {
506
+ "schema_version": SCHEMA_VERSION,
507
+ "state": RECONCILED_STATE,
508
+ "maturity": "MEASURED",
509
+ "observed_at": fixture["observed_at"],
510
+ "repository": REPOSITORY,
511
+ "qualified_revision": QUALIFIED_REVISION,
512
+ "public_head_revision": PUBLIC_HEAD_REVISION,
513
+ "receipt_signature_validity": {
514
+ "training": True,
515
+ "evaluation": True,
516
+ "key_id": signature_evidence["training"]["key_id"],
517
+ "trust_boundary": signature_evidence["trust_boundary"],
518
+ },
519
+ "exact_qualified_artifact_binding": {
520
+ "verified": True,
521
+ "qualification_receipt_sha256": qualification_receipt["receipt_sha256"],
522
+ "model_raw_sha256": candidate["model_file"]["sha256"],
523
+ "model_receipt_directory_sha256": candidate["model_file"][
524
+ "receipt_directory_sha256"
525
+ ],
526
+ "adapter_raw_sha256": candidate["adapter_file"]["sha256"],
527
+ "adapter_receipt_directory_sha256": candidate["adapter_file"][
528
+ "receipt_directory_sha256"
529
+ ],
530
+ "model_lfs_pointer_git_blob_sha1": lfs_pointer_blobs["model_file"],
531
+ "adapter_lfs_pointer_git_blob_sha1": lfs_pointer_blobs["adapter_file"],
532
+ "digest_domain": fixture_binding["digest_domain"],
533
+ },
534
+ "current_public_head_equivalence": {
535
+ "verified": True,
536
+ "qualified_commit_git_object_verified": True,
537
+ "public_head_commit_git_object_verified": True,
538
+ "complete_revision_tree_delta_verified": True,
539
+ "inference_bearing_blob_count": len(entries),
540
+ "all_inference_bearing_git_blobs_equal": True,
541
+ "non_inference_delta": delta,
542
+ },
543
+ "authorization": fixture["authorization"],
544
+ "non_claims": fixture["non_claims"],
545
+ "fixture_sha256": sha256_bytes(canonical_bytes(fixture)),
546
+ }
547
+ result["reconciliation_sha256"] = self_digest(result, "reconciliation_sha256")
548
+ return result
549
+
550
+
551
+ def main() -> int:
552
+ parser = argparse.ArgumentParser(description=__doc__)
553
+ parser.add_argument("--fixture", type=Path, required=True)
554
+ parser.add_argument("--qualification-receipt", type=Path, required=True)
555
+ parser.add_argument("--output", type=Path)
556
+ parser.add_argument("--check", type=Path)
557
+ args = parser.parse_args()
558
+
559
+ try:
560
+ result = reconcile(load_json(args.fixture), load_json(args.qualification_receipt))
561
+ if args.check:
562
+ expected = load_json(args.check)
563
+ _require(expected == result, "stored reconciliation artifact is stale")
564
+ if args.output:
565
+ args.output.parent.mkdir(parents=True, exist_ok=True)
566
+ args.output.write_text(
567
+ json.dumps(result, indent=2, ensure_ascii=False) + "\n",
568
+ encoding="utf-8",
569
+ )
570
+ print(json.dumps(result, sort_keys=True, separators=(",", ":")))
571
+ return 0
572
+ except (OSError, ValueError, json.JSONDecodeError, ReconciliationRefusal) as exc:
573
+ print(f"REFUSED: {exc}")
574
+ return 2
575
+
576
+
577
+ if __name__ == "__main__":
578
+ raise SystemExit(main())