zeekayandHanzo Dev 0037b6071c cek: record which key sealed a store, so a store that will not open can say why
"wrong master key, or a damaged store" was one sentence covering two faults with
opposite remedies. The first wants the other key and the bytes are intact. The
second wants a restore and the bytes are gone. Nothing on disk told them apart,
so telling them apart meant forensics: reading 18MB for a SQLite header that was
not there, dating a lock file to the minute of the first conversion, and finding
no backup beside it — while an identity store sat unreadable and every relying
party in the estate had no JWKS to fetch.

So the seal now records its key. `<database>.keyid` holds SHA-256 over a
domain-separating label and the DERIVED key, truncated — a commitment, not the
key: it cannot be run backwards, it cannot be replayed as one, and it says
nothing about any other database, because two stores under one master derive
different keys and so carry different ids. On a store that will not read,
diagnose() compares the recorded id with the id of the key in hand and answers
which fault this is. A store sealed before ids existed cannot answer, and says
that rather than inventing a verdict — a guess there aims a restore at the wrong
file.

convert() now finishes through settle() instead of repeating it. Its own check
opened a handle and closed it, which proves nothing: database/sql connects
lazily, so a read has to be forced or the key never meets a page. That is the
same mistake as trusting the header, wearing different clothes. One place decides
a store is good, and that place reads the schema, records the key, and only then
releases the plaintext.

Mutation-proven on three axes, each restored before staging and the file
confirmed byte-identical after: not recording the id fails the test; never
detecting a different key falls back to blaming damage, which is the ambiguity
this removes; and writing the raw key instead of a commitment fails on the
assertion that the id must not contain the key.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-13 11:38:16 -07:00

cek

Opens a namespace's SQLite database encrypted at rest.

cek.SetMaster(k)                            // once, at boot, from KMS
db, err := cek.Open(ns, "treasury", dataDir) // everywhere else

The key is derived from the master and the namespace. It is not generated, not wrapped, not stored, and not rotated in place — so there is no unwrap step, no rewrap step, no per-file key material to lose, and no migration path to maintain. A database is born encrypted or it does not exist.

Losing the master loses the data. That is the property you want from encryption at rest, and the reason the master lives in KMS.

Where it sits

hanzoai/namespace names the entity, and where its file lives
hanzoai/cek turns the master + that name into the file's key, and opens it
hanzoai/sqlite opens a file under a raw key; knows nothing about who owns it
hanzoai/kms holds the master

Nothing here knows about orgs, users, billing or plugins. It knows a namespace, a subsystem, and a master key.

S
Description
No description provided
Readme MIT
128 KiB
Languages
Go 100%