Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/gunnar

crates/gunnar-policy/src/blind.rs

//! Deliberately broken gates, shipped on purpose.
//!
//! # Why this is in the library and not in `tests/`
//!
//! A green must be seen red before it is believed. For a policy gate
//! the specific failure is named by the pre-receive gate's own rule:
//!
//! > A gate that always returns `Allow` is indistinguishable from a working gate
//! > in any test that only pushes valid commits.
//!
//! The usual way to honour that is to comment a gate out, watch the test fail,
//! and put it back. That proves the assertion could fail *on the day somebody
//! did it*, and nothing at all thereafter. [`AlwaysAllow`] makes it permanent:
//! every crafted-bad-push fixture is run twice, once through the real gate and
//! once through this one, and the suite asserts the real gate refuses **and**
//! that the blind one does not.
//!
//! # Exactly what each half catches: measured, not assumed
//!
//! The division of labour was checked by mutating this crate and watching which
//! test went red. It is not what one would guess, so it is written down:
//!
//! | mutation | caught by |
//! |---|---|
//! | a gate silently becomes always-allow | `tests/gates.rs` |
//! | a fixture stops being a genuinely bad push | `tests/gates.rs` (the real gate allows it) |
//! | **the assertion itself can no longer fail** | **`tests/blind.rs`, and nothing else** |
//!
//! That last row is the whole reason this module exists. A harness whose
//! `expect_reject` had been softened into always returning `Ok` leaves every
//! rejection test in the crate green and meaningless; `tests/gates.rs` cannot
//! see it, because it is the thing being deceived. Replaying the same fixtures
//! through a gate that is *known* to allow is the only way to observe it.
//!
//! Nothing here is wired into [`PolicyConfig`](crate::PolicyConfig), so a
//! configuration cannot select one by accident.
//!
use crate::context::PushContext;
use crate::error::Result;
use crate::{Gate, Verdict};

/// A gate that allows everything, wearing another gate's name.
///
/// This is the failure mode a measured assertion exists to catch, made
/// available so it can be caught on purpose.
#[derive(Clone, Debug)]
pub struct AlwaysAllow {
    name: String,
}

impl AlwaysAllow {
    /// A blind stand-in that answers to `name`.
    ///
    /// Pass the name of the gate it stands in for, so a rejection message that
    /// somehow gets produced still points at the right place.
    pub fn named(name: impl Into<String>) -> Self {
        AlwaysAllow { name: name.into() }
    }

    /// A blind stand-in for `gate`.
    pub fn instead_of(gate: &dyn Gate) -> Self {
        AlwaysAllow::named(gate.name())
    }
}

impl Gate for AlwaysAllow {
    fn name(&self) -> &str {
        &self.name
    }

    fn check(&self, _ctx: &PushContext<'_>) -> Result<Verdict> {
        Ok(Verdict::Allow)
    }
}

/// A gate that refuses everything.
///
/// The other half of the pair: it proves that an "this push must be allowed"
/// assertion is also capable of failing. An allow-direction test that cannot go
/// red is exactly as worthless as a reject-direction one.
#[derive(Clone, Debug)]
pub struct AlwaysReject {
    name: String,
}

impl AlwaysReject {
    /// A stand-in that refuses everything, answering to `name`.
    pub fn named(name: impl Into<String>) -> Self {
        AlwaysReject { name: name.into() }
    }

    /// A refusing stand-in for `gate`.
    pub fn instead_of(gate: &dyn Gate) -> Self {
        AlwaysReject::named(gate.name())
    }
}

impl Gate for AlwaysReject {
    fn name(&self) -> &str {
        &self.name
    }

    fn check(&self, _ctx: &PushContext<'_>) -> Result<Verdict> {
        Ok(Verdict::reject("blind gate: refuses everything"))
    }
}