fix: compile SQLite 3.53.0 from source to fix WAL-reset corruption bug - #6900
Conversation
|
| Filename | Overview |
|---|---|
| Dockerfile | Builds and validates SQLite 3.53.0, verifies its pinned archive checksum, and removes compilation dependencies afterward. |
| tests/test_sqlite_wal_reset_upgrade.py | Adds repository-standard structural assertions covering the SQLite source build, checksum verification, feature flags, runtime guards, and layer ordering. |
Reviews (4): Last reviewed commit: "docker(sqlite): compile with SQLITE_SECU..." | Re-trigger Greptile
8b9ca65 to
c3e8958
Compare
nesquena-hermes
left a comment
There was a problem hiding this comment.
Thanks for this — the WAL-reset corruption bug is real and worth fixing, and the source-compile approach with a build-time version assertion is a sound shape. CI is green (25/25 incl. the docker-build + all three compose-smoke jobs), but a regression gate on the exact head (c3e8958) surfaced two blockers that the smoke jobs structurally can't catch (they only probe startup + /health), so I'm requesting changes before this can ship.
1. [BLOCKER] The compiled SQLite drops FTS5 → silent full-text search breakage
The sqlite-autoconf amalgamation compiled with the current ./configure --disable-static --disable-readline flags does not enable FTS5. Debian's stock libsqlite3 ships with -DSQLITE_ENABLE_FTS5=1; the from-source build here does not, so the replacement library loses FTS5.
state.db (shared with the Agent in the two/three-container modes) uses FTS5 for session/message full-text recall. With an FTS5-less library:
CREATE VIRTUAL TABLE … USING fts5raisessqlite3.OperationalError: no such module: fts5.- The Agent detects this and silently drops FTS triggers + returns empty search results rather than erroring, so it looks fine on boot but session search quietly returns nothing.
- In multi-container mode, opening the shared
state.dbfrom a no-FTS5 process can remove the persisted FTS triggers until a capable process rebuilds them.
This trades a corruption bug for a silent search-loss regression, so it's a net downgrade until FTS5 is restored.
Fix: enable FTS5 in the compile (either --enable-fts5 on ./configure, or CFLAGS="-DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_RTREE" — mirror the feature set Debian's package enables; --all/--enable-all is the simplest way to match the distro build). Then extend the build-time Python assertion to prove FTS5 survived, not just the version:
python3 -c "import sqlite3; \
v=sqlite3.sqlite_version; \
assert tuple(int(x) for x in v.split('.')) >= (3,51,3), f'SQLite {v} still vulnerable'; \
c=sqlite3.connect(':memory:'); c.execute('CREATE VIRTUAL TABLE t USING fts5(x)'); \
print(f'OK sqlite {v} + fts5')"The FTS5 vtable creation is the part that would have failed this build as-is.
2. [BLOCKER] Pin the amalgamation SHA-256 before extraction
The tarball is fetched over HTTPS but extracted + its build scripts run as root with no content verification, so an artifact substitution at the origin would execute in every published image. Pin the checksum and verify before tar:
ARG SQLITE_SHA256=<official 3.53.0 amalgamation sha256>
...
&& curl -fsSL "https://sqlite.org/${SQLITE_YEAR}/sqlite-autoconf-${SQLITE_VERSION}.tar.gz" -o sqlite.tar.gz \
&& echo "${SQLITE_SHA256} sqlite.tar.gz" | sha256sum -c - \
&& tar xzf sqlite.tar.gz \(Please compute the SHA-256 from the official download yourself rather than trusting a value pasted in review.)
Not blockers
- The linked-library mechanism itself is verified working: build installs
/usr/local/lib/libsqlite3.so.0,ldconfigruns, and the Python version assertion passes on the compiled lib. - Build-tool purge-in-same-layer is correct; no separate regression.
- The structural Dockerfile tests are fine as invariant pins; once you add the FTS5 config, please also assert
--enable-fts5(or the CFLAGS) is present so a future refactor can't silently drop it again.
Once FTS5 is restored (with the build proving an FTS5 vtable creates) and the checksum is pinned, this is a strong reliability fix. Happy to re-gate on the re-push.
|
Thanks for the detailed review. Both blockers addressed in 1. FTS5/FTS4/R-Tree restored Added 2. SHA-256 pinned The amalgamation tarball is now verified with Regression tests updated to cover both: checksum verification before |
The python:3.12-slim base ships SQLite 3.46.1 (Debian Trixie), which is vulnerable to the WAL-reset corruption bug discovered March 2026. Debian has not backported the fix. Compiles SQLite 3.53.0 from the official amalgamation tarball during the Docker build. Installs to /usr/local/lib (takes ldconfig priority over /usr/lib). Build tools (gcc, make, libc6-dev) are purged in the same layer. A build-time Python assertion fails the image build if the linked library is still vulnerable. Version and year are build args for easy bumps. https://sqlite.org/wal.html#walresetbug
Address review feedback (nesquena-hermes): 1. Add --enable-fts5 --enable-fts4 --enable-rtree to ./configure so the compiled SQLite matches the distro package's feature set. Without FTS5, state.db session/message full-text search breaks silently. 2. Pin the amalgamation tarball SHA-256 as a build arg and verify with sha256sum -c before extraction. 3. Extend the build-time assertion to create and drop an FTS5 virtual table, proving the module is available - not just the version number. 4. Add regression tests for checksum verification, FTS5 configure flag, and FTS5 build-time vtable assertion.
…-row erasure Codex gate found a SILENT data-privacy regression: the Debian base image's SQLite is built with SQLITE_SECURE_DELETE (PRAGMA secure_delete=1, deleted content overwritten), but compiling 3.53.0 from the amalgamation without the flag drops it to 0 -> deleting a session removes its rows but leaves transcript bytes recoverable in state.db. Reproduced end-to-end via api/models.py delete path. Add CPPFLAGS=-DSQLITE_SECURE_DELETE and a build-time assertion that PRAGMA secure_delete==1 (fails the image build if not). Co-authored-by: qxxaa <qxxaa@users.noreply.github.com>
38f89a9 to
a6fb254
Compare
Stale — on a superseded head (c3e8958). Re-gated the converged head a6fb254: SHA-256 independently verified against sqlite.org, Docker image build + all 3 container smoke tests green, Codex-reviewed. Codex found the build dropped SQLITE_SECURE_DELETE (deleted rows recoverable) — I applied the fix (CPPFLAGS=-DSQLITE_SECURE_DELETE + build-time PRAGMA secure_delete==1 assertion, Co-authored @qxxaa) and CI's Docker build validates it. Dismissing to unblock.
|
Shipped in exp-v0.52.227 🎉 Thanks @qxxaa — the Docker image now compiles SQLite 3.53.0 from source to fix the WAL-reset corruption bug. I independently verified the pinned SHA-256 matches the official sqlite.org archive, and the gate caught one thing worth calling out: compiling from the amalgamation dropped Debian's |
…follow-up to #6900 (#7044) * fix(docker): register /usr/local/lib in ld.so.conf.d so the source-built SQLite loads on arm64 The #6900 SQLite-from-source upgrade passed the amd64 docker-smoke but FAILED the multi-arch release build on linux/arm64 with 'AssertionError: SQLite 3.46.1 still vulnerable' — Python's sqlite3 kept loading the base image's /usr/lib multiarch libsqlite3 (3.46.1) instead of the freshly-compiled /usr/local/lib copy (3.53.0), because /usr/local/lib is NOT in the default ld.so search path on Debian arm64 (it happened to be picked up on amd64). Register /usr/local/lib via an ld.so.conf.d entry before ldconfig so the new lib wins on every architecture. The PR's own build-time version assertion is what surfaced this (correctly), and it also serves as the verification that the fix works once the arm64 build passes. Follow-up to #6900 (exp-v0.52.227, whose multi-arch image failed to build/push). * test-fix: keep wal.html link within 500 chars of ARG (condense arm64 comment) --------- Co-authored-by: nesquena-hermes <agent@nesquena-hermes>
nesquena#6900) * fix: compile SQLite 3.53.0 from source to fix WAL-reset corruption bug The python:3.12-slim base ships SQLite 3.46.1 (Debian Trixie), which is vulnerable to the WAL-reset corruption bug discovered March 2026. Debian has not backported the fix. Compiles SQLite 3.53.0 from the official amalgamation tarball during the Docker build. Installs to /usr/local/lib (takes ldconfig priority over /usr/lib). Build tools (gcc, make, libc6-dev) are purged in the same layer. A build-time Python assertion fails the image build if the linked library is still vulnerable. Version and year are build args for easy bumps. https://sqlite.org/wal.html#walresetbug * fix: enable FTS5/FTS4/R-Tree and pin tarball SHA-256 Address review feedback (nesquena-hermes): 1. Add --enable-fts5 --enable-fts4 --enable-rtree to ./configure so the compiled SQLite matches the distro package's feature set. Without FTS5, state.db session/message full-text search breaks silently. 2. Pin the amalgamation tarball SHA-256 as a build arg and verify with sha256sum -c before extraction. 3. Extend the build-time assertion to create and drop an FTS5 virtual table, proving the module is available - not just the version number. 4. Add regression tests for checksum verification, FTS5 configure flag, and FTS5 build-time vtable assertion. * docker(sqlite): compile with SQLITE_SECURE_DELETE to preserve deleted-row erasure Codex gate found a SILENT data-privacy regression: the Debian base image's SQLite is built with SQLITE_SECURE_DELETE (PRAGMA secure_delete=1, deleted content overwritten), but compiling 3.53.0 from the amalgamation without the flag drops it to 0 -> deleting a session removes its rows but leaves transcript bytes recoverable in state.db. Reproduced end-to-end via api/models.py delete path. Add CPPFLAGS=-DSQLITE_SECURE_DELETE and a build-time assertion that PRAGMA secure_delete==1 (fails the image build if not). Co-authored-by: qxxaa <qxxaa@users.noreply.github.com> --------- Co-authored-by: qxxaa <qxxaa@users.noreply.github.com> Co-authored-by: nesquena-hermes <agent@nesquena-hermes>
…te preserved) (nesquena#6900, @qxxaa) (nesquena#7043) Co-authored-by: nesquena-hermes <agent@nesquena-hermes>
…follow-up to nesquena#6900 (nesquena#7044) * fix(docker): register /usr/local/lib in ld.so.conf.d so the source-built SQLite loads on arm64 The nesquena#6900 SQLite-from-source upgrade passed the amd64 docker-smoke but FAILED the multi-arch release build on linux/arm64 with 'AssertionError: SQLite 3.46.1 still vulnerable' — Python's sqlite3 kept loading the base image's /usr/lib multiarch libsqlite3 (3.46.1) instead of the freshly-compiled /usr/local/lib copy (3.53.0), because /usr/local/lib is NOT in the default ld.so search path on Debian arm64 (it happened to be picked up on amd64). Register /usr/local/lib via an ld.so.conf.d entry before ldconfig so the new lib wins on every architecture. The PR's own build-time version assertion is what surfaced this (correctly), and it also serves as the verification that the fix works once the arm64 build passes. Follow-up to nesquena#6900 (exp-v0.52.227, whose multi-arch image failed to build/push). * test-fix: keep wal.html link within 500 chars of ARG (condense arm64 comment) --------- Co-authored-by: nesquena-hermes <agent@nesquena-hermes>
…quena#6900) (nesquena#7044) (nesquena#7045) Co-authored-by: nesquena-hermes <agent@nesquena-hermes>
Problem
The
python:3.12-slimbase image ships SQLite 3.46.1 from Debian Trixie,which is vulnerable to the WAL-reset corruption bug discovered March 2026.
All three Docker deployment modes (single-container, two-container,
three-container) share this Dockerfile and are affected.
state.db(sessions, messages, FTS indexes) runs in WAL mode by default.Debian has not backported the fix and shows no indication of doing so.
Ref: https://sqlite.org/wal.html#walresetbug
Fix
Compiles SQLite 3.53.0 from the official amalgamation tarball during the
Docker build. The shared library installs to
/usr/local/lib, which takesldconfig priority over the system
/usr/libwithout removing the distropackage.
--disable-static --disable-readlinekeeps compilation minimalgcc,make,libc6-dev) are purged in the same layerSQLITE_VERSIONandSQLITE_YEARare build args for easy bumpsstill vulnerable
Alternatives considered
python:3.13-slimon a distro that ships3.51.3+, or Alpine which tracks SQLite upstream more closely). Less
build complexity but more intrusive - changes the package manager,
available system libraries, and potentially the Python version. Left to
maintainer's discretion whether a base image bump is preferred over the
source compile.
a silent corruption risk, not a crash, so distro urgency is low.
Verification
hermes doctorno longer reports the WAL-reset advisorypython3 -c "import sqlite3; print(sqlite3.sqlite_version)"returns 3.53.0Image size impact
The compiled
libsqlite3.so.3.53.0is ~5 MB. The build toolchain (~204 MB)is purged in the same layer and does not persist.