{
  "$schema_version": "1.0",
  "name": "Rensei audit-chain sample signed entry",
  "description": "A single real, signed audit-chain entry from Rensei's own dogfooding workspace, published so anyone can run a complete end-to-end verification without a Rensei account. Recompute the entry hash, fetch the public key from jwks_url, and verify the Ed25519 signature offline.",
  "provenance": "policy.evaluated deny (graph-policy deny-by-default) on Rensei's own production audit chain. Rensei dogfooding its own platform; not customer data. The chain is per-workspace and a workspace is an org.",
  "workspace_id": "org_8a1bfa98",
  "jwks_url": "https://app.rensei.ai/.well-known/audit-keys/org_8a1bfa98.json",
  "catalog_url": "https://rensei.ai/.well-known/audit-keys.json",
  "entry": {
    "workspace_id": "org_8a1bfa98",
    "sequence_number": 12779,
    "event_type": "policy.evaluated",
    "actor_id": "0c1983ca-dfc4-41e4-8e24-13f6e09f5676",
    "occurred_at": "2026-06-10T04:15:56.311Z",
    "prev_hash": "f3824a699bf7422120a8d8e88e06b4f24a85f992ba0d000631b490f3da658f41",
    "payload": {
      "action": "read_node",
      "reason": "No matching permit policy (deny-by-default)",
      "context": {
        "same_org": true,
        "environment": "production",
        "workspace_id": "org_8a1bfa98",
        "project_match": true,
        "correlation_id": ""
      },
      "decision": "deny",
      "matchedPolicies": [],
      "evaluationTimeUs": 7
    }
  },
  "verification": {
    "algorithm": "Ed25519",
    "signed_payload": "sha256(canonical(entry))",
    "entry_canonicalization": "RFC 8785 (JCS), ASCII subset",
    "signing_key_id": "ksk_40bbf07c3f9f",
    "canonical_preimage": "{\"actor_id\":\"0c1983ca-dfc4-41e4-8e24-13f6e09f5676\",\"event_type\":\"policy.evaluated\",\"occurred_at\":\"2026-06-10T04:15:56.311Z\",\"payload\":{\"action\":\"read_node\",\"context\":{\"correlation_id\":\"\",\"environment\":\"production\",\"project_match\":true,\"same_org\":true,\"workspace_id\":\"org_8a1bfa98\"},\"decision\":\"deny\",\"evaluationTimeUs\":7,\"matchedPolicies\":[],\"reason\":\"No matching permit policy (deny-by-default)\"},\"prev_hash\":\"f3824a699bf7422120a8d8e88e06b4f24a85f992ba0d000631b490f3da658f41\",\"sequence_number\":12779,\"workspace_id\":\"org_8a1bfa98\"}",
    "entry_hash": "f98d07ce0f02cbd53ec31e8b790a3fedb086f3582b5d3be978561aaf0c272120",
    "signature": "f+is8kM8/BdVD/uDwpvZJUu4YOyBN8zOpEUItGgG6RntVUOQZXKXRlqkpctVKYcmMlgCzD/pEEzxSRijV7JJBw==",
    "public_key_base64": "rvyRHGft7Ly5ZcxQqzsKlAmWrURHbhEVfpdvSxCuu4A=",
    "public_key_base64url": "rvyRHGft7Ly5ZcxQqzsKlAmWrURHbhEVfpdvSxCuu4A",
    "jwks_url": "https://app.rensei.ai/.well-known/audit-keys/org_8a1bfa98.json"
  },
  "verification_steps": [
    "Take the `entry` object (workspace_id, sequence_number, event_type, actor_id, payload, occurred_at, prev_hash).",
    "Canonicalize those seven fields per RFC 8785 (JCS): sort all object keys lexicographically (recursively), emit compact JSON with no whitespace. The result must equal `verification.canonical_preimage` byte-for-byte.",
    "Compute SHA-256 over the canonical preimage. The hex digest must equal `verification.entry_hash`.",
    "Fetch the Ed25519 public key for `verification.signing_key_id` from the JWKS at `jwks_url` (the `x` member, base64url). It must equal `verification.public_key_base64url`.",
    "Verify the Ed25519 signature `verification.signature` (base64) against the 32-byte SHA-256 digest from step 3 (the raw digest bytes, NOT the canonical JSON string). Use an Ed25519 implementation that accepts the pre-hashed 32-byte input; libraries that hash the message internally will mismatch.",
    "Confirm the key has no `rensei:revoked_at` earlier than `entry.occurred_at`."
  ],
  "verify_command": "# npm i @noble/ed25519 @noble/hashes\nnode --input-type=module -e '\nimport { createHash } from \"node:crypto\";\nimport * as ed from \"@noble/ed25519\";\nimport { sha512 } from \"@noble/hashes/sha2.js\";\ned.hashes.sha512 = sha512;\n// Paste the entry + verification block from /.well-known/audit-sample:\nconst entry = {\"workspace_id\":\"org_8a1bfa98\",\"sequence_number\":12779,\"event_type\":\"policy.evaluated\",\"actor_id\":\"0c1983ca-dfc4-41e4-8e24-13f6e09f5676\",\"occurred_at\":\"2026-06-10T04:15:56.311Z\",\"prev_hash\":\"f3824a699bf7422120a8d8e88e06b4f24a85f992ba0d000631b490f3da658f41\",\"payload\":{\"action\":\"read_node\",\"reason\":\"No matching permit policy (deny-by-default)\",\"context\":{\"same_org\":true,\"environment\":\"production\",\"workspace_id\":\"org_8a1bfa98\",\"project_match\":true,\"correlation_id\":\"\"},\"decision\":\"deny\",\"matchedPolicies\":[],\"evaluationTimeUs\":7}};\nconst v = {\"signature\":\"f+is8kM8/BdVD/uDwpvZJUu4YOyBN8zOpEUItGgG6RntVUOQZXKXRlqkpctVKYcmMlgCzD/pEEzxSRijV7JJBw==\",\"public_key_base64\":\"rvyRHGft7Ly5ZcxQqzsKlAmWrURHbhEVfpdvSxCuu4A=\",\"entry_hash\":\"f98d07ce0f02cbd53ec31e8b790a3fedb086f3582b5d3be978561aaf0c272120\"};\n// Canonicalize (sort keys recursively) and hash:\nconst sortKeys = (x) => Array.isArray(x) ? x.map(sortKeys) : (x && typeof x === \"object\" ? Object.keys(x).sort().reduce((a,k)=>(a[k]=sortKeys(x[k]),a),{}) : x);\nconst canonical = JSON.stringify(sortKeys(entry));\nconst hashHex = createHash(\"sha256\").update(canonical).digest(\"hex\");\nconst pub = Buffer.from(v.public_key_base64, \"base64\");\nconst sig = Buffer.from(v.signature, \"base64\");\nconst ok = await ed.verifyAsync(sig, Buffer.from(hashHex, \"hex\"), pub);\nconsole.log(\"hash matches:\", hashHex === v.entry_hash);\nconsole.log(\"signature valid:\", ok);\n'",
  "notes": [
    "The signature is over the 32-byte SHA-256 digest, not the canonical JSON string. Use a raw Ed25519 verify (no internal message hashing).",
    "The entry hash is computed over exactly the seven fields in `entry`: workspace_id, sequence_number, event_type, actor_id, payload, occurred_at, prev_hash.",
    "occurred_at must be hashed as the exact ISO-8601 string shown."
  ]
}