The same open-standards posture that turned JCR-1 into a standard
(three independent implementations agreeing byte-for-byte across
canonical CBOR + COSE_Sign1), now applied to policy receipts. A
policy receipt is a real spec, not a Rust house format.
## What ships
- conformance/vectors-policy.json — 3 vectors spanning the
decision space: Allow with named rule, Explicit deny with named
rule, and No-matching-allow (deny-by-default). Each carries the
receipt JSON, the canonical signed-core CBOR hex, and the
COSE_Sign1 envelope hex.
- conformance/verify.py — Python verifier (cbor2 + cryptography
only). Re-encodes each canonical core, signs a fresh envelope
under the same seed, asserts byte-equal against committed hex.
- conformance/verify.go — Go verifier (stdlib only, no go.mod).
From-scratch RFC 8949 §4.2.1 length-first CBOR encoder + COSE
reader. Stdlib crypto/ed25519 verifies the envelope.
- conformance/README.md — vector descriptions, regeneration
procedure, scope.
- examples/gen_policy_vectors.rs — Rust regenerator. Run with a
path argument to write the vectors JSON; argument-less prints
to stdout for inspection.
- Embedded POLICY_VECTORS_JSON const + the
policy_vectors_match_committed_conformance regression test in
src/lib.rs — a drifting Rust producer fails BEFORE the Python
and Go verifiers ever run.
## Cross-implementation verification
All three implementations cross-verified locally on the same vectors:
Rust (cargo test policy_vectors_match_committed_conformance): pass
Python (python3 verify.py): pass on 3/3 vectors
Go (go run verify.go): pass on 3/3 vectors
Same seed JCR-1 uses for cascade-receipt vectors, so a third party
can cross-validate both receipt families under a single test key.
## Workspace
102 crates, 2,533 lib tests pass (+1 for the conformance regression),
0 failures.
78 lines
2.8 KiB
Markdown
78 lines
2.8 KiB
Markdown
# JouleClaw policy-receipt conformance vectors
|
|
|
|
Independent verifiers cross-checking the canonical signed core
|
|
(det-CBOR per RFC 8949 §4.2.1) and the COSE_Sign1 envelope (RFC 9052,
|
|
EdDSA / Ed25519) every Rust producer of a `PolicyReceipt` must emit.
|
|
Three implementations — Rust + Python + Go — produce bit-identical
|
|
bytes on every vector.
|
|
|
|
## Files
|
|
|
|
| File | What |
|
|
|------|------|
|
|
| `vectors-policy.json` | 3 canonical vectors: allow / explicit-deny / no-matching-allow. Each carries the receipt JSON, the canonical signed-core CBOR hex, and the COSE_Sign1 envelope hex. |
|
|
| `verify.py` | Python verifier (cbor2 + cryptography). |
|
|
| `verify.go` | Go verifier (stdlib only — no go.mod required). |
|
|
|
|
## Vectors
|
|
|
|
1. **Allow** — filesystem read of a workspace file under the
|
|
`read-workspace` rule. Decision `Allow(rule="read-workspace")`,
|
|
action `Filesystem(/workspace/notes.md, read)`.
|
|
2. **Explicit deny** — filesystem read of a workspace secret shadowed
|
|
by the `no-secrets` rule. Decision
|
|
`Deny(explicit_deny, rule="no-secrets")`.
|
|
3. **No-matching-allow** — network connect against an empty policy.
|
|
Decision `Deny(no_matching_allow)`, action
|
|
`Network(api.example.com:443, connect)`.
|
|
|
|
## Test key
|
|
|
|
Same Ed25519 seed JCR-1 uses for its v1 cascade-receipt vectors so
|
|
verifiers can cross-validate both receipt families against one key.
|
|
|
|
```
|
|
seed: 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
|
|
pub: 03a107bff3ce10be1d70dd18e74bc09967e4d6309ba50d5f1ddc8664125531b8
|
|
kid: did:keri:EJ9testStewardAID000000000000000
|
|
```
|
|
|
|
**TEST KEY ONLY.** Never use in production.
|
|
|
|
## Running
|
|
|
|
```bash
|
|
# Python:
|
|
python3 verify.py vectors-policy.json
|
|
|
|
# Go (stdlib only):
|
|
go run verify.go vectors-policy.json
|
|
```
|
|
|
|
Both must print PASS on all three vectors. Any byte mismatch means a
|
|
producer somewhere has drifted; fix the producer, not the vectors.
|
|
|
|
## Regenerating
|
|
|
|
Vectors are regenerated by the Rust example
|
|
`gen_policy_vectors.rs`. The Rust-side test
|
|
`policy_vectors_match_committed_conformance` (in `src/lib.rs`) loads
|
|
the committed JSON and re-derives every byte from the embedded
|
|
receipt, so a drifting producer fails the Rust test before the
|
|
Python and Go verifiers ever run.
|
|
|
|
```bash
|
|
cargo run -p jouleclaw-policy-receipt --example gen_policy_vectors \
|
|
-- crates/jouleclaw-policy-receipt/conformance/vectors-policy.json
|
|
```
|
|
|
|
## Scope (v1)
|
|
|
|
- Schema id: `policy/1`. The wire shape is the v1 form of
|
|
`jouleclaw_policy_receipt::PolicyReceipt` — `(jc_receipt, id,
|
|
closed_at, steward, engine_id, audit_sequence, policy_version,
|
|
agent, action, decision)`. Any future schema bump will land
|
|
alongside `vectors-policy-v1.1.json`, leaving v1 vectors frozen.
|
|
- Signing algorithm: EdDSA over Ed25519 (`alg = -8`) only.
|
|
ES256 (`alg = -7`) is permitted by COSE but not currently
|
|
exercised here.
|