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

nordisk/edda

crates/storage-git-gix/parked-gix-2/gunnar-wire-gix/tests/unnamed_policy.rs

//! **`deepen-since` meant something different on gunnar than in git, and said
//! nothing about it.**
//!
//! Every case here is a diff against stock `git` 2.53.0, driven through the
//! real client over the `ext::` helper, in the shape `second_sweep.rs`
//! established.
//!
//! # The class
//!
//! `caps::ADVERTISED` makes *"advertised and honoured by nothing"* impossible.
//! Its inverse — a behaviour the server applies that the wire never
//! declares — has now produced four wrong answers in this tree in one day, and
//! the two guards added to `tests/advertisement.rs`
//! (`every_capability_the_server_reads_is_one_it_advertises` and
//! `every_serving_policy_is_declared_somewhere`) close the two shapes that are
//! *visible in the source*: a capability read but never offered, and a `Config`
//! field enforced but never classified.
//!
//! This file is the third shape, and no census can catch it: gunnar advertises
//! `shallow`, which is a promise to accept all five deepening arguments — and
//! `deepen-since` was accepted and then **interpreted differently from git**.
//! The advertisement is a word, and the word has a meaning; a server may be
//! entirely honest about which words it speaks and still mean something else by
//! one of them. Only a differential against the definition can see that, which
//! is why every arm below runs the identical request against stock
//! `git-upload-pack` first.
//!
//! # What was wrong
//!
//! `deepen-since` is `rev-list --max-age=<since>` in git: a commit older than
//! the cutoff is not selected, and **being a tip does not exempt it**. gunnar's
//! walk seeded every `want` unconditionally and tested only *parents'* dates.
//! So a request whose tip predated the cutoff was answered with that tip.
//!
//! MEASURED oden 2026-08-05, git 2.53.0, three commits dated
//! `1700001000/2000/3000`, `--shallow-since=@1700009000`:
//!
//! | server | result |
//! |---|---|
//! | stock `git-upload-pack` | `fatal: no commits selected for shallow requests` |
//! | gunnar, before | a one-commit clone of a commit **older than the cutoff** |
//!
//! The client asked for history newer than a date and was handed history older
//! than it, marked shallow, exit 0, nothing in either log. A refusal that is
//! not a refusal but a different answer — the same shape as the `deepen-not`
//! defect next door in `second_sweep.rs`, and the reason both live under the
//! same heading.
//!
//! # Both halves of the fix were seen red, separately
//!
//! The fix is two lines apart in `shallow.rs::compute`, and each was reverted
//! on its own to check it carries weight:
//!
//! * without the **seed filter**, `since_past_every_commit` fails with *"gunnar
//!   served a --shallow-since past every commit … `git rev-list` says
//!   `1700005000 D`"* — commit `D`, dated `+5000`, against a cutoff of `+9000`;
//! * with the seed filter but without the **empty-selection refusal**, the same
//!   case fails differently — *"gunnar refused, but not in git's words"*, with
//!   `error: Could not read …` / `fatal: Failed to traverse parents of commit
//!   …`. Cutting every want away and then serving the result is a **corrupt**
//!   clone rather than a wrong one, which is why the refusal is not decoration
//!   on top of the filter.
//!
//! Both v0 and v2 arms went red both times, and the fourth case
//! (`an_ordinary_since_…`) stayed green throughout — a seed filter that simply
//! cut everything would have taken it down.

#[path = "git_harness/mod.rs"]
mod git_harness;

use git_harness::*;
use gix_hash::Kind;
use gunnar_wire::ProtocolVersion;

fn main() {
    serve_if_asked();

    let cases: &[(&str, fn())] = &[
        (
            "CONTROL_stock_git_refuses_a_since_past_every_commit",
            control_stock_git_since_past_every_commit,
        ),
        (
            "since_past_every_commit_is_refused_like_stock_git",
            since_past_every_commit,
        ),
        (
            "since_past_every_commit_is_refused_on_v0_too",
            since_past_every_commit_v0,
        ),
        (
            "an_ordinary_since_still_serves_and_matches_stock_git",
            an_ordinary_since_matches,
        ),
        (
            "a_deepen_not_excluding_every_tip_is_refused_like_stock_git",
            deepen_not_excluding_everything,
        ),
    ];

    run_cases("unnamed_policy", cases, 5);
}

/// A cutoff later than every commit in `Scene::dated`, whose newest is
/// `DATED_BASE + 5000`.
fn past_everything() -> String {
    format!("@{} +0000", DATED_BASE + 9000)
}

/// A cutoff between `B` (+2000) and `M` (+4000), so the request is ordinary:
/// something is selected and something is cut.
fn between() -> String {
    format!("@{} +0000", DATED_BASE + 3500)
}

/// **The contract.** git does not serve a smaller answer when the date excludes
/// everything — it dies, by name.
///
/// Without this arm the two gunnar arms below would be asserting gunnar against
/// gunnar's own reading of the documentation, which is exactly how
/// `deepen-since` came to mean two things.
fn control_stock_git_since_past_every_commit() {
    let scene = Scene::dated(Kind::Sha1);

    let (ok, _, stderr) = Git::new()
        .cwd(&scene.root)
        .args(["clone", "-q", "--shallow-since"])
        .arg(past_everything())
        .arg(scene.local_url())
        .arg(scene.root.join("stock-past").to_str().unwrap())
        .run();
    assert!(
        !ok,
        "stock git served a --shallow-since past every commit, so there is no contract here to \
         hold gunnar to and both arms below would pass on anything"
    );
    assert!(
        stderr.contains("no commits selected"),
        "stock git refused for some other reason than the one under test:\n{stderr}"
    );

    // …and the same server serves an ordinary cutoff, so "it refuses" above is
    // about the date and not about the fixture being unservable.
    Git::new()
        .cwd(&scene.root)
        .args(["clone", "-q", "--shallow-since"])
        .arg(between())
        .arg(scene.local_url())
        .arg(scene.root.join("stock-between").to_str().unwrap())
        .ok();
}

/// gunnar served the tip anyway. Now it refuses, and the refusal reaches the
/// client.
fn since_past_every_commit() {
    let scene = Scene::dated(Kind::Sha1);
    let into = scene.root.join("gunnar-past");

    let (ok, _, stderr) = scene
        .client(ProtocolVersion::V2)
        .args(["clone", "-q", "--shallow-since"])
        .arg(past_everything())
        .arg(scene.url())
        .arg(into.to_str().unwrap())
        .run();

    assert!(
        !ok,
        "gunnar served a --shallow-since past every commit where stock git refuses. The client \
         asked for commits newer than a date and got one older than it, marked shallow, exit 0 \
         — a different answer wearing a success's clothes. `git rev-list` says {:?}",
        std::fs::read_dir(&into)
            .map(|_| git_in(&into).args(["log", "--format=%ct %s"]).ok())
            .unwrap_or_else(|_| "no clone at all".to_owned())
    );
    assert!(
        stderr.contains("no commits selected"),
        "gunnar refused, but not in git's words, so a client cannot tell the two servers \
         apart:\n{stderr}"
    );
}

/// The same, on protocol v0. Three of today's four defects in this class were
/// green on v2 and broken on v0, so a v2-only arm is not evidence here.
fn since_past_every_commit_v0() {
    let scene = Scene::dated(Kind::Sha1);

    let (ok, _, stderr) = scene
        .client(ProtocolVersion::V0)
        .args(["clone", "-q", "--shallow-since"])
        .arg(past_everything())
        .arg(scene.url())
        .arg(scene.root.join("gunnar-past-v0").to_str().unwrap())
        .run();
    assert!(
        !ok,
        "protocol v0 served a --shallow-since past every commit that v2 refuses. Every defect \
         in this class so far has been green on v2 and broken on v0"
    );
    assert!(
        stderr.contains("no commits selected"),
        "v0 refused for a different reason than v2:\n{stderr}"
    );
}

/// **The other direction, and it is what makes the two arms above mean
/// anything.** An ordinary cutoff must still be served, and served the way git
/// serves it — a seed filter that cut too much would satisfy every assertion
/// above while breaking `--shallow-since` outright.
fn an_ordinary_since_matches() {
    let scene = Scene::dated(Kind::Sha1);
    let mine = scene.root.join("gunnar-between");
    let stock = scene.root.join("stock-between");

    scene
        .client(ProtocolVersion::V2)
        .args(["clone", "-q", "--shallow-since"])
        .arg(between())
        .arg(scene.url())
        .arg(mine.to_str().unwrap())
        .ok();
    Git::new()
        .cwd(&scene.root)
        .args(["clone", "-q", "--shallow-since"])
        .arg(between())
        .arg(scene.local_url())
        .arg(stock.to_str().unwrap())
        .ok();

    let commits = |dir: &std::path::Path| -> usize {
        git_in(dir)
            .args(["rev-list", "--count", "HEAD"])
            .ok()
            .parse()
            .unwrap()
    };
    let shallow = |dir: &std::path::Path| -> Vec<String> {
        let mut lines: Vec<String> = std::fs::read_to_string(dir.join(".git").join("shallow"))
            .unwrap_or_default()
            .lines()
            .map(str::to_owned)
            .collect();
        lines.sort();
        lines
    };

    assert_eq!(
        (commits(&mine), shallow(&mine)),
        (commits(&stock), shallow(&stock)),
        "gunnar and stock git disagree about an ordinary --shallow-since"
    );
    // Not vacuous: the cutoff really cuts, so "they agree" is not "they both
    // sent the whole repository".
    assert!(
        commits(&mine) < 5 && !shallow(&mine).is_empty(),
        "the cutoff between B and M selected everything ({} commits, {:?} cut points), so this \
         arm compares two full clones and would agree however `since` were implemented",
        commits(&mine),
        shallow(&mine)
    );
}

/// **The other way to select nothing, because the refusal names both.**
///
/// `compute`'s error says *"deepen-since and deepen-not between them exclude
/// every requested tip"*, and until this case that claim was half asserted:
/// only the date path had ever reached it. `--shallow-exclude=main` while
/// cloning `main` removes every want through the exclusion set instead.
///
/// MEASURED oden 2026-08-05: stock git 2.53.0 answers this with the identical
/// `fatal: no commits selected for shallow requests` and leaves no clone
/// behind, so the two paths really are one contract and not two.
fn deepen_not_excluding_everything() {
    let scene = Scene::dated(Kind::Sha1);

    let (stock_ok, _, stock_err) = Git::new()
        .cwd(&scene.root)
        .args(["clone", "-q", "--shallow-exclude=main"])
        .arg(scene.local_url())
        .arg(scene.root.join("stock-excl-all").to_str().unwrap())
        .run();
    assert!(
        !stock_ok,
        "stock git served a clone whose only branch was excluded, so there is no contract here"
    );
    assert!(
        stock_err.contains("no commits selected"),
        "stock git refused for another reason:\n{stock_err}"
    );

    for protocol in [ProtocolVersion::V0, ProtocolVersion::V2] {
        let (ok, _, stderr) = scene
            .client(protocol)
            .args(["clone", "-q", "--shallow-exclude=main"])
            .arg(scene.url())
            .arg(
                scene
                    .root
                    .join(format!("gunnar-excl-all-{protocol:?}"))
                    .to_str()
                    .unwrap(),
            )
            .run();
        assert!(
            !ok,
            "{protocol:?}: gunnar served a clone whose only branch was excluded, where stock \
             git refuses"
        );
        assert!(
            stderr.contains("no commits selected"),
            "{protocol:?}: gunnar refused, but not in git's words:\n{stderr}"
        );
    }
}