use std::fs;
use std::process::Command;
use insta_cmd::assert_cmd_snapshot;
fn bin() -> &'static str {
env!("CARGO_BIN_EXE_monosecret")
}
fn test_home(name: &str) -> std::path::PathBuf {
let home = std::path::PathBuf::from(format!("/tmp/monosecret-cli-snapshots-{name}"));
let _ = fs::remove_dir_all(&home);
home
}
fn snapshot_settings() -> insta::Settings {
let mut settings = insta::Settings::clone_current();
settings.add_filter(r"/private/var/folders/\S+", "[TMPDIR]");
settings.add_filter(r"/var/folders/\S+", "[TMPDIR]");
settings.add_filter(r"/tmp/\S+", "[TMPDIR]");
settings.add_filter(r"/home/runner/work/_temp/\S+", "[TMPDIR]");
settings.add_filter(r"[A-Z]:/Users/\S+/AppData/Local/Temp/\S+", "[TMPDIR]");
settings.add_filter(r"[A-Z]:/a/_temp/\S+", "[TMPDIR]");
settings.add_filter(r"note: \S+ is now recording \S+ access to \S+[^\n]*\n", "");
settings.add_filter(r"monosecret\.exe", "monosecret");
settings.add_filter(r"dotenv://\[TMPDIR\].*", "dotenv://[TMPDIR]...");
settings
}
fn forward_slashes(p: &std::path::Path) -> String {
p.display().to_string().replace('\\', "/")
}
fn write_config(dir: &std::path::Path, toml: &str) {
fs::write(dir.join("monosecret.toml"), toml).unwrap();
}
#[test]
fn help_output() {
let mut cmd = Command::new(bin());
cmd.arg("--help");
snapshot_settings().bind(|| {
assert_cmd_snapshot!(cmd);
});
}
#[test]
fn schema_and_check_json_are_value_free() {
let dir = tempfile::tempdir().unwrap();
write_config(
dir.path(),
r#"
[project]
name = "demo"
revision = "1.0"
[profiles.default]
TOKEN = { description = "token", required = true }
OPTIONAL = { description = "optional", required = false }
"#,
);
let env_path = dir.path().join("values.env");
fs::write(&env_path, "TOKEN=super-secret-value\n").unwrap();
let schema = Command::new(bin())
.args([
"--file",
dir.path().join("monosecret.toml").to_str().unwrap(),
"schema",
])
.output()
.unwrap();
assert!(schema.status.success());
let schema: serde_json::Value = serde_json::from_slice(&schema.stdout).unwrap();
assert_eq!(
schema.get("title").and_then(serde_json::Value::as_str),
Some("Monosecret")
);
let report = Command::new(bin())
.args([
"--file",
dir.path().join("monosecret.toml").to_str().unwrap(),
"check",
"--json",
"--provider",
&format!("dotenv:{}", env_path.display()),
])
.env("HOME", dir.path())
.output()
.unwrap();
assert!(
report.status.success(),
"{}",
String::from_utf8_lossy(&report.stderr)
);
let report_text = String::from_utf8(report.stdout).unwrap();
assert!(!report_text.contains("super-secret-value"));
let report: serde_json::Value = serde_json::from_str(&report_text).unwrap();
let entries = report
.get("secrets")
.and_then(serde_json::Value::as_array)
.expect("report secrets array");
assert_eq!(
entries
.first()
.and_then(|entry| entry.get("name"))
.and_then(serde_json::Value::as_str),
Some("OPTIONAL")
);
assert_eq!(
entries
.get(1)
.and_then(|entry| entry.get("name"))
.and_then(serde_json::Value::as_str),
Some("TOKEN")
);
}
#[test]
fn manifest_json() {
let dir = tempfile::tempdir().unwrap();
write_config(
dir.path(),
r#"
[project]
name = "demo"
revision = "1.0"
[providers]
local = "dotenv://.env"
[profiles.default]
DATABASE_URL = { description = "PostgreSQL connection string", required = true }
API_TOKEN = { description = "API authentication token", required = true, generate = true, type = "password" }
OPTIONAL = { description = "Optional config", required = false, default = "not-a-secret" }
"#,
);
let mut cmd = Command::new(bin());
cmd.env("HOME", test_home("manifest-json"))
.current_dir(dir.path())
.args(["manifest", "--format", "json"]);
snapshot_settings().bind(|| {
assert_cmd_snapshot!(cmd);
});
}
#[test]
fn env_dotenv() {
let dir = tempfile::tempdir().unwrap();
let dotenv = dir.path().join(".env");
fs::write(
&dotenv,
"DATABASE_URL=postgres://localhost\nAPI_TOKEN=secret\n",
)
.unwrap();
write_config(
dir.path(),
&format!(
r#"
[project]
name = "demo"
revision = "1.0"
[providers]
local = "dotenv://{}"
[profiles.default]
DATABASE_URL = {{ description = "Database URL", required = true, providers = ["local"] }}
API_TOKEN = {{ description = "API token", required = true, providers = ["local"] }}
"#,
forward_slashes(&dotenv)
),
);
let mut cmd = Command::new(bin());
cmd.env("HOME", test_home("env-dotenv"));
cmd.current_dir(dir.path()).args([
"--reason",
"test",
"env",
"--shell",
"dotenv",
"--provider",
"local",
]);
snapshot_settings().bind(|| {
assert_cmd_snapshot!(cmd);
});
}
#[test]
fn env_bash() {
let dir = tempfile::tempdir().unwrap();
let dotenv = dir.path().join(".env");
fs::write(
&dotenv,
"DATABASE_URL=postgres://localhost\nAPI_TOKEN=secret\n",
)
.unwrap();
write_config(
dir.path(),
&format!(
r#"
[project]
name = "demo"
revision = "1.0"
[providers]
local = "dotenv://{}"
[profiles.default]
DATABASE_URL = {{ description = "Database URL", required = true, providers = ["local"] }}
API_TOKEN = {{ description = "API token", required = true, providers = ["local"] }}
"#,
forward_slashes(&dotenv)
),
);
let mut cmd = Command::new(bin());
cmd.env("HOME", test_home("env-bash"));
cmd.current_dir(dir.path()).args([
"--reason",
"test",
"env",
"--shell",
"bash",
"--provider",
"local",
]);
snapshot_settings().bind(|| {
assert_cmd_snapshot!(cmd);
});
}
#[test]
fn check_all_present() {
let dir = tempfile::tempdir().unwrap();
let dotenv = dir.path().join(".env");
fs::write(
&dotenv,
"DATABASE_URL=postgres://localhost\nAPI_TOKEN=secret\n",
)
.unwrap();
write_config(
dir.path(),
&format!(
r#"
[project]
name = "demo"
revision = "1.0"
[providers]
local = "dotenv://{}"
[profiles.default]
DATABASE_URL = {{ description = "Database URL", required = true, providers = ["local"] }}
API_TOKEN = {{ description = "API token", required = true, providers = ["local"] }}
"#,
forward_slashes(&dotenv)
),
);
let mut cmd = Command::new(bin());
cmd.env("HOME", test_home("check-all-present"));
cmd.current_dir(dir.path()).args([
"--reason",
"test",
"check",
"--no-prompt",
"--provider",
"local",
]);
snapshot_settings().bind(|| {
assert_cmd_snapshot!(cmd);
});
}
#[test]
fn check_missing_required() {
let dir = tempfile::tempdir().unwrap();
let dotenv = dir.path().join(".env");
fs::write(&dotenv, "").unwrap();
write_config(
dir.path(),
&format!(
r#"
[project]
name = "demo"
revision = "1.0"
[providers]
local = "dotenv://{}"
[profiles.default]
API_TOKEN = {{ description = "API token", required = true, providers = ["local"] }}
"#,
forward_slashes(&dotenv)
),
);
let mut cmd = Command::new(bin());
cmd.env("HOME", test_home("check-missing-required"));
cmd.current_dir(dir.path()).args([
"--reason",
"test",
"check",
"--no-prompt",
"--provider",
"local",
]);
snapshot_settings().bind(|| {
assert_cmd_snapshot!(cmd);
});
}
#[test]
fn get_secret_value() {
let dir = tempfile::tempdir().unwrap();
let dotenv = dir.path().join(".env");
fs::write(&dotenv, "API_TOKEN=my-secret-token\n").unwrap();
write_config(
dir.path(),
&format!(
r#"
[project]
name = "demo"
revision = "1.0"
[providers]
local = "dotenv://{}"
[profiles.default]
API_TOKEN = {{ description = "API token", required = true, providers = ["local"] }}
"#,
forward_slashes(&dotenv)
),
);
let mut cmd = Command::new(bin());
cmd.env("HOME", test_home("get-secret-value"));
cmd.current_dir(dir.path()).args([
"--reason",
"test",
"get",
"API_TOKEN",
"--provider",
"local",
]);
snapshot_settings().bind(|| {
assert_cmd_snapshot!(cmd);
});
}
#[test]
fn get_secret_with_default() {
let dir = tempfile::tempdir().unwrap();
let dotenv = dir.path().join(".env");
fs::write(&dotenv, "").unwrap();
write_config(
dir.path(),
&format!(
r#"
[project]
name = "demo"
revision = "1.0"
[providers]
local = "dotenv://{}"
[profiles.default]
DATABASE_URL = {{ description = "Database URL", required = false, default = "postgres://localhost/dev", providers = ["local"] }}
"#,
forward_slashes(&dotenv)
),
);
let mut cmd = Command::new(bin());
cmd.env("HOME", test_home("get-secret-with-default"));
cmd.current_dir(dir.path()).args([
"--reason",
"test",
"get",
"DATABASE_URL",
"--provider",
"local",
]);
snapshot_settings().bind(|| {
assert_cmd_snapshot!(cmd);
});
}