59 Commits

Author SHA1 Message Date
4661a994bf Merge pull request 'Fix N7/N8: human session fingerprint epoch; drop duplicate view_ttl' (#17) from leora/fix-n7-n8-human-fp-view-ttl into sigil-initial 2026-10-06 06:27:47 +08:00
ad51b2548a Fix N7/N8: human session fingerprint epoch; drop duplicate view_ttl
resolve() now requires sess_fp == live_fp for every session that carries
a fingerprint (including human_via_agent), so a redeem-vs-rekey race
cannot leave a view:read bearer alive. Drop the duplicate view_ttl key
in issue_code's return dict. Regression tests cover both.
2026-10-06 06:27:46 +08:00
a5bbbccb29 Merge pull request 'Fix R11: pin cryptography>=44.0.1 with hash lock' (#16) from leora/fix-r11-cryptography-pin into sigil-initial 2026-10-06 06:23:50 +08:00
9e76d68344 Fix R11: pin cryptography>=44.0.1 and add hash lock
Raise the floor past CVE-2024-12797-affected wheels (43.x / 44.0.0).
Add constraints.txt (exact 44.0.1) and requirements.lock.txt with
sha256 hashes for cryptography and its runtime deps.
2026-10-06 06:23:49 +08:00
618fb5401c Merge pull request 'Fix N4/N5/N6: enrol wording, suspended checkpoint, test count' (#15) from leora/fix-n4-n5-n6-docs-checkpoint-suspend into sigil-initial 2026-10-06 06:23:18 +08:00
6578a1fe8f Fix N4/N5/N6: enrol wording, suspended checkpoint, test count
Drop misleading "or re-enrol" after permanent revoke; enrol refuses an
existing agent before spending the seed. checkpoint() refuses a currently
revoked/suspended signer. README (and DESIGN) test count updated to 156.
2026-10-06 06:23:17 +08:00
c46cd52323 Merge pull request 'Fix N3: dedicated rekey rate-limit bucket; charge only on failure' (#14) from leora/fix-n3-rekey-rate-bucket into sigil-initial 2026-10-06 06:22:49 +08:00
fae03444af Fix N3: dedicated rekey rate-limit bucket; charge only on failure
enrol_rekey shared the enrol: bucket and metered before auth, so junk
calls could lock out incident-response rekey. Use a separate rekey:
bucket and charge it only after a bad bootstrap secret, so a valid seed
always proceeds.
2026-10-06 06:22:48 +08:00
a1cc241923 Merge pull request 'Fix N2: agent_keys history; dedicated checkpoint-signer docs' (#13) from leora/fix-n2-key-history into sigil-initial 2026-10-06 06:22:14 +08:00
73b9ab4515 Fix N2: agent_keys history keeps checkpoints verifiable after revoke
Permanent revoke and rekey retired the live pubkey without retaining it,
so historical checkpoints and off-box anchors became permanently
unverifiable. Add append-only agent_keys (public material only); retire
on revoke/rekey; verify against the fingerprint-named historical key.
Document a dedicated checkpoint-signer identity in the runbook.
2026-10-06 06:22:13 +08:00
668577f3ea Merge pull request 'Fix N1: resolve re-checks agent state; codes bind fingerprint' (#12) from leora/fix-n1-resolve-recheck into sigil-initial 2026-10-06 06:21:19 +08:00
096a7dd072 Fix N1: resolve re-checks agent; codes bind key fingerprint
In-flight verify/issue_code could insert a session or code after revoke
or rekey. sessions.resolve now refuses if the agent is revoked, has no
live key, or (agent sessions) the fingerprint no longer matches.
View codes store the issuing fingerprint and redeem refuses after
rekey/wipe; issue_code re-checks agent state. DESIGN matches the choke
point. Regression tests plant race-surviving sessions and stale codes.
2026-10-06 06:21:18 +08:00
75423dc301 Merge pull request 'Fix R11: pin cryptography; prod runbook for SIGIL_ANCHOR + SIGIL_SEAL_PASS' (#11) from leora/fix-r11-runbook-deps into sigil-initial 2026-10-06 06:16:05 +08:00
7d1a827ba2 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).
2026-10-06 06:16:05 +08:00
db5aaff6fb Merge pull request 'Fix R6/R7/R8: claim_code expiry CAS, rate-limit rekey, delete spent bootstrap' (#10) from leora/fix-r6-r7-r8-cas-rekey-bootstrap into sigil-initial 2026-10-06 06:15:16 +08:00
1530bfd010 Fix R6/R7/R8: claim_code expiry CAS, rate-limit rekey, delete spent bootstrap
claim_code now requires redeem_expires_at > now in the CAS UPDATE.
enrol_rekey shares the enrol: rate-limit bucket. spend_bootstrap and
sibling clear delete rows instead of retaining spent hashes, matching
the schema comment.
2026-10-06 06:15:15 +08:00
cd87be6b8d Merge pull request 'Fix R5: SealedStore plaintext tmp 0600 + SQLCipher deferred note' (#9) from leora/fix-r5-sealed-tmp-hardening into sigil-initial 2026-10-06 06:14:42 +08:00
4e65f6671a Fix R5: SealedStore plaintext tmp is 0600 with fsync/cleanup
Plaintext working copy and export backup were creatable world-readable
under a 0700 temp dir. Write via os.open(mode=0600), fsync, unlink on
failure; pin temp dir 0700; remove export after flush. Document SQLCipher
as deferred — seal-on is not an encrypted DB while the process is open.
2026-10-06 06:14:41 +08:00
7e0ac5020c Merge pull request 'Fix R4: checkpoint binds private key to enrolled fingerprint' (#8) from leora/fix-r4-checkpoint-key-binding into sigil-initial 2026-10-06 06:14:01 +08:00
7872bd92b9 Fix R4: checkpoint requires private key match enrolled fingerprint
checkpoint() only checked that the signer name was enrolled, so a stranger
key could write a polluting checkpoint row. Refuse unless the private key's
fingerprint equals the enrolled fingerprint for that signer.
2026-10-06 06:14:00 +08:00
f39946a983 Merge pull request 'Fix R3: permanent revoke clears key; reinstate requires rekey' (#7) from leora/fix-r3-reinstate-requires-rekey into sigil-initial 2026-10-06 06:13:24 +08:00
b49d2087d6 Fix R3: permanent revoke clears key; reinstate requires rekey
DESIGN claimed permanent revoke meant dead until re-enrol, but reinstate
restored the same compromised public key. Permanent revoke now wipes
pubkey/fingerprint; reinstate lifts ban flags only. Timed suspend keeps
the key. Compromise recovery may bootstrap+rekey while still revoked,
then reinstate. Regression tests cover reinstate-alone and timed path.
2026-10-06 06:13:23 +08:00
2e0900e15b Merge pull request 'Fix R2: bootstrap hygiene — one live seed, clear siblings on enrol' (#6) from leora/fix-r2-bootstrap-hygiene into sigil-initial 2026-10-06 06:12:25 +08:00
23cc531711 Fix R2: bootstrap hygiene — one live seed, clear siblings on enrol
Unspent bootstrap secrets accumulated and remained usable for enrol_rekey
after enrol. put_bootstrap now spends prior unspent seeds for the agent
(one live secret), and successful enrol / enrol_rekey clear any siblings.
Regression tests cover leftover-after-enrol, one-live-secret, and
leftover-after-rekey.
2026-10-06 06:12:24 +08:00
d4af46cc1b Merge pull request 'Fix R1: invalidate view codes on revoke/rekey/suspend' (#5) from leora/fix-r1-invalidate-view-codes into sigil-initial 2026-10-06 06:10:55 +08:00
4a7b7d6fd7 Fix R1: invalidate view codes on revoke/rekey/suspend
Outstanding view codes survived revoke and rekey, so a pre-issued code
could mint a fresh human_via_agent session after compromise revoke or
key rotation. Invalidate unused codes when sessions are revoked (covers
revoke, suspend, and rekey), and refuse redeem when the agent is
currently revoked. Regression tests cover all three paths.
2026-10-06 06:10:42 +08:00
c0027bb9f6 Prod hardening: SealedStore encryption at rest
Merge PR #4: AES-GCM sealed store (SIGIL_SEAL_PASS)
2026-10-06 04:59:29 +08:00
746e3e590a Prod hardening: off-box audit chain tip (SIGIL_ANCHOR)
Merge PR #3: off-box audit chain tip
2026-10-06 04:59:14 +08:00
leora
bd7d62c21c Sealed store: AES-256-GCM encryption at rest for the DB file
Tokens/codes/secrets were already digests; a stolen cleartext SQLite file
still leaked the agent roster, revocation state and audit history.
SealedStore / SIGIL_SEAL_PASS wraps on-disk bytes in AES-256-GCM
(PBKDF2-HMAC-SHA256, 480k iters). Working copy is plaintext only while
open (temp file); flush/close re-seals. Incremental path short of
SQLCipher page-level encryption.

11 new tests in test_sealed.py (stolen seal has no SQLite header / no
agent rows; wrong passphrase fails; works with off-box anchor). Suite
130 green.

Part of Quarry 18a5d762. Independent crypto review + platform glue remain.
2026-10-06 04:59:07 +08:00
leora
29fd9a1388 Off-box audit chain tip: publish/verify outside the SQLite file
A signed checkpoint inside the same database is still only as strong as that
file. Store(..., anchor_path=) / SIGIL_ANCHOR now writes the signed tip to a
filesystem path outside the DB (atomic tip file + append-only .log).
verify_external_anchors catches a rewrite even after in-DB checkpoints are
deleted. 8 new tests in test_anchor.py; suite 119 green.

Part of Quarry 18a5d762 (Sigil prod build). Do not merge to main yet:
sealed store and independent crypto review still open.
2026-10-06 04:58:02 +08:00
leora
1c2e9d16c2 Drop stray tests/probe.txt (push probe, not a test fixture) 2026-10-06 04:55:44 +08:00
leora
35fc6373a6 Close three review blockers: rekey, dual-enrol race, redeem quotas
- put_agent is INSERT OR IGNORE (enrol create-if-absent); update_agent_key
  preserves revocation columns so rekey cannot un-revoke
- enrol_rekey and seed_bootstrap refuse while the agent is revoked
- redeem_code uses per-agent code_redeem / code_redeem_fail; anonymous
  guesses no longer lock valid codes for other agents
- remove dead duplicate revoke_agent; tests for each finding (111 total)

Do not merge to main yet: independent crypto review, off-box chain head,
sealed store, and platform glue still open.
2026-10-05 23:27:33 +08:00
01279f6282 Document the second pass and what is still open 2026-10-05 21:51:25 +08:00
b24236f740 Document the second pass and what is still open 2026-10-05 21:51:23 +08:00
a59e668ca2 Route the human-session tests through the real code path 2026-10-05 21:51:21 +08:00
9ce8da7573 One test per finding in the second review pass 2026-10-05 21:51:18 +08:00
e784be8d3f Document revocation and bump to 0.3.0 2026-10-05 21:51:15 +08:00
806a97437e Expose checkpoint, revoke, reinstate and sweep on the CLI 2026-10-05 21:51:13 +08:00
57708eb7ac Close the second round of review findings: public_from_private 2026-10-05 21:51:10 +08:00
fc7858ef82 Close the second round of review findings: no credentials in the audit log 2026-10-05 21:51:08 +08:00
8ead217556 Close the second round of review findings: GrantedCode, no minting from a name 2026-10-05 21:51:06 +08:00
d402d7e498 Close the second round of review findings: revoke, reinstate, expiry 2026-10-05 21:51:03 +08:00
b3b154fe3c Close the second round of review findings: checkpoints, revocation, WAL, sweep 2026-10-05 21:51:01 +08:00
ea827c8e42 Harden Sigil: tests/test_hardening.py 2026-10-05 21:26:17 +08:00
47abc7d717 Harden Sigil: tests/helpers.py 2026-10-05 21:26:15 +08:00
9cbc3f5122 probe 2026-10-05 21:25:47 +08:00
908ea0439f Harden Sigil: tests/test_viewcodes.py 2026-10-05 21:24:53 +08:00
f1ad41f6d9 Harden Sigil: tests/test_sessions.py 2026-10-05 21:24:50 +08:00
01a8f5bbe2 Harden Sigil: sigil/viewcodes.py 2026-10-05 21:24:48 +08:00
a3c6c8d5c6 Harden Sigil: sigil/store.py 2026-10-05 21:24:45 +08:00