//! `pic secrets` smoke tests. Covers set→ls→rm round trip and the //! "value must come from stdin" contract. use predicates::prelude::*; use crate::common; use crate::common::cleanup::AppGuard; #[ignore = "needs DATABASE_URL pointing at a running Postgres"] #[test] fn set_ls_rm_round_trip() { let Some(fx) = common::fixture_or_skip() else { return; }; let env = common::admin_env(fx); let slug = common::unique_slug("sec-rt"); common::pic_as(&env) .args(["apps", "create", &slug]) .assert() .success(); let _guard = AppGuard::new(&env.url, &env.token, &slug); // Set — value via stdin (the only valid channel). common::pic_as(&env) .args(["secrets", "set", "--app", &slug, "api_key"]) .write_stdin("xyzzy") .assert() .success() .stdout(predicate::str::contains("Set secret api_key")); // Ls — name appears, value never leaves the server. let out = common::pic_as(&env) .args(["secrets", "ls", "--app", &slug]) .output() .expect("secrets ls"); let stdout = String::from_utf8(out.stdout).unwrap(); let header = stdout.lines().next().expect("header"); assert_eq!(common::cells(header), vec!["name", "env", "updated_at"]); assert!( stdout.lines().skip(1).any(|l| l.starts_with("api_key")), "api_key missing from ls: {stdout}" ); // Rm — name dropped. common::pic_as(&env) .args(["secrets", "rm", "--app", &slug, "api_key"]) .assert() .success() .stdout(predicate::str::contains("Deleted secret api_key")); let out = common::pic_as(&env) .args(["secrets", "ls", "--app", &slug]) .output() .expect("secrets ls after rm"); let stdout = String::from_utf8(out.stdout).unwrap(); assert_eq!(stdout.lines().count(), 1, "no rows after rm: {stdout}"); } #[ignore = "needs DATABASE_URL pointing at a running Postgres"] #[test] fn set_empty_stdin_errors() { let Some(fx) = common::fixture_or_skip() else { return; }; let env = common::admin_env(fx); let slug = common::unique_slug("sec-empty"); common::pic_as(&env) .args(["apps", "create", &slug]) .assert() .success(); let _guard = AppGuard::new(&env.url, &env.token, &slug); common::pic_as(&env) .args(["secrets", "set", "--app", &slug, "anything"]) .write_stdin("") .assert() .failure() .stderr(predicate::str::contains( "empty stdin — secret value must not be empty", )); } #[ignore = "needs DATABASE_URL pointing at a running Postgres"] #[test] fn set_with_json_flag_round_trips_object() { let Some(fx) = common::fixture_or_skip() else { return; }; let env = common::admin_env(fx); let slug = common::unique_slug("sec-json"); common::pic_as(&env) .args(["apps", "create", &slug]) .assert() .success(); let _guard = AppGuard::new(&env.url, &env.token, &slug); common::pic_as(&env) .args(["secrets", "set", "--app", &slug, "cfg", "--json"]) .write_stdin(r#"{"endpoint":"https://example.com","retries":3}"#) .assert() .success(); // Ls confirms the name landed. let out = common::pic_as(&env) .args(["secrets", "ls", "--app", &slug]) .output() .expect("ls"); let stdout = String::from_utf8(out.stdout).unwrap(); assert!( stdout.lines().skip(1).any(|l| l.starts_with("cfg")), "cfg missing: {stdout}" ); }