use std::borrow::Cow;
use std::fs;
use std::io::Write;
use std::path::PathBuf;
mod common;
use common::Environment;
fn create_environment(use_external_policy: bool,
create_internal_policy: bool,
signer: Option<&str>)
-> anyhow::Result<(Environment, String, Option<PathBuf>)>
{
let (e, root) = if create_internal_policy {
Environment::scooby_gang_bootstrap(signer)?
} else {
let e = Environment::new()?;
e.init_repo(None)?;
let root = e.git_commit(&[("initial-commit", Some(b"xxx"))],
"Initial commit (no signing policy)",
Some(&e.willow_release))
.expect("can commit");
(e, root)
};
let repo = e.scratch_state().join("repo");
e.git(&["init", "--bare", &repo.display().to_string()])?;
e.git(&["remote", "add", "origin", &repo.display().to_string()])?;
e.git(&["checkout", "-b", "main"])?;
e.git(&["push", "origin", "main"])?;
let external_policy_file = if use_external_policy {
let external_policy_file = e.scratch_state().join("policy.toml");
e.scooby_gang_bootstrap_policy(&external_policy_file)?;
Some(external_policy_file)
} else {
None
};
let update_hook = repo.join("hooks").join("update");
let mut update = fs::File::create(&update_hook)?;
writeln!(update, "#!/bin/sh")?;
writeln!(update)?;
writeln!(update,
"{} update-hook --trust-root={} {}{} \"$@\"",
Environment::sq_git_path()?.display(),
root,
if external_policy_file.is_some() {
"--policy-file="
} else {
""
},
if let Some(file) = external_policy_file.as_ref() {
Cow::Owned(file.display().to_string())
} else {
Cow::Borrowed("")
})?;
eprintln!("Update hook {}:\n{}",
update_hook.display(),
String::from_utf8_lossy(
&std::fs::read(&update_hook)
.expect("Can read update hook file")));
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let metadata = update.metadata()?;
let mut permissions = metadata.permissions();
permissions.set_mode(0o755);
update.set_permissions(permissions)?;
}
Ok((e, root, external_policy_file))
}
#[test]
fn update_hook_internal_policy() -> anyhow::Result<()> {
let (e, _root, _) = create_environment(false, true, None)?;
let p = e.git_state();
e.git(&["checkout", "-b", "test-base"])?;
e.git(&["checkout", "-b", "test-willow"])?;
fs::write(p.join("a"), "Aller Anfang ist schwer.")?;
e.git(&["add", "a"])?;
e.git(&[
"commit",
"-m", "First change.",
&format!("-S{}", e.willow.fingerprint),
])?;
e.git(&["push", "origin", "test-willow"])?;
e.git(&["checkout", "test-base"])?;
e.git(&["clean", "-fdx"])?;
e.git(&["checkout", "-b", "test-willow-release"])?;
fs::write(p.join("a"), "Aller Anfang ist schwer. -- Schiller")?;
e.git(&["add", "a"])?;
e.git(&[
"commit",
"-m", "Someone is not quite correct on the internet.",
&format!("-S{}", e.willow_release.fingerprint),
])?;
e.git(&["push", "origin", "test-willow-release"])?;
e.git(&["checkout", "test-base"])?;
e.git(&["clean", "-fdx"])?;
e.git(&["checkout", "-b", "test-buffy"])?;
fs::write(p.join("a"),
"Aller Anfang ist schwer, unless you are super strong!1")?;
e.git(&["add", "a"])?;
e.git(&[
"commit",
"-m", "Well, actually...",
&format!("-S{}", e.buffy.fingerprint),
])?;
if let Ok(output) = e.git(&["push", "origin", "test-buffy"]) {
eprintln!("stderr: {}", String::from_utf8_lossy(&output.stderr));
}
assert!(e.git(&["push", "origin", "test-buffy"]).is_err());
Ok(())
}
#[test]
fn update_hook_external_policy() -> anyhow::Result<()> {
let (e, _root, _policy_file) = create_environment(true, false, None)?;
e.git(&["checkout", "-b", "willow"])?;
e.git_commit(&[("xxx", Some(b"2"))],
"commit-1",
Some(&e.willow_release))
.expect("can commit");
assert!(e.git(&["push", "origin", "willow"]).is_ok());
e.git(&["checkout", "-b", "xander"])?;
e.git_commit(&[("xxx", Some(b"3"))],
"commit-2",
Some(&e.xander))
.expect("can commit");
assert!(e.git(&["push", "origin", "xander"]).is_err());
Ok(())
}
#[test]
fn update_hook_ignore_internal_policy() -> anyhow::Result<()> {
let (e, _root, external_policy_file)
= create_environment(true, true, Some("Riley Finn"))?;
let external_policy_file = external_policy_file
.expect("have external policy");
std::fs::remove_file(&external_policy_file).expect("Can remove file");
e.sq_git(
&[
"policy",
"authorize",
"--policy-file", &external_policy_file.display().to_string(),
e.riley.petname,
&e.riley.fingerprint.to_string(),
"--sign-commit",
"--sign-tag",
"--sign-archive",
"--add-user",
"--retire-user",
"--audit",
])?;
e.git(&["checkout", "-b", "xander", "main"])?;
e.git_commit(&[("xxx", Some(b"xander"))],
"xander commit",
Some(&e.xander))
.expect("can commit");
e.git_log_graph().expect("can display graph");
assert!(e.git(&["push", "origin", "xander"]).is_err());
e.git(&["checkout", "-b", "willow", "main"])?;
e.git_commit(&[("xxx", Some(b"willow"))],
"willow commit",
Some(&e.willow_release))
.expect("can commit");
e.git_log_graph().expect("can display graph");
assert!(e.git(&["push", "origin", "willow"]).is_err());
e.git(&["checkout", "-b", "riley", "main"])?;
e.git_commit(&[("xxx", Some(b"riley"))],
"riley commit",
Some(&e.riley))
.expect("can commit");
e.git_log_graph().expect("can display graph");
assert!(e.git(&["push", "origin", "riley"]).is_ok());
Ok(())
}
#[test]
fn rebase() -> anyhow::Result<()> {
let (e, _root, _policy_file) = create_environment(false, true, None)?;
let p = e.git_state();
e.git(&["checkout", "-b", "test-base"])?;
e.git(&["checkout", "-b", "feature-one"])?;
fs::write(p.join("a"), "Aller Anfang ist schwer.")?;
e.git(&["add", "a"])?;
e.git(&[
"commit",
"-m", "First change of the first feature.",
&format!("-S{}", e.willow.fingerprint),
])?;
e.git(&["push", "origin", "feature-one"])?;
e.git(&["checkout", "test-base"])?;
e.git(&["clean", "-fdx"])?;
e.git(&["checkout", "-b", "feature-two"])?;
fs::write(p.join("b"), "And now for something completely different.")?;
e.git(&["add", "b"])?;
e.git(&[
"commit",
"-m", "First change of the second feature.",
&format!("-S{}", e.willow.fingerprint),
])?;
e.git(&["push", "origin", "feature-two"])?;
e.git(&[
"rebase",
"feature-one",
&format!("-S{}", e.willow.fingerprint),
])?;
e.git(&["push", "origin", "--force", "feature-two"])?;
Ok(())
}