app

Local-first trade for farms and co-ops
git clone https://radroots.dev/git/app.git
Log | Files | Refs | README | LICENSE

commit 5c22ceeaebfca8dd25c867c84851860b9ded8c4d
parent cc2b3b030ed2aaf4e370f3b5a7b60cdf012b9770
Author: triesap <tyson@radroots.org>
Date:   Wed, 22 Jul 2026 21:02:53 +0000

sqlite: enforce registry bundled runtime

- remove the deleted sibling libsqlite3-sys source override
- lock libsqlite3-sys 0.37.0 to its crates.io checksum
- reject local patches and ambiguous SQLite lock entries
- retain SQLx bundled-runtime and alternative-runtime guards

Diffstat:
MCargo.lock | 3+++
MCargo.toml | 1-
Mcrates/store/Cargo.toml | 3+++
Mcrates/store/src/source_guards.rs | 94+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
4 files changed, 96 insertions(+), 5 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -3574,6 +3574,8 @@ dependencies = [ [[package]] name = "libsqlite3-sys" version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f111c8c41e7c61a49cd34e44c7619462967221a6443b0ec299e0ac30cfb9b1" dependencies = [ "cc", "pkg-config", @@ -5512,6 +5514,7 @@ dependencies = [ "serde_json", "sqlx", "thiserror 2.0.18", + "toml 0.8.23", "uuid", ] diff --git a/Cargo.toml b/Cargo.toml @@ -73,4 +73,3 @@ unsafe_code = "forbid" [patch.crates-io] block = { path = "vendor/block" } -libsqlite3-sys = { path = "../lib/crates/libsqlite3_sys_3_53_3" } diff --git a/crates/store/Cargo.toml b/crates/store/Cargo.toml @@ -26,5 +26,8 @@ uuid.workspace = true [features] test-support = [] +[dev-dependencies] +toml.workspace = true + [lints] workspace = true diff --git a/crates/store/src/source_guards.rs b/crates/store/src/source_guards.rs @@ -4,8 +4,10 @@ use std::{ }; const WORKSPACE_SQLX_DEPENDENCY: &str = r#"sqlx = { version = "0.9.0", default-features = false, features = ["derive", "sqlite-bundled"] }"#; -const WORKSPACE_LIBSQLITE3_PATCH: &str = - r#"libsqlite3-sys = { path = "../lib/crates/libsqlite3_sys_3_53_3" }"#; +const LIBSQLITE3_SYS_VERSION: &str = "0.37.0"; +const LIBSQLITE3_SYS_SOURCE: &str = "registry+https://github.com/rust-lang/crates.io-index"; +const LIBSQLITE3_SYS_CHECKSUM: &str = + "b1f111c8c41e7c61a49cd34e44c7619462967221a6443b0ec299e0ac30cfb9b1"; #[test] fn app_sqlite_runtime_uses_sqlx_bundled_sqlite_only() { @@ -16,9 +18,24 @@ fn app_sqlite_runtime_uses_sqlx_bundled_sqlite_only() { workspace_manifest.contains(WORKSPACE_SQLX_DEPENDENCY), "workspace SQLx dependency must stay pinned to SQLx 0.9.0 with sqlite-bundled" ); + + let manifest: toml::Value = + toml::from_str(workspace_manifest.as_str()).expect("workspace Cargo.toml should parse"); + let libsqlite3_patch = manifest + .get("patch") + .and_then(|patch| patch.get("crates-io")) + .and_then(|crates_io| crates_io.get("libsqlite3-sys")); assert!( - workspace_manifest.contains(WORKSPACE_LIBSQLITE3_PATCH), - "workspace must keep the approved SQLite 3.53.3 libsqlite3-sys patch" + libsqlite3_patch.is_none(), + "workspace must resolve libsqlite3-sys from crates.io without a source override" + ); + + let lockfile = read_source(app_root.join("Cargo.lock").as_path()); + let lockfile_findings = libsqlite3_lock_findings(lockfile.as_str()); + assert!( + lockfile_findings.is_empty(), + "app SQLite lockfile findings:\n{}", + lockfile_findings.join("\n") ); let findings = sqlite_runtime_drift_findings(app_root.as_path()); @@ -29,6 +46,50 @@ fn app_sqlite_runtime_uses_sqlx_bundled_sqlite_only() { ); } +fn libsqlite3_lock_findings(lockfile: &str) -> Vec<String> { + let lock: toml::Value = match toml::from_str(lockfile) { + Ok(lock) => lock, + Err(error) => return vec![format!("Cargo.lock is not valid TOML: {error}")], + }; + let packages = lock + .get("package") + .and_then(toml::Value::as_array) + .map(Vec::as_slice) + .unwrap_or_default(); + let libsqlite3_packages = packages + .iter() + .filter(|package| { + package.get("name").and_then(toml::Value::as_str) == Some("libsqlite3-sys") + }) + .collect::<Vec<_>>(); + + if libsqlite3_packages.len() != 1 { + return vec![format!( + "Cargo.lock must contain exactly one libsqlite3-sys package, found {}", + libsqlite3_packages.len() + )]; + } + + let package = libsqlite3_packages[0]; + let expected_fields = [ + ("version", LIBSQLITE3_SYS_VERSION), + ("source", LIBSQLITE3_SYS_SOURCE), + ("checksum", LIBSQLITE3_SYS_CHECKSUM), + ]; + expected_fields + .into_iter() + .filter_map(|(field, expected)| { + let actual = package.get(field).and_then(toml::Value::as_str); + (actual != Some(expected)).then(|| { + format!( + "libsqlite3-sys {field} must be `{expected}`, found `{}`", + actual.unwrap_or("<missing>") + ) + }) + }) + .collect() +} + fn sqlite_runtime_drift_findings(app_root: &Path) -> Vec<String> { sqlite_guard_paths(app_root) .into_iter() @@ -56,6 +117,7 @@ fn forbidden_sqlite_findings(path: &str, source: &str) -> Vec<String> { } for pattern in [ + "libsqlite3-sys = { path =", "sqlite-wasm-rs", "rsqlite-vfs", "bundled-sqlcipher", @@ -80,6 +142,30 @@ fn forbidden_sqlite_findings(path: &str, source: &str) -> Vec<String> { findings } +#[test] +fn sqlite_lock_guard_rejects_local_or_ambiguous_sources() { + let valid = format!( + r#"[[package]] +name = "libsqlite3-sys" +version = "{LIBSQLITE3_SYS_VERSION}" +source = "{LIBSQLITE3_SYS_SOURCE}" +checksum = "{LIBSQLITE3_SYS_CHECKSUM}" +"# + ); + assert!(libsqlite3_lock_findings(valid.as_str()).is_empty()); + + let local = format!( + r#"[[package]] +name = "libsqlite3-sys" +version = "{LIBSQLITE3_SYS_VERSION}" +"# + ); + assert_eq!(libsqlite3_lock_findings(local.as_str()).len(), 2); + + let duplicate = format!("{valid}\n{valid}"); + assert_eq!(libsqlite3_lock_findings(duplicate.as_str()).len(), 1); +} + fn sqlite_guard_paths(app_root: &Path) -> Vec<PathBuf> { let mut paths = vec![app_root.join("Cargo.toml"), app_root.join("Cargo.lock")]; collect_guard_paths(app_root.join("crates").as_path(), &mut paths);