# CTRL-C Handling for Sudo Password Prompts\n\n## Problem\n\nWhen running `provisioning -c server create` with `fix_local_hosts: true`, the command\nmodifies `/etc/hosts` and SSH config files using `sudo`. If the user presses CTRL-C during\nthe password prompt, the operation exits with a non-zero code causing:\n\n1. Cryptic error messages about pipeline input and non-zero exit codes\n2. Incomplete server setup with null values propagating up the call stack\n3. Poor user experience with no clear indication of what happened\n\n## Solution\n\n**IMPORTANT**: Due to Unix signal handling, pressing CTRL-C at the sudo password prompt will interrupt the entire Nushell process. This is **expected\nbehavior** and cannot be prevented.\n\nHowever, the system **does** gracefully handle these cancellation scenarios:\n\n### 1. Pre-emptive Warning (User Awareness)\n\nWhen `fix_local_hosts` is enabled and sudo credentials are not cached, display a clear warning:\n\n```\n⚠ Sudo access required for --fix-local-hosts\nℹ You will be prompted for your password, or press CTRL-C to cancel\n  Tip: Run 'sudo -v' beforehand to cache credentials\n```\n\n### 2. Password Cancellation Detection (Graceful Exit)\n\nAll sudo commands are wrapped with error handling that detects password cancellation:\n\n**Scenarios handled gracefully:**\n\n- No password provided (press Enter at prompt)\n- Wrong password 3 times\n- Sudo timeout\n\n```\nlet result = (do --ignore-errors { ^sudo <command> } | complete)\n# Check for cancellation: exit code 1 (password required) or 130 (timeout/failure)\nif ($result.exit_code == 1 and ($result.stderr | str contains "password is required")) or $result.exit_code == 130 {\n  print "\n⚠ Operation cancelled - sudo password required but not provided"\n  print "ℹ Run 'sudo -v' first to cache credentials, or run without --fix-local-hosts"\n  return false  # Return false to signal cancellation, let caller handle gracefully\n}\n```\n\n**Not handled** (Unix limitation):\n\n- CTRL-C at password prompt → SIGINT interrupts entire process\n\n### 3. Helper Functions (Code Reuse)\n\nAdded reusable helper functions for consistent handling:\n\n- `check_sudo_cached`: Checks if sudo credentials are already cached\n- `run_sudo_with_interrupt_check`: Wraps sudo commands with CTRL-C detection\n\n## User Workflows\n\n### Option 1: Cache Credentials First (Recommended)\n\n```\nsudo -v  # Cache credentials for 5 minutes\nprovisioning -c server create\n```\n\n### Option 2: Enter Password When Prompted\n\n```\nprovisioning -c server create\n# Enter password when prompted\n# Press CTRL-C to cancel if needed\n```\n\n### Option 3: Disable /etc/hosts Modification\n\nIn your settings file, set:\n\n```\nfix_local_hosts = false\n```\n\n## Technical Details\n\n### Return Values\n\nFunctions that require sudo now return:\n\n- **true**: Operation succeeded\n- **false**: Operation cancelled (no password / wrong password / timeout)\n- **error**: Actual failure (throws exception)\n\n### Detection Logic\n\nThe implementation detects password cancellation by checking:\n\n1. Exit code is 1 (sudo failed) AND stderr contains "password is required"\n2. OR exit code is 130 (timeout/failure)\n\n**Handled gracefully**:\n\n- No password provided (press Enter at prompt)\n- Wrong password 3 times\n- Sudo timeout\n\n**Not handled** (Unix signal limitation):\n\n- CTRL-C at password prompt → SIGINT interrupts entire Nushell process\n\nWhen you press CTRL-C at an external command's interactive prompt, SIGINT is sent to the\nentire process group. Nushell's signal handler catches this before `complete` can capture\nthe exit code. This is fundamental Unix behavior and cannot be prevented.\n\n### Files Modified\n\n- `provisioning/core/nulib/servers/ssh.nu`:\n  - Added `check_sudo_cached()` helper\n  - Added `run_sudo_with_interrupt_check()` helper (returns bool)\n  - Added pre-check warning in `on_server_ssh()`\n  - Wrapped all sudo commands with CTRL-C detection\n  - Modified `on_server_ssh()` to return false on cancellation\n  - Modified `server_ssh()` to propagate cancellation status\n\n- `provisioning/core/nulib/servers/create.nu`:\n  - Added return value check for `on_server_ssh()`\n  - Returns false with clear message on cancellation\n\n- `provisioning/core/nulib/servers/generate.nu`:\n  - Added return value check for `on_server_ssh()`\n  - Returns false with clear message on cancellation\n\n## Testing\n\nTest the CTRL-C handling:\n\n```\n# Test 1: Cancel at password prompt\nprovisioning -c server create\n# When prompted for password, press CTRL-C\n# Expected: Clean exit with helpful message\n\n# Test 2: Pre-cached credentials\nsudo -v\nprovisioning -c server create\n# Expected: No password prompt, seamless operation\n\n# Test 3: Without fix_local_hosts\n# Set fix_local_hosts = false in settings\nprovisioning -c server create\n# Expected: No sudo required, no password prompt\n```\n\n## Best Practices\n\n1. **For Interactive Use**: Cache sudo credentials before long-running operations\n\n   ```bash\n   sudo -v && provisioning -c server create\n   ```\n\n1. **For Automation**: Disable `fix_local_hosts` in CI/CD environments\n\n   ```kcl\n   fix_local_hosts = false  # No sudo needed\n   ```\n\n2. **For Development**: Keep sudo credentials cached\n\n   ```bash\n   # In .bashrc or .zshrc\n   alias prvng='sudo -v && provisioning'\n   ```\n\n## Error Messages\n\n### Before (Cryptic)\n\n```\nPassword:\nsudo: a password is required\nError: nu::shell::eval_block_with_input\n  × Eval block failed with pipeline input\nError: nu::shell::non_zero_exit_code\n  × External command had a non-zero exit code\n    exited with code 1\n```\n\n### After (Clear)\n\n```\n⚠ Sudo access required for --fix-local-hosts\nℹ You will be prompted for your password, or press CTRL-C to cancel\n  Tip: Run 'sudo -v' beforehand to cache credentials\n\nPassword: [CTRL-C pressed]\n\n⚠ Operation cancelled - sudo password required but not provided\nℹ Run 'sudo -v' first to cache credentials, or run without --fix-local-hosts\n```\n\n## Related\n\n- Issue: Server creation fails with sudo password prompt\n- Related: CTRL-C handling in all external command invocations\n- See also: `docs/configuration/security.md` for sudo-less alternatives
