{"record":{"id":"232c4793f797c9f3","repo":"Hmbown/CodeWhale","slug":"external-credential-consent-was-not-saved-non-int","errorCode":null,"errorMessage":"external credential consent was not saved: non-interactive use requires explicit --yes after reviewing the preview","messagePattern":"external credential consent was not saved: non-interactive use requires explicit --yes after reviewing the preview","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/cli/src/lib.rs","lineNumber":3959,"sourceCode":"            \"  access: read_only ({})\",\n            codewhale_config::EXTERNAL_CREDENTIAL_READ_ONLY_SEMANTICS\n        ),\n        \"  managed: unavailable (no reviewed schema-safe preservation adapter)\".to_string(),\n        format!(\n            \"  revoke: codewhale auth external-revoke --provider {}\",\n            provider.as_str()\n        ),\n    ]\n}\n\nfn confirm_external_consent(yes: bool) -> Result<()> {\n    use std::io::IsTerminal;\n\n    if yes {\n        return Ok(());\n    }\n    if !std::io::stdin().is_terminal() {\n        bail!(\n            \"external credential consent was not saved: non-interactive use requires explicit --yes after reviewing the preview\"\n        );\n    }\n    confirm_external_consent_answer(&mut std::io::stdin().lock(), &mut std::io::stdout().lock())\n}\n\nfn confirm_external_consent_answer(\n    reader: &mut impl std::io::BufRead,\n    writer: &mut impl std::io::Write,\n) -> Result<()> {\n    write!(writer, \"Type 'yes' to grant this exact read-only access: \")?;\n    writer.flush()?;\n    let mut answer = String::new();\n    reader\n        .read_line(&mut answer)\n        .context(\"reading external credential consent confirmation\")?;\n    if answer.trim() != \"yes\" {\n        bail!(\"external credential consent cancelled; no configuration was changed\");","sourceCodeStart":3941,"sourceCodeEnd":3977,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/cli/src/lib.rs#L3941-L3977","documentation":"`confirm_external_consent` guards credential-consent writes: if `--yes` was not passed and stdin is not a terminal (piped, redirected, CI, daemon), Codewhale refuses to save consent rather than hang on an invisible prompt. The fix named in the message is to review the printed preview lines and pass an explicit `--yes`.","triggerScenarios":"Running the external-credentials command without `--yes` in CI, cron, Docker, or with stdin piped from a file/heredoc; SSH one-liners without a TTY; scripts calling the command non-interactively.","commonSituations":"Automation pipelines that were tested interactively first; containerized runs where /dev/null is stdin; `curl | sh`-style bootstrap scripts.","solutions":["Add `--yes` after reviewing the consent preview the command prints","Run the command in an interactive terminal and type `yes` at the prompt","For scripts, capture the preview in a log first, then re-run with `--yes` so the grant is auditable"],"exampleFix":"# before (CI job, stdin not a tty)\n$ codewhale external-credentials --provider grok --mode read-only < /dev/null\n# external credential consent was not saved...\n\n# after\n$ codewhale external-credentials --provider grok --mode read-only --yes","handlingStrategy":"validation","validationCode":"#!/usr/bin/env bash\nif [ ! -t 0 ]; then\n  # non-interactive context: consent must be pre-approved\n  exec codewhale external-credentials --provider grok --mode read-only --yes\nfi\nexec codewhale external-credentials --provider grok --mode read-only","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Gate automation on TTY detection and inject `--yes` only there","Log the printed consent preview next to the `--yes` run so grants stay auditable"],"tags":["consent","non-interactive","ci","tty","cli","credentials"],"backgroundTag":"tty-required","analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}