crates/gunnar-policy/tests/gates.rs
//! Both directions, for every gate.
//!
//! The pre-receive gate's rule: *every gate must be seen to REJECT a crafted bad push before it is
//! trusted to allow a good one.* So this file runs the crafted-bad-push set and
//! asserts each one is refused **with the right reason**, then runs the
//! good-push set and asserts each one is let through.
//!
//! Neither half is sufficient alone. A gate that always allows passes the second
//! half; a gate that always rejects passes the first. `tests/blind.rs` proves
//! this file would notice either.
mod common;
use common::{bad_pushes, good_pushes};
#[test]
fn every_crafted_bad_push_is_refused_with_the_right_reason() {
let cases = bad_pushes();
assert!(
cases.len() >= 15,
"the crafted-bad-push set has shrunk to {}; a gate has lost its red case",
cases.len()
);
let mut failures = Vec::new();
for case in &cases {
if let Err(err) = (case.run)(case.gate.as_ref()) {
failures.push(format!(" {}\n {err}", case.name));
}
}
assert!(
failures.is_empty(),
"{} of {} crafted bad pushes were not refused correctly:\n{}",
failures.len(),
cases.len(),
failures.join("\n")
);
}
#[test]
fn every_good_push_is_allowed() {
let cases = good_pushes();
assert!(cases.len() >= 6, "the good-push set has shrunk");
let mut failures = Vec::new();
for case in &cases {
if let Err(err) = (case.run)(case.gate.as_ref()) {
failures.push(format!(" {}\n {err}", case.name));
}
}
assert!(
failures.is_empty(),
"{} of {} good pushes were refused:\n{}",
failures.len(),
cases.len(),
failures.join("\n")
);
}
#[test]
fn every_gate_has_at_least_one_case_in_each_direction() {
// A gate with only bad cases has never been seen to allow anything, and one
// with only good cases has never been seen to refuse. Either is the failure
// this crate is most exposed to, so the coverage itself is asserted rather
// than left to whoever adds the next gate.
use std::collections::BTreeSet;
let bad: BTreeSet<String> = bad_pushes()
.iter()
.map(|c| c.gate.name().to_owned())
.collect();
let good: BTreeSet<String> = good_pushes()
.iter()
.map(|c| c.gate.name().to_owned())
.collect();
let expected: BTreeSet<String> = [
"branch-protection",
"ref-name",
"signed-commits",
"limits",
"ai-trailers",
]
.into_iter()
.map(str::to_owned)
.collect();
assert_eq!(bad, expected, "gates missing a rejection case");
assert_eq!(good, expected, "gates missing an allow case");
}