Skip to content

Commit c576292

Browse files
committed
setup nuke: require stdout TTY so confirmation summary is visible
Redirecting stdout could hide the destructive summary while stdin stayed interactive. Check stdout().is_terminal() before stdin, bail with a clear message, and document in README, manual, and CLI help. Integration test expects the stdout requirement when both streams are piped. Made-with: Cursor
1 parent 7298ad2 commit c576292

File tree

5 files changed

+16
-6
lines changed

5 files changed

+16
-6
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ Use `decrypt --non-interactive` in CI with `A8C_SECRETS_IDENTITY` (or a key file
111111

112112
### Terminals, prompts, and private keys on stdout
113113
- **`setup init`** and **`keys rotate`** require **stdout** connected to a terminal so new private keys are not accidentally written to a file or pipe. `keys rotate` also needs **stdin** for its menus and confirmations.
114-
- **`setup nuke`** and **`rm`** (without `--non-interactive`) require **stdin** for confirmation prompts.
114+
- **`setup nuke`** requires **stdout** and **stdin** connected to a terminal (you must see the destructive summary before confirming). **`rm`** (without `--non-interactive`) requires **stdin** for confirmation prompts.
115115
- **`decrypt`** orphan handling uses **stdin** for the orphan prompt (unless `--non-interactive` is set or stdin is not an interactive terminal — see above).
116116
- **`edit`** is for interactive use (`$EDITOR`, optional create prompt).
117117

src/cli.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,8 @@ Deletes .a8c-secrets/ from the repo, the private key at
260260
~/.a8c-secrets/keys/<host>/<org>/<name>.key, and all decrypted files at
261261
~/.a8c-secrets/<host>/<org>/<name>/. Requires typing the repo identifier to confirm.
262262
263-
Requires stdin connected to a terminal to type the repo identifier confirmation.")]
263+
Requires stdout connected to a terminal so the destructive summary is visible (do not
264+
redirect stdout). Requires stdin connected to a terminal to type the confirmation.")]
264265
Nuke,
265266

266267
/// Output shell completion script

src/commands/setup/nuke.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,19 @@ use crate::keys;
88

99
/// Remove repo and local `a8c-secrets` data for the current repository.
1010
///
11+
/// Requires stdout and stdin to be terminals so the destructive summary and confirmation
12+
/// prompt are visible and typed interactively.
13+
///
1114
/// # Errors
1215
///
1316
/// Returns an error if repo/config discovery fails, user input fails, or any
1417
/// of the cleanup file operations fail.
1518
pub fn run() -> Result<()> {
19+
if !std::io::stdout().is_terminal() {
20+
anyhow::bail!(
21+
"`a8c-secrets setup nuke` must not redirect stdout — it prints a destructive summary and confirmation prompt. Run it in a terminal so you can see what you are confirming."
22+
);
23+
}
1624
if !std::io::stdin().is_terminal() {
1725
anyhow::bail!(
1826
"`a8c-secrets setup nuke` requires stdin connected to a terminal for confirmation."

src/manual.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@ GETTING STARTED
7373
7474
setup init and keys rotate require stdout connected to a terminal (private keys
7575
are printed; do not redirect). keys rotate also needs stdin for prompts. setup
76-
nuke and rm (without --non-interactive) need stdin for confirmation. edit uses
76+
nuke needs stdout and stdin (see the destructive summary before typing the repo id).
77+
rm (without --non-interactive) needs stdin for confirmation. edit uses
7778
$EDITOR and prompts; intended for interactive use.
7879
7980
If stdout is not a terminal, private key blocks are redacted in output (defense in

tests/commands_integration.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -794,13 +794,13 @@ fn setup_nuke_fails_without_tty_and_preserves_repo_secrets_key_and_decrypted() {
794794
.expect("wait_with_output on setup nuke");
795795
assert!(
796796
!out.status.success(),
797-
"setup nuke should fail when stdin is not a terminal"
797+
"setup nuke should fail when stdout/stdin are not terminals"
798798
);
799799
let combined =
800800
String::from_utf8_lossy(&out.stderr).to_string() + &String::from_utf8_lossy(&out.stdout);
801801
assert!(
802-
combined.contains("stdin") && combined.contains("terminal"),
803-
"expected stdin terminal requirement message, got: {combined}"
802+
combined.contains("stdout") && combined.contains("terminal"),
803+
"expected stdout terminal requirement message, got: {combined}"
804804
);
805805
assert!(
806806
repo_dir.join(".a8c-secrets").exists(),

0 commit comments

Comments
 (0)