# CTRL-C Handling for Sudo Password Prompts

## Problem

When running `provisioning -c server create` with `fix_local_hosts: true`, the command modifies `/etc/hosts` and SSH config files using `sudo`. If the user presses CTRL-C during the password prompt, the operation exits with a non-zero code causing:

1. Cryptic error messages about pipeline input and non-zero exit codes
2. Incomplete server setup with null values propagating up the call stack
3. Poor user experience with no clear indication of what happened

## Solution

**IMPORTANT**: Due to Unix signal handling, pressing CTRL-C at the sudo password prompt will interrupt the entire Nushell process. This is **expected behavior** and cannot be prevented.

However, the system **does** gracefully handle these cancellation scenarios:

### 1. Pre-emptive Warning (User Awareness)

When `fix_local_hosts` is enabled and sudo credentials are not cached, display a clear warning:

```plaintext
⚠ Sudo access required for --fix-local-hosts
ℹ You will be prompted for your password, or press CTRL-C to cancel
  Tip: Run 'sudo -v' beforehand to cache credentials
```plaintext

### 2. Password Cancellation Detection (Graceful Exit)

All sudo commands are wrapped with error handling that detects password cancellation:

**Scenarios handled gracefully:**

- No password provided (press Enter at prompt)
- Wrong password 3 times
- Sudo timeout

```nushell
let result = (do --ignore-errors { ^sudo <command> } | complete)
# Check for cancellation: exit code 1 (password required) or 130 (timeout/failure)
if ($result.exit_code == 1 and ($result.stderr | str contains "password is required")) or $result.exit_code == 130 {
  print "\n⚠ Operation cancelled - sudo password required but not provided"
  print "ℹ Run 'sudo -v' first to cache credentials, or run without --fix-local-hosts"
  return false  # Return false to signal cancellation, let caller handle gracefully
}
```plaintext

**Not handled** (Unix limitation):

- CTRL-C at password prompt → SIGINT interrupts entire process

### 3. Helper Functions (Code Reuse)

Added reusable helper functions for consistent handling:

- `check_sudo_cached`: Checks if sudo credentials are already cached
- `run_sudo_with_interrupt_check`: Wraps sudo commands with CTRL-C detection

## User Workflows

### Option 1: Cache Credentials First (Recommended)

```bash
sudo -v  # Cache credentials for 5 minutes
provisioning -c server create
```plaintext

### Option 2: Enter Password When Prompted

```bash
provisioning -c server create
# Enter password when prompted
# Press CTRL-C to cancel if needed
```plaintext

### Option 3: Disable /etc/hosts Modification

In your settings file, set:

```kcl
fix_local_hosts = false
```plaintext

## Technical Details

### Return Values

Functions that require sudo now return:

- **true**: Operation succeeded
- **false**: Operation cancelled (no password / wrong password / timeout)
- **error**: Actual failure (throws exception)

### Detection Logic

The implementation detects password cancellation by checking:

1. Exit code is 1 (sudo failed) AND stderr contains "password is required"
2. OR exit code is 130 (timeout/failure)

**Handled gracefully**:

- No password provided (press Enter at prompt)
- Wrong password 3 times
- Sudo timeout

**Not handled** (Unix signal limitation):

- CTRL-C at password prompt → SIGINT interrupts entire Nushell process

When you press CTRL-C at an external command's interactive prompt, SIGINT is sent to the entire process group. Nushell's signal handler catches this before the `complete` command can capture the exit code. This is fundamental Unix behavior and cannot be prevented.

### Files Modified

- `provisioning/core/nulib/servers/ssh.nu`:
    - Added `check_sudo_cached()` helper
    - Added `run_sudo_with_interrupt_check()` helper (returns bool)
    - Added pre-check warning in `on_server_ssh()`
    - Wrapped all sudo commands with CTRL-C detection
    - Modified `on_server_ssh()` to return false on cancellation
    - Modified `server_ssh()` to propagate cancellation status

- `provisioning/core/nulib/servers/create.nu`:
    - Added return value check for `on_server_ssh()`
    - Returns false with clear message on cancellation

- `provisioning/core/nulib/servers/generate.nu`:
    - Added return value check for `on_server_ssh()`
    - Returns false with clear message on cancellation

## Testing

Test the CTRL-C handling:

```bash
# Test 1: Cancel at password prompt
provisioning -c server create
# When prompted for password, press CTRL-C
# Expected: Clean exit with helpful message

# Test 2: Pre-cached credentials
sudo -v
provisioning -c server create
# Expected: No password prompt, seamless operation

# Test 3: Without fix_local_hosts
# Set fix_local_hosts = false in settings
provisioning -c server create
# Expected: No sudo required, no password prompt
```plaintext

## Best Practices

1. **For Interactive Use**: Cache sudo credentials before long-running operations

   ```bash
   sudo -v && provisioning -c server create
   ```

1. **For Automation**: Disable `fix_local_hosts` in CI/CD environments

   ```kcl
   fix_local_hosts = false  # No sudo needed
   ```

2. **For Development**: Keep sudo credentials cached

   ```bash
   # In .bashrc or .zshrc
   alias prvng='sudo -v && provisioning'
   ```

## Error Messages

### Before (Cryptic)

```plaintext
Password:
sudo: a password is required
Error: nu::shell::eval_block_with_input
  × Eval block failed with pipeline input
Error: nu::shell::non_zero_exit_code
  × External command had a non-zero exit code
    exited with code 1
```plaintext

### After (Clear)

```plaintext
⚠ Sudo access required for --fix-local-hosts
ℹ You will be prompted for your password, or press CTRL-C to cancel
  Tip: Run 'sudo -v' beforehand to cache credentials

Password: [CTRL-C pressed]

⚠ Operation cancelled - sudo password required but not provided
ℹ Run 'sudo -v' first to cache credentials, or run without --fix-local-hosts
```plaintext

## Related

- Issue: Server creation fails with sudo password prompt
- Related: CTRL-C handling in all external command invocations
- See also: `docs/configuration/security.md` for sudo-less alternatives
