chronogrid/docs/ARCHITECTURE/ADR/0003-core-sqlcipher-db-init.md

2.8 KiB
Raw Blame History

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.sql are 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).