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)
);
}