From 7d1a827ba2d779d7b6718ca2c0ba22e08bbcb939 Mon Sep 17 00:00:00 2001 From: leora Date: Tue, 6 Oct 2026 06:16:05 +0800 Subject: [PATCH] Fix R11: pin cryptography; add prod runbook for seal + anchor Add requirements.txt (cryptography>=43.0.0,<45) and docs/PROD_RUNBOOK.md requiring SIGIL_SEAL_PASS and SIGIL_ANCHOR on separate storage. Document info findings R9/R12/R13 in DESIGN; leave R10 domain separation as a versioned follow-up (not backward-safe). --- DESIGN.md | 24 ++++++++++++++++++++---- README.md | 7 ++++++- docs/PROD_RUNBOOK.md | 33 +++++++++++++++++++++++++++++++++ requirements.txt | 3 +++ 4 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 docs/PROD_RUNBOOK.md create mode 100644 requirements.txt diff --git a/DESIGN.md b/DESIGN.md index 95025f3..85470ab 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -229,7 +229,7 @@ sessions mintable from a bare agent name, no revocation operation at all, an unkeyed chain that a database-level attacker could rebuild, and SQLite without a busy timeout. -Leora's contracted prod pass (Quarry 18a5d762) closed three remaining review blockers on this branch: rekey no longer un-revokes, dual-bootstrap enrol is exactly-one under race, and redeem rate limits are per-agent (anonymous fails isolated from success). Off-box checkpoint tip publish/verify ships when `anchor_path` / `SIGIL_ANCHOR` is set. SealedStore / `SIGIL_SEAL_PASS` seals the DB file with AES-256-GCM (incremental path short of SQLCipher). Independent review and platform glue remain. +Leora's contracted prod pass (Quarry 18a5d762) closed three remaining review blockers on this branch: rekey no longer un-revokes, dual-bootstrap enrol is exactly-one under race, and redeem rate limits are per-agent (anonymous fails isolated from success). Off-box checkpoint tip publish/verify ships when `anchor_path` / `SIGIL_ANCHOR` is set. SealedStore / `SIGIL_SEAL_PASS` seals the DB file with AES-256-GCM (incremental path short of SQLCipher). Independent review returned GO-WITH-FIXES; R1–R8/R11 fixes on this branch. Platform glue remains off. **Still not production ready**, and the reason is not a to-do list: @@ -252,11 +252,27 @@ The tests show the logic is correct. They do not make it safe. ## Next -1. Independent security review before this guards anything real. Two hardening - passes made it reviewable; neither substituted for one. +1. ~~Independent security review~~ — independent review returned GO-WITH-FIXES + (tip c0027bb); fix PRs for R1–R8/R11 landed on `sigil-initial`. Platform glue + remains off until integration review. See `docs/PROD_RUNBOOK.md`. 2. ~~Anchor the checkpoint head digest outside the database~~ — done via `Store(..., anchor_path=)` / `SIGIL_ANCHOR` (signed tip file + `.log`). + **Prod must set it** (see runbook). 3. Secret broker on top — scoped, short-lived leases bound to a key fingerprint. Its issuance and redemption logs *are* the work-attestation substrate, so it is the natural second piece. -4. Deprecate passcode login across the platform, then rotate live credentials. \ No newline at end of file +4. Deprecate passcode login across the platform, then rotate live credentials. + +### Info / follow-ups (no code change required yet) + +- **R9 — `issue_agent_session`:** library helper mints `agent:act` from a name + after the caller claims to have verified. Keep internal; integration must + never mint from headers/names. Consider renaming to `_issue_agent_session`. +- **R10 — challenge domain separation:** signatures currently cover + `nonce.encode()` with no context prefix. Adding + `b"sigil-challenge-v1\0" + nonce` is not backward-compatible with in-flight + challenges; schedule with a protocol version bump (follow-up). +- **R12 — multi-process rate limits:** quotas are per-`Store` / per-process. + Single writer until a shared limiter exists (documented in README + runbook). +- **R13 — opt-in anchor:** without `SIGIL_ANCHOR`, deleting in-DB checkpoints + allows silent history rewrite. Runbook requires the anchor on separate storage. diff --git a/README.md b/README.md index 874fc1f..d682469 100644 --- a/README.md +++ b/README.md @@ -158,4 +158,9 @@ The tests assert the logic is correct. They do not make it safe. ## See also `DESIGN.md` — the design page: rationale, flows, session stamps, the invariant -and its reasoning, and what is deferred. \ No newline at end of file +and its reasoning, and what is deferred. + +`docs/PROD_RUNBOOK.md` — production checklist: require `SIGIL_SEAL_PASS` and +`SIGIL_ANCHOR` on separate storage, verify-chain alerts, integration sharp edges. + +`requirements.txt` — pinned `cryptography>=43.0.0,<45`. diff --git a/docs/PROD_RUNBOOK.md b/docs/PROD_RUNBOOK.md new file mode 100644 index 0000000..bca4b37 --- /dev/null +++ b/docs/PROD_RUNBOOK.md @@ -0,0 +1,33 @@ +# Sigil production runbook + +Short checklist before Sigil guards anything real. Library-only today — do **not** +enable platform glue until an integration review covers session minting. + +## Required environment + +| Variable | Purpose | Notes | +|----------|---------|--------| +| `SIGIL_DB` | Path to the store file | Prefer a dedicated volume; backups are sensitive (roster + audit). | +| `SIGIL_SEAL_PASS` | AES-256-GCM seal passphrase | **Required in prod.** ≥12 chars. Without it the DB file is cleartext on disk. Seal-on still uses a plaintext `0600` working copy while the process is open — not SQLCipher. | +| `SIGIL_ANCHOR` | Off-box signed tip path | **Required in prod.** Must be on storage **separate** from `SIGIL_DB` (different volume/host). Every checkpoint publishes here; `verify_external_anchors` / `verify-chain` must alert on failure. | + +Optional: agent private keys stay **off** the platform host whenever possible; checkpoint signer key preferably offline. + +## Ops loop + +1. Open with seal + anchor configured (CLI respects the env vars above). +2. Periodically run chain verify **and** external-anchor verify; page on failure. +3. After permanent revoke (compromise): bootstrap + `enrol_rekey`, then `reinstate`. Reinstate alone does not restore a wiped key. +4. Single writer process until a shared rate-limit store exists (in-process quotas multiply across processes). + +## Integration sharp edges (do not ignore) + +- Never mint `issue_agent_session` from a client-supplied name or header. Only after a verified challenge-response. Prefer keeping that helper internal to verified paths. +- Human view codes are ~40 bits; keep TTL short; never log raw codes (already hashed in audit). +- Challenge signatures today sign the raw nonce (no domain separation). Changing the signed payload needs a coordinated version bump — tracked as a follow-up, not a silent break. + +## Deferred + +- SQLCipher / page-level encryption for multi-tenant co-resident hosts. +- Domain-separated challenge payloads (`sigil-challenge-v1` prefix) — backward-incompatible without a protocol version. +- Shared cross-process rate limiter. diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..79a50e0 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +# Runtime dependency for Ed25519 + AES-GCM (SealedStore / optional key files). +# Pin a known-good lower bound; upper bound avoids surprise major breaks in CI. +cryptography>=43.0.0,<45