Spaces:
Running
Running
chore(sync): mirror backend .py + Dockerfile to Space (hf-sync-backend)
Browse filesAutomated backend sync from szl-holdings/a11oy main via hf-sync-backend.
Updated (differed from the Space): (none)
Deleted (gone from the repo + Dockerfile COPY set): szl_nemo_verify.py
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.
- szl_nemo_verify.py +0 -116
szl_nemo_verify.py
DELETED
|
@@ -1,116 +0,0 @@
|
|
| 1 |
-
#!/usr/bin/env python3
|
| 2 |
-
# SPDX-License-Identifier: Apache-2.0
|
| 3 |
-
# © 2026 Lutar, Stephen P. — SZL Holdings · ORCID 0009-0001-0110-4173 · Doctrine v11/v12
|
| 4 |
-
# Authored by the NEMOTRON SIGNED-TRAJECTORY build team. Co-Authored-By: Perplexity Computer Agent.
|
| 5 |
-
"""
|
| 6 |
-
szl_nemo_verify — standalone verifier for the SZL-Nemo signed-trajectory corpus.
|
| 7 |
-
|
| 8 |
-
Anyone can run this against a downloaded corpus JSONL to independently check:
|
| 9 |
-
1. CONTENT INTEGRITY — recompute each step's sha256 step_hash and compare.
|
| 10 |
-
2. SIGNATURE — if a step carries a DSSE signature, verify it against the
|
| 11 |
-
published SZLHOLDINGS cosign public key (cosign.pub).
|
| 12 |
-
|
| 13 |
-
USAGE:
|
| 14 |
-
python szl_nemo_verify.py path/to/corpus.jsonl
|
| 15 |
-
cat corpus.jsonl | python szl_nemo_verify.py -
|
| 16 |
-
|
| 17 |
-
EXIT CODE: 0 if every present signature verifies AND every hash matches; else 1.
|
| 18 |
-
|
| 19 |
-
HONEST: when the corpus was emitted in an environment without the private signing
|
| 20 |
-
key, the receipts are UNSIGNED (signatures: []) — this verifier reports that
|
| 21 |
-
transparently and does NOT treat "unsigned" as a pass of the signature check. The
|
| 22 |
-
hash check still applies and proves content integrity / tamper-evidence.
|
| 23 |
-
|
| 24 |
-
Prefers the shipped szl_trajectory_sign + szl_dsse modules when importable (full
|
| 25 |
-
DSSE verification). Falls back to a self-contained hash-only check if they are not
|
| 26 |
-
on the path, so the script still runs standalone. NO network required.
|
| 27 |
-
"""
|
| 28 |
-
from __future__ import annotations
|
| 29 |
-
|
| 30 |
-
import hashlib
|
| 31 |
-
import json
|
| 32 |
-
import sys
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
def _canon(obj) -> bytes:
|
| 36 |
-
return json.dumps(obj, sort_keys=True, separators=(",", ":"),
|
| 37 |
-
ensure_ascii=False).encode("utf-8")
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
def _step_hash(action, observation, restraint_verdict: str) -> str:
|
| 41 |
-
body = _canon({"action": action, "observation": observation,
|
| 42 |
-
"restraint_verdict": restraint_verdict})
|
| 43 |
-
return "sha256:" + hashlib.sha256(body).hexdigest()
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
def _verify_full(text: str):
|
| 47 |
-
"""Full verification using the shipped modules (DSSE + hash)."""
|
| 48 |
-
import szl_trajectory_sign as sts # type: ignore
|
| 49 |
-
return sts.verify_jsonl(text)
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
def _verify_hash_only(text: str):
|
| 53 |
-
"""Self-contained hash-only fallback (no DSSE module on path)."""
|
| 54 |
-
results = []
|
| 55 |
-
for ln in text.splitlines():
|
| 56 |
-
ln = ln.strip()
|
| 57 |
-
if not ln:
|
| 58 |
-
continue
|
| 59 |
-
try:
|
| 60 |
-
d = json.loads(ln)
|
| 61 |
-
except Exception as exc:
|
| 62 |
-
results.append({"parse_error": str(exc)})
|
| 63 |
-
continue
|
| 64 |
-
recomputed = _step_hash(d.get("action"), d.get("observation", ""),
|
| 65 |
-
d.get("restraint_verdict", "ALLOW"))
|
| 66 |
-
env = d.get("signature") or {}
|
| 67 |
-
sigs = env.get("signatures") or []
|
| 68 |
-
results.append({
|
| 69 |
-
"trajectory_id": d.get("trajectory_id"),
|
| 70 |
-
"step": d.get("step"),
|
| 71 |
-
"hash_ok": recomputed == d.get("step_hash"),
|
| 72 |
-
"signed": bool(sigs),
|
| 73 |
-
"sig_ok": False, # cannot DSSE-verify without the module
|
| 74 |
-
})
|
| 75 |
-
total = len(results)
|
| 76 |
-
hash_ok = sum(1 for r in results if r.get("hash_ok"))
|
| 77 |
-
signed = sum(1 for r in results if r.get("signed"))
|
| 78 |
-
return {
|
| 79 |
-
"total_steps": total, "hash_ok": hash_ok, "signed": signed, "sig_ok": 0,
|
| 80 |
-
"all_hash_ok": hash_ok == total and total > 0,
|
| 81 |
-
"all_sig_ok": False, "results": results,
|
| 82 |
-
"note": "hash-only fallback (szl_dsse not importable; signatures not checked)",
|
| 83 |
-
}
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
def main(argv) -> int:
|
| 87 |
-
if len(argv) < 2:
|
| 88 |
-
print(__doc__)
|
| 89 |
-
return 2
|
| 90 |
-
src = argv[1]
|
| 91 |
-
text = sys.stdin.read() if src == "-" else open(src, encoding="utf-8").read()
|
| 92 |
-
try:
|
| 93 |
-
res = _verify_full(text)
|
| 94 |
-
mode = "full (DSSE + hash)"
|
| 95 |
-
except Exception:
|
| 96 |
-
res = _verify_hash_only(text)
|
| 97 |
-
mode = "hash-only fallback"
|
| 98 |
-
summary = {k: res[k] for k in ("total_steps", "hash_ok", "signed", "sig_ok",
|
| 99 |
-
"all_hash_ok", "all_sig_ok") if k in res}
|
| 100 |
-
summary["verify_mode"] = mode
|
| 101 |
-
print(json.dumps(summary, indent=2))
|
| 102 |
-
# PASS iff every hash matches AND (no signatures present OR all verify).
|
| 103 |
-
hashes_ok = res.get("all_hash_ok", False)
|
| 104 |
-
sig_present = res.get("signed", 0) > 0
|
| 105 |
-
sigs_ok = res.get("sig_ok", 0) == res.get("signed", 0)
|
| 106 |
-
ok = hashes_ok and (not sig_present or sigs_ok)
|
| 107 |
-
print("RESULT:", "PASS" if ok else "FAIL")
|
| 108 |
-
if sig_present and not sigs_ok:
|
| 109 |
-
print(" (signatures present but not all verified)")
|
| 110 |
-
if not sig_present:
|
| 111 |
-
print(" (no signatures present — UNSIGNED corpus; hash integrity only)")
|
| 112 |
-
return 0 if ok else 1
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
if __name__ == "__main__":
|
| 116 |
-
sys.exit(main(sys.argv))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|