fix(durable): enforce encryption_gate INV-8 policy at runtime#6040
Merged
Conversation
zeph_durable::encryption_gate was a unit-tested pure function that no production call site ever reached. load_write_cipher and open_backend in src/commands/durable.rs each made their own cipher decision from encrypt_payload alone, ignoring backend and shared-database status, so a misconfigured shared-DB deployment silently persisted durable journal payloads in plaintext with no warning and no error. Both call sites, plus the TUI durable panel poller which had the same gap, now evaluate encryption_gate before deciding on a cipher: a forbidden combination fails closed with a hard error (or, in the TUI poller, a graceful non-durable-mode fallback), and the permitted single-user local override emits the documented startup warning. Adds a `[durable] shared_db` config field so operators can declare a shared-database deployment explicitly, with a postgres:// URL-scheme sniff as defense in depth. Includes a config-migration step, --init wizard prompt, and regression tests for both the write and read paths. Closes #5996
bug-ops
enabled auto-merge (squash)
July 11, 2026 15:16
This was referenced Jul 11, 2026
Closed
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
zeph_durable::encryption_gate(the documented INV-8 AEAD enforcement policy) was a unit-tested pure function that no production call site ever reached.load_write_cipher/open_backendinsrc/commands/durable.rseach made their own cipher decision fromencrypt_payloadalone, ignoring backend and shared-database status, so a misconfigured shared-DB deployment silently persisted durable journal payloads (tool outputs, agent-turn state) in plaintext with zero warning and zero error.encryption_gatebefore deciding on a cipher: a forbidden combination (encrypt_payload = falseon a non-local or shared-DB backend) fails closed with a hard error, and the permitted single-user local override emits the documented startuptracing::warn!.[durable] shared_dbconfig field (defaultfalse) so operators can declare a shared-database deployment explicitly; apostgres:///postgresql://resolved journal URL is also treated as shared automatically, as defense in depth.durable_poll_task, featuretui) had the same gap and bypassed the gate entirely — it now evaluates the same policy and degrades gracefully to the panel's existing "non-durable mode" state on rejection, instead of rendering a journal the CLI would refuse to open.scheduler_daemon.rs::build_durable_adapter: the gate check now runs before the backend is opened, avoiding a stray empty journal file being created on a forbidden config.config.tomldocumentation, a config-migration step (step 79), an--initwizard prompt, mdBook docs, and a testing playbook scenario + coverage-status.md row.Closes #5996
Test plan
cargo +nightly fmt --check— cleancargo clippy --profile ci --workspace --all-targets --features "desktop,ide,server,chat,pdf,scheduler,testing" -- -D warnings— cleancargo nextest run --config-file .github/nextest.toml --workspace --features "desktop,ide,server,chat,pdf,scheduler" --lib --bins— 12808 passed, 0 failedRUSTFLAGS="-D warnings" RUSTDOCFLAGS="--deny rustdoc::broken_intra_doc_links" cargo doc --no-deps --workspace --features "desktop,ide,server,chat,pdf,scheduler"— cleanload_write_cipher) and the read path (open_backend) rejecting the forbiddenencrypt_payload=false+ shared-DB combination, plus the permitted local-only override and postgres:// URL-scheme detection