From 54827bacd8f73615e05cd24f9edbf33c653f4961 Mon Sep 17 00:00:00 2001 From: schickling-assistant <261620128+schickling-assistant@users.noreply.github.com> Date: Tue, 10 Nov 2026 16:29:41 +0100 Subject: [PATCH 1/2] feat(instance): enforce local-only fixture network boundary agent-identity: agent/dotfiles/fractal-product-lead agent-persona: generalist agent-supervisor: unavailable agent-tool: OMP agent-tool-version: 18.12.5 agent-runtime: OMP 18.12.5 agent-model: openai-codex/gpt-6.1-sol --- crates/fractal-api-core/src/api.rs | 13 ++ crates/fractal-api-core/src/api/local_only.rs | 98 ++++++++++++ crates/fractal-kernel/src/config.rs | 4 + .../fractal-kernel/src/config/local_only.rs | 142 ++++++++++++++++++ crates/fractal-peer/src/peer.rs | 7 + .../fractal-peer/src/peer/local_only_tests.rs | 42 ++++++ crates/fractal/src/fleet_cli.rs | 2 + crates/fractal/src/main.rs | 1 + docs/st3/instances.md | 24 +++ .../client-control-fixture-local-only.json | 11 ++ 10 files changed, 344 insertions(+) create mode 100644 crates/fractal-api-core/src/api/local_only.rs create mode 100644 crates/fractal-kernel/src/config/local_only.rs create mode 100644 crates/fractal-peer/src/peer/local_only_tests.rs create mode 100644 release-notes/client-control-fixture-local-only.json diff --git a/crates/fractal-api-core/src/api.rs b/crates/fractal-api-core/src/api.rs index bc24089dc22..b52ca4da4de 100644 --- a/crates/fractal-api-core/src/api.rs +++ b/crates/fractal-api-core/src/api.rs @@ -189,6 +189,7 @@ pub mod records; mod write_principal; mod native_delivery; pub mod replication; +mod local_only; mod runs; pub mod sessions; pub mod work; @@ -1058,6 +1059,7 @@ pub fn router_for_transport(state: AppState, transport: ClientTransportBoundary, (state.clone(), transport), response_envelope, )) + .layer(from_fn_with_state(state.clone(), local_only::enforce)) .with_state(state) } @@ -6709,6 +6711,9 @@ pub fn remote_unavailable(host: &str) -> ApiError { /// A known dial-out owner syncs outward but has no inbound owner transport. pub fn remote_unavailable_for_owner(state: &AppState, host: &str) -> ApiError { + if state.local_only() { + return local_only::refusal(crate::config::NetworkOperation::PeerRelay); + } let dial_out = if let Some(relay) = &state.client_relay { relay.is_dial_out_owner(host) } else { @@ -8243,6 +8248,8 @@ pub fn overlay_seat_admission(state: &AppState, items: &mut [Value], history: bo } async fn health(State(state): State) -> Result, ApiError> { + let network_policy = crate::config::NetworkPolicy::for_state_dir(&state.state_dir); + let network_enabled = !network_policy.is_local_only(); let mut health = json!({ "status": "ready", "node": state.node, @@ -8251,6 +8258,12 @@ async fn health(State(state): State) -> Result, ApiError> "isolation": isolation_name(fractal_runtime::isolation_mode()), "store_index": state.store.index().map_err(ApiError::internal)?, "security": "trusted-network-no-tls-no-acls", + "network_policy": { + "mode": network_policy, + "fleet_join": network_enabled, + "replication": network_enabled, + "peer_relay": network_enabled, + }, "features": {"owned_sets":1,"seat_rollout":1,"seat_rollout_manual":1,"bounded_legacy_events":1,"person_directive_note":1,"declared_admission":1,"declared_attention":1,"github_plugin":2}, }); // How far this member's messages stream has come. Absent when it holds no shard, so a diff --git a/crates/fractal-api-core/src/api/local_only.rs b/crates/fractal-api-core/src/api/local_only.rs new file mode 100644 index 00000000000..bdbc502eb10 --- /dev/null +++ b/crates/fractal-api-core/src/api/local_only.rs @@ -0,0 +1,98 @@ +use super::*; +use crate::config::{NetworkOperation, NetworkPolicy}; + +impl AppState { + pub fn local_only(&self) -> bool { + NetworkPolicy::for_state_dir(&self.state_dir).is_local_only() + } +} + +pub(super) fn refusal(operation: NetworkOperation) -> ApiError { + let refused = NetworkPolicy::LocalOnly.require(operation).unwrap_err(); + ApiError { + status: StatusCode::FORBIDDEN, + code: refused.code.into(), + message: refused.to_string(), + details: Box::new(serde_json::Map::from_iter([ + ("network_policy".into(), json!(NetworkPolicy::LocalOnly)), + ("operation".into(), json!(operation)), + ])), + } +} + +fn network_operation(path: &str) -> Option { + if path.starts_with("/v1/internal/replication/") || path == "/v1/internal/replication-wake" { + Some(NetworkOperation::Replication) + } else if path.starts_with("/v1/internal/fleet/") { + Some(NetworkOperation::FleetJoin) + } else if path == crate::peer::CLIENT_READ_FORWARD_PATH + || path == crate::peer::SEAT_FRESHNESS_INTERNAL_PATH + || path == crate::peer::SEAT_FRESHNESS_READS_INTERNAL_PATH + { + Some(NetworkOperation::PeerRelay) + } else { + None + } +} + +pub(super) async fn enforce( + State(state): State, + request: Request, + next: Next, +) -> Response { + if state.local_only() + && let Some(operation) = network_operation(request.uri().path()) + { + return refusal(operation).into_response(); + } + next.run(request).await +} + +#[cfg(test)] +mod tests { + use super::*; + use tower::ServiceExt as _; + + #[tokio::test] + async fn fixture_refuses_join_replication_and_peer_relay_before_body_or_store_effects() { + let root = tempfile::tempdir().unwrap(); + let mut state = super::super::tests_shared::state(root.path()); + state.state_dir = root.path().join(".fractal-instance/client-control-fixture/state/fractal"); + assert!(state.local_only()); + let before = state.store.index().unwrap(); + let app = super::super::router(state.clone()); + for (path, code) in [ + ("/v1/internal/fleet/redeem", "local-only-fleet-join-refused"), + ("/v1/internal/fleet/pairing-admission", "local-only-fleet-join-refused"), + ("/v1/internal/replication/export", "local-only-replication-refused"), + ("/v1/internal/replication/receive", "local-only-replication-refused"), + ("/v1/internal/replication/shard/messages/receive", "local-only-replication-refused"), + (crate::peer::CLIENT_READ_FORWARD_PATH, "local-only-peer-relay-refused"), + (crate::peer::SEAT_FRESHNESS_INTERNAL_PATH, "local-only-peer-relay-refused"), + ] { + let response = app.clone().oneshot(Request::builder().method("POST").uri(path) + .body(Body::from("not even valid JSON")).unwrap()).await.unwrap(); + assert_eq!(response.status(), StatusCode::FORBIDDEN, "{path}"); + let bytes = axum::body::to_bytes(response.into_body(), usize::MAX).await.unwrap(); + let value: Value = serde_json::from_slice(&bytes).unwrap(); + assert_eq!(value["code"], code, "{path}: {value}"); + assert_eq!(value["details"]["network_policy"], "local-only"); + } + assert_eq!(state.store.index().unwrap(), before); + } + + #[tokio::test] + async fn health_proves_fixture_network_policy_and_nonfixture_stays_fleet_capable() { + let root = tempfile::tempdir().unwrap(); + let mut state = super::super::tests_shared::state(root.path()); + let ordinary = super::super::health(State(state.clone())).await.unwrap().0; + assert_eq!(ordinary["network_policy"]["mode"], "fleet-capable"); + state.state_dir = root.path().join(".st-instance/client-control-fixture/state/fractal"); + let health = super::super::health(State(state.clone())).await.unwrap().0; + assert_eq!(health["network_policy"], json!({ + "mode":"local-only", "fleet_join":false, "replication":false, "peer_relay":false, + })); + let error = super::super::remote_unavailable_for_owner(&state, "host/personal"); + assert_eq!(error.code, "local-only-peer-relay-refused"); + } +} diff --git a/crates/fractal-kernel/src/config.rs b/crates/fractal-kernel/src/config.rs index 85ff65a7fa4..df776ecf4ce 100644 --- a/crates/fractal-kernel/src/config.rs +++ b/crates/fractal-kernel/src/config.rs @@ -13,6 +13,8 @@ use crate::model::PlannerSpec; pub mod changes; mod client; +mod local_only; +pub use local_only::{CLIENT_CONTROL_FIXTURE, LocalOnlyRefusal, NetworkOperation, NetworkPolicy}; /// The per-host switch for seat lanes. #[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)] @@ -998,6 +1000,7 @@ impl Config { let Some(file) = FleetFile::load(&self.state_dir)? else { return Ok(()); }; + self.network_policy().require(NetworkOperation::FleetJoin)?; if let Some(configured) = &self.fleet_id { anyhow::ensure!( *configured == file.fleet_id, @@ -1024,6 +1027,7 @@ impl Config { } pub fn validate(&self) -> Result<()> { + self.network_policy().validate_config(self)?; if let Some(usage_limits) = &self.usage_limits { usage_limits.validate()?; } diff --git a/crates/fractal-kernel/src/config/local_only.rs b/crates/fractal-kernel/src/config/local_only.rs new file mode 100644 index 00000000000..d53711ae2f3 --- /dev/null +++ b/crates/fractal-kernel/src/config/local_only.rs @@ -0,0 +1,142 @@ +//! The fixture instance is an isolation boundary, not an operator-toggleable fleet member. +use std::path::Path; + +use serde::Serialize; + +use super::Config; + +pub const CLIENT_CONTROL_FIXTURE: &str = "client-control-fixture"; + +#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize)] +#[serde(rename_all = "kebab-case")] +pub enum NetworkPolicy { + FleetCapable, + LocalOnly, +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize)] +#[serde(rename_all = "kebab-case")] +pub enum NetworkOperation { + FleetJoin, + Replication, + PeerRelay, +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize)] +pub struct LocalOnlyRefusal { + pub code: &'static str, + pub operation: NetworkOperation, +} + +impl std::fmt::Display for LocalOnlyRefusal { + fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(formatter, "{}: the client-control-fixture instance is permanently local-only", self.code) + } +} + +impl std::error::Error for LocalOnlyRefusal {} + +impl NetworkPolicy { + /// The instance environment is set before threads start. Recognize its state path too so + /// an explicit config or service invocation cannot turn the fixture into a fleet member. + pub fn for_state_dir(state_dir: &Path) -> Self { + let instance = crate::instance::current(); + Self::for_instance(instance.as_ref().map(crate::instance::Instance::name), state_dir) + } + + fn for_instance(instance: Option<&str>, state_dir: &Path) -> Self { + let fixture_path = state_dir.ancestors().any(|path| { + path.file_name().is_some_and(|name| name == CLIENT_CONTROL_FIXTURE) + && path.parent().and_then(Path::file_name).is_some_and(|name| { + name == ".st-instance" || name == ".fractal-instance" + }) + }); + if instance == Some(CLIENT_CONTROL_FIXTURE) || fixture_path { + Self::LocalOnly + } else { + Self::FleetCapable + } + } + + pub fn is_local_only(self) -> bool { + self == Self::LocalOnly + } + + pub fn require(self, operation: NetworkOperation) -> Result<(), LocalOnlyRefusal> { + if !self.is_local_only() { + return Ok(()); + } + Err(LocalOnlyRefusal { + code: match operation { + NetworkOperation::FleetJoin => "local-only-fleet-join-refused", + NetworkOperation::Replication => "local-only-replication-refused", + NetworkOperation::PeerRelay => "local-only-peer-relay-refused", + }, + operation, + }) + } + + pub fn validate_config(self, config: &Config) -> Result<(), LocalOnlyRefusal> { + if config.fleet_id.is_some() || config.fleet.is_some() { + self.require(NetworkOperation::FleetJoin)?; + } + if config.peer_listen.is_some() || config.shared_secret_file.is_some() { + self.require(NetworkOperation::Replication)?; + } + if !config.peers.is_empty() { + self.require(NetworkOperation::PeerRelay)?; + } + Ok(()) + } +} + +impl Config { + pub fn network_policy(&self) -> NetworkPolicy { + NetworkPolicy::for_state_dir(&self.state_dir) + } + + pub fn local_only(&self) -> bool { + self.network_policy().is_local_only() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn reserved_instance_cannot_escape_with_an_explicit_state_directory() { + assert_eq!(NetworkPolicy::for_instance(Some(CLIENT_CONTROL_FIXTURE), Path::new("/tmp/elsewhere")), NetworkPolicy::LocalOnly); + for root in [".st-instance", ".fractal-instance"] { + assert_eq!(NetworkPolicy::for_instance(None, &Path::new("/home/operator").join(root).join(CLIENT_CONTROL_FIXTURE).join("state/fractal")), NetworkPolicy::LocalOnly); + } + assert_eq!(NetworkPolicy::for_instance(Some("other"), Path::new("/tmp/state")), NetworkPolicy::FleetCapable); + assert_eq!(NetworkPolicy::for_instance(None, Path::new("/tmp/client-control-fixture/state")), NetworkPolicy::FleetCapable); + } + + #[test] + fn each_network_operation_has_a_typed_refusal() { + for (operation, code) in [ + (NetworkOperation::FleetJoin, "local-only-fleet-join-refused"), + (NetworkOperation::Replication, "local-only-replication-refused"), + (NetworkOperation::PeerRelay, "local-only-peer-relay-refused"), + ] { + assert_eq!(NetworkPolicy::LocalOnly.require(operation), Err(LocalOnlyRefusal { code, operation })); + assert!(NetworkPolicy::FleetCapable.require(operation).is_ok()); + } + } + + #[test] + fn stale_or_injected_network_configuration_is_refused() { + let mut config = Config::default(); + assert!(NetworkPolicy::LocalOnly.validate_config(&config).is_ok()); + config.fleet_id = Some("personal-fleet".into()); + assert_eq!(NetworkPolicy::LocalOnly.validate_config(&config).unwrap_err().operation, NetworkOperation::FleetJoin); + config.fleet_id = None; + config.peer_listen = Some("127.0.0.1:31313".into()); + assert_eq!(NetworkPolicy::LocalOnly.validate_config(&config).unwrap_err().operation, NetworkOperation::Replication); + config.peer_listen = None; + config.peers.push(super::super::PeerConfig { name: "personal".into(), url: "http://127.0.0.1:31313".into() }); + assert_eq!(NetworkPolicy::LocalOnly.validate_config(&config).unwrap_err().operation, NetworkOperation::PeerRelay); + } +} diff --git a/crates/fractal-peer/src/peer.rs b/crates/fractal-peer/src/peer.rs index 6ed7dd9e02d..facdf483aa7 100644 --- a/crates/fractal-peer/src/peer.rs +++ b/crates/fractal-peer/src/peer.rs @@ -48,6 +48,8 @@ mod seat_freshness; pub use seat_freshness::*; mod seat_freshness_reads; pub use seat_freshness_reads::*; +#[cfg(test)] +mod local_only_tests; /// The peer listener's shared state, with this node's daemon as the store. type PeerState = smallclaims::sync::PeerState; @@ -531,6 +533,10 @@ impl ClientRelay { } pub fn from_config(config: &Config) -> Result> { + if config.local_only() { + config.network_policy().validate_config(config)?; + return Ok(None); + } let (Some(fleet), Some(secret)) = ( config.fleet_id.as_deref(), config.shared_secret_file.as_deref(), @@ -2104,6 +2110,7 @@ pub async fn conversation_gateway_relay( /// Run the replication worker: sync this node's store, through its daemon, with the fleet. pub async fn run_worker(config: Config, splice: RawSplice) -> Result<()> { + config.network_policy().require(crate::config::NetworkOperation::Replication)?; config.validate()?; if let Err(error) = crate::replication_worker_build::record(&config.state_dir) { eprintln!("st replication-worker: WARNING: cannot report worker build: {error:#}"); diff --git a/crates/fractal-peer/src/peer/local_only_tests.rs b/crates/fractal-peer/src/peer/local_only_tests.rs new file mode 100644 index 00000000000..da26fb0308e --- /dev/null +++ b/crates/fractal-peer/src/peer/local_only_tests.rs @@ -0,0 +1,42 @@ +use super::*; +use crate::config::{LocalOnlyRefusal, NetworkOperation}; + +fn fixture_config(root: &Path) -> Config { + Config { + state_dir: root.join(".st-instance/client-control-fixture/state/fractal"), + ..Config::default() + } +} + +#[test] +fn fixture_never_constructs_a_peer_relay_even_without_fleet_configuration() { + let root = tempfile::tempdir().unwrap(); + let mut config = fixture_config(root.path()); + assert!(ClientRelay::from_config(&config).unwrap().is_none()); + config.peers.push(PeerConfig { name: "personal".into(), url: "http://127.0.0.1:31313".into() }); + let error = match ClientRelay::from_config(&config) { + Err(error) => error, + Ok(_) => panic!("fixture peer configuration must be refused"), + }; + let refusal = error.downcast_ref::().unwrap(); + assert_eq!(refusal.operation, NetworkOperation::PeerRelay); + assert_eq!(refusal.code, "local-only-peer-relay-refused"); + assert!(!config.state_dir.exists()); +} + +#[tokio::test] +async fn fixture_worker_refuses_before_creating_state_or_loading_keys() { + fn never_splice(_: axum::extract::ws::WebSocket, _: tokio::net::UnixStream) + -> std::pin::Pin + Send>> + { + panic!("a refused worker cannot start a peer transport"); + } + let root = tempfile::tempdir().unwrap(); + let config = fixture_config(root.path()); + let state_dir = config.state_dir.clone(); + let error = run_worker(config, never_splice).await.unwrap_err(); + let refusal = error.downcast_ref::().unwrap(); + assert_eq!(refusal.operation, NetworkOperation::Replication); + assert_eq!(refusal.code, "local-only-replication-refused"); + assert!(!state_dir.exists()); +} diff --git a/crates/fractal/src/fleet_cli.rs b/crates/fractal/src/fleet_cli.rs index 514aece1eba..8a8505a7858 100644 --- a/crates/fractal/src/fleet_cli.rs +++ b/crates/fractal/src/fleet_cli.rs @@ -517,6 +517,8 @@ async fn bootstrap_fabric_invite( } pub(super) async fn run_fleet(endpoint: &Endpoint, command: FleetCommand, json_output: bool) -> Result<()> { + Config::load_unvalidated(None)?.network_policy() + .require(fractal_daemon::config::NetworkOperation::FleetJoin)?; // Recording an override only asks this member's daemon; it reads no fleet configuration. let command = match command { FleetCommand::AdmitWithout { peers, reason, actor } => { diff --git a/crates/fractal/src/main.rs b/crates/fractal/src/main.rs index 24e3e1dc5e1..a2f8db0e2de 100644 --- a/crates/fractal/src/main.rs +++ b/crates/fractal/src/main.rs @@ -5973,6 +5973,7 @@ async fn run(cli: Cli) -> Result<()> { if !args.peer.is_empty() { config.peers = args.peer; } + config.network_policy().require(fractal_daemon::config::NetworkOperation::Replication)?; config.apply_fleet_file()?; fractal_daemon::node_identity::resolve(&mut config)?; let mut telemetry = diff --git a/docs/st3/instances.md b/docs/st3/instances.md index ac7a4fa281a..e1ecd3fea86 100644 --- a/docs/st3/instances.md +++ b/docs/st3/instances.md @@ -25,6 +25,30 @@ A name is 1 to 24 lowercase letters, digits and single hyphens. The flag works b subcommand and wins over the environment variable. Inside an instance, a different name is an error, so a seat of one instance cannot start another by accident. +## Client-control fixture: permanently local-only + +The reserved `client-control-fixture` instance is a fixture-data boundary, not a +second fleet member. Its network policy cannot be switched off in configuration. +It refuses fleet commands before service or membership changes, never starts a +replication worker, and never constructs a peer relay. Stale fleet membership, +peer listeners, shared secrets or configured peers make daemon startup fail closed. +This also applies when an explicit state directory points beneath the reserved +instance's `.st-instance` or `.fractal-instance` directory without an instance flag. + +The daemon refuses fleet admission, replication export/receive (including shards), +and peer-forwarding requests before processing their bodies or changing the store. +The typed refusal codes are `local-only-fleet-join-refused`, +`local-only-replication-refused` and `local-only-peer-relay-refused`. +`GET /v1/health` reports `network_policy.mode: "local-only"` and +`fleet_join`, `replication` and `peer_relay` all `false`. These are enforced +restrictions, not merely a report that no peers happen to be configured. + +Paired clients may still reach the fixture's client socket. Local-only does not +authorize setup, enrollment, grants, Fabric exposure or any live instance changes; +those require their own consent and scope. Other instance names and the default +daemon retain their existing fleet behavior. + + ## Directory discovery The daemon, CLI, standalone client and TUI share one resolver for product config diff --git a/release-notes/client-control-fixture-local-only.json b/release-notes/client-control-fixture-local-only.json new file mode 100644 index 00000000000..abf27783427 --- /dev/null +++ b/release-notes/client-control-fixture-local-only.json @@ -0,0 +1,11 @@ +{ + "version": 1, + "summary": "Make the reserved client-control-fixture instance permanently local-only with typed fleet, replication and peer-relay refusals and health proof.", + "replay": {"status": "none", "detail": "No startup replay or history rewrite."}, + "schema": {"status": "none", "detail": "No claim, store or generated client schema changes. The health response adds network_policy with the enforced mode and network capability booleans."}, + "rules": {"status": "none", "detail": "No admission vocabulary, canonical ordering, checkpoint or retention changes."}, + "compatibility": {"status": "changed", "detail": "The reserved client-control-fixture instance refuses fleet operations, replication workers and peer relays. Existing fleet membership or peer configuration fails startup closed. Default and other named instances keep their existing behavior. Paired fixture client transport remains available."}, + "manual": {"status": "none", "detail": "Source-only change; no setup, instance initialization, enrollment, grant, service exposure or live activation is authorized or performed."}, + "recovery": {"status": "none", "detail": "There is no configuration bypass for the reserved instance. Incorrect fleet or peer configuration must be removed before it can start; no automatic cleanup of state is performed."}, + "downtime": {"status": "unknown", "detail": "No builds, tests, daemon launches or restarts were run for this source change."} +} From 68388ebecddd9b300bd4a801386e3cdd6ff2339f Mon Sep 17 00:00:00 2001 From: schickling-assistant <261620128+schickling-assistant@users.noreply.github.com> Date: Wed, 11 Nov 2026 01:37:56 +0100 Subject: [PATCH 2/2] Repair fixture policy CI route inventory and neutral test roots Register only test include site lv-hc95cad153008, owner fractal_api_core::api::legacy_handler_guard_tests, TODO trace-statement-and-value-representation. Approved by agent/dotfiles/fractal-product-lead. No generator drift was present: genie-freshness failed on the public repository path guard; linux-gate collected the Clippy unused-import and route-family registry failures. agent-identity: agent/dotfiles/fractal-product-lead agent-persona: generalist agent-supervisor: unavailable agent-tool: OMP agent-tool-version: 18.12.5 agent-runtime: OMP 18.12.5 agent-model: openai-codex/gpt-6.1-sol --- crates/fractal-api-core/src/api/legacy_handler_guard_tests.rs | 1 + crates/fractal-api-core/src/api/local_only.rs | 1 - crates/fractal-kernel/src/config/local_only.rs | 3 ++- docs/st3/large-value-sites.json | 1 + 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/crates/fractal-api-core/src/api/legacy_handler_guard_tests.rs b/crates/fractal-api-core/src/api/legacy_handler_guard_tests.rs index 4b92577a2c1..727f02755d8 100644 --- a/crates/fractal-api-core/src/api/legacy_handler_guard_tests.rs +++ b/crates/fractal-api-core/src/api/legacy_handler_guard_tests.rs @@ -11,6 +11,7 @@ fn removed_legacy_handlers_are_absent_from_api_and_its_route_families() { ("client_reads", /* sqlite-large-value: allow-for-now lv-h7507c9c06532 owner=fractal_api_core::api::legacy_handler_guard_tests TODO=trace-statement-and-value-representation */ include_str!("client_reads.rs")), ("fleet", /* sqlite-large-value: allow-for-now lv-hd82cb2e4adf3 owner=fractal_api_core::api::legacy_handler_guard_tests TODO=trace-statement-and-value-representation */ include_str!("fleet.rs")), ("launches", /* sqlite-large-value: allow-for-now lv-hb3cca75d21d1 owner=fractal_api_core::api::legacy_handler_guard_tests TODO=trace-statement-and-value-representation */ include_str!("launches.rs")), + ("local_only", /* sqlite-large-value: allow-for-now lv-hc95cad153008 owner=fractal_api_core::api::legacy_handler_guard_tests TODO=trace-statement-and-value-representation */ include_str!("local_only.rs")), ("messages", /* sqlite-large-value: allow-for-now lv-h43c19aca2faa owner=fractal_api_core::api::legacy_handler_guard_tests TODO=trace-statement-and-value-representation */ include_str!("messages.rs")), ("native_delivery", /* sqlite-large-value: allow-for-now lv-h487b327aa403 owner=fractal_api_core::api::legacy_handler_guard_tests TODO=trace-statement-and-value-representation */ include_str!("native_delivery.rs")), ("operations", /* sqlite-large-value: allow-for-now lv-h5489ceb8d6c0 owner=fractal_api_core::api::legacy_handler_guard_tests TODO=trace-statement-and-value-representation */ include_str!("operations.rs")), diff --git a/crates/fractal-api-core/src/api/local_only.rs b/crates/fractal-api-core/src/api/local_only.rs index bdbc502eb10..5d9960f5a59 100644 --- a/crates/fractal-api-core/src/api/local_only.rs +++ b/crates/fractal-api-core/src/api/local_only.rs @@ -51,7 +51,6 @@ pub(super) async fn enforce( #[cfg(test)] mod tests { use super::*; - use tower::ServiceExt as _; #[tokio::test] async fn fixture_refuses_join_replication_and_peer_relay_before_body_or_store_effects() { diff --git a/crates/fractal-kernel/src/config/local_only.rs b/crates/fractal-kernel/src/config/local_only.rs index d53711ae2f3..90f5202375a 100644 --- a/crates/fractal-kernel/src/config/local_only.rs +++ b/crates/fractal-kernel/src/config/local_only.rs @@ -107,8 +107,9 @@ mod tests { #[test] fn reserved_instance_cannot_escape_with_an_explicit_state_directory() { assert_eq!(NetworkPolicy::for_instance(Some(CLIENT_CONTROL_FIXTURE), Path::new("/tmp/elsewhere")), NetworkPolicy::LocalOnly); + let home = tempfile::tempdir().unwrap(); for root in [".st-instance", ".fractal-instance"] { - assert_eq!(NetworkPolicy::for_instance(None, &Path::new("/home/operator").join(root).join(CLIENT_CONTROL_FIXTURE).join("state/fractal")), NetworkPolicy::LocalOnly); + assert_eq!(NetworkPolicy::for_instance(None, &home.path().join(root).join(CLIENT_CONTROL_FIXTURE).join("state/fractal")), NetworkPolicy::LocalOnly); } assert_eq!(NetworkPolicy::for_instance(Some("other"), Path::new("/tmp/state")), NetworkPolicy::FleetCapable); assert_eq!(NetworkPolicy::for_instance(None, Path::new("/tmp/client-control-fixture/state")), NetworkPolicy::FleetCapable); diff --git a/docs/st3/large-value-sites.json b/docs/st3/large-value-sites.json index 1f14b74d731..b26065af8ee 100644 --- a/docs/st3/large-value-sites.json +++ b/docs/st3/large-value-sites.json @@ -4193,6 +4193,7 @@ {"id": "lv-hc8fbf8a65fc9", "path": "crates/smallclaims/src/store/operation_claim_digests.rs", "kind": "sql-template", "fingerprint": "d645ccc0e9492c88420c78b15bb7c323b9b78f58f32243988588d153a451955b", "owner": "smallclaims::store::operation_claim_digests", "todo": "bound-or-reference-values-and-reclamation", "disposition": "allow-for-now", "line_hint": 214, "excerpt": "UPDATE operation_claim_digests_backfill SET operation=?1, claim_rowid=?2, ready=?3 WHERE singleton=1"}, {"id": "lv-hc901cd51dd6c", "path": "crates/smallclaims/src/store/sealed_view_cache_tests.rs", "kind": "sql-template", "fingerprint": "8d5a4d5d8f9bd69cfa35171e15bf47ab9d47ef439db16d0fded39d4848a63f83", "owner": "smallclaims::store::sealed_view_cache_tests", "todo": "chunk-or-reference-exact-wire-values", "disposition": "allow-for-now", "line_hint": 278, "excerpt": "INSERT INTO replica_envelope_signatures(writer,sequence,envelope_hash,member_key,signature,stored_at_unix_ms) VALUES(?1,?2,?3,?4,?5,?6)"}, {"id": "lv-hc9439392b3a3", "path": "crates/fractal-reconcile/src/reconcile/tests/terminal_step_guard.rs", "kind": "unresolved-sql-sink", "fingerprint": "160e804026917a32ca102da71a10bda54195713cc6916ddac581bee13ee81333", "owner": "fractal_reconcile::reconcile::tests::terminal_step_guard", "todo": "trace-statement-and-value-representation", "disposition": "allow-for-now", "line_hint": 50, "excerpt": "[ subject ] , | row | { ( 0 . . columns ) . map ( | column | row . get ( column ) ) . collect : : < rusqlite : : Result < Vec < _ > > > ( ) }"}, + {"id": "lv-hc95cad153008", "path": "crates/fractal-api-core/src/api/legacy_handler_guard_tests.rs", "kind": "included-source", "fingerprint": "0458cd7c68da69526d59938f0bdcd17c62efccb8e2d7d3dfc8c4770cf25c4718", "owner": "fractal_api_core::api::legacy_handler_guard_tests", "todo": "trace-statement-and-value-representation", "disposition": "allow-for-now", "line_hint": 14, "excerpt": "include_str ! ( \"local_only.rs\" )"}, {"id": "lv-hc96730cc68a9", "path": "crates/fractal-store/src/store.rs", "kind": "unresolved-sql-sink", "fingerprint": "4ec7c53222c8a758c722e2111541035ce700d5ae7bd0898c5f1b1a743e6450fd", "owner": "fractal_store::store", "todo": "trace-statement-and-value-representation", "disposition": "allow-for-now", "line_hint": 16377, "excerpt": "sql"}, {"id": "lv-hc96b6a3952ad", "path": "crates/fractal-store/src/store/arrangements.rs", "kind": "sql-template", "fingerprint": "7ddc6493d7f051021ccdbc0c6c276b4b7037d6b0f52bceb592a381f003ebe580", "owner": "fractal_store::store::arrangements", "todo": "bound-or-reference-values-and-reclamation", "disposition": "allow-for-now", "line_hint": 117, "excerpt": "INSERT INTO arrangement_registers(subject,register,value,revision,winner) VALUES(?1,?2,?3,?4,?5) ON CONFLICT(subject,register) DO UPDATE SET value=excluded.value,revision=excluded.revision,winner=excl"}, {"id": "lv-hc981b0645ac6", "path": "crates/fractal-delivery/src/store/projection_divergence_tests.rs", "kind": "sql-template", "fingerprint": "1f6900921caf95ee5f6f98ec81784e7cac837f6de3de6e03e4a5afc70130c37f", "owner": "fractal_delivery::store::projection_divergence_tests", "todo": "chunk-or-reference-variable-columns", "disposition": "allow-for-now", "line_hint": 52, "excerpt": "CREATE TEMP TABLE wrong_desired AS SELECT * FROM desired WHERE subject='exec/work'; PRAGMA foreign_keys=OFF; DELETE FROM desired WHERE subject='exec/work'; PRAGMA foreign_keys=ON;"},