feat(sp12): SQLCipher encryption at rest (optional)

- New cyclone.db_crypto module:
  * is_sqlcipher_available() — capability check
  * is_encryption_enabled() — Keychain key + sqlcipher3 present
  * get_db_key() — reads 'cyclone.db.key' from Keychain
  * make_sqlcipher_connect_creator(url, key) — SQLAlchemy creator
- db._make_engine() now switches to SQLCipher when key is present
- pyproject.toml: optional 'sqlcipher' extra (sqlcipher3>=0.6,<1)
- Fallback: without Keychain key, DB stays plain SQLite (no surprise
  behavior for operators who haven't set up encryption yet)
- Verified: encrypted file is unreadable as plain SQLite, wrong key
  raises on first query, migrations + ORM work transparently
- HIPAA §164.312(a)(2)(iv) compliance note in docs

Tests: 705 -> 717 (12 new for SQLCipher). All 717 backend tests pass.
This commit is contained in:
Tyler
2026-06-20 23:52:41 -06:00
parent 84d2f39760
commit d54c44f04a
5 changed files with 406 additions and 1 deletions
+5
View File
@@ -25,6 +25,11 @@ dev = [
"pytest-asyncio>=0.23,<1",
"httpx>=0.27,<1",
]
sqlcipher = [
# SP12: encryption at rest. Optional — without it the DB is plain SQLite.
# Install via: pip install -e .[sqlcipher] (after brew install sqlcipher).
"sqlcipher3>=0.6,<1",
]
[project.scripts]
cyclone = "cyclone.cli:main"