use assert_cmd::Command;
use predicates::str::contains;
use tempfile::tempdir;
fn tsafe() -> Command {
Command::cargo_bin("tsafe").unwrap()
}
fn init_vault(dir: &std::path::Path) {
tsafe()
.args(["init"])
.env("TSAFE_VAULT_DIR", dir)
.env("TSAFE_PASSWORD", "test-pw")
.assert()
.success();
}
const FAKE_SSH_PRIVATE_KEY: &str =
"-----BEGIN OPENSSH PRIVATE KEY-----\nfakebase64content\n-----END OPENSSH PRIVATE KEY-----\n";
#[test]
fn ssh_list_empty_vault_prints_no_keys_message() {
let dir = tempdir().unwrap();
init_vault(dir.path());
tsafe()
.args(["ssh", "list"])
.env("TSAFE_VAULT_DIR", dir.path())
.env("TSAFE_PASSWORD", "test-pw")
.assert()
.success()
.stdout(contains("No SSH keys found"));
}
#[test]
fn ssh_list_shows_key_imported_via_ssh_import_command() {
let dir = tempdir().unwrap();
init_vault(dir.path());
let key_file = dir.path().join("id_test");
std::fs::write(&key_file, FAKE_SSH_PRIVATE_KEY).unwrap();
tsafe()
.args([
"ssh-import",
key_file.to_str().unwrap(),
"--name",
"TEST_SSH_KEY",
])
.env("TSAFE_VAULT_DIR", dir.path())
.env("TSAFE_PASSWORD", "test-pw")
.assert()
.success();
tsafe()
.args(["ssh", "list"])
.env("TSAFE_VAULT_DIR", dir.path())
.env("TSAFE_PASSWORD", "test-pw")
.assert()
.success()
.stdout(contains("TEST_SSH_KEY"));
}
#[test]
fn ssh_list_shows_key_stored_with_ssh_tag() {
let dir = tempdir().unwrap();
init_vault(dir.path());
let key_file = dir.path().join("id_tagged");
std::fs::write(&key_file, FAKE_SSH_PRIVATE_KEY).unwrap();
tsafe()
.args([
"ssh-import",
key_file.to_str().unwrap(),
"--name",
"TAGGED_KEY",
"--tag",
"env=ci",
])
.env("TSAFE_VAULT_DIR", dir.path())
.env("TSAFE_PASSWORD", "test-pw")
.assert()
.success();
tsafe()
.args(["ssh", "list"])
.env("TSAFE_VAULT_DIR", dir.path())
.env("TSAFE_PASSWORD", "test-pw")
.assert()
.success()
.stdout(contains("TAGGED_KEY"));
}
#[test]
fn ssh_public_key_missing_key_errors_with_hint() {
let dir = tempdir().unwrap();
init_vault(dir.path());
tsafe()
.args(["ssh", "public-key", "DOES_NOT_EXIST"])
.env("TSAFE_VAULT_DIR", dir.path())
.env("TSAFE_PASSWORD", "test-pw")
.assert()
.failure()
.stderr(contains("DOES_NOT_EXIST"))
.stderr(contains("not found"));
}
#[test]
fn ssh_public_key_non_ssh_secret_errors() {
let dir = tempdir().unwrap();
init_vault(dir.path());
tsafe()
.args(["set", "PLAIN_SECRET", "notaprivatekey"])
.env("TSAFE_VAULT_DIR", dir.path())
.env("TSAFE_PASSWORD", "test-pw")
.assert()
.success();
tsafe()
.args(["ssh", "public-key", "PLAIN_SECRET"])
.env("TSAFE_VAULT_DIR", dir.path())
.env("TSAFE_PASSWORD", "test-pw")
.assert()
.failure()
.stderr(contains("does not appear to be an SSH private key"));
}
#[test]
fn ssh_generate_ed25519_stores_private_key_in_vault() {
if std::process::Command::new("ssh-keygen")
.args(["-V"])
.output()
.is_err()
{
eprintln!(
"skipping ssh_generate_ed25519_stores_private_key_in_vault: ssh-keygen not found"
);
return;
}
let dir = tempdir().unwrap();
init_vault(dir.path());
tsafe()
.args(["ssh", "generate", "MY_DEPLOY_KEY"])
.env("TSAFE_VAULT_DIR", dir.path())
.env("TSAFE_PASSWORD", "test-pw")
.assert()
.success()
.stdout(contains("Generated ed25519 SSH key pair"))
.stdout(contains("MY_DEPLOY_KEY"))
.stdout(contains("ssh-ed25519"));
tsafe()
.args(["get", "MY_DEPLOY_KEY"])
.env("TSAFE_VAULT_DIR", dir.path())
.env("TSAFE_PASSWORD", "test-pw")
.assert()
.success()
.stdout(contains("PRIVATE KEY"));
tsafe()
.args(["ssh", "list"])
.env("TSAFE_VAULT_DIR", dir.path())
.env("TSAFE_PASSWORD", "test-pw")
.assert()
.success()
.stdout(contains("MY_DEPLOY_KEY"));
}
#[test]
fn ssh_public_key_extracted_after_generate() {
if std::process::Command::new("ssh-keygen")
.args(["-V"])
.output()
.is_err()
{
eprintln!("skipping ssh_public_key_extracted_after_generate: ssh-keygen not found");
return;
}
let dir = tempdir().unwrap();
init_vault(dir.path());
tsafe()
.args(["ssh", "generate", "EXTRACT_KEY"])
.env("TSAFE_VAULT_DIR", dir.path())
.env("TSAFE_PASSWORD", "test-pw")
.assert()
.success();
tsafe()
.args(["ssh", "public-key", "EXTRACT_KEY"])
.env("TSAFE_VAULT_DIR", dir.path())
.env("TSAFE_PASSWORD", "test-pw")
.assert()
.success()
.stdout(contains("ssh-ed25519"));
}