//! End-to-end credential store behavior through the `smith auth` CLI //! (`SMH-SPEC-SPEC0001`, Providers: authentication). use assert_cmd::Command; use std::path::PathBuf; fn scratch(name: &str) -> PathBuf { std::env::temp_dir().join(format!("smith-auth-test-{name}-{}", std::process::id())) } fn smith(name: &str) -> Command { let mut command = Command::cargo_bin("smith").unwrap(); command .env("XDG_DATA_HOME", scratch(name)) .env_remove("ANTHROPIC_API_KEY") .env_remove("OPENAI_API_KEY") .env_remove("GEMINI_API_KEY"); command } #[test] fn add_list_remove_round_trips_with_user_only_permissions() { let mut add = smith("roundtrip"); add.args(["auth", "add", "--provider", "anthropic"]) .write_stdin("sk-test-secret\n") .assert() .success() .stdout("anthropic: stored\n"); let mut list = smith("roundtrip"); list.args(["auth", "list"]) .assert() .success() .stdout("anthropic: store\n"); let mut check = smith("roundtrip"); check .args(["auth", "check", "--provider", "anthropic"]) .assert() .success() .stdout("anthropic: store\n"); let mut remove = smith("roundtrip"); remove .args(["auth", "remove", "--provider", "anthropic"]) .assert() .success() .stdout("anthropic: removed\n"); let mut gone = smith("roundtrip"); gone.args(["auth", "check", "--provider", "anthropic"]) .assert() .failure() .stderr(predicates::str::contains( "no credential for anthropic (tried store, env ANTHROPIC_API_KEY)", )); let mut empty = smith("roundtrip"); empty .args(["auth", "remove", "--provider", "anthropic"]) .assert() .failure() .stderr(predicates::str::contains( "no stored credential for anthropic", )); } #[test] fn stored_secret_never_prints_and_permissions_are_user_only() { let mut add = smith("hygiene"); add.args(["auth", "add", "--provider", "openai"]) .write_stdin("sk-super-secret-value\n") .assert() .success(); let secret_file = scratch("hygiene").join("smith/auth/openai"); #[cfg(unix)] { use std::os::unix::fs::PermissionsExt; let mode = std::fs::metadata(&secret_file) .unwrap() .permissions() .mode(); assert_eq!(mode & 0o777, 0o600); } let mut list = smith("hygiene"); list.args(["auth", "list"]) .assert() .stdout("openai: store\n"); } #[test] fn check_reports_environment_source() { let mut check = smith("envsource"); check .args(["auth", "check", "--provider", "google"]) .env("GEMINI_API_KEY", "sk-env") .assert() .success() .stdout("google: env:GEMINI_API_KEY\n"); }