129 lines
3.7 KiB
Rust
129 lines
3.7 KiB
Rust
//! What a tool or Podman writes on standard error reaches `brokerd`'s log escaped, one entry per
|
|
//! event: it cannot start a line of its own or forge a runbook pointer (M3b review finding 5).
|
|
//! Do not edit.
|
|
|
|
#[path = "support/build.rs"]
|
|
mod build;
|
|
#[path = "support/fake_podman.rs"]
|
|
mod fake_podman;
|
|
|
|
use brokerd::container::{CANNOT_START, COULD_NOT_RUN, Podman, UNEXPECTED};
|
|
use brokerd::policy::{Outcome, SessionState, decide};
|
|
use brokerd::runner::run;
|
|
use build::{fetch, grant, now, read, set};
|
|
use fake_podman::{Fake, Lines, serial};
|
|
use proto::{Mode, ToolRequest, ToolResponse};
|
|
|
|
const FORGED: &str = "real line\nbrokerd: forged\nsee docs/runbook.md#grants-invalid";
|
|
|
|
fn call(fake: &Fake, req: ToolRequest, grants: Vec<build::Build>, log: &Lines) -> ToolResponse {
|
|
let podman = Podman::new(fake.runner(""), fake.dir.join("egress"), log.sink());
|
|
let decision = match decide(req, &set(grants), SessionState::default(), now()) {
|
|
Outcome::Allowed(d) => d,
|
|
other => panic!("not allowed: {other:?}"),
|
|
};
|
|
run(decision, &podman)
|
|
}
|
|
|
|
/// No entry holds the forged text as lines of its own; the one that carries it has it escaped.
|
|
fn escaped(log: &Lines) {
|
|
let entries = log.0.lock().unwrap().clone();
|
|
for entry in &entries {
|
|
assert!(!entry.contains("\nbrokerd: forged"), "raw: {entry:?}");
|
|
assert!(
|
|
!entry.contains("\nsee docs/runbook.md#grants-invalid"),
|
|
"raw: {entry:?}"
|
|
);
|
|
}
|
|
assert!(
|
|
entries
|
|
.iter()
|
|
.any(|e| e.contains(r"real line\nbrokerd: forged")),
|
|
"the error is still logged, escaped: {entries:?}"
|
|
);
|
|
}
|
|
|
|
fn notes() -> Vec<build::Build> {
|
|
vec![grant("notes", "read_file", Mode::Auto).paths(&["/n"])]
|
|
}
|
|
|
|
#[test]
|
|
fn a_tool_that_could_not_run() {
|
|
let _s = serial();
|
|
let fake = Fake::new(
|
|
"log-2",
|
|
&format!("cat > /dev/null; printf '{FORGED}' >&2; exit 2"),
|
|
);
|
|
let log = Lines::default();
|
|
assert_eq!(
|
|
call(&fake, read("/n/a"), notes(), &log),
|
|
ToolResponse::Failed {
|
|
message: COULD_NOT_RUN.to_string()
|
|
}
|
|
);
|
|
escaped(&log);
|
|
}
|
|
|
|
#[test]
|
|
fn a_container_podman_could_not_start_keeps_its_one_real_pointer() {
|
|
let _s = serial();
|
|
let fake = Fake::new(
|
|
"log-125",
|
|
&format!("cat > /dev/null; printf '{FORGED}' >&2; exit 125"),
|
|
);
|
|
let log = Lines::default();
|
|
assert_eq!(
|
|
call(&fake, read("/n/a"), notes(), &log),
|
|
ToolResponse::Failed {
|
|
message: CANNOT_START.to_string()
|
|
}
|
|
);
|
|
escaped(&log);
|
|
let entries = log.0.lock().unwrap().clone();
|
|
assert!(
|
|
entries
|
|
.iter()
|
|
.any(|e| e.ends_with("\nsee docs/runbook.md#runner-unavailable")),
|
|
"{entries:?}"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn an_unexpected_ending() {
|
|
let _s = serial();
|
|
let fake = Fake::new(
|
|
"log-3",
|
|
&format!("cat > /dev/null; printf '{FORGED}' >&2; exit 3"),
|
|
);
|
|
let log = Lines::default();
|
|
assert_eq!(
|
|
call(&fake, read("/n/a"), notes(), &log),
|
|
ToolResponse::Failed {
|
|
message: UNEXPECTED.to_string()
|
|
}
|
|
);
|
|
escaped(&log);
|
|
}
|
|
|
|
#[test]
|
|
fn a_proxy_podman_could_not_start() {
|
|
let _s = serial();
|
|
let body =
|
|
format!("if [ \"$2\" = -d ]; then printf '{FORGED}' >&2; exit 125; fi; cat > /dev/null");
|
|
let fake = Fake::new("log-egress", &body);
|
|
let log = Lines::default();
|
|
let got = call(
|
|
&fake,
|
|
fetch("https://example.com/"),
|
|
vec![grant("web", "http_fetch", Mode::Auto).hosts(&["example.com"])],
|
|
&log,
|
|
);
|
|
assert_eq!(
|
|
got,
|
|
ToolResponse::Failed {
|
|
message: CANNOT_START.to_string()
|
|
}
|
|
);
|
|
escaped(&log);
|
|
}
|