Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 16 additions & 9 deletions ARCHITECTURE.toml
Original file line number Diff line number Diff line change
Expand Up @@ -247,17 +247,23 @@ mode = "required"
# sbx-mgr's node-local SQLite database (`sandboxes` and every other sbx-mgr
# table) is opened, migrated and queried only by its store, the
# `pplx-space-sbx-mgr-store` crate. The guarantee is that crate's boundary:
# `dependency_fence.sbxmgr_rusqlite` below keeps rusqlite out of every other
# sbx-mgr crate, and outside its `test-support` feature the store's API hands
# `dependency_fence.sbxmgr_rusqlite` below keeps rusqlite and
# `pplx-space-sqlite` (the shared helpers that open, migrate and delete a
# SQLite database by path) out of every other sbx-mgr crate; CI's
# `run_sbxmgr_production_checks` (ci/scripts/run-rust-checks.sh) asserts that
# nothing else in the server's production graph brings either in; and
# outside its `test-support` feature the store's API hands
# out no rusqlite connection, transaction, statement or row. (Its `FromSql`
# impl for a column type can return rusqlite's `FromSqlError`, an error type
# rather than a database capability, to a caller holding a rusqlite value.)
# This ratchet is a line-based tripwire on top of it, within sbx-mgr's
# crates: naming rusqlite, opening a connection or transaction, using the
# shared SQLite open and migration helpers or the shared job store's SQL
# functions, binding parameters, executing a statement, or writing an SQL
# statement literal outside the store is a crossing. Aliases, wrapped
# imports and calls through names imported earlier escape it. Other services' crates use rusqlite for their own databases, so
# shared job store's SQL functions, binding parameters, executing a
# statement, or writing an SQL statement literal outside the store is a
# crossing. Aliases, wrapped imports and calls through names imported
# earlier escape it. Its `sql::sqlite` pattern predates the shared helpers'
# move into `pplx-space-sqlite` and matches nothing now; the fence and the
# graph assertion cover them. Other services' crates use rusqlite for their own databases, so
# `paths` limits the rule to sbx-mgr's.
[rules.pattern_ratchet.sbxmgr_sqlite]
patterns = [
Expand Down Expand Up @@ -331,10 +337,11 @@ mode = "required"
mode = "required"

# Only the store may depend on the SQLite drivers that can open sbx-mgr's
# database, so no other sbx-mgr crate can name rusqlite: no normal, dev or
# build dependency, for any target, under any name.
# database, or on the shared helpers that open, migrate and delete one by
# path, so no other sbx-mgr crate can name them: no normal, dev or build
# dependency, for any target, under any name.
[rules.dependency_fence.sbxmgr_rusqlite]
packages = ["libsqlite3-sys", "rusqlite"]
packages = ["libsqlite3-sys", "pplx-space-sqlite", "rusqlite"]
members = ["crates/libs/sbx/mgr/**", "crates/apps/sbx/**"]
allow = ["crates/libs/sbx/mgr/store"]

Expand Down
25 changes: 24 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ members = [
"crates/libs/sbx/mgr/migrations",
"crates/libs/sbx/mgr/server",
"crates/libs/sbx/mgr/store",
"crates/libs/sqlite",
"crates/libs/node/api/client",
"crates/libs/node/api/server",
"crates/libs/node/ctl/server",
Expand Down Expand Up @@ -346,6 +347,7 @@ pplx-space-sbxmgr-migrations = { path = "crates/libs/sbx/mgr/migrations" }
pplx-space-sbx-mgr = { path = "crates/libs/sbx/mgr/server" }
pplx-space-sbx-mgr-client = { path = "crates/libs/sbx/mgr/client" }
pplx-space-sbx-mgr-store = { path = "crates/libs/sbx/mgr/store" }
pplx-space-sqlite = { path = "crates/libs/sqlite" }
pplx-space-spaced-build = { path = "crates/libs/spaced/build" }
pplx-space-spaced-guest-protocol = { path = "crates/libs/spaced/guest/protocol" }
pplx-space-spaced-guest-execution = { path = "crates/libs/spaced/guest/execution" }
Expand Down
3 changes: 3 additions & 0 deletions ci/rust-artifact-inputs.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
"crates/libs/sbx/mgr/store",
"crates/libs/spaced/build",
"crates/libs/spaced/common",
"crates/libs/sqlite",
"crates/libs/template/mgr-client",
"crates/libs/template/publish"
]
Expand Down Expand Up @@ -103,6 +104,7 @@
"crates/libs/sbx/mgr/store",
"crates/libs/spaced/build",
"crates/libs/spaced/common",
"crates/libs/sqlite",
"crates/libs/template/mgr-client"
]
},
Expand Down Expand Up @@ -271,6 +273,7 @@
"crates/libs/spaced/guest/server",
"crates/libs/spaced/host/client",
"crates/libs/spaced/host/server",
"crates/libs/sqlite",
"crates/libs/template/mgr",
"crates/libs/template/mgr-client",
"crates/libs/vol/mgr/client",
Expand Down
57 changes: 57 additions & 0 deletions ci/scripts/run-rust-checks.sh
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,36 @@ run_fmt_check() {
cargo fmt --all -- --check
}

# The direct dependents of package $1 in the normal dependency graph of
# sbx-mgr's server and service, built with the feature arguments that follow
# up to `--`, must all be among the packages after `--`. `dependency_fence`
# checks only sbx-mgr's own manifests; this catches a crate elsewhere in the
# graph that starts depending on the package and re-exports it.
sbxmgr_assert_direct_dependents() {
local package="$1"
shift
local feature_args=()
while [ "$1" != "--" ]; do
feature_args+=("$1")
shift
done
shift
local allowed=" $* "
local graph dependent
local unexpected=()
graph="$(cargo tree --locked -p pplx-space-sbx-mgr -p pplx-space-sbxmgr-svc \
"${feature_args[@]}" -e normal -i "${package}" --depth 1 --prefix none)"
while read -r dependent; do
if [[ "${allowed}" != *" ${dependent} "* ]]; then
unexpected+=("${dependent}")
fi
done < <(awk 'NR > 1 { print $1 }' <<<"${graph}" | sort -u)
if [ "${#unexpected[@]}" -gt 0 ]; then
echo "${package} enters sbx-mgr's production graph (${feature_args[*]:-no features}) through ${unexpected[*]}; only $* may depend on it" >&2
return 1
fi
}

# sbx-mgr's SQLite store makes its raw connection and statement methods
# public only under its `test-support` feature, which the workspace pass's
# `--all-features` turns on. Lint sbx-mgr's production libraries and
Expand Down Expand Up @@ -283,6 +313,16 @@ run_sbxmgr_production_checks() {
echo "sbx-mgr's production graph (features: ${sbxmgr_features:-none}) must not enable the store's test-support" >&2
return 1
fi
# The shared SQLite helpers open, migrate and delete a database by
# path; only the store may bring them into the server's graph.
sbxmgr_assert_direct_dependents pplx-space-sqlite "${sbxmgr_feature_args[@]}" -- \
pplx-space-sbx-mgr-store
# rusqlite enters only through the store, the helpers it depends on,
# and two shared crates whose rusqlite use hands no connection out:
# common-jobs' functions take a connection in, and common-core only
# implements rusqlite's value conversion traits for its types.
sbxmgr_assert_direct_dependents rusqlite "${sbxmgr_feature_args[@]}" -- \
pplx-space-sbx-mgr-store pplx-space-sqlite pplx-space-common-jobs pplx-space-common-core
done
}

Expand Down Expand Up @@ -322,6 +362,23 @@ run_clippy_checks() {
-- \
-D warnings

# Built alone, so a sqlx or common-svc feature these crates need but only
# get through unification with the rest of the workspace fails here.
echo "--- :rust: Running isolated SQLite helper clippy"
CARGO_TARGET_DIR="${target_dir}" cargo clippy \
--locked \
-p pplx-space-sqlite \
--lib \
-- \
-D warnings
CARGO_TARGET_DIR="${target_dir}" cargo clippy \
--locked \
-p pplx-space-common-svc \
--no-default-features \
--features migration-checksums \
-- \
-D warnings

run_sbxmgr_production_checks "${target_dir}"

# feature-flags must lint clean with no vendor SDK compiled in; the matching
Expand Down
2 changes: 1 addition & 1 deletion crates/libs/build/mgr/server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ sqlx = { workspace = true, features = ["macros", "migrate"] }
pplx-space-build-mgr-client = { workspace = true, features = ["test-support"] }
axum = { workspace = true }
base64 = { workspace = true }
pplx-space-common-svc = { workspace = true, features = ["test-support", "test-hooks", "k8s", "sqlite"] }
pplx-space-common-svc = { workspace = true, features = ["test-support", "test-hooks", "k8s"] }
pplx-space-test-env = { workspace = true }
rstest = { workspace = true }
tempfile = { workspace = true }
Expand Down
7 changes: 5 additions & 2 deletions crates/libs/common/svc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ datadog = ["otel", "pplx-space-observability/datadog"]
# Deprecated for one release; use otel and datadog.
datadog-otel = ["otel", "datadog"]
k8s = ["dep:k8s-openapi", "dep:kube"]
sqlite = ["dep:rusqlite", "dep:toml", "sqlx/migrate", "sqlx/runtime-tokio", "sqlx/sqlite-bundled", "sqlx/tls-rustls-aws-lc-rs"]
# Exposes `sql::migration_checksums`, the accepted-checksums adapter every
# migration runner embeds.
migration-checksums = ["dep:toml", "sqlx/migrate"]
# Exposes shared route and authentication test helpers to other crates.
# Unit tests get them under `cfg(test)`; external test suites opt in through
# a dev-dependency. Mirrors `pplx-space-metrics`'s `test-capture`.
Expand All @@ -43,7 +45,6 @@ nix = { workspace = true, features = ["fs", "user"] }
pin-project-lite = { workspace = true }
redis = { workspace = true }
rand = { workspace = true }
rusqlite = { workspace = true, optional = true }
rustls = { workspace = true, default-features = false, features = ["aws_lc_rs", "std", "tls12"] }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
Expand All @@ -70,6 +71,8 @@ pplx-space-metrics = { workspace = true }
pplx-space-observability = { workspace = true }

[dev-dependencies]
# The accepted-checksums tests migrate in-memory SQLite databases.
sqlx = { workspace = true, features = ["sqlite-bundled"] }
insta = { workspace = true }
pplx-space-common-core = { workspace = true, features = ["test-hooks"] }
nix = { workspace = true, features = ["signal"] }
Expand Down
5 changes: 1 addition & 4 deletions crates/libs/common/svc/src/sql/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,15 @@ use sqlx::ConnectOptions as _;
use sqlx::PgPool;
use sqlx::postgres::{PgConnectOptions, PgPoolOptions};

pub mod baselines;
pub mod contention;
pub mod federated_service_grants;
pub mod identity;
#[cfg(feature = "sqlite")]
#[cfg(feature = "migration-checksums")]
pub mod migration_checksums;
pub mod node_registration;
pub mod sandbox_quarantine;
pub mod sandbox_residency;
pub mod sandbox_routability;
#[cfg(feature = "sqlite")]
pub mod sqlite;

const POOL_METRICS_INTERVAL: Duration = Duration::from_secs(10);

Expand Down
3 changes: 2 additions & 1 deletion crates/libs/db/migrator/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ tokio = { workspace = true, features = ["macros", "rt-multi-thread", "time"] }
tracing = { workspace = true }

# internal
pplx-space-common-svc = { workspace = true, features = ["sqlite"] }
pplx-space-common-svc = { workspace = true, features = ["migration-checksums"] }
pplx-space-sqlite = { workspace = true }
pplx-space-sbx-mgr-store = { workspace = true }

[dev-dependencies]
Expand Down
6 changes: 3 additions & 3 deletions crates/libs/db/migrator/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
//! carry that weight, and no long-running service links this.

use pplx_space_common_svc::sql;
use pplx_space_common_svc::sql::sqlite::runtime_manager::MIGRATOR as RUNTIME_MANAGER_MIGRATOR;
use pplx_space_sqlite::runtime_manager::MIGRATOR as RUNTIME_MANAGER_MIGRATOR;
use std::borrow::Cow;
use std::collections::BTreeSet;
use std::path::{Path, PathBuf};
Expand All @@ -25,7 +25,7 @@ use sqlx::postgres::PgPoolOptions;
use sqlx::sqlite::{SqliteConnectOptions, SqlitePoolOptions};
use sqlx::{PgConnection, PgPool, SqlitePool};

use pplx_space_common_svc::sql::sqlite::{self, SqliteError};
use pplx_space_sqlite::{self as sqlite, SqliteError};

pub mod bootstrap_roles;
pub mod migration_retry;
Expand Down Expand Up @@ -577,7 +577,7 @@ async fn rollback_last_sqlite_database(
.last()
.copied();
if common_version.is_some_and(|version| {
version > pplx_space_common_svc::sql::baselines::PUBLIC_SQLITE_BASELINE
version > pplx_space_sqlite::baselines::PUBLIC_SQLITE_BASELINE
&& Some(version) > service_version
}) {
return rollback_last_sqlite(&pool, &common).await;
Expand Down
2 changes: 1 addition & 1 deletion crates/libs/db/migrator/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ fn embedded_migrations_have_unique_versions_and_public_baselines() {
let baseline = if *name == "postgres" {
20261002070625
} else {
pplx_space_common_svc::sql::baselines::PUBLIC_SQLITE_BASELINE
pplx_space_sqlite::baselines::PUBLIC_SQLITE_BASELINE
};
assert_eq!(
migrator
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::{borrow::Cow, sync::LazyLock};

use super::*;
use pplx_space_common_svc::sql::baselines;
use pplx_space_sqlite::baselines;
use sqlx::SqlSafeStr as _;
use sqlx::migrate::{Migration, MigrationType};

Expand Down
3 changes: 2 additions & 1 deletion crates/libs/node/ctl/server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ k8s-openapi = { workspace = true, features = ["v1_32"], optional = true }
kube = { workspace = true, default-features = false, features = ["aws-lc-rs", "client", "config", "rustls-tls"], optional = true }
pplx-space-common-core = { workspace = true }
pplx-space-common-grpc = { workspace = true, features = ["internal-tls"] }
pplx-space-common-svc = { workspace = true, features = ["sqlite"] }
pplx-space-common-svc = { workspace = true }
pplx-space-sqlite = { workspace = true }
pplx-space-execution-common = { workspace = true }
pplx-space-net-common = { workspace = true }
pplx-space-metrics = { workspace = true }
Expand Down
Loading
Loading