v1.5.6 — Python verifier + Node↔Python cross-language proof
Extends the verifier reach past Node. Banks whose SIEM pipelines are Python-based (Splunk SDK, pandas-based audit tooling, custom compliance harnesses) no longer need Node on the box.
What's new
- `python/shadow_verify/` — pure-Python verifier. Same wire contract as the Node primitive (pipe-delimited signing payload, sorted-key JSON canonicalization, base64 signature for Ed25519, hex for HMAC). Response shape identical to the Node MCP tool + HTTP endpoint. Stdlib-only for HMAC mode; `cryptography>=41` required only for Ed25519 PEM parsing.
- `python/pyproject.toml` — `pip install python/` works out of the box. Ready for PyPI publish as `shadow-verify` v0.1.0.
- `test/python-verify-cross-lang.test.js` — 5 cross-language tests where Node signs and Python verifies. Includes a nested-array-in-nested-object edge case that catches ANY canonicalization drift between the two implementations. Skips gracefully if `python3` or `cryptography` aren't installed on the runner — CI without Python stays green, but Python-equipped environments actively prove compat.
Verifier surface (cross-language complete)
| Language | Surface | Path | Best for |
|---|---|---|---|
| Node | CLI | `bin/verify-attestation.mjs` | dev machines, procurement demos |
| Node | MCP tool | `shadow_verify_attestation` | Claude Desktop / Cursor / OpenCode chat |
| Node | HTTP endpoint | `POST /api/verify-attestation` | SIEM pipelines, CI, curl from anywhere |
| Python | library | `from shadow_verify import verify_attestation` | Splunk SDK, pandas audit tooling, Python compliance harnesses |
Why this matters
Banks are typically Python shops for compliance work. A Node-only verifier told a bank: "your ops team has to learn Node just to check a signature." That's friction that scuttles procurement conversations. `pip install shadow-verify` removes it.
Use
```python
from shadow_verify import verify_attestation
result = verify_attestation(
attestation=persisted["response"]["attestation"],
original_request=persisted["request"],
original_response={k: v for k, v in persisted["response"].items()
if k != "attestation"},
public_key_pem=open("shadow-public.pem").read(),
)
if result["ok"]:
print(f"verified — model_id: {result['model_id']}, key_id: {result['key_id']}")
```
Response shape identical to the Node MCP tool + HTTP endpoint, so audit-trail comparability holds regardless of language.
Tests
- Node test suite: 543 → 548 (+5 cross-language). All green.
- Python test suite: 16/16 passed via `python3 python/tests/test_verify.py`.
Not yet shipped
- PyPI publish (needs Alex's Trusted Publisher setup at pypi.org)
Full details: CHANGELOG.md