Run against a tree whose binary will not boot, cipher printed four rows of "refuses — " with nothing after the dash and exited 2, silently, before its own control could speak. Three defects, each of which alone would have hidden the other two. GREP EXITS NON-ZERO WHEN IT MATCHES NOTHING. `hits()` piped it into wc under `set -o pipefail`, so finding no canary — which is exactly what an encrypted store is supposed to look like — failed the substitution and `set -e` took the lane down. The one outcome the lane exists to report was the one that killed it. THE REFUSAL REASON WAS MATCHED ON ONE BUILD'S WORDING. `grep 'cek:'` finds the message this tree prints and nothing else, so a tree that refuses for another reason produced an empty row that still read like a measurement. It now says where the log is and keeps it, and that is how the actual cause turned up: the private cloud's `project` plugin cannot open a temp data dir and `console` refuses to start without it. Not this suite's bug, but it took four silent rows to become visible. AND THE CONTROL COULD NOT TELL "ZERO" FROM "NEVER RAN". probe leaves CONTROL_DIR unset when the server refused, so the control searched a directory nothing had written and read a clean zero. It checks now, and says "the control never started, so nothing above is evidence". Unchanged where it works: against hanzoai/cloud the lane still reads 7 stores, 7 distinct headers, canary in 0 files on both encrypting builds, refuses on the cgo build, and finds the canary in 1 file on the unencrypted control. rc=0. Co-authored-by: Hanzo Dev <[email protected]>
cipher
What is on the disk.
self/ measures that a plain build cannot encrypt and refuses rather than
pretending. This is the other half: build one that can, write a value through
the API, and then look for that value in the files.
bench/cipher/run.sh
Taken on an M-series laptop, 2026-09-11. Three builds, given a master key.
| build | with a master key |
|---|---|
CGO_ENABLED=0 |
7 stores · 7 distinct headers · canary in 0 files |
CGO_ENABLED=1, as make build does it |
refuses — "this build cannot encrypt a store" |
CGO_ENABLED=1 -tags libsqlite3 |
7 stores · 7 distinct headers · canary in 0 files |
the control: CLOUD_DEV_UNENCRYPTED=1 |
7 stores · 1 header, SQLite format 3 · canary in 1 file |
The refusal is a result, not an error. cgo is on by default on macOS and that build links ordinary SQLite, so it cannot encrypt. Given a key it stops and names the recipe rather than writing a plaintext store and reporting success — which is what it did before the check existed, and the second boot then died on a SQLCipher function it did not have.
Two builds do encrypt, and they agree: seven stores, seven different first bytes, and the value nowhere on the disk.
A value nothing else could have written goes in through
POST /v1/base/collections/notes. Then the server is stopped and every file
under the data directory is searched for it.
Seven headers against one is the second signal. Each store gets its own data encryption key, so each file begins with different ciphertext. A plaintext run writes the same magic seven times.
The control is the point
The second column is not a comparison with a competitor. It is the proof that the first column measures anything at all: the same binary, the same two writes, the same search, on a store that is deliberately not encrypted. It finds the canary in one file. Without that, a zero on the left could mean the write never reached the disk, or that the search does not work on the file — and both of those happened while this lane was being written.
The second one is worth keeping. A store is a binary file, and grep declines
to read one unless told: the first control run reported a clean zero for a file
that plainly contained the string. LC_ALL=C grep -a is in the script for that
reason, and the lane fails if the control ever reports zero again.
What this does and does not say
It says the value is not in the file. Two writes, seven stores, one search, with a control that proves the search works.
It is not a cryptanalysis. SQLCipher's construction, the KDF and the page MAC are its own; this measures that the data plane uses it and that the plaintext is absent, not that the cipher is sound.
The key is not in the picture. CLOUD_KMS_MASTER_KEY_REF is the one the
operator injects, and where it comes from is the KMS's question, not this one.
A per-store DEK sits beside each database as <store>.db.dek, wrapped by that
master key — so this lane says the store is unreadable without the master key,
and says nothing about how well the master key is kept.