Seiten der Dokumentation

Diese Seite gibt es bisher nur auf Englisch.

Data at rest, backups and erasure#

Status: decision record, 2026-11-05.

Decision: volume encryption, not SQLCipher#

Groundnote requires the operator to store data/ on an encrypted volume (LUKS/dm-crypt on Linux, FileVault on macOS, an encrypted block volume at a cloud provider). Groundnote itself does not encrypt SQLite pages.

Options considered:

Option Protects against Cost Verdict
SQLCipher (page encryption) Copy of the file without the key A native fork of SQLite instead of stock SQLite; key must be on the same host to run the service, so a host compromise yields both; Litestream replicates pages and would need the same build; sqlite3 .backup, the restore probe and every operator tool need the SQLCipher build too; FTS5 and sqlite-vec must be compiled into the same fork rejected for now
Volume encryption Stolen disk, VM image, decommissioned hardware Operator setup, no code required
Application-level field encryption Leaked file and leaked backup, if keys live elsewhere Breaks FTS over encrypted fields only for erasure (crypto-shredding option below)

Reasoning: the realistic threats for a single-operator service are a lost or copied disk and a leaked backup. Volume encryption covers the first at zero code cost. SQLCipher would add a second SQLite build to every path that touches the file (service, backup, restore probe, export) while the key would still sit on the running host. The backup threat is handled separately below, because neither SQLCipher-with-key-on-host nor volume encryption protects a bucket.

File permissions (built, F2)#

  • Data directory 0700, files 0600, owned by the service user. The server sets umask 077 before opening or creating any file.
  • At start the server checks the data directory, scopes/ and every SQLite file and refuses to run if one is group- or world-accessible (data-dir-permissions, no silent chmod; commit 25231ea).
  • The container image runs as a non-root user; the volume is mounted only into this container.

Backups#

backup.kind Encryption Recommendation
copy + restic/borg Client-side, by the backup tool (restic encrypts every repository) Recommended for scopes with personal data
litestream None client-side. Litestream 0.5.x rejects the age encryption block at start (since 0.5.1; configuration reference, retrieved 2026-11-05). Only with a bucket that enforces provider-side encryption, a bucket-scoped key with no list permission on other buckets, object lock or versioning against deletion, and a lifecycle rule matching the erasure deadline

The restore probe (daily) and the manual probe (quarterly, on another machine) are part of the contract; a backup without a passed restore does not count.

Erasure despite append-only#

A person named in a mail or meeting may demand erasure (GDPR Art. 17). The scope file forbids UPDATE and DELETE on history by trigger. The design that replaces the earlier proposal (an ops command groundnote redact with a free-text reason) is ../redaction.md: a tombstone with a category from an enum, one narrow trigger exemption, redaction only from the approval channel by a person, secure delete, and per-scope age keys for backups and exports (crypto-shredding). It is not built; the order of its slices is in architecture.md section 15.2. Volume encryption stays mandatory, SQLCipher is not adopted (redaction.md section 10).

Secrets and logs#

Secrets only from the environment; never in groundnote.json, never logged, never in error messages. Service bearers stored as SHA-256. Logs carry no request bodies, quotes or excerpts (see threat model, "Logging").

Auf GitHub bearbeiten