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/gates/signed.rs

//! Gate 3. Every commit this push adds must carry a verifying ssh signature.
//!
//! The cryptography lives in [`crate::signature`]; this is the policy wrapper
//! around it. What the wrapper decides is *which commits* and *whose keys*, and
//! both answers are ones a blind implementation gets to skip entirely. A gate
//! that checks no commits is indistinguishable from a gate that checks them all
//! successfully.
//!
//! So the commit set comes from a walk bounded by the pack's own new-object set
//! ([`crate::ancestry::introduced_commits`]) rather than from a caller-supplied
//! list, and an empty key set rejects rather than vacuously passing.

use std::collections::HashSet;

use crate::config::SignaturePolicy;
use crate::context::PushContext;
use crate::error::Result;
use crate::{Gate, Verdict};

/// Requires ssh signatures on newly added commits.
#[derive(Clone, Debug)]
pub struct SignedCommitsGate {
    policy: SignaturePolicy,
}

impl SignedCommitsGate {
    /// A gate over `policy`.
    pub fn new(policy: SignaturePolicy) -> Self {
        SignedCommitsGate { policy }
    }

    /// The policy this gate enforces.
    pub fn policy(&self) -> &SignaturePolicy {
        &self.policy
    }
}

impl Gate for SignedCommitsGate {
    fn name(&self) -> &str {
        "signed-commits"
    }

    fn check(&self, ctx: &PushContext<'_>) -> Result<Verdict> {
        if !self.policy.required {
            return Ok(Verdict::Allow);
        }
        let mut checked: HashSet<gix_hash::ObjectId> = HashSet::new();
        for update in ctx.updates {
            let verdict = super::verify_update_signatures(
                ctx,
                update,
                self.policy.scope,
                &self.policy.namespace,
                self.policy.budget,
                &mut checked,
                self.name(),
            )?;
            if verdict.is_reject() {
                return Ok(verdict);
            }
        }
        Ok(Verdict::Allow)
    }
}