2.8 KiB
ADR-0003: chronogrid_core – SQLCipher 4.x Database Initializer
- Date: 2026-08-19
- Status: Accepted
- Task: 1.3
Context
ChronoGrid requires an encrypted local-first database for storing namespaces, projects, tasks, notes, links, and ingestion logs. The schema is defined in docs/API_CONTRACTS/schema.sql and mandates SQLCipher 4.x (AES-256-CBC) per docs/ARCHITECTURE/02-security-and-crypto.md.
Decision
Dependency Choice
Adopted rusqlite v0.31 with the bundled-sqlcipher-vendored-openssl feature. This bundles both the SQLCipher C library and OpenSSL, producing a hermetic build that requires no external system libraries beyond a C compiler and Perl (for the OpenSSL build step).
Key Handling
The 32-byte master key derived by chronogrid_crypto::kdf::derive_master_key (Argon2id) is passed as a raw hex key via PRAGMA key = "x'…'". This instructs SQLCipher to use the key material directly, bypassing its internal PBKDF2-HMAC-SHA512 derivation. Rationale: Argon2id is a strictly stronger KDF than PBKDF2; double-derivation would add latency without meaningful security improvement.
PRAGMA Configuration
| PRAGMA | Value | Purpose |
|---|---|---|
key |
Raw hex (32 bytes) | Encrypt/decrypt the database |
cipher_compatibility |
4 |
Enforce SQLCipher 4.x defaults |
foreign_keys |
ON |
Required by schema FK constraints |
Schema Embedding
The canonical schema SQL is embedded at compile time via include_str!("../../../docs/API_CONTRACTS/schema.sql"), ensuring the crate always stays in sync with the single source of truth without runtime file I/O.
Post-Init Validation
After running the DDL, the initializer queries sqlite_master to verify all 6 expected tables (namespaces, projects, tasks, notes, task_note_links, ingestion_logs) and 4 indexes exist. A quick SELECT count(*) FROM sqlite_master immediately after keying detects wrong-key or corrupt-file conditions early.
Consequences
- Positive: Fully encrypted at-rest storage with zero cloud dependencies. Schema changes in
schema.sqlare automatically picked up on recompilation. 11 unit tests validate correctness. - Negative: First build requires Perl (Strawberry Perl on Windows) for OpenSSL compilation. Build time is ~10 minutes on first compile due to OpenSSL/SQLCipher C compilation (subsequent builds are cached).
- Trade-off: Using raw key (bypassing SQLCipher PBKDF2) means the security of the database encryption relies entirely on the Argon2id KDF strength, which is acceptable given our pinned parameters (64 MiB, 3 iterations, 4 threads).