{"record":{"id":"f5e8566ffd910752","repo":"Hmbown/CodeWhale","slug":"import-refused-non-interactive-use-requires-explicit-yes","errorCode":null,"errorMessage":"import refused: non-interactive use requires explicit --yes after reviewing the plan","messagePattern":"import refused: non-interactive use requires explicit --yes after reviewing the plan","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/cli/src/config_bundles.rs","lineNumber":1428,"sourceCode":"    let (_file, path) = backup\n        .keep()\n        .map_err(|error| error.error)\n        .context(\"persisting bundle backup\")?;\n    Ok(path)\n}\n\n// ---------------------------------------------------------------------------\n// Consent\n// ---------------------------------------------------------------------------\n\n/// Require explicit consent before mutating: interactive sessions get a\n/// prompt; headless runs require `--yes`.\npub fn require_import_consent(yes: bool, plan: &ImportPlan) -> Result<()> {\n    if yes {\n        return Ok(());\n    }\n    if !std::io::stdin().is_terminal() {\n        bail!(\n            \"import refused: non-interactive use requires explicit --yes after reviewing the plan\"\n        );\n    }\n    print!(\n        \"Apply this bundle ({} added, {} changed)? Type 'yes': \",\n        plan.added.len(),\n        plan.changed.len()\n    );\n    use std::io::Write;\n    std::io::stdout().flush()?;\n    let mut answer = String::new();\n    std::io::stdin()\n        .read_line(&mut answer)\n        .context(\"reading import consent\")?;\n    if answer.trim() != \"yes\" {\n        bail!(\"import cancelled; no configuration was changed\");\n    }\n    Ok(())","sourceCodeStart":1410,"sourceCodeEnd":1446,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/cli/src/config_bundles.rs#L1410-L1446","documentation":"require_import_consent enforces an explicit consent gate before applying a bundle. If --yes was not passed and stdin is not a TTY (non-interactive run), no interactive confirmation prompt can be shown, so the import is refused instead of mutating configuration without review.","triggerScenarios":"Running `config import` (apply_bundle path) from CI, a script, or any piped/non-TTY stdin without the --yes flag.","commonSituations":"Automation pipelines importing bundles headlessly; Docker/CI steps where stdin is not a terminal; forgetting --yes after previously running interactively.","solutions":["Run the import once with the dry-run/plan output to review what will be added/changed.","Re-run with `--yes` to confirm non-interactive application.","If the run should be interactive, ensure a real TTY is attached (no stdin redirect/piping)."],"exampleFix":"// before (CI)\ncodewhale config import bundle.toml\n// after\ncodewhale config import bundle.toml --yes","handlingStrategy":"validation","validationCode":"if !std::io::stdin().is_terminal() && !args_yes { eprintln!(\"non-interactive: pass --yes after reviewing the plan\"); std::process::exit(2); }\n","typeGuard":null,"tryCatchPattern":"match run_import(&args, &store) {\n    Err(e) if e.to_string().contains(\"requires explicit --yes\") => {\n        eprintln!(\"review the plan, then re-run with --yes\");\n    }\n    other => other?,\n}","preventionTips":["Always pass --yes in CI/scripted imports.","Gate scripts on is_terminal() before invoking interactive commands.","Run the dry-run/plan first and log it for audit before applying."],"tags":["cli","config","import","non-interactive","consent"],"backgroundTag":"missing-required-flag","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-22T06:17:15.046Z"}