Repository navigation
verifier-service: sqlx 0.9 → rusqlite 0.42, clearing RUSTSEC-2026-0459 (stacked on #3535) - #3537
Merged
brandon-coproduct merged 1 commit intoNov 14, 2026
Conversation
RUSTSEC-2026-0459: bundled SQLite before 3.54.0 can return uninitialized page-cache memory when a database is opened beside a -wal file with a different page size. sqlx-sqlite 0.9.0, the newest sqlx release with pre-releases included, requires libsqlite3-sys >=0.30.1, <0.38.0. The patched line starts at 0.39, so no sqlx bump clears it. rusqlite 0.42 uses libsqlite3-sys 0.40 (SQLite 3.54+). Semantics first: docs/verifier-service-storage.md states what the database and the transparency log guarantee (G1-G8), what they do not, and how the driver change was checked against them. - One rusqlite connection behind a mutex, run on tokio's blocking pool. It sets the same pragmas sqlx did: WAL, synchronous=NORMAL, foreign_keys=ON, 5 s busy timeout. - Migrations keep sqlx's `_sqlx_migrations` table, SHA-384 checksums and descriptions. build.rs derives the list from migrations/. - tests/fixtures/sqlx-0.9-created.db was written by this crate at 7f51115 (sqlx). src/db_sqlx_compat_tests.rs checks four things against it: sqlx's checksums equal this build's, opening it re-runs nothing, every row reads back with the chain intact, and the log continues from sqlx's tip. Computing the checksum over a trimmed script fails all four. - `--db` query parameters, which sqlx accepted, are refused. Found, not changed (recorded in the doc): the retention sweep fails with FOREIGN KEY constraint failed on any logged row, so it deletes nothing; and the in-memory Merkle tree can take leaves out of seq order under concurrent appends. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JpH4L6YWcVu9DFsq8PZypJ
brandon-coproduct
merged commit Nov 14, 2026
23d1f45
into
deps/rustsec-20261113
94 of 95 checks passed
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.
Stacked on #3535. Base:
deps/rustsec-20261113. Neither PR clearsauditanddenyon its own:They are separate so the storage change is reviewed on its own. Once it is approved, merging it into #3535's branch makes #3535 pass
denyandauditwith every advisory cleared and no ignore. Its diff against that base is the storage change and nothing else.Why a storage change, not a version bump
RUSTSEC-2026-0459 is
libsqlite3-sys0.30.1, whichnucleus-verifier-servicereaches throughsqlx-sqlite0.9.0. Every bundled SQLite before 3.54.0 can return uninitialized page-cache memory when a database is opened beside a-walfile with a different page size.No sqlx release, pre-releases included, allows the patched
libsqlite3-sys(>= 0.39):>=0.30.1, <0.38.0<0.36.0^0.30.1Upstream
mainallows<0.40.0and transact-rs/sqlx#4525 proposes<0.41, but neither is released. So this moves the service to rusqlite 0.42, which useslibsqlite3-sys0.40 (SQLite 3.54+).Semantics first
docs/verifier-service-storage.mdstates what the database and the transparency log guarantee (G1–G8):seqis never reused;It also states what is not guaranteed, what the driver change keeps and changes, and how each was checked.
Compatibility with existing databases
tests/fixtures/sqlx-0.9-created.dbwas written by this crate at7f511159f(sqlx 0.9.0, libsqlite3-sys 0.30.1), through its public functions. It holds three verifications and two log entries.src/db_sqlx_compat_tests.rschecks four things against it:_sqlx_migrationsunchanged, includinginstalled_onandexecution_time;seq3.checksum mismatch. Restored, they pass.--dbfile.GET /v1/log/sizeas{"tree_size":2}and rebuiltmerkle_leaves=2, with no errors.{"tree_size":0}.Behaviour that changes
synchronous=NORMAL,foreign_keys=ON, and a 5 s busy timeout.--dbquery parameters (?mode=…) are refused. sqlx accepted them.build.rs. It is derived frommigrations/instead ofsqlx::migrate!.Evidence
Run on macOS arm64 at this head (stacked on
023828bed).cargo deny check advisories bans licenses sourcesprintsadvisories ok, bans ok, licenses ok, sources ok.cargo audit --deny warningsexits 0.nucleus-verifier-service:cargo test --lockedpasses 116 tests (64 lib, 1, 51 integration).cargo clippy --all-targets -D warningspasses fornucleus-verifier-service,ctf-mcpandctf-server.Cargo.lockis cargo's own re-resolution of deps: rmcp 3 and lockfile bumps clear five of the six open RustSec advisories #3535's lockfile with this manifest. sqlx and its transitive crates leave; rusqlite brings 8.-D warningsand the crate's tests pass.Known, out of scope
Both are documented in
docs/verifier-service-storage.md. Both behave the same under sqlx onmain.retention::sweep_oncerunsDELETE FROM verifications WHERE submitted_at < ?. Withforeign_keys=ON, that fails withFOREIGN KEY constraint failedwhenever a row it would delete is referenced bylog_entries, which is every successful verification. The statement is atomic, so the sweep deletes nothing and logs a warning. I confirmed this with a throwaway test. Fixing it means deciding whether the foreign key or the sweep's scope gives way.seqorder under concurrent appends.routes.rspushes the leaf afterappend_entryreturns, in a separate step. Two concurrent verify requests can push in the opposite order to theirseq, so proofs served before a restart can be over a different leaf order than after it. This comes from reading the code; I did not measure it.🤖 Generated with Claude Code
https://claude.ai/code/session_01JpH4L6YWcVu9DFsq8PZypJ