use crate::support::*;
use std::fs;
#[test]
fn test_setup_creates_global_identity() {
let t = Test::new();
let output = t.cmd().arg("setup").output().unwrap();
assert_success(&output);
assert_stdout_contains(&output, "generated identity");
let identity_path = t.home.path().join(".dugout/identity.key");
assert!(
identity_path.exists(),
"~/.dugout/identity.key should exist"
);
let pubkey_path = t.home.path().join(".dugout/identity.pub");
assert!(pubkey_path.exists(), "~/.dugout/identity.pub should exist");
let pubkey = fs::read_to_string(&pubkey_path).unwrap();
assert!(pubkey.trim().starts_with("age1"));
}
#[test]
fn test_setup_idempotent_without_force() {
let t = Test::new();
let output = t.cmd().arg("setup").output().unwrap();
assert_success(&output);
let pubkey_path = t.home.path().join(".dugout/identity.pub");
let first_pubkey = fs::read_to_string(&pubkey_path).unwrap();
let output = t.cmd().arg("setup").output().unwrap();
assert_success(&output);
assert_stdout_contains(&output, "already exists");
let second_pubkey = fs::read_to_string(&pubkey_path).unwrap();
assert_eq!(
first_pubkey, second_pubkey,
"public key should not change without --force"
);
}
#[test]
fn test_setup_with_force_overwrites() {
let t = Test::new();
let output = t.cmd().arg("setup").output().unwrap();
assert_success(&output);
let pubkey_path = t.home.path().join(".dugout/identity.pub");
let first_pubkey = fs::read_to_string(&pubkey_path).unwrap();
let output = t.cmd().args(["setup", "--force"]).output().unwrap();
assert_success(&output);
assert_stdout_contains(&output, "generated identity");
let second_pubkey = fs::read_to_string(&pubkey_path).unwrap();
assert_ne!(
first_pubkey, second_pubkey,
"public key should change with --force"
);
}
#[test]
fn test_whoami_prints_public_key() {
let t = Test::new();
let setup_output = t.cmd().arg("setup").output().unwrap();
assert_success(&setup_output);
let output = t.cmd().arg("whoami").output().unwrap();
assert_success(&output);
let output_str = stdout(&output);
assert!(output_str.trim().starts_with("age1"));
let pubkey_path = t.home.path().join(".dugout/identity.pub");
let expected_pubkey = fs::read_to_string(&pubkey_path).unwrap();
assert_eq!(output_str.trim(), expected_pubkey.trim());
}
#[test]
fn test_whoami_without_setup_fails() {
let t = Test::new();
let output = t.cmd().arg("whoami").output().unwrap();
assert_failure(&output);
assert_stderr_contains(&output, "no identity found");
assert_stdout_contains(&output, "dugout setup");
}
#[test]
fn test_setup_then_init_uses_global_identity() {
let t = Test::new();
let output = t.cmd().arg("setup").output().unwrap();
assert_success(&output);
let pubkey_path = t.home.path().join(".dugout/identity.pub");
let global_pubkey = fs::read_to_string(&pubkey_path).unwrap();
let output = t.cmd().arg("init").output().unwrap();
assert_success(&output);
let output = t
.cmd()
.args(["set", "DB_PASSWORD", "s3cret"])
.output()
.unwrap();
assert_success(&output);
let output = t.cmd().args(["get", "DB_PASSWORD"]).output().unwrap();
assert_success(&output);
assert_eq!(stdout(&output).trim(), "s3cret");
let output = t.cmd().args(["team", "list", "--json"]).output().unwrap();
assert_success(&output);
assert!(
stdout(&output).contains(global_pubkey.trim()),
"vault recipient should be the global identity key"
);
}
#[test]
fn test_setup_then_init_dot_works() {
let t = Test::new();
let output = t.cmd().arg("setup").output().unwrap();
assert_success(&output);
let output = t.cmd().arg("init").output().unwrap();
assert_success(&output);
let output = t.cmd().args(["set", "MY_KEY", "12345"]).output().unwrap();
assert_success(&output);
fs::write(t.dir.path().join("Makefile"), "dev:\n\techo test\n").unwrap();
let output = t.cmd().arg(".").output().unwrap();
let combined = format!("{}{}", stdout(&output), stderr(&output));
assert!(
!combined.contains("no access"),
"should have access after setup+init, got: {combined}"
);
assert!(
!combined.contains("knock"),
"should not suggest knock after setup+init, got: {combined}"
);
}
#[test]
fn test_setup_output_includes_paths() {
let t = Test::new();
let output = t.cmd().arg("setup").output().unwrap();
assert_success(&output);
assert_stdout_contains(&output, "generated identity");
let out = stdout(&output);
assert!(out.contains("age1")); }
#[test]
fn test_open_falls_back_to_global_identity_when_project_key_stale() {
use age::secrecy::ExposeSecret;
let t = Test::new();
let output = t.cmd().arg("setup").output().unwrap();
assert_success(&output);
let output = t.cmd().args(["init", "--name", "alice"]).output().unwrap();
assert_success(&output);
let output = t
.cmd()
.args(["set", "FALLBACK_KEY", "fallback_value"])
.output()
.unwrap();
assert_success(&output);
let project_id = t
.dir
.path()
.file_name()
.unwrap()
.to_string_lossy()
.to_string();
let project_identity_path = t
.home
.path()
.join(".dugout/keys")
.join(project_id)
.join("identity.key");
let stale_identity = age::x25519::Identity::generate();
let stale_secret = stale_identity.to_string();
fs::write(
&project_identity_path,
format!("{}\n", stale_secret.expose_secret()),
)
.unwrap();
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
fs::set_permissions(&project_identity_path, fs::Permissions::from_mode(0o600)).unwrap();
}
let output = t.cmd().args(["get", "FALLBACK_KEY"]).output().unwrap();
assert_success(&output);
assert_eq!(stdout(&output).trim(), "fallback_value");
}