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
226 changes: 226 additions & 0 deletions crates/busbar-kernel/tests/plane_driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2122,3 +2122,229 @@ async fn a_vetoed_units_refusal_names_the_hook_and_writes_its_rejected_row() {
)]
);
}

// ── a credential that cannot be presented ───────────────────────────────────────────────────────

/// What one failing secret leaves behind: the reference, and every string of it a caller must never
/// be handed (the variable, the path, the module, the reference as written).
struct Failing {
secret: busbar_contract::secret_ref::SecretRef,
markers: Vec<String>,
}

/// THE FAILING SECRETS this cell plants, one per source shape, each with its own markers: an unset
/// variable, a file that is not there, and a module no secret plugin answers.
fn failing_secrets() -> Vec<Failing> {
use busbar_contract::secret_ref::SecretRef;
let pid = std::process::id();
let var = format!("BUSBAR_KERNEL_SECRET_MARKER_{pid}");
std::env::remove_var(&var);
let path = std::env::temp_dir()
.join(format!("busbar-kernel-secret-marker-{pid}"))
.display()
.to_string();
let _ = std::fs::remove_file(&path);
let module = format!("secret-marker-module-{pid}");
let opaque = format!("secret-marker-setting-{pid}");
let plugin: SecretRef = serde_json::from_value(
serde_json::json!({ "module": module, "settings": { "at": opaque } }),
)
.expect("a module reference");
[
(SecretRef::env(&var), vec![var.clone()]),
(SecretRef::file(&path), vec![path.clone()]),
(plugin, vec![module.clone()]),
]
.into_iter()
.map(|(secret, mut markers)| {
markers.push(secret.describe());
Failing { secret, markers }
})
.collect()
}

/// The markers `text` carries, without case.
fn markers_in(text: &str, failing: &Failing) -> Vec<String> {
let lower = text.to_ascii_lowercase();
failing
.markers
.iter()
.filter(|m| lower.contains(&m.to_ascii_lowercase()))
.cloned()
.collect()
}

/// A FAR END WHOSE MEMBERS' CREDENTIALS CANNOT BE PRESENTED, the two ways production's far end meets
/// a secret that did not resolve: the member's one auth call is refused (its auth plugin holds no
/// credential), so nothing is sent; and the member's program is never spawned (the connector refuses
/// the open), so its attempt fails over before any byte reaches the plane. Each member's operator
/// text, naming the source, is held here, where the plugin and the connector hold theirs: nothing on
/// the far end's seam can carry it to the kernel.
struct Unpresentable {
/// The refusal the secret source gave the operator.
operator_text: String,
}

/// The member whose auth call is refused.
const UNBOUND: &str = "unbound";
/// The member whose program is never spawned.
const UNSPAWNED: &str = "unspawned";

impl busbar_kernel::plane_driver::FarEnd for Unpresentable {
fn member<'a>(
&'a self,
_: &'a busbar_contract::caps::Pass<busbar_contract::caps::Route>,
attempt_no: u32,
) -> impl Future<Output = busbar_kernel::plane_driver::Pick> + Send + 'a {
use busbar_kernel::plane_driver::Pick;
let pick = match [UNBOUND, UNSPAWNED].get(attempt_no as usize - 1) {
Some(m) => Pick::Member {
name: (*m).to_string(),
pool: "pool-a".to_string(),
passthrough: false,
provider: "acme".to_string(),
},
None => Pick::Exhausted {
status: 503,
retry_after: Some(2),
},
};
async move { pick }
}

async fn send(
&self,
_: &busbar_contract::caps::Pass<busbar_contract::caps::Route>,
request: busbar_kernel::plane_driver::OutboundRequest,
) -> bool {
request.member != UNBOUND
}

async fn next(
&self,
_: &busbar_contract::caps::Pass<busbar_contract::caps::Route>,
) -> Option<busbar_kernel::plane_driver::FarPiece> {
Some(busbar_kernel::plane_driver::FarPiece {
last: true,
fail_over: true,
..busbar_kernel::plane_driver::FarPiece::default()
})
}

fn failure(
&self,
_: &busbar_contract::caps::Pass<busbar_contract::caps::Route>,
) -> Option<&'static str> {
Some("credential_unavailable")
}

async fn write(
&self,
_: &busbar_contract::caps::Pass<busbar_contract::caps::Route>,
_: busbar_kernel::plane_driver::OutboundRequest,
) -> bool {
false
}
}

/// Run one unit through the one loop over any far end; its outcome.
async fn drive_over<F: busbar_kernel::plane_driver::FarEnd>(
units: &busbar_kernel::plane_driver::PlaneUnits<'_, common::TestUnits, F, cases::Caller>,
) -> busbar_contract::caps::Outcome {
use busbar_kernel::teller::{run_unit_async, AccrualMeter, Ended, Kernel, Run};
let kernel = Kernel::new();
let (gauge, canary, leases, meter) = (
busbar_kernel::slice::ConcurrencyGauge::new(),
busbar_contract::caps::Canary::new(),
busbar_kernel::slice::LeaseCell::new(),
AccrualMeter::new(),
);
let cell = common::cell(&kernel);
let run = Run {
cell: &cell,
parent: None,
leases: &leases,
gauge: &gauge,
canary: &canary,
meter: &meter,
};
match run_unit_async(&kernel, units, &common::ctx(7), run, units).await {
Ended::Settled { end, .. } => end.outcome(),
Ended::AlreadySettled => panic!("nothing else holds this unit's cell"),
}
}

/// A SECRET THAT DOES NOT RESOLVE REACHES THE CALLER AS A FIXED-CLASS REFUSAL NAMING NO SOURCE
/// (status row 127; the cell the retired tool-plane crate's `SetupRefusal::client_message` redaction
/// was until #511). For each failing source (an unset variable, a missing file, a module nothing
/// answers) the kernel's own resolver refuses with the operator's text, which names the source (the
/// control: the markers are there to be found). A unit whose every member's credential cannot be
/// presented (the auth call refused; the program never spawned) ends at the walk's terminal: the
/// plane's `refusal` is handed the one reason (`breaker_open`, class `Unreachable`) and that
/// reason's own word, and the caller's render is byte-identical whichever source failed and carries
/// none of its markers. RED: a kernel that handed the plane any operator text would fail the
/// double's own rule (a kernel refusal's text is its reason's word, else FAULT and an empty body),
/// the byte-identity across sources, and the marker scan.
#[tokio::test]
async fn a_credential_that_cannot_be_presented_reaches_the_caller_as_a_fixed_class_refusal() {
use busbar_contract::abi::plane::{class_of, RefusalClass};
use busbar_contract::caps::{Outcome as UnitOutcome, ReasonCode, StepName};
assert_eq!(class_of(ReasonCode::BreakerOpen), RefusalClass::Unreachable);
let mut renders = Vec::new();
for failing in failing_secrets() {
let operator_text = busbar_kernel::config::secret::resolve_linked_string(&failing.secret)
.expect_err("the reference does not resolve");
assert!(
!markers_in(&operator_text, &failing).is_empty(),
"the control: the operator's text names the source: {operator_text}"
);
let r = rig(Way::Double, BufferCaps::default(), cases::Book::default());
let (steps, far, caller) = (
common::TestUnits::passing(),
Unpresentable { operator_text },
cases::Caller::default(),
);
assert!(!markers_in(&far.operator_text, &failing).is_empty());
let units = r
.driver
.unit(&steps, &far, &caller, cases::arrival("/call", b"p"), 0);
let outcome = drive_over(&units).await;
assert!(
matches!(
outcome,
UnitOutcome::Refused(StepName::Route, ReasonCode::BreakerOpen)
| UnitOutcome::Failed(StepName::Route, ReasonCode::BreakerOpen)
),
"{}: {outcome:?}",
failing.secret.describe()
);
let rendered = units.take_rendered().expect("the terminal is rendered");
let render = format!(
"{} {:?} {}",
rendered.status,
rendered.fields,
String::from_utf8_lossy(&rendered.body)
);
assert_eq!(
rendered.body, b"refused:503:breaker_open:retry=2",
"the plane is handed the fixed reason and its own word: {render}"
);
let found = markers_in(&render, &failing);
assert!(
found.is_empty(),
"the caller was handed {found:?}: {render}"
);
assert_eq!(
caller.text(),
"",
"nothing reached the caller but the refusal"
);
renders.push((rendered.status, rendered.fields, rendered.body));
}
renders.dedup();
assert_eq!(
renders.len(),
1,
"one fixed class: the caller cannot tell which source failed"
);
}
4 changes: 4 additions & 0 deletions crates/busbar/src/root/tests/secret_source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -428,3 +428,7 @@ async fn decisions_a_provider_key_gone_by_an_apply_reaches_the_caller_without_it
.expect("the body reads");
assert_clean(instance, status, &headers, &body, &secret);
}

// The scan's fixed-class half and its kept RED arm (status row 127).
#[path = "secret_source_class.rs"]
mod class;
108 changes: 108 additions & 0 deletions crates/busbar/src/root/tests/secret_source_class.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright (C) 2026 Busbar Inc and contributors

//! THE SCAN'S FIXED-CLASS HALF AND ITS KEPT RED ARM (status row 127). The scan beside this file
//! proves a failing secret's source never reaches a door plane's caller; this file proves two more
//! things about the same renders:
//! * the refusal is a FIXED CLASS: two different sources failing (an unset variable, a missing file)
//! hand the caller the same status and the same body, so nothing in it depends on which source
//! failed or how;
//! * the scan SEES a leak: the operator's text spliced into a real door's caller render (what the
//! retired `SetupRefusal::client_message` redaction stood in front of until #511) is found by the
//! same detector and fails the same assertion every door's cell makes. A scan that could not fail
//! would prove nothing; this arm stays in the tree so it cannot quietly go blind.

use axum::http::{HeaderMap, StatusCode};
use busbar_contract::secret_ref::SecretRef;

use super::{
assert_clean, call, member_secrets_installed, missing, program_section,
refused_naming_its_source, rendered, source_in, unset,
};
use crate::root::door_steps::tests::tool_door::try_rig_tools;
use crate::root::serve::planes_tests::{Published, PUBLISHING};

/// One caller-facing answer: its status, its headers and its body.
type Answer = (StatusCode, HeaderMap, Vec<u8>);

/// The caller's answer to a call on a member program whose `env` reference is `secret`, which does
/// not resolve, served by the tool door as `instance`.
async fn refused_call(instance: &'static str, secret: &SecretRef) -> Answer {
let _published = Published(instance);
let rig = try_rig_tools(instance, 0, program_section(secret))
.unwrap_or_else(|e| panic!("{instance}: a member's env is not resolved at compose: {e}"));
call(&rig).await
}

/// THE REFUSAL IS ONE FIXED CLASS: an unset variable and a missing file, each the `env` reference of
/// a member program, reach the caller as the same status and the same body, both free of either
/// source.
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn two_failing_sources_reach_the_caller_as_one_fixed_refusal() {
let _one = PUBLISHING.lock().await;
member_secrets_installed();
let cases = [
("tools-class-env", SecretRef::env(unset("TOOLS_CLASS_ENV"))),
(
"tools-class-file",
SecretRef::file(missing("tools-class-file")),
),
];
let mut answers = Vec::new();
for (instance, secret) in &cases {
refused_naming_its_source(secret);
let (status, headers, body) = refused_call(instance, secret).await;
for (_, other) in &cases {
assert_clean(instance, status, &headers, &body, other);
}
answers.push((status, body));
}
let (first, second) = (&answers[0], &answers[1]);
assert_eq!(
first.0, second.0,
"the refusal's status does not depend on the source that failed"
);
assert_eq!(
String::from_utf8_lossy(&first.1),
String::from_utf8_lossy(&second.1),
"the refusal's body does not depend on the source that failed"
);
}

/// THE KEPT RED ARM: the scan catches a leak. A real tool-door caller render for a reference that
/// does not resolve is first proven clean; the operator's text for the same reference is then
/// spliced into its body in place of the connector's fixed words (exactly the leak #511's redaction
/// stood in front of), and the same detector names the source and the same assertion fails.
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn the_scan_catches_a_source_spliced_into_a_real_door_render() {
let _one = PUBLISHING.lock().await;
member_secrets_installed();
let fixed = busbar_contract::conn::ConnError::Refused.text();
let cases = [
("tools-red-env", SecretRef::env(unset("TOOLS_RED_ENV"))),
("tools-red-file", SecretRef::file(missing("tools-red-file"))),
];
for (instance, secret) in &cases {
let operator = refused_naming_its_source(secret);
let (status, headers, body) = refused_call(instance, secret).await;
assert_clean(instance, status, &headers, &body, secret);
let text = String::from_utf8_lossy(&body).into_owned();
let leaked = if text.contains(fixed) {
text.replace(fixed, &operator)
} else {
format!("{text}{operator}")
};
let found = source_in(&rendered(status, &headers, leaked.as_bytes()), secret);
assert!(
!found.is_empty(),
"{instance}: the scan must find the spliced source in:\n{leaked}"
);
let caught = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
assert_clean(instance, status, &headers, leaked.as_bytes(), secret);
}));
assert!(
caught.is_err(),
"{instance}: the cell every door runs must fail on a render that carries {found:?}"
);
}
}
Loading