gunnar-ssh 3.0.0

gunnar's SSH server: a russh listener with publickey identity, a strict git exec dispatch, and the repository path sandbox.
Documentation
//! **The front door hands a push its standing in the namespace's byte ledger,
//! and takes it BEFORE the gates measure anything.**
//!
//! `gunnar-wire/tests/concurrent_pack_ceiling.rs` proves the receive loop
//! spends a shared budget instead of a per-connection one. It proves it against
//! a ledger the test writes itself, because `gunnar-wire` cannot name the real
//! one. This file is the other half: that
//! [`Dispatch::authorise_service`](gunnar_ssh::server::Dispatch::authorise_service)
//! actually produces the standing, that it produces it in the right ORDER, and
//! that the pack meter is not the LFS meter wearing a hat.
//!
//! Without this file the fix would be a mechanism with no proof that anything
//! wires it up — the receive loop would ask a ledger that production never
//! attaches, and every test would still be green.
//!
//! # A namespace per test, because the ledger is a process-wide `static`
//!
//! `AllowanceLedger::shared_pack()` is one counter per namespace for the whole
//! process — that is deliberate (a namespace's room is a fact about the BOX,
//! not about whichever `Dispatch` happened to answer), and `cargo test` runs
//! these five in threads of one process. A mark is RELATIVE, so a charge that
//! landed before it is invisible to it; a charge that lands after it is not,
//! and that is exactly what a sibling test spending its own ceiling looks like.
//! MEASURED, on the first run of this file with every test on `nordisk`:
//!
//! ```text
//! ---- two_pushes_arriving_together_share_one_namespaces_room stdout ----
//! assertion `left == right` failed: the first push may spend the whole of the
//! room that was measured for it
//!   left: 0
//!  right: 65536
//! ```
//!
//! So each test registers a namespace of its own. Not a workaround for a flaky
//! test — a test that shared a tenant with four other tenants and expected its
//! room to itself would be asserting something production does not promise.

mod common;

use std::sync::Arc;

use common::{mint_key, principal, Plane};
use gunnar_core::model::{Grant, Visibility};
use gunnar_core::{NewRepo, RepoRef};
use gunnar_ssh::command::GitService;
use gunnar_ssh::server::Dispatch;
use gunnar_ssh::{Access, PackCeiling, PlanAction, PlanGate, PlanVerdict, ServiceRequest};

/// The namespace's remaining room, as a gate would report it.
const CEILING: u64 = 64 * 1024;

/// The LFS meter's room. **Deliberately a different number** from [`CEILING`]:
/// two caps that happened to be equal would let a test pass while the two
/// meters were in fact one counter.
const LFS_ROOM: u64 = 16 * 1024;

const REFUSAL: &str = "plan 10gb would pass its pack quota with this push";

/// A metered gate: a pack ceiling, an LFS allowance, and nothing else refused.
///
/// `during_the_walk` is the interleaving made deliberate — see
/// [`the_mark_is_taken_before_the_gate_measures`].
struct Metered {
    /// Bytes admitted to this namespace by SOMEONE ELSE while this gate is
    /// measuring the disk. `0` for an ordinary gate.
    during_the_walk: u64,
}

impl PlanGate for Metered {
    fn verdict(&self, _: &str, _: PlanAction) -> PlanVerdict {
        PlanVerdict::Allow
    }

    fn pack_quota(&self, _: &str) -> PlanVerdict {
        PlanVerdict::Allow
    }

    fn pack_ceiling(&self, namespace: &str) -> Option<PackCeiling> {
        if self.during_the_walk > 0 {
            // Another connection, admitted between the mark and the answer.
            // This is exactly the window the ordering exists for: its bytes are
            // in the ledger, and they may or may not be in the number this gate
            // is about to return.
            let other = gunnar_lfs::AllowanceLedger::shared_pack().mark(namespace);
            assert_eq!(
                other.admit_upto(self.during_the_walk, u64::MAX),
                self.during_the_walk,
                "the fixture's own admission must have been charged"
            );
        }
        Some(PackCeiling {
            bytes: CEILING,
            refusal: REFUSAL.to_owned(),
        })
    }

    fn lfs_allowance(&self, _: &str) -> Option<gunnar_lfs::Allowance> {
        Some(gunnar_lfs::Allowance {
            bytes: LFS_ROOM,
            refusal: "plan 10gb has no LFS room left".to_owned(),
        })
    }

    fn name(&self) -> &'static str {
        "metered"
    }
}

/// A gate with no byte cap at all — the community build's one gate.
struct Uncapped;

impl PlanGate for Uncapped {
    fn verdict(&self, _: &str, _: PlanAction) -> PlanVerdict {
        PlanVerdict::Allow
    }
    fn pack_quota(&self, _: &str) -> PlanVerdict {
        PlanVerdict::Allow
    }
    fn name(&self) -> &'static str {
        "uncapped"
    }
}

/// The repository this test's tenant pushes to. One namespace per test — see
/// the header.
fn repo(namespace: &str) -> RepoRef {
    RepoRef::new(namespace, "osm-katana").expect("a legitimate path")
}

/// One push through the front door, authorised.
fn authorise(dispatch: &Dispatch, namespace: &str, service: GitService) -> ServiceRequest {
    dispatch
        .authorise_service(&principal("principal-1"), None, service, repo(namespace))
        .expect("the gates allow this push")
}

/// A front door onto a namespace of this test's own, with `gate` in the chain.
///
/// The catalog and the identity table are the real ones (see `common`), reached
/// through their own public doors: this registers the namespace, the
/// repository, the principal, its key and its grant exactly as an operator
/// would, so nothing here is a fixture pretending to be a plane.
fn door(namespace: &str, gate: Arc<dyn PlanGate>) -> Dispatch {
    let key = mint_key();
    let plane = Plane::empty()
        .with_principal("principal-1")
        .with_key("principal-1", &key);
    plane
        .catalog()
        .create_namespace(namespace)
        .expect("create namespace");
    plane
        .catalog()
        .create(NewRepo::new(repo(namespace)).visibility(Visibility::Private))
        .expect("create repository");
    plane
        .auth()
        .grant(Grant::repo("principal-1", repo(namespace), Access::Write))
        .expect("grant");
    Dispatch::new(plane.control.with_plan_gate(gate))
}

// ── the standing exists, and it is the namespace's ─────────────────────────

#[test]
fn a_capped_push_carries_both_the_number_and_its_standing_in_the_ledger() {
    let dispatch = door("one-push", Arc::new(Metered { during_the_walk: 0 }));
    let request = authorise(&dispatch, "one-push", GitService::ReceivePack);

    assert_eq!(
        request.pack_ceiling.as_ref().expect("a ceiling").bytes,
        CEILING,
        "the gate's number must reach the transport unchanged"
    );
    let mark = request.pack_mark.as_ref().expect(
        "a capped push with no mark is a ceiling every connection is held to separately, which \
         is the defect this closed",
    );
    assert_eq!(
        mark.namespace(),
        "one-push",
        "the standing must be in the pushing namespace's counter and no other"
    );
}

/// **The fix, at the seam that produces it.** Two pushes authorised before
/// either sends — the shape of two connections arriving together — spend ONE
/// namespace's room between them, not one each.
#[test]
fn two_pushes_arriving_together_share_one_namespaces_room() {
    let dispatch = door("two-pushes", Arc::new(Metered { during_the_walk: 0 }));

    // Both measured, neither has sent a byte. Before the ledger this was the
    // whole bug: two ceilings of CEILING bytes each.
    let first = authorise(&dispatch, "two-pushes", GitService::ReceivePack);
    let second = authorise(&dispatch, "two-pushes", GitService::ReceivePack);

    let first_mark = first.pack_mark.expect("a mark");
    let second_mark = second.pack_mark.expect("a mark");

    assert_eq!(
        first_mark.admit_upto(CEILING, CEILING),
        CEILING,
        "the first push may spend the whole of the room that was measured for it"
    );
    assert_eq!(
        second_mark.admit_upto(CEILING, CEILING),
        0,
        "the second push was admitted against room the first one is already spending: that is \
         the same measurement handed out twice"
    );
}

/// **The ordering is the contract**, not an accident of where the line sits.
///
/// The gate charges the namespace while it is "walking the disk". Marking
/// before the walk puts that admission after the mark, so this push is held to
/// what is left of the room; marking after it would hide the admission and hand
/// this push the whole ceiling on top of it. Only one of those two roundings is
/// a quota that leaks.
#[test]
fn the_mark_is_taken_before_the_gate_measures() {
    let landed = CEILING / 2;
    let dispatch = door(
        "mid-walk",
        Arc::new(Metered {
            during_the_walk: landed,
        }),
    );
    let request = authorise(&dispatch, "mid-walk", GitService::ReceivePack);
    let mark = request.pack_mark.expect("a mark");

    assert_eq!(
        mark.admit_upto(CEILING, CEILING),
        CEILING - landed,
        "an admission that landed while the gate measured is invisible to this push: the mark \
         was taken AFTER the walk, and the namespace's room has now been handed out twice"
    );
}

/// **Two meters, two counters.** `pack_bytes` and `lfs_bytes` are capped
/// separately on the signed fact and reported separately by `Usage.Read`. One
/// shared counter would cut a push mid-transfer over room its own cap never
/// lost — a quota that refuses wrongly, which is this defect pointing the other
/// way.
#[test]
fn the_pack_meter_and_the_lfs_meter_are_not_the_same_counter() {
    let dispatch = door("two-meters", Arc::new(Metered { during_the_walk: 0 }));
    let request = authorise(&dispatch, "two-meters", GitService::ReceivePack);

    // Spend the whole pack meter.
    let mark = request.pack_mark.expect("a mark");
    assert_eq!(mark.admit_upto(CEILING, CEILING), CEILING);

    // The LFS door of the same session, measured in the same breath, still has
    // every byte of its own room.
    request
        .lfs_allowance
        .expect("an LFS allowance")
        .admit(LFS_ROOM)
        .expect(
            "a push spending the pack cap has taken the tenant's LFS room with it; they are two \
             caps on the fact and two counters here",
        );
}

/// the other half: no cap, no bookkeeping. A mark with no number to be
/// judged against is a lock nobody reads — and a read never grows the tenant's
/// data, so it is never asked for one.
#[test]
fn a_push_with_no_ceiling_carries_no_mark() {
    let uncapped = door("uncapped", Arc::new(Uncapped));
    let push = authorise(&uncapped, "uncapped", GitService::ReceivePack);
    assert!(
        push.pack_ceiling.is_none() && push.pack_mark.is_none(),
        "an uncapped plan must carry neither a ceiling nor a standing in one"
    );

    let capped = door(
        "no-ceiling-on-a-clone",
        Arc::new(Metered { during_the_walk: 0 }),
    );
    let clone = authorise(&capped, "no-ceiling-on-a-clone", GitService::UploadPack);
    assert!(
        clone.pack_ceiling.is_none() && clone.pack_mark.is_none(),
        "a clone takes no byte ceiling and must not spend a byte of the push meter"
    );
}