use similar_asserts::assert_eq;
use std::sync::Arc;
use zenops::{
Cmd,
config_files::ConfigFilePath,
output::{AppliedAction, FileStatus, Status},
};
use zenops_safe_relative_path::srpath;
use test_env::{Entry, Output, paths};
mod test_env;
#[test]
fn ssh_allowed_signers_manual_entry_roundtrips_through_apply_and_status() {
let env = test_env::TestEnv::load();
env.init_config(
r#"
[[ssh.allowed_signers]]
type = "manual"
principal = "bob@example.com"
key_type = "ssh-ed25519"
key = "AAAAKEY"
"#,
);
let file_path = env.cfpath(".ssh/allowed_signers", ConfigFilePath::Home);
let dir_path = env.cfpath(".ssh", ConfigFilePath::Home);
let want_body = Arc::<str>::from(
"# Generated by zenops — do not edit.\nbob@example.com ssh-ed25519 AAAAKEY\n",
);
assert_eq!(
env.run(&Cmd::Status {
diff: false,
all: false,
}),
Ok(Output {
entries: vec![
env.git_repo_clean_entry(),
Entry::Status(Status::Generated {
want_content: want_body.clone(),
cur_content: None,
path: file_path.clone(),
status: FileStatus::New,
}),
],
}),
);
assert_eq!(
env.run(&Cmd::Apply {
pull_config: false,
yes: true,
dry_run: false,
allow_dirty: true,
}),
Ok(Output {
entries: vec![
Entry::AppliedAction(AppliedAction::CreatedDir(dir_path.clone())),
Entry::AppliedAction(AppliedAction::CreatedFile(file_path.clone())),
],
}),
);
let disk = std::fs::read_to_string(
env.resolve_path(paths::HOME_DIR.safe_join(srpath!(".ssh/allowed_signers"))),
)
.unwrap();
assert_eq!(disk, want_body.as_ref());
assert_eq!(
env.run(&Cmd::Status {
diff: false,
all: false,
}),
Ok(Output {
entries: vec![
env.git_repo_clean_entry(),
Entry::Status(Status::Generated {
want_content: want_body,
cur_content: Some(
"# Generated by zenops — do not edit.\nbob@example.com ssh-ed25519 AAAAKEY\n"
.to_string(),
),
path: file_path,
status: FileStatus::Ok,
}),
],
}),
);
}
#[test]
fn git_config_ssh_signing_with_allowed_signers_writes_full_gitconfig() {
let env = test_env::TestEnv::load();
env.init_config(
r#"
[user]
name = "Ada Lovelace"
email = "ada@example.com"
[git.signing]
type = "ssh"
key = "~/.ssh/id_ed25519-github.pub"
[[ssh.allowed_signers]]
type = "manual"
principal = "ada@example.com"
key_type = "ssh-ed25519"
key = "AAAAKEY"
"#,
);
let allowed_signers_path = env.cfpath(".ssh/allowed_signers", ConfigFilePath::Home);
let allowed_signers_dir = env.cfpath(".ssh", ConfigFilePath::Home);
let gitconfig_path = env.cfpath(".gitconfig", ConfigFilePath::Home);
let want_gitconfig = Arc::<str>::from(
"# Generated by zenops — do not edit.\n\
[user]\n\
\tname = Ada Lovelace\n\
\temail = ada@example.com\n\
\tsigningkey = ~/.ssh/id_ed25519-github.pub\n\
[gpg]\n\
\tformat = ssh\n\
[gpg \"ssh\"]\n\
\tallowedSignersFile = ~/.ssh/allowed_signers\n\
[commit]\n\
\tgpgsign = true\n",
);
let want_allowed_signers = Arc::<str>::from(
"# Generated by zenops — do not edit.\nada@example.com ssh-ed25519 AAAAKEY\n",
);
assert_eq!(
env.run(&Cmd::Apply {
pull_config: false,
yes: true,
dry_run: false,
allow_dirty: true,
}),
Ok(Output {
entries: vec![
Entry::AppliedAction(AppliedAction::CreatedDir(allowed_signers_dir)),
Entry::AppliedAction(AppliedAction::CreatedFile(allowed_signers_path)),
Entry::AppliedAction(AppliedAction::CreatedFile(gitconfig_path.clone())),
],
}),
);
let disk =
std::fs::read_to_string(env.resolve_path(paths::HOME_DIR.safe_join(srpath!(".gitconfig"))))
.unwrap();
assert_eq!(disk, want_gitconfig.as_ref());
let disk = std::fs::read_to_string(
env.resolve_path(paths::HOME_DIR.safe_join(srpath!(".ssh/allowed_signers"))),
)
.unwrap();
assert_eq!(disk, want_allowed_signers.as_ref());
}
#[test]
fn git_config_ssh_signing_without_allowed_signers_omits_gpg_ssh_block() {
let env = test_env::TestEnv::load();
env.init_config(
r#"
[user]
name = "Ada Lovelace"
email = "ada@example.com"
[git.signing]
type = "ssh"
key = "~/.ssh/id_ed25519.pub"
"#,
);
let gitconfig_path = env.cfpath(".gitconfig", ConfigFilePath::Home);
assert_eq!(
env.run(&Cmd::Apply {
pull_config: false,
yes: true,
dry_run: false,
allow_dirty: true,
}),
Ok(Output {
entries: vec![Entry::AppliedAction(AppliedAction::CreatedFile(
gitconfig_path
))],
}),
);
let disk =
std::fs::read_to_string(env.resolve_path(paths::HOME_DIR.safe_join(srpath!(".gitconfig"))))
.unwrap();
assert!(
!disk.contains("allowedSignersFile"),
"gitconfig should not reference allowed_signers when none configured:\n{disk}"
);
assert!(disk.contains("\tname = Ada Lovelace\n"));
assert!(disk.contains("\tformat = ssh\n"));
assert!(disk.contains("\tgpgsign = true\n"));
}