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

nordisk/gunnar

crates/gunnar-cli/tests/settings_verb.rs

#![cfg(feature = "server")]

//! **`gunnar settings` against the real door** (ba0822e7, lane OX-WIRED2): the `gunnar`
//! binary asks the forge's SSH door (`gunnar-repo`) of a REAL server (the harness's
//! `Server::start`, its control plane on), signed in with the person's SSH key by the same
//! `ssh` git runs, and the server answers with its own `Repos` handlers and rules:
//!
//! * a person who may write the repository reads its settings, and is refused changing its
//!   default branch (a repository admin's act) by the server's words; nothing changes;
//! * once the server's admin, the same person makes it public and moves its default branch,
//!   and the catalog holds exactly that;
//! * a caller with no key is refused.
//!
//! Before this, the verb was driven only against a stub door (gunnar-ssh tests/repo_verb.rs).

mod common;

use std::process::{Command, Output};

use common::{tools_present, Harness};
use gunnar_core::{Grant, HashKind, Level, RepoRef, Visibility};

fn settings(harness: &Harness, ssh: &str, args: &[&str]) -> Output {
    Command::new(env!("CARGO_BIN_EXE_gunnar-cli"))
        .arg("settings")
        .args(args)
        .arg("--host")
        .arg(format!("ssh://git@127.0.0.1:{}", harness.ssh_port))
        .env("HOME", harness.dir.path())
        .env("SSH_AUTH_SOCK", "")
        .env("GIT_SSH_COMMAND", ssh)
        .output()
        .expect("run the gunnar binary")
}

fn said(out: &Output) -> String {
    String::from_utf8_lossy(&out.stdout).to_string() + &String::from_utf8_lossy(&out.stderr)
}

#[test]
fn gunnar_settings_asks_the_real_door_and_the_server_decides() {
    assert!(
        tools_present(),
        "this test requires `git` and `ssh` on PATH"
    );
    let harness = Harness::start_with_grpc("team", "project", HashKind::Sha1);
    let path = RepoRef::new("team", "project").expect("a legal path");
    let stored = || {
        harness
            .stores
            .catalog()
            .get(&path)
            .expect("the catalog reads")
            .expect("the repository is there")
    };
    let before = stored();
    assert_eq!(
        before.visibility,
        Visibility::Private,
        "a new repository is private"
    );
    let ssh = harness.ssh_command();

    // A writer reads the settings: the server's own words for the repository.
    let shown = settings(&harness, &ssh, &["team/project"]);
    assert!(
        shown.status.success(),
        "a writer reads the settings: {}",
        said(&shown)
    );
    assert!(said(&shown).contains("team/project"), "{}", said(&shown));

    // ...and is refused a repository admin's act, by the server; nothing changes.
    let refused = settings(
        &harness,
        &ssh,
        &["team/project", "--default-branch", "trunk"],
    );
    assert!(
        !refused.status.success(),
        "a writer may not move the default branch: {}",
        said(&refused)
    );
    assert_eq!(
        stored().default_branch,
        before.default_branch,
        "the refusal changed nothing"
    );
    let refused = settings(&harness, &ssh, &["team/project", "--visibility", "public"]);
    assert!(
        !refused.status.success(),
        "a writer may not publish the repository: {}",
        said(&refused)
    );
    assert_eq!(stored().visibility, Visibility::Private);

    // The server's admin: both settings change, and the catalog holds exactly that.
    harness
        .stores
        .auth()
        .grant(Grant::server("tester", Level::Admin))
        .expect("make tester the server's admin");
    let changed = settings(
        &harness,
        &ssh,
        &[
            "team/project",
            "--visibility",
            "public",
            "--default-branch",
            "trunk",
        ],
    );
    assert!(
        changed.status.success(),
        "the admin changes both: {}",
        said(&changed)
    );
    let after = stored();
    assert_eq!(after.visibility, Visibility::Public, "{after:?}");
    assert_eq!(after.default_branch, "refs/heads/trunk", "{after:?}");

    // A caller with no key is refused.
    let anon = settings(
        &harness,
        &harness.anonymous_ssh_command(),
        &["team/project"],
    );
    assert!(
        !anon.status.success(),
        "no key, no settings: {}",
        said(&anon)
    );
}