Repository navigation
Move the shared SQLite helpers out of common-svc so only sbx-mgr's store can reach them - #586
Conversation
6cf2675 to
ef22a34
Compare
Review — 3 findingsNo correctness findings. The four moved files match their originals after the listed path rewrites. CI's new Low
Verified against |
the-gigi-pplx
left a comment
There was a problem hiding this comment.
Approved. 3 non-blocking findings in the review comment above.
ef22a34 to
1fbf246
Compare
…ore can reach them common-svc's `sql::sqlite` module opens, migrates and deletes a service's SQLite database by path (`open_rusqlite`, `migrate_embedded`, `migrate`, `remove_database_files`, `restrict_database_permissions`). It sat behind common-svc's `sqlite` feature, and Cargo feature unification turns that on for every crate that depends on common-svc once any crate in the build asks for it. So sbx-mgr's server could reach those helpers, and through them sbx-mgr's database, although only its store enables them. The module moves, as a pure move, into its own crate, `crates/libs/sqlite` (`pplx-space-sqlite`), with its runtime-manager catalog, its tests and the SQLite migration baseline constant. Only path rewrites change in the moved lines: `super::` paths into common-svc, `crate::baselines`, and the relative `migrate!`/`include_str!` paths, which are shorter now. common-svc loses the `sqlite` feature and its rusqlite dependency. Its `migration_checksums` module, which opens nothing and which the migrator's Postgres retry also uses, moves to a narrower `migration-checksums` feature. The store, node-ctl, node-mgr, runtime-manager, template-mgr, vol-mgr and the database migrator depend on the new crate instead; build-mgr never used the module and drops the feature. `dependency_fence.sbxmgr_rusqlite` now lists `pplx-space-sqlite`, so among sbx-mgr's crates only the store may depend on it, and a crate can only name what it depends on. `dependency_fence` reads only sbx-mgr's own manifests, so CI's `run_sbxmgr_production_checks` also asserts, for each feature configuration sbx-mgr's images are built with, that `pplx-space-sqlite` enters the server's and service's production graph only through the store, and rusqlite only through the store, the helpers, common-jobs and common-core. The new crate and common-svc's `migration-checksums` feature are also linted alone, so a feature that only unification supplies (as sqlx's `macros` was) fails CI. No behavior or message changes. Observable differences: - the `sqlite.migrate` span's module path, file and line, which OTel exports as `code.namespace`, `code.filepath` and `code.lineno` (`pplx_space_common_svc::sql::sqlite`, `sql/sqlite.rs:350` becomes `pplx_space_sqlite`, `crates/libs/sqlite/src/lib.rs:360`); - `sql!` locators in the moved code: the production one becomes `pplx_space_sqlite:252` (was `…::sql::sqlite:242`); the test-only `lib.rs:469` (was 459) and the four in `tests.rs` (same lines) change module path; - locator line shifts in callers: common-svc `sql/mod.rs` 188->185 and 264->261, runtime-manager `installs/store.rs` 175->172, 225->222 and 248->245.
1fbf246 to
d9f6b99
Compare
Summary
Milestone 4, stacked on #578. This concerns sbx-mgr's node-local SQLite database, not the control-plane Postgres.
After #578, the one remaining way for sbx-mgr's server to reach its database outside the store was common-svc's
sql::sqlitemodule. Cargo feature unification exposes it to every crate that depends on common-svc as soon as any crate in the build enables common-svc'ssqlitefeature, and the store did. Its path-taking functions (open_rusqlite,migrate_embedded,migrate,remove_database_files,restrict_database_permissions) act on any SQLite database by path without naming a rusqlite type.This PR moves those helpers into their own crate,
crates/libs/sqlite(packagepplx-space-sqlite). It removes thesqlitefeature from common-svc and fences the new crate withdependency_fence. Only sbx-mgr's store, among sbx-mgr's crates, can depend on it, and a crate can only name what it depends on.What moved (pure move)
pplx-space-sqlite)src/sql/sqlite.rssrc/lib.rssrc/sql/sqlite/runtime_manager.rssrc/runtime_manager.rssrc/sql/sqlite/tests.rssrc/tests.rssrc/sql/baselines.rs(onlyPUBLIC_SQLITE_BASELINE, already gated onsqlite)src/baselines.rssql::migration_checksumsstays in common-svc. It opens nothing: it validates sqlx migrators against an existingMigrateconnection, and the migrator's Postgres retry uses it too. It moves from thesqlitefeature to a narrowermigration-checksumsfeature (dep:toml,sqlx/migrate), which the new crate and the migrator enable.sqlitefeature is gone from common-svc, and so is its rusqlite dependency. Its accepted-checksums tests migrate in-memory SQLite, so they getsqlx/sqlite-bundledas a dev-dependency.crate_namespasses:pplx,spaceandsqliteare not banned tokens.Callers:
sqlitefeature and depends onpplx-space-sqlite; the migrator also enablesmigration-checksums.pplx_space_common_svc::sql::sqlite→pplx_space_sqlite;pplx_space_common_svc::sql::baselines→pplx_space_sqlite::baselines;use …::sql::sqlite::{self, SqliteError}→use pplx_space_sqlite::{self as sqlite, SqliteError}, so itssqlite::…call sites are unchanged;rustfmt rejoined a few calls onto one line where the shorter path now fits, dropping their trailing commas. It also reordered
uselines in three files: the new crate'slib.rs, the store'sdb.rsand vol-mgr'srun.rs. No other code changed.Fence:
dependency_fence.sbxmgr_rusqlitenow listspplx-space-sqlitebesiderusqliteandlibsqlite3-sys; onlycrates/libs/sbx/mgr/storemay depend on it. The server already had no direct dependency on it, so it cannot name it.Transitive reach:
dependency_fencereads only sbx-mgr's own manifests, so CI'srun_sbxmgr_production_checksaddssbxmgr_assert_direct_dependents. For each feature configuration sbx-mgr's images are built with (none, the release set and the Kind set), it runscargo tree --locked -p pplx-space-sbx-mgr -p pplx-space-sbxmgr-svc -e normal -i <package> --depth 1and fails on any direct dependent outside an explicit list:pplx-space-sqlite: onlypplx-space-sbx-mgr-store;rusqlite: onlypplx-space-sbx-mgr-store,pplx-space-sqlite,pplx-space-common-jobsandpplx-space-common-core.common-jobs' functions take a connection in; common-core only implements rusqlite's value-conversion traits.
Isolated builds:
run_clippy_checksalso lintspplx-space-sqlitealone (--lib) and common-svc with onlymigration-checksums. Built alone like that, CI catches a feature that only unification supplied, as sqlx'smacroswas here.Pure-move proof
Per moved file, the multiset of non-blank code lines at #578's head (
92f0dc5, rebased ontomain825b786), compared with the new file, after these path rewrites:super::migration_checksums::AcceptedChecksums→pplx_space_common_svc::sql::migration_checksums::AcceptedChecksums;super::super::baselines::→crate::baselines::(once inruntime_manager.rs, three times intests.rs);sqlx::migrate!("../../../../db/runtime-manager")→("../../../db/runtime-manager");include_str!("../../../../../../../db/runtime-manager/history/prototype-baseline.sql")→("../../../../db/…");CARGO_MANIFEST_DIR+"../../../../db/node-manager"→"../../../db/node-manager"(test).runtime_manager.rstests.rslib.rspub mod baselines;(plus the new crate doc comment)baselines.rs#[cfg(feature = "sqlite")], which no longer appliesHidden observable changes
Tracing and OTel: the
sqlite.migratespan's metadata changes. OTel exports these fields ascode.namespace,code.filepathandcode.lineno:pplx_space_common_svc::sql::sqlite→pplx_space_sqlite;crates/libs/common/svc/src/sql/sqlite.rs→crates/libs/sqlite/src/lib.rs;The query-trace event keeps its explicit
rusqlite::querytarget, and no other event is in the moved code. No configuration in this repository filters on these targets.sql!locators in the moved code:lib.rs:252,/*pplx_space_sqlite:252*/(was/*pplx_space_common_svc::sql::sqlite:242*/);lib.rs:469(under#[cfg(test)], was 459), and the four intests.rs(lines 172, 277, 284, 355, unchanged), whose module path becomespplx_space_sqlite::tests.Their SQL text is unchanged.
sql!line shifts in callers (module paths unchanged), caused by removed lines above them:sql/mod.rs: 188→185 and 264→261;installs/store.rs: 175→172, 225→222 and 248→245.file!()panic locations in the moved code now printcrates/libs/sqlite/src/….Messages: every
SqliteErrormessage and everyRunSbxMgrError/RunDbMigrateErrortext is unchanged. No other behavior changed in any service.Audit of the server's dependency graph
The question for each crate: does any public API in
pplx-space-sbx-mgr's normal dependency graph return a rusqlite connection, transaction or statement, or open, migrate or delete a database by path?Method:
cargo tree -p pplx-space-sbx-mgr -e normal -i <crate> --depth 1gives the direct dependents ofrusqlite,libsqlite3-sys,sqlx-sqlite,sqlxandpplx-space-sqlitein that graph.Connection::open*,open_in_memory,Sqlite{Pool,Connection,ConnectOptions}) and for path-taking or deleting operations.pplx-space-sqlite(new)open_rusqlite,migrate_embedded,migrate,remove_database_files,restrict_database_permissions,SqliteU64,runtime_manager::catalogdependency_fenceadmits only the store.sql::migration_checksums(on through unification) hasfrom_toml,embedded,validate,acceptsandrun<C: Migrate>(…, conn: &mut C).runneeds an existing sqlxMigrateconnection. The server has no sqlx dependency, and common-svc hands out only Postgres pools (another database).db::*functions andBackgroundWorker::newtake a&rusqlite::Connection/Arc<Mutex<rusqlite::Connection>>.try_prune_terminal_jobs_once's rusqlite error was closed in #570. No function opens by path.types::sqliteToSql/FromSqlimpls.host::linux::paths::SANDBOX_MANAGER_DB, the database path as a&str.sbx-manager.db, outside the store is ansbxmgr_sqlite_schematripwire.db::open,db::migrate,db::migrate_at(path),db::migration::target()run.rsopens and migrates through them, and the migrator takes its target.dependency_fencekeeps it that way.std::fs,tokio::fs,rustix,nix,tempfile)Result: after this PR no crate the server can name returns a rusqlite connection, transaction or statement, or opens or migrates a SQLite database by path, other than the store.
Review round 1 (final)
pplx-space-sqlitesbxmgr_assert_direct_dependentsasserts the direct dependents ofpplx-space-sqlite(store only) and ofrusqlite(store,pplx-space-sqlite, common-jobs, common-core). It runs over the server's and service's normal graph in each of the three feature configurations. Probes: givingpplx-space-events, a non-sbx-mgr crate in that graph, a dependency onpplx-space-sqlitefails with "pplx-space-sqlite enters sbx-mgr's production graph (no features) through pplx-space-events; only pplx-space-sbx-mgr-store may depend on it". Giving itrusqlitefails with "rusqlite enters … through pplx-space-events; only pplx-space-sbx-mgr-store pplx-space-sqlite pplx-space-common-jobs pplx-space-common-core may depend on it". Probes removed, lockfile restored.code.*); production vs test-only locators; the five caller line shifts.usereorderslib.rs, the store'sdb.rsand vol-mgr'srun.rs.ARCHITECTURE.toml'ssbxmgr_sqlitecomment now names the fence and the graph assertion, and says thesql::sqlitepattern matches nothing since the move. The store'sAGENTS.mdand the archcheck README (its example now listspplx-space-sqlite, plus a note that fences are direct-only and what covers the transitive side) are updated too.run_clippy_checks:-p pplx-space-sqlite --lib, and-p pplx-space-common-svc --no-default-features --features migration-checksums.Rebased onto #578's final head
51364ca.Rebased with the stack onto
main825b786, without conflicts.main's common-svc changes since the original base (#567'sbootstrap.rssplit, the routability and residency SQL,template_lookup) touch none of the moved files or thesqlitefeature, and no new caller namessql::sqlite. The pure-move result above and every locator in "Hidden observable changes" are re-checked on the rebased heads and unchanged.Rebased with the stack onto
mainc4be884, without conflicts. The caps are unchanged. One advisoryfile_sizefinding comes from this PR itself and predates the rebase: the import split grows the store'sdb/auto_lifecycle_delete_receipts.rsfrom 1147 to 1148 code lines, and its cap is not raised.Decisions
migration_checksumsstays in common-svc. It opens no database and takes no path. The migrator's Postgres retry needs it as much as the SQLite helpers do. A narrowermigration-checksumsfeature keeps itstoml/sqlx/migratedependencies opt-in, assqlitedid.PUBLIC_SQLITE_BASELINEmoves with the helpers. It was alreadysqlite-gated and names the first supported SQLite migration epoch.sbxmgr_sqlitesql::sqlitepattern is left in place. It no longer matches any helper, but per the owner decision the regexes are not touched. The fence onpplx-space-sqlitereplaces it.derive,macros,migrate,runtime-tokio,sqlite-bundled,tls-rustls-aws-lc-rs). In common-svc,migrate!compiled only because other crates' features were unified in. A lib-onlycargo check -p pplx-space-sqliteshowedmacroswas missing.sql!locator renames listed above.Validation
bash ci/scripts/run-rust-checks.sh fmt(includes the Rust error policy)bash ci/scripts/run-rust-checks.sh clippy: the workspace--all-featurespass, the feature-isolation passes, the new isolatedpplx-space-sqliteandcommon-svc --features migration-checksumsbuilds, and the sbx-mgr production step. That step runs clippy plus thetest-support,pplx-space-sqliteandrusqlitegraph assertions, once per feature configuration (none, release, Kind).cargo check -p <crate> --libwithout features, each separately: common-svc,pplx-space-sqlite, store, server, migrator, node-ctl, node-mgr, runtime-manager, template-mgr, vol-mgr, build-mgr, common-jobscargo arch --base-baseline <main> --base-architecture <main>d9f6b99: pre-existingfile_sizedrift and #578's moved-file entries)cargo test --locked -p pplx-space-archcheckSPACE_CI_REQUIRE_TEST_DEPS=1 cargo nextest run --lockedover all 12 affected packages, as CI splits it:-E 'not group(privileged)'as the user1fbf246: 3251 passed, 0 failed. On the previous rebase (6ceee0c, patch-identical, onemaincommit set earlier), three runs from one build: 3250 passed, 0 failed, each run. Before the rebase: 3101 passed, 0 failed (initial run and the final round)ci/scripts/with-nocow-test-filesystem.shloop-backed btrfs fixture, from the same build's archive (--run-ignored all)6ceee0c, three runs: 35 passed, 0 failed, each run. Before the rebase: 33 passed, 0 failed (initial run and the final round)sudohad droppedDOCKER_HOST, so root could not reach this host's Docker daemon. ENVIRONMENTAL; withDOCKER_HOSTpassed through, the same archive passed (row above). Before the rebase, the first full-inventory run as a non-root user without the btrfs fixture failed 5 NoCoW tests closed ("CI must provide the disposable NoCoW btrfs fixture"), also ENVIRONMENTAL: those tests are in the privileged group.After the
c4be884rebase, fmt, clippy,cargo archagainstmainand the archcheck tests re-ran on every head of the stack and passed. Nextest ran once, on #586's headd9f6b99:SPACE_CI_REQUIRE_TEST_DEPS=1 cargo nextest run --locked --all-features -p pplx-space-sbx-mgr -p pplx-space-sbx-mgr-store -p pplx-space-db-migrate -p pplx-space-sqlite -p pplx-space-db-test-fixtures --retries 0gave 1808 passed, 0 failed (server 1367, store 366, migrator 53, sqlite 12, test fixtures 10). The 1 skip is the root-only#[ignore]transfer_directoryUID test. Kind was not re-run, because the rebase changed no code.Kind ran on the final head
1fbf246, on a fresh cluster on Linux/KVM; no cluster existed on the host beforehand. The run on the previous rebase (6ceee0c, patch-identical) also passed both smokes; the final rebase brought inmain's common-svc changes, so Kind ran again on the final head.docker builder prune -af,docker image prune -fandcrictl rmi --prune(unused images only, 37 images) on this run's own fresh nodes took it from 20,720,427,008 to 31,543,037,952 bytes. No volume was pruned;tilt triggerwas never used.scripts/tests/smoke-kind-e2e.sh(bootstrap, Tilt, Rust build from this worktree), withDATA_PLANE_URLandBOOTSTRAP_TIMEOUT=1800as CI sets them.space-sandbox-managerpods run/opt/space/bin/space-sbxmgr-svc,/proc/<pid>/exesha256413d40bf…1b070a8e, equal to the binary in the locally builtspace-rust-build-kind:local. The worktree was clean at1fbf246before the build. The binary containspplx_space_sbx_mgr_store::db::teardown_jobs:57,pplx_space_sqlite:252andmain's #551 messagedrop stopped artifact pin, and nopplx_space_sbx_mgr::db::orpplx_space_common_svc::sql::sqlite:locator.ok, 2not_applicable, none pending or in progress, after the e2e and again after the prune.smoke-kind-e2e.shsmoke-kind-typed.sh all, set up as CI's step does but unshardedSKIP_BOOTSTRAP=1, an admin token file,SPACE_SMOKE_KIND_COLD_RECEIPTSin a0700directory, and the data-plane health wait. ECW surface: 80 passed, 0 failed, 0 inconclusive. Native surface: 25 passed, 0 failed, 0 inconclusive. The suite skipped two scenarios as environmental:local.telemetry_reaches_local_backendsandlocal.btrfs_send_restore_pulls_parent_templateneed telemetry mode otel, and this bench runs datadog.6ceee0c5c66eb14…05b33e3matched its artifact image.infra/space/kind/scripts/teardown.shafter each run: Tilt stopped, cluster deleted, no Kind containers left.🤖 Generated with Claude Code