server/lib/tests/the_console_is_seen_per_server.rs
//! ★ **A console is seen by the server it called, and only from its own proof**
//! (HOL-SYNC-SKEW, the review of HOL-FLOW-SMART).
//!
//! The flow draws a console box only when this installation has a console: one that called
//! this server lately. Two servers in one process each keep their own record, so a console
//! of the one never draws on the other. And only holger-ui's own calls count: the console
//! proves itself with its own bearer in `x-holger-proxy-authorization`; an administrator's
//! plain call (a CLI, a script) is no console.
use std::io::Write as _;
use holger_server_lib::{read_ron_config, wire_holger, Holger};
use traits::test_support::hold_port;
const CONSOLE: &str = "c0nsole-bearer-0123456789abcdefghij";
const CONSOLE_NODE: &str = "estate:console";
struct Running {
_data: tempfile::TempDir,
_cfg: tempfile::NamedTempFile,
_holger: Holger,
base: String,
}
fn start() -> Running {
let mut last = String::new();
for _ in 0..8 {
match try_start(hold_port(), hold_port()) {
Ok(r) => return r,
Err(e) => last = e,
}
}
panic!("server never started; last error: {last}");
}
fn try_start(grpc: u16, http: u16) -> Result<Running, String> {
let data = tempfile::tempdir().unwrap();
let d = data.path().display().to_string();
std::fs::create_dir_all(data.path().join("audit")).unwrap();
let ron = format!(
r#"(
repositories: [
(ron_name: "crates", ron_repo_type: "raw", ron_upstreams: [], ron_in: None,
ron_out: Some((ron_storage_endpoint: "storage", ron_exposed_endpoint: "door")),
ron_data_dir: Some("{d}/crates")),
],
exposed_endpoints: [
(ron_name: "door", ron_url: "127.0.0.1:{grpc}", ron_http_url: Some("127.0.0.1:{http}")),
],
storage_endpoints: [ (ron_name: "storage", ron_storage_type: "znippy", ron_path: "{d}") ],
audit: (dir: "{d}/audit", enabled: true),
auth: Some((
methods: [ StaticToken(subject: "console", token: Some("{CONSOLE}")) ],
roles: {{"console": Admin}},
)),
)"#
);
let mut cfg = tempfile::NamedTempFile::new().unwrap();
cfg.write_all(ron.as_bytes()).unwrap();
let mut holger: Holger = read_ron_config(cfg.path()).map_err(|e| format!("config: {e}"))?;
holger
.instantiate_backends()
.map_err(|e| format!("backends: {e}"))?;
wire_holger(&mut holger).map_err(|e| format!("wire: {e}"))?;
holger.start().map_err(|e| format!("start: {e}"))?;
Ok(Running {
_data: data,
_cfg: cfg,
_holger: holger,
base: format!("http://127.0.0.1:{http}"),
})
}
async fn wait_healthy(c: &reqwest::Client, base: &str) {
for _ in 0..200 {
if let Ok(r) = c.get(format!("{base}/healthz")).send().await {
if r.status() == 200 {
return;
}
}
tokio::time::sleep(std::time::Duration::from_millis(20)).await;
}
panic!("gateway never became healthy at {base}");
}
/// Does this server's flow (level 1) draw a console?
async fn draws_a_console(c: &reqwest::Client, base: &str) -> bool {
let r = c
.get(format!("{base}/-/flow.json"))
.bearer_auth(CONSOLE)
.send()
.await
.expect("the flow door answers");
assert_eq!(r.status(), 200, "an administrator reads the flow");
let v: serde_json::Value = r.json().await.expect("the flow is JSON");
v["nodes"]
.as_array()
.expect("nodes")
.iter()
.any(|n| n["id"] == CONSOLE_NODE)
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn a_console_is_seen_by_the_server_it_called_and_only_from_its_own_proof() {
let (a, b) = (start(), start());
let c = reqwest::Client::new();
wait_healthy(&c, &a.base).await;
wait_healthy(&c, &b.base).await;
assert!(
!draws_a_console(&c, &a.base).await,
"no console has called a"
);
// An administrator's own call is no console's (a CLI, a script).
let r = c
.get(format!("{}/-/settings/console.a-switch", b.base))
.bearer_auth(CONSOLE)
.send()
.await
.unwrap();
assert!(r.status().as_u16() < 500, "{}", r.status());
assert!(
!draws_a_console(&c, &b.base).await,
"a plain administrator's call draws no console"
);
// holger-ui reads its switch on a with its own proof.
let r = c
.get(format!("{}/-/settings/console.a-switch", a.base))
.header("x-holger-proxy-authorization", format!("Bearer {CONSOLE}"))
.send()
.await
.unwrap();
assert!(r.status().as_u16() < 500, "{}", r.status());
assert!(
draws_a_console(&c, &a.base).await,
"the console that called a is drawn on a"
);
assert!(
!draws_a_console(&c, &b.base).await,
"and never on b, the other server in this process"
);
}