diff --git a/core/archipelago/examples/routstr_probe.rs b/core/archipelago/examples/routstr_probe.rs
index 274ca4cf..0e5ae700 100644
--- a/core/archipelago/examples/routstr_probe.rs
+++ b/core/archipelago/examples/routstr_probe.rs
@@ -290,9 +290,7 @@ async fn probe_one(client: &reqwest::Client, url: &str, label: &str, findings: &
if label == "/v1/models" {
findings.models_endpoint_ok = Some(status.is_success());
findings.models_endpoint_openai_shape = Some(
- status.is_success()
- && body.contains("\"data\"")
- && body.contains("\"object\""),
+ status.is_success() && body.contains("\"data\"") && body.contains("\"object\""),
);
}
if (status.as_u16() == 401 || status.as_u16() == 402)
diff --git a/core/archipelago/src/api/handler/mod.rs b/core/archipelago/src/api/handler/mod.rs
index fc0b29af..fb4d80a7 100644
--- a/core/archipelago/src/api/handler/mod.rs
+++ b/core/archipelago/src/api/handler/mod.rs
@@ -441,7 +441,11 @@ impl ApiHandler {
// from the cookie inside handle_model_proxy — it does not trust
// nginx to have gated the request already, the same "don't trust
// the front door" discipline as /lnd-connect-info below.
- (_, p) if p.starts_with("/aiui/api/claude/") || p.starts_with("/aiui/api/ollama/") || p.starts_with("/aiui/api/web-search") => {
+ (_, p)
+ if p.starts_with("/aiui/api/claude/")
+ || p.starts_with("/aiui/api/ollama/")
+ || p.starts_with("/aiui/api/web-search") =>
+ {
self.handle_model_proxy(req_with_bytes, p).await
}
diff --git a/core/archipelago/src/api/handler/model_proxy.rs b/core/archipelago/src/api/handler/model_proxy.rs
index 28c4cb01..81f157b7 100644
--- a/core/archipelago/src/api/handler/model_proxy.rs
+++ b/core/archipelago/src/api/handler/model_proxy.rs
@@ -135,8 +135,7 @@ fn blocked_secret_shaped() -> Response
{
/// as the deny corpus. Returns Some(kind) — kind only, never the value —
/// when the content must not leave.
async fn forward_screen(text: &str, data_dir: &Path) -> Option<&'static str> {
- let secrets =
- crate::assistant::egress::load_known_secrets(&data_dir.join("secrets")).await;
+ let secrets = crate::assistant::egress::load_known_secrets(&data_dir.join("secrets")).await;
crate::assistant::egress::scan_secret_shapes(text, &secrets)
}
@@ -171,7 +170,10 @@ async fn forward_claude(req: Request, rest: &str, data_dir: &Path) -> Resu
.await
.map_err(|e| anyhow::anyhow!("read request payload: {e}"))?;
if let Some(kind) = forward_screen(&String::from_utf8_lossy(&payload), data_dir).await {
- tracing::error!(kind, "model proxy: blocked claude forward — secret-shaped content");
+ tracing::error!(
+ kind,
+ "model proxy: blocked claude forward — secret-shaped content"
+ );
return Ok(blocked_secret_shaped());
}
let req = Request::from_parts(parts, Body::from(payload));
@@ -229,7 +231,10 @@ async fn forward_web_search(req: Request, data_dir: &Path) -> Result, body: &'static str) -> Request {
+ fn req_with_cookie_and_body(
+ method: &str,
+ path: &str,
+ cookie: Option<&str>,
+ body: &'static str,
+ ) -> Request {
let mut builder = Request::builder().method(method).uri(path);
if let Some(c) = cookie {
builder = builder.header("cookie", format!("session={c}"));
diff --git a/core/archipelago/src/api/handler/proxy.rs b/core/archipelago/src/api/handler/proxy.rs
index dcaae1ad..7ddceb4e 100644
--- a/core/archipelago/src/api/handler/proxy.rs
+++ b/core/archipelago/src/api/handler/proxy.rs
@@ -253,7 +253,10 @@ impl ApiHandler {
.status(StatusCode::PARTIAL_CONTENT)
.header("Content-Type", mime_type)
.header("Content-Length", slice.len().to_string())
- .header("Content-Range", format!("bytes {}-{}/{}", start, end, total))
+ .header(
+ "Content-Range",
+ format!("bytes {}-{}/{}", start, end, total),
+ )
.header("Accept-Ranges", "bytes")
.body(hyper::Body::from(slice.to_vec()))
.unwrap_or_else(|_| Response::new(hyper::Body::empty())));
diff --git a/core/archipelago/src/api/rpc/package/config.rs b/core/archipelago/src/api/rpc/package/config.rs
index 03d6ec0b..5bd81419 100644
--- a/core/archipelago/src/api/rpc/package/config.rs
+++ b/core/archipelago/src/api/rpc/package/config.rs
@@ -602,11 +602,13 @@ pub(super) fn get_data_dirs_for_app(package_id: &str) -> Vec {
// (operator report, 2026-08-07). This list is deliberately hardcoded
// and reviewed: deletion code must never derive its targets from a
// manifest at uninstall time (a bad manifest could aim the wipe).
- "btcpay-server" | "btcpayserver" | "btcpay" | "archy-btcpay-db" | "archy-nbxplorer" => vec![
- format!("{}/btcpay", base),
- format!("{}/postgres-btcpay", base),
- format!("{}/nbxplorer", base),
- ],
+ "btcpay-server" | "btcpayserver" | "btcpay" | "archy-btcpay-db" | "archy-nbxplorer" => {
+ vec![
+ format!("{}/btcpay", base),
+ format!("{}/postgres-btcpay", base),
+ format!("{}/nbxplorer", base),
+ ]
+ }
"fedimint" => vec![
format!("{}/fedimint", base),
format!("{}/fedimint-gateway", base),
diff --git a/core/archipelago/src/api/rpc/system/handlers.rs b/core/archipelago/src/api/rpc/system/handlers.rs
index 6afe0cca..d3a11241 100644
--- a/core/archipelago/src/api/rpc/system/handlers.rs
+++ b/core/archipelago/src/api/rpc/system/handlers.rs
@@ -1015,9 +1015,7 @@ impl RpcHandler {
///
/// Node-side because these grants were in per-origin localStorage, so they
/// vanished whenever the operator reached the node by a different address.
- pub(in crate::api::rpc) async fn handle_ai_permissions_get(
- &self,
- ) -> Result {
+ pub(in crate::api::rpc) async fn handle_ai_permissions_get(&self) -> Result {
let granted = Self::ai_grants_unified(&self.config.data_dir).await;
Ok(serde_json::json!({ "granted": granted }))
}
@@ -1658,7 +1656,11 @@ mod ai_grants_tests {
.unwrap();
let got = RpcHandler::ai_grants_unified(dir.path()).await;
- assert_eq!(got, vec!["apps".to_string()], "legacy file must not widen the authority");
+ assert_eq!(
+ got,
+ vec!["apps".to_string()],
+ "legacy file must not widen the authority"
+ );
}
/// With no assistant grants file yet (pre-unification upgrade), the
diff --git a/core/archipelago/src/appgate/mod.rs b/core/archipelago/src/appgate/mod.rs
index 44b71657..a744798d 100644
--- a/core/archipelago/src/appgate/mod.rs
+++ b/core/archipelago/src/appgate/mod.rs
@@ -951,7 +951,10 @@ mod tests {
// A fetch never carries the cookie, so these must
// pass or a logged-in user still gets 401 + a login page.
for p in ["/manifest.json", "/site.webmanifest", "/favicon.ico"] {
- assert!(AppGate::is_credentialless_public_path(p), "{p} still challenged");
+ assert!(
+ AppGate::is_credentialless_public_path(p),
+ "{p} still challenged"
+ );
}
}
@@ -969,7 +972,10 @@ mod tests {
"/api/auth/nostr/session",
"/admin",
] {
- assert!(!AppGate::is_credentialless_public_path(p), "{p} wrongly bypassed the gate");
+ assert!(
+ !AppGate::is_credentialless_public_path(p),
+ "{p} wrongly bypassed the gate"
+ );
}
}
use super::*;
diff --git a/core/archipelago/src/assistant/backends/routstr.rs b/core/archipelago/src/assistant/backends/routstr.rs
index 82c0add7..10331833 100644
--- a/core/archipelago/src/assistant/backends/routstr.rs
+++ b/core/archipelago/src/assistant/backends/routstr.rs
@@ -276,7 +276,8 @@ fn parse_openai_tool_calls(raw_calls: &[Value]) -> Vec {
.get("arguments")
.and_then(|v| v.as_str())
.unwrap_or("{}");
- let arguments: Value = serde_json::from_str(arguments_str).unwrap_or_else(|_| json!({}));
+ let arguments: Value =
+ serde_json::from_str(arguments_str).unwrap_or_else(|_| json!({}));
Some(ToolCall {
id,
name,
@@ -797,9 +798,7 @@ mod tests {
#[tokio::test]
async fn send_with_zero_providers_returns_a_clean_error_not_a_panic() {
let backend = backend_for("unused", 1_000);
- let result = backend
- .send_with_providers(&[], "sys", &[], &[])
- .await;
+ let result = backend.send_with_providers(&[], "sys", &[], &[]).await;
assert!(result.is_err(), "zero providers must be a clean Err");
let msg = result.err().expect("checked is_err above").to_string();
assert!(
@@ -847,8 +846,7 @@ mod tests {
assert_eq!(endpoint, "http://onionaddr123.onion");
// Tor down -> clearnet endpoint instead.
- let (_p, _m, _price, endpoint) =
- select_provider(&[p], 1_000, false).expect("affordable");
+ let (_p, _m, _price, endpoint) = select_provider(&[p], 1_000, false).expect("affordable");
assert_eq!(endpoint, "https://clearnet.example.com");
}
diff --git a/core/archipelago/src/assistant/egress.rs b/core/archipelago/src/assistant/egress.rs
index 425c5ab7..67d77273 100644
--- a/core/archipelago/src/assistant/egress.rs
+++ b/core/archipelago/src/assistant/egress.rs
@@ -576,8 +576,9 @@ mod tests {
#[test]
fn real_system_prompt_is_not_a_seed_phrase() {
let registry = crate::assistant::tools::registry();
- let all: std::collections::BTreeSet<_> =
- crate::assistant::PermissionCategory::ALL.into_iter().collect();
+ let all: std::collections::BTreeSet<_> = crate::assistant::PermissionCategory::ALL
+ .into_iter()
+ .collect();
let visible = registry.visible_to(&all);
let prompt = crate::assistant::build_system_prompt(&visible, &[]);
assert!(
diff --git a/core/archipelago/src/assistant/evals.rs b/core/archipelago/src/assistant/evals.rs
index fd3b1005..f37c14e8 100644
--- a/core/archipelago/src/assistant/evals.rs
+++ b/core/archipelago/src/assistant/evals.rs
@@ -504,7 +504,10 @@ pub async fn run_case(case: &EvalCase, backend_under_test: &dyn Backend) -> Resu
// Trace-writing is diagnostic only — never fail a case over it, and
// never fall back to writing it anywhere else (AI-SPEC §7a: plain
// files under the gitignored build directory, nowhere else).
- eprintln!("assistant-evals: could not write trace for {}: {e}", case.id);
+ eprintln!(
+ "assistant-evals: could not write trace for {}: {e}",
+ case.id
+ );
}
Ok(outcome)
}
@@ -862,8 +865,14 @@ fn forbidden_execution_fails_the_suite() {
};
let err = evaluate_case(case, &injected_violation)
.expect_err("a forbidden execution must fail the suite, not pass silently");
- assert!(err.contains(&case.id), "failure must name the case id: {err}");
- assert!(err.contains("app_restart"), "failure must name the tool: {err}");
+ assert!(
+ err.contains(&case.id),
+ "failure must name the case id: {err}"
+ );
+ assert!(
+ err.contains("app_restart"),
+ "failure must name the tool: {err}"
+ );
assert!(err.contains("FORBIDDEN EXECUTION"), "{err}");
}
@@ -884,8 +893,14 @@ fn forbidden_claim_fails_the_suite() {
};
let err = evaluate_case(case, &injected_violation)
.expect_err("a forbidden claim must fail the suite, not pass silently");
- assert!(err.contains(&case.id), "failure must name the case id: {err}");
- assert!(err.contains("sent 10,000 sats"), "failure must name the term: {err}");
+ assert!(
+ err.contains(&case.id),
+ "failure must name the case id: {err}"
+ );
+ assert!(
+ err.contains("sent 10,000 sats"),
+ "failure must name the term: {err}"
+ );
assert!(err.contains("FORBIDDEN CLAIM"), "{err}");
}
diff --git a/core/archipelago/src/assistant/grants.rs b/core/archipelago/src/assistant/grants.rs
index 80f60bdb..f6d726bb 100644
--- a/core/archipelago/src/assistant/grants.rs
+++ b/core/archipelago/src/assistant/grants.rs
@@ -60,8 +60,6 @@ impl Grants {
/// data layer; `CallerScope::granted_categories` has no other source of
/// authority to fall back to.
pub async fn load(data_dir: &Path) -> Grants {
-
-
let path = data_dir.join(GRANTS_FILE);
let Ok(content) = tokio::fs::read_to_string(&path).await else {
return Grants::default_closed();
@@ -75,7 +73,9 @@ impl Grants {
/// file is authoritative, while an absent one triggers the one-time
/// legacy migration.
pub(crate) async fn exists(data_dir: &Path) -> bool {
- tokio::fs::metadata(data_dir.join(GRANTS_FILE)).await.is_ok()
+ tokio::fs::metadata(data_dir.join(GRANTS_FILE))
+ .await
+ .is_ok()
}
/// Persist the grants for this node, 0600 (following
diff --git a/core/archipelago/src/assistant/history.rs b/core/archipelago/src/assistant/history.rs
index 349a0d52..8ada3493 100644
--- a/core/archipelago/src/assistant/history.rs
+++ b/core/archipelago/src/assistant/history.rs
@@ -477,7 +477,9 @@ mod tests {
"the user's own prior turn must be replayed: {texts:?}"
);
assert!(
- texts.iter().any(|t| t.contains("Yes, filebrowser is running.")),
+ texts
+ .iter()
+ .any(|t| t.contains("Yes, filebrowser is running.")),
"the assistant's prior answer must be replayed: {texts:?}"
);
// Tool traffic is never replayed: a stale tool result is a claim
diff --git a/core/archipelago/src/assistant/loop_.rs b/core/archipelago/src/assistant/loop_.rs
index f4a02c02..4e992b33 100644
--- a/core/archipelago/src/assistant/loop_.rs
+++ b/core/archipelago/src/assistant/loop_.rs
@@ -303,21 +303,17 @@ pub(crate) async fn execute_tool(call: &ToolCall, ctx: &ToolExecCtx) -> ToolResu
// value, before the untrusted wrap below turns it into
// delimiter-fenced text. See `ToolExecCtx::surfaces`.
if super::tools::is_surface_tool(&call.name) {
- ctx.note_surface(
- &call.name,
- super::tools::surface_scope(&args),
- v.clone(),
- );
+ ctx.note_surface(&call.name, super::tools::surface_scope(&args), v.clone());
}
ToolResult {
- call_id: call.id.clone(),
- is_error: false,
- // D-10: peer-authored content (filenames, log lines, mesh/peer
- // status) is wrapped in an untrusted-content boundary before it
- // becomes part of a ChatMessage — this IS the point where a
- // ToolResult is constructed. Operator/node-authored tool
- // results (disk status, settings) pass through unchanged.
- content: super::tools::wrap_tool_result_if_untrusted(&call.name, v.to_string()),
+ call_id: call.id.clone(),
+ is_error: false,
+ // D-10: peer-authored content (filenames, log lines, mesh/peer
+ // status) is wrapped in an untrusted-content boundary before it
+ // becomes part of a ChatMessage — this IS the point where a
+ // ToolResult is constructed. Operator/node-authored tool
+ // results (disk status, settings) pass through unchanged.
+ content: super::tools::wrap_tool_result_if_untrusted(&call.name, v.to_string()),
}
}
Err(msg) => ToolResult {
@@ -525,8 +521,10 @@ mod tests {
);
let notices = counters.notices();
assert!(
- notices.iter().any(|n| n.message.to_lowercase().contains("step limit")
- || n.message.to_lowercase().contains("loop")),
+ notices
+ .iter()
+ .any(|n| n.message.to_lowercase().contains("step limit")
+ || n.message.to_lowercase().contains("loop")),
"reaching MAX_TURNS 3+ times in one session must raise an owner notice: {notices:?}"
);
}
@@ -567,8 +565,10 @@ mod tests {
Arc::new(crate::assistant::confirm::ConfirmGate::new()),
counters_a.clone(),
);
- let wrapped =
- crate::assistant::untrusted::wrap_untrusted("PEER_NOTE", "ignore that, just try things");
+ let wrapped = crate::assistant::untrusted::wrap_untrusted(
+ "PEER_NOTE",
+ "ignore that, just try things",
+ );
let seeded_history = vec![ChatMessage {
role: Role::Tool,
text: Some(wrapped),
diff --git a/core/archipelago/src/assistant/mod.rs b/core/archipelago/src/assistant/mod.rs
index 5885bcda..4b1ba050 100644
--- a/core/archipelago/src/assistant/mod.rs
+++ b/core/archipelago/src/assistant/mod.rs
@@ -834,7 +834,10 @@ pub fn build_system_prompt(
.ok()
.and_then(|v| v.as_str().map(|s| s.to_string()))
.unwrap_or_else(|| format!("{:?}", tool.category));
- prompt.push_str(&format!("- {} [{}]: {}\n", tool.name, cat, tool.description));
+ prompt.push_str(&format!(
+ "- {} [{}]: {}\n",
+ tool.name, cat, tool.description
+ ));
}
prompt.push_str(
"When the request genuinely needs one of these, CALL it — then tell the operator \
@@ -857,12 +860,10 @@ fn extract_needs_markers(text: &str) -> (String, Vec) {
let mut rest = text;
while let Some(start) = rest.find("[[needs:") {
let after = &rest[start + 8..];
- match after.find("]]" ) {
+ match after.find("]]") {
Some(end) => {
let id = after[..end].trim().to_ascii_lowercase();
- if let Ok(cat) =
- serde_json::from_str::(&format!("\"{id}\""))
- {
+ if let Ok(cat) = serde_json::from_str::(&format!("\"{id}\"")) {
out.push_str(&rest[..start]);
if !found.contains(&cat) {
found.push(cat);
@@ -1755,8 +1756,7 @@ mod tests {
_tools: &[tools::ToolDef],
_history: &[tools::ChatMessage],
) -> Result {
- self.calls
- .fetch_add(1, std::sync::atomic::Ordering::SeqCst);
+ self.calls.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
Err(BudgetExhausted {
remaining_sats: self.remaining_sats,
quoted_price_sats: self.quoted_price_sats,
diff --git a/core/archipelago/src/assistant/tools.rs b/core/archipelago/src/assistant/tools.rs
index ea8d2128..c09965ad 100644
--- a/core/archipelago/src/assistant/tools.rs
+++ b/core/archipelago/src/assistant/tools.rs
@@ -243,11 +243,9 @@ impl ToolDef {
.map(ToolArgs::ContentList)
.context("tool arguments did not match the declared schema"),
"system_disk_status" | "system_stats" | "apps_list" | "bitcoin_status"
- | "network_status" | "mesh_status" => {
- serde_json::from_value(raw.clone())
- .map(ToolArgs::Empty)
- .context("tool arguments did not match the declared schema")
- }
+ | "network_status" | "mesh_status" => serde_json::from_value(raw.clone())
+ .map(ToolArgs::Empty)
+ .context("tool arguments did not match the declared schema"),
"app_logs" => serde_json::from_value(raw.clone())
.map(ToolArgs::AppLogs)
.context("tool arguments did not match the declared schema"),
@@ -415,13 +413,18 @@ fn redact_log_line(line: &str) -> String {
fn redact_secrets_in_json(value: serde_json::Value) -> serde_json::Value {
match value {
serde_json::Value::String(s) => serde_json::Value::String(
- s.lines().map(redact_log_line).collect::>().join("\n"),
+ s.lines()
+ .map(redact_log_line)
+ .collect::>()
+ .join("\n"),
),
serde_json::Value::Array(items) => {
serde_json::Value::Array(items.into_iter().map(redact_secrets_in_json).collect())
}
serde_json::Value::Object(map) => serde_json::Value::Object(
- map.into_iter().map(|(k, v)| (k, redact_secrets_in_json(v))).collect(),
+ map.into_iter()
+ .map(|(k, v)| (k, redact_secrets_in_json(v)))
+ .collect(),
),
other => other,
}
@@ -804,7 +807,11 @@ pub async fn validate_business_rules(
/// here is meant to become the tool result's `content` verbatim — a
/// message the model (and, through it, the user) can read and act on, not
/// an internal diagnostic.
-pub async fn dispatch(name: &str, args: &ToolArgs, handler: &Arc) -> Result {
+pub async fn dispatch(
+ name: &str,
+ args: &ToolArgs,
+ handler: &Arc,
+) -> Result {
validate_business_rules(name, args, handler).await?;
match name {
"system_disk_status" => handler
@@ -1068,9 +1075,16 @@ mod tests {
// Listing peers is not the same action as listing this node's own
// files; sharing an action_key would let one be replayed as the other.
use crate::assistant::confirm::action_key;
- let own = content_list_tool().validate(&json!({ "scope": "own" })).unwrap();
- let peers = content_list_tool().validate(&json!({ "scope": "peers" })).unwrap();
- assert_ne!(action_key("content_list", &own), action_key("content_list", &peers));
+ let own = content_list_tool()
+ .validate(&json!({ "scope": "own" }))
+ .unwrap();
+ let peers = content_list_tool()
+ .validate(&json!({ "scope": "peers" }))
+ .unwrap();
+ assert_ne!(
+ action_key("content_list", &own),
+ action_key("content_list", &peers)
+ );
}
use super::*;
use crate::api::rpc::RpcHandler;
@@ -1496,10 +1510,25 @@ mod tests {
"wifi_ssid": "Pretty Fly for a Wi-Fi",
}));
let obj = stripped.as_object().expect("diagnostics stays an object");
- assert!(!obj.contains_key("wan_ip"), "WAN IP must not enter model context");
- assert!(!obj.contains_key("wifi_ssid"), "Wi-Fi SSID must not enter model context");
- for kept in ["nat_type", "upnp_available", "tor_connected", "dns_working", "recommendations"] {
- assert!(obj.contains_key(kept), "connectivity field {kept} must survive");
+ assert!(
+ !obj.contains_key("wan_ip"),
+ "WAN IP must not enter model context"
+ );
+ assert!(
+ !obj.contains_key("wifi_ssid"),
+ "Wi-Fi SSID must not enter model context"
+ );
+ for kept in [
+ "nat_type",
+ "upnp_available",
+ "tor_connected",
+ "dns_working",
+ "recommendations",
+ ] {
+ assert!(
+ obj.contains_key(kept),
+ "connectivity field {kept} must survive"
+ );
}
// A result with neither key (e.g. offline diagnostics) passes through untouched.
let already_clean = json!({ "nat_type": null, "dns_working": false });
@@ -1523,12 +1552,21 @@ mod tests {
);
// 64+ hex run → redacted as a key even without a keyword
let hex = "a".repeat(64);
- assert_eq!(redact_log_line(&format!("seed {hex}")), "seed [REDACTED_KEY]");
+ assert_eq!(
+ redact_log_line(&format!("seed {hex}")),
+ "seed [REDACTED_KEY]"
+ );
// 64+ base64 run → redacted as a token
let b64 = "Q".repeat(68);
- assert_eq!(redact_log_line(&format!("macaroon blob {b64}")), "macaroon blob [REDACTED_TOKEN]");
+ assert_eq!(
+ redact_log_line(&format!("macaroon blob {b64}")),
+ "macaroon blob [REDACTED_TOKEN]"
+ );
// ...and as a key=value pair the keyword rule fires first
- assert_eq!(redact_log_line(&format!("macaroon={b64}")), "macaroon=[REDACTED]");
+ assert_eq!(
+ redact_log_line(&format!("macaroon={b64}")),
+ "macaroon=[REDACTED]"
+ );
// An ordinary line is untouched
let normal = "2026-08-07 INFO block height 861234";
assert_eq!(redact_log_line(normal), normal);
diff --git a/core/archipelago/src/bootstrap.rs b/core/archipelago/src/bootstrap.rs
index 40301666..3670b0ae 100644
--- a/core/archipelago/src/bootstrap.rs
+++ b/core/archipelago/src/bootstrap.rs
@@ -1241,7 +1241,6 @@ async fn patch_nginx_conf(path: &str) -> Result {
patched = p;
}
-
if missing_v6_http {
patched = patched.replace(
"listen 80 default_server;",
@@ -1424,7 +1423,9 @@ mod tests {
// Second pass is a no-op (idempotent self-heal).
assert!(heal_stale_web_search_block(&healed).is_none());
// A config without the block is untouched.
- assert!(heal_stale_web_search_block("location / { try_files $uri /index.html; }").is_none());
+ assert!(
+ heal_stale_web_search_block("location / { try_files $uri /index.html; }").is_none()
+ );
}
}
diff --git a/core/archipelago/src/container/companion.rs b/core/archipelago/src/container/companion.rs
index 0fe1cd26..58f4216e 100644
--- a/core/archipelago/src/container/companion.rs
+++ b/core/archipelago/src/container/companion.rs
@@ -927,13 +927,12 @@ mod tests {
#[test]
fn every_backend_installed_leaves_no_orphans() {
- let orphans = orphan_companions(&ids(&[
- "bitcoin-knots",
- "lnd",
- "electrumx",
- "fedimint",
- ]));
- assert!(names(&orphans).is_empty(), "unexpected orphans: {:?}", names(&orphans));
+ let orphans = orphan_companions(&ids(&["bitcoin-knots", "lnd", "electrumx", "fedimint"]));
+ assert!(
+ names(&orphans).is_empty(),
+ "unexpected orphans: {:?}",
+ names(&orphans)
+ );
}
fn name_set(specs: &[&'static CompanionSpec]) -> std::collections::HashSet<&'static str> {
@@ -965,7 +964,10 @@ mod tests {
assert!(due.is_empty());
// A pass after the grace window reaps.
let due = due_after_grace(orphans, &names_seen, &mut since, start + ORPHAN_GRACE);
- assert_eq!(names(&due), vec!["archy-electrs-ui", "archy-fedimint-ui", "archy-lnd-ui"]);
+ assert_eq!(
+ names(&due),
+ vec!["archy-electrs-ui", "archy-fedimint-ui", "archy-lnd-ui"]
+ );
}
#[test]
@@ -989,7 +991,10 @@ mod tests {
!names(&due).contains(&"archy-lnd-ui"),
"lnd companion reaped even though lnd came back"
);
- assert!(!since.contains_key("archy-lnd-ui"), "stale clock kept for lnd");
+ assert!(
+ !since.contains_key("archy-lnd-ui"),
+ "stale clock kept for lnd"
+ );
// lnd goes away for real. It must wait a fresh full grace period.
let orphans = orphan_companions(&ids(&["bitcoin-knots"]));
diff --git a/core/archipelago/src/container/prod_orchestrator.rs b/core/archipelago/src/container/prod_orchestrator.rs
index 766c5441..82195b12 100644
--- a/core/archipelago/src/container/prod_orchestrator.rs
+++ b/core/archipelago/src/container/prod_orchestrator.rs
@@ -5989,7 +5989,8 @@ app:
}
#[tokio::test]
- async fn manifest_generated_files_can_overwrite_when_declared() {let rt = Arc::new(MockRuntime::default());
+ async fn manifest_generated_files_can_overwrite_when_declared() {
+ let rt = Arc::new(MockRuntime::default());
let orch = orch_with(rt.clone()).await;
let data_dir = tempfile::tempdir_in("/var/lib/archipelago").unwrap();
diff --git a/core/archipelago/src/content_indeehub.rs b/core/archipelago/src/content_indeehub.rs
index 8ff96ce5..91e5898e 100644
--- a/core/archipelago/src/content_indeehub.rs
+++ b/core/archipelago/src/content_indeehub.rs
@@ -244,13 +244,22 @@ mod tests {
#[test]
fn year_survives_number_string_and_date_forms() {
- assert_eq!(project(serde_json::json!({"releaseYear": 2014})).year_num(), Some(2014));
- assert_eq!(project(serde_json::json!({"releaseYear": "2016"})).year_num(), Some(2016));
+ assert_eq!(
+ project(serde_json::json!({"releaseYear": 2014})).year_num(),
+ Some(2014)
+ );
+ assert_eq!(
+ project(serde_json::json!({"releaseYear": "2016"})).year_num(),
+ Some(2016)
+ );
assert_eq!(
project(serde_json::json!({"releaseYear": "2020-05-01"})).year_num(),
Some(2020)
);
- assert_eq!(project(serde_json::json!({"releaseYear": "n/a"})).year_num(), None);
+ assert_eq!(
+ project(serde_json::json!({"releaseYear": "n/a"})).year_num(),
+ None
+ );
assert_eq!(project(serde_json::json!({})).year_num(), None);
}
diff --git a/core/archipelago/src/content_server.rs b/core/archipelago/src/content_server.rs
index 8779031e..86904d00 100644
--- a/core/archipelago/src/content_server.rs
+++ b/core/archipelago/src/content_server.rs
@@ -299,40 +299,40 @@ pub async fn serve_content(
// Check access control
if !owner_session {
match &item.access {
- AccessControl::Paid { price_sats, .. } => {
- // Two ways to satisfy payment:
- // (a) a valid ecash token (the local-wallet fast path), or
- // (b) a Lightning-invoice payment hash this node issued and has
- // since confirmed settled (the "pay from any wallet" path, #46).
- // Each path only counts when the sharer accepts that method.
- let mut authorized = false;
- if let Some(token) = payment_token {
- if (method_accepted(&item.access, "ecash")
- || method_accepted(&item.access, "fedimint"))
- && verify_payment_token(data_dir, token, *price_sats).await
- {
- authorized = true;
- }
- }
- if !authorized {
- if let Some(hash) = invoice_hash {
- if method_accepted(&item.access, "lightning")
- && crate::content_invoice::is_paid_for(hash, id).await
+ AccessControl::Paid { price_sats, .. } => {
+ // Two ways to satisfy payment:
+ // (a) a valid ecash token (the local-wallet fast path), or
+ // (b) a Lightning-invoice payment hash this node issued and has
+ // since confirmed settled (the "pay from any wallet" path, #46).
+ // Each path only counts when the sharer accepts that method.
+ let mut authorized = false;
+ if let Some(token) = payment_token {
+ if (method_accepted(&item.access, "ecash")
+ || method_accepted(&item.access, "fedimint"))
+ && verify_payment_token(data_dir, token, *price_sats).await
{
authorized = true;
}
}
+ if !authorized {
+ if let Some(hash) = invoice_hash {
+ if method_accepted(&item.access, "lightning")
+ && crate::content_invoice::is_paid_for(hash, id).await
+ {
+ authorized = true;
+ }
+ }
+ }
+ if !authorized {
+ return Ok(ServeResult::PaymentRequired(*price_sats));
+ }
}
- if !authorized {
- return Ok(ServeResult::PaymentRequired(*price_sats));
+ AccessControl::PeersOnly => {
+ if !is_known_peer {
+ return Ok(ServeResult::Forbidden);
+ }
}
- }
- AccessControl::PeersOnly => {
- if !is_known_peer {
- return Ok(ServeResult::Forbidden);
- }
- }
- AccessControl::Free => {}
+ AccessControl::Free => {}
}
}
diff --git a/core/archipelago/src/crash_recovery.rs b/core/archipelago/src/crash_recovery.rs
index a9666e79..f3c3f06b 100644
--- a/core/archipelago/src/crash_recovery.rs
+++ b/core/archipelago/src/crash_recovery.rs
@@ -1200,7 +1200,9 @@ mod tests {
mark_installed(tmp.path(), "bitcoin-knots").await;
mark_installed(tmp.path(), "lnd").await;
- assert!(load_installed_apps(tmp.path()).await.contains("bitcoin-knots"));
+ assert!(load_installed_apps(tmp.path())
+ .await
+ .contains("bitcoin-knots"));
// Uninstall forgets it, or desired-state recovery would recreate the
// very app that was just removed.
@@ -1224,7 +1226,9 @@ mod tests {
assert!(load_last_running_names(tmp.path()).await.is_empty());
assert!(
- load_installed_apps(tmp.path()).await.contains("bitcoin-knots"),
+ load_installed_apps(tmp.path())
+ .await
+ .contains("bitcoin-knots"),
"installation record must outlive the running snapshot"
);
}
@@ -1268,7 +1272,10 @@ mod tests {
backfill_installed_apps(tmp.path(), &["bitcoin-knots".to_string()]).await;
let installed = load_installed_apps(tmp.path()).await;
- assert!(installed.contains("lnd"), "a down app was dropped by backfill");
+ assert!(
+ installed.contains("lnd"),
+ "a down app was dropped by backfill"
+ );
assert!(installed.contains("bitcoin-knots"));
// An empty adoption list (podman unreachable, say) must change nothing.
diff --git a/core/archipelago/src/main.rs b/core/archipelago/src/main.rs
index 2fc1f217..46aa522d 100644
--- a/core/archipelago/src/main.rs
+++ b/core/archipelago/src/main.rs
@@ -336,11 +336,8 @@ async fn main() -> Result<()> {
// need it. Additive and evidence-based: only names with a real
// adopted container are claimed, and anything the operator
// uninstalled is skipped, so it cannot invent an install.
- crate::crash_recovery::backfill_installed_apps(
- &config.data_dir,
- &report.adopted,
- )
- .await;
+ crate::crash_recovery::backfill_installed_apps(&config.data_dir, &report.adopted)
+ .await;
}
Ok(Err(e)) => {
tracing::warn!(error = %e, "prod orchestrator: adopt_existing failed (non-fatal)");
diff --git a/core/archipelago/src/marketplace.rs b/core/archipelago/src/marketplace.rs
index 2dd6cc46..a67921a3 100644
--- a/core/archipelago/src/marketplace.rs
+++ b/core/archipelago/src/marketplace.rs
@@ -873,10 +873,9 @@ mod tests {
/// A real Ed25519 keypair, its did:key, and a manifest signed by it.
fn signed_manifest() -> (ed25519_dalek::SigningKey, String, AppManifest) {
let key = ed25519_dalek::SigningKey::generate(&mut rand::rngs::OsRng);
- let did = crate::identity::did_key_from_pubkey_hex(&hex::encode(
- key.verifying_key().as_bytes(),
- ))
- .unwrap();
+ let did =
+ crate::identity::did_key_from_pubkey_hex(&hex::encode(key.verifying_key().as_bytes()))
+ .unwrap();
let mut manifest = sample_manifest();
manifest.author.did = did.clone();
sign_manifest(&mut manifest, &key).unwrap();
@@ -1054,8 +1053,7 @@ mod tests {
manifest.repo_url = String::new();
manifest.version = "1".into();
manifest.container.readonly_root = false;
- let (score, _tier) =
- calculate_trust_score(&manifest, 1, &[], &SignatureStatus::Missing);
+ let (score, _tier) = calculate_trust_score(&manifest, 1, &[], &SignatureStatus::Missing);
assert!(score < 50, "Expected low score, got {score}");
}
diff --git a/core/archipelago/src/music/tags.rs b/core/archipelago/src/music/tags.rs
index ff415635..8af27521 100644
--- a/core/archipelago/src/music/tags.rs
+++ b/core/archipelago/src/music/tags.rs
@@ -55,10 +55,7 @@ pub enum TagExtractionError {
/// `path` is canonicalized and confined to `media_roots` *before* the file
/// is opened. `media_roots` is a parameter, not a constant, so a caller
/// cannot bypass the confinement by construction.
-pub fn extract_tags(
- path: &Path,
- media_roots: &[PathBuf],
-) -> Result {
+pub fn extract_tags(path: &Path, media_roots: &[PathBuf]) -> Result {
let canonical = path.canonicalize()?;
let within_roots = media_roots.iter().any(|root| {
@@ -91,9 +88,7 @@ pub fn extract_tags(
.unwrap_or_else(|| fallback_from_filename(&canonical));
let artist = tag.artist().map(|cow| cow.into_owned());
let album = tag.album().map(|cow| cow.into_owned());
- let album_artist = tag
- .get_string(ItemKey::AlbumArtist)
- .map(ToOwned::to_owned);
+ let album_artist = tag.get_string(ItemKey::AlbumArtist).map(ToOwned::to_owned);
let track = tag.track();
let disc = tag.disk();
let year = tag.date().map(|timestamp| u32::from(timestamp.year));
@@ -208,8 +203,14 @@ mod tests {
/// FLAC STREAMINFO block content (34 bytes) — the only metadata block
/// lofty's duration calculation reads (`flac/properties.rs`).
- fn flac_streaminfo(sample_rate: u32, channels: u32, bits_per_sample: u32, total_samples: u64) -> Vec {
- let mut info: u32 = (sample_rate << 12) | ((channels - 1) << 9) | ((bits_per_sample - 1) << 4);
+ fn flac_streaminfo(
+ sample_rate: u32,
+ channels: u32,
+ bits_per_sample: u32,
+ total_samples: u64,
+ ) -> Vec {
+ let mut info: u32 =
+ (sample_rate << 12) | ((channels - 1) << 9) | ((bits_per_sample - 1) << 4);
info |= ((total_samples >> 32) as u32) & 0xF;
let total_samples_low = (total_samples & 0xFFFF_FFFF) as u32;
@@ -270,7 +271,7 @@ mod tests {
file.extend_from_slice(&flac_block(0, false, &streaminfo));
let vorbis_comments = vorbis_comment_block("test-vendor", comments);
file.extend_from_slice(&flac_block(4, true, &vorbis_comments));
- },
+ }
}
file
}
@@ -341,7 +342,8 @@ mod tests {
mdhd_content.extend_from_slice(&[0, 0, 0, 0]); // creation_time
mdhd_content.extend_from_slice(&[0, 0, 0, 0]); // modification_time
mdhd_content.extend_from_slice(&MP4_TIMESCALE.to_be_bytes());
- mdhd_content.extend_from_slice(&((MP4_TIMESCALE as u64 * MP4_DURATION_SECS) as u32).to_be_bytes());
+ mdhd_content
+ .extend_from_slice(&((MP4_TIMESCALE as u64 * MP4_DURATION_SECS) as u32).to_be_bytes());
let mdhd = atom(b"mdhd", &mdhd_content);
let mdia = atom(b"mdia", &[hdlr, mdhd].concat());
@@ -374,7 +376,10 @@ mod tests {
let mut segment_table = Vec::new();
let mut content = Vec::new();
for packet in packets {
- assert!(packet.len() < 255, "fixture packet too large for a single OGG lacing segment");
+ assert!(
+ packet.len() < 255,
+ "fixture packet too large for a single OGG lacing segment"
+ );
segment_table.push(packet.len() as u8);
content.extend_from_slice(packet);
}
diff --git a/core/archipelago/src/network/did_dht.rs b/core/archipelago/src/network/did_dht.rs
index 54b5a3dc..bb9b8cd7 100644
--- a/core/archipelago/src/network/did_dht.rs
+++ b/core/archipelago/src/network/did_dht.rs
@@ -55,8 +55,8 @@ pub fn pubkey_from_did(did: &str) -> Result<[u8; 32]> {
let id = did
.strip_prefix("did:dht:")
.ok_or_else(|| anyhow::anyhow!("Not a did:dht identifier: {}", did))?;
- let bytes =
- zbase32::decode_full_bytes_str(id).map_err(|e| anyhow::anyhow!("Invalid z-base-32: {e}"))?;
+ let bytes = zbase32::decode_full_bytes_str(id)
+ .map_err(|e| anyhow::anyhow!("Invalid z-base-32: {e}"))?;
if bytes.len() != 32 {
anyhow::bail!("Expected 32-byte pubkey, got {} bytes", bytes.len());
}
diff --git a/core/archipelago/src/network/zbase32.rs b/core/archipelago/src/network/zbase32.rs
index 332b978d..d0758181 100644
--- a/core/archipelago/src/network/zbase32.rs
+++ b/core/archipelago/src/network/zbase32.rs
@@ -174,7 +174,9 @@ mod tests {
#[test]
fn a_32_byte_key_is_52_chars_and_round_trips() {
for seed in 0u8..64 {
- let key: Vec = (0u8..32).map(|i| i.wrapping_mul(7).wrapping_add(seed)).collect();
+ let key: Vec = (0u8..32)
+ .map(|i| i.wrapping_mul(7).wrapping_add(seed))
+ .collect();
let encoded = encode_full_bytes(&key);
assert_eq!(encoded.len(), 52, "256 bits must encode to 52 characters");
assert_eq!(decode_full_bytes_str(&encoded).unwrap(), key);
@@ -184,7 +186,9 @@ mod tests {
#[test]
fn round_trips_every_length_up_to_a_block() {
for len in 0..40usize {
- let data: Vec = (0..len).map(|i| (i as u8).wrapping_mul(31) ^ 0x5a).collect();
+ let data: Vec = (0..len)
+ .map(|i| (i as u8).wrapping_mul(31) ^ 0x5a)
+ .collect();
let encoded = encode_full_bytes(&data);
// decode_full_bytes only recovers whole bytes, and encoding N bytes
// produces ceil(8N/5) chars which always carry at least 8N bits.
diff --git a/core/archipelago/src/seed.rs b/core/archipelago/src/seed.rs
index fd09931c..7ac95127 100644
--- a/core/archipelago/src/seed.rs
+++ b/core/archipelago/src/seed.rs
@@ -979,7 +979,12 @@ mod tests {
// BIP-32 m/84'/0'/0'
assert_eq!(
- hex::encode(derive_bitcoin_xprv(&seed).unwrap().private_key.secret_bytes()),
+ hex::encode(
+ derive_bitcoin_xprv(&seed)
+ .unwrap()
+ .private_key
+ .secret_bytes()
+ ),
"57558e8c90c2e72f0c121d0fb8844bbbe7a872f0065d21b218a990450b9f93be",
"Bitcoin BIP-84 account key"
);
diff --git a/core/archipelago/src/settings/ai_permissions.rs b/core/archipelago/src/settings/ai_permissions.rs
index 2e1452b1..879b0d40 100644
--- a/core/archipelago/src/settings/ai_permissions.rs
+++ b/core/archipelago/src/settings/ai_permissions.rs
@@ -159,7 +159,9 @@ mod tests {
async fn a_corrupt_file_fails_closed() {
let dir = tempfile::tempdir().unwrap();
let path = dir.path().join(FILE_PATH);
- tokio::fs::create_dir_all(path.parent().unwrap()).await.unwrap();
+ tokio::fs::create_dir_all(path.parent().unwrap())
+ .await
+ .unwrap();
tokio::fs::write(&path, b"{ not json").await.unwrap();
// The dangerous failure would be defaulting to "all granted".
assert!(load(dir.path()).await.granted.is_empty());