|
| 1 | +# PR Review: feat/passwordless-sudo (Passwordless Sudo) |
| 2 | + |
| 3 | +**Branch:** `feat/passwordless-sudo` |
| 4 | +**PR file:** `PR_feat-passwordless-sudo.md` |
| 5 | +**Implementation plan:** `dev/IMPROVEMENTS/PASSWORDLESS_SUDO_IMPLEMENTATION_PLAN.md` |
| 6 | + |
| 7 | +This document summarizes the review of the passwordless sudo pull request, including security considerations, alignment with project standards (CONTRIBUTING.md, AGENTS.md), and concrete suggestions for improvements. **No code changes were made; this is review-only.** |
| 8 | + |
| 9 | +--- |
| 10 | + |
| 11 | +## 1. Summary of changes reviewed |
| 12 | + |
| 13 | +- **`src/logic/password.rs`** — `check_passwordless_sudo_available()`, `should_use_passwordless_sudo()`, password validation; test env var handling. |
| 14 | +- **`src/theme/types.rs`** — `Settings.use_passwordless_sudo`, `Default`. |
| 15 | +- **`src/theme/settings/parse_settings.rs`** — Parsing of `use_passwordless_sudo` (and aliases). |
| 16 | +- **`config/settings.conf`** — New option and comments. |
| 17 | +- **`src/install/direct.rs`** — Install/remove flows; when to show `PasswordPrompt` vs proceed with `None` password. |
| 18 | +- **`src/args/update.rs`** — CLI update path and its password/passwordless handling. |
| 19 | +- **`tests/passwordless_sudo/`** — Helpers, integration tests (install, update, remove, downgrade, filesync). |
| 20 | +- **`dev/PR/PR_feat-passwordless-sudo.md`** — PR description and checklist. |
| 21 | + |
| 22 | +--- |
| 23 | + |
| 24 | +## 2. Security review |
| 25 | + |
| 26 | +### 2.1 Critical: Test env var honored in production |
| 27 | + |
| 28 | +**Location:** `src/logic/password.rs` — `check_passwordless_sudo_available()` and `should_use_passwordless_sudo()`. |
| 29 | + |
| 30 | +**Finding:** |
| 31 | +`PACSEA_TEST_SUDO_PASSWORDLESS` is read in **all builds** (including release). If an attacker or script runs the application with `PACSEA_TEST_SUDO_PASSWORDLESS=1`, the app will treat passwordless sudo as enabled even when `use_passwordless_sudo` is `false` in settings. That bypasses the intended opt-in and weakens the safety barrier. |
| 32 | + |
| 33 | +**Suggestion:** |
| 34 | +- Honor `PACSEA_TEST_SUDO_PASSWORDLESS` only when the process is clearly in a test context, for example: |
| 35 | + - Only when another env var set exclusively by the test harness is present (e.g. `PACSEA_INTEGRATION_TEST=1`), or |
| 36 | + - When compiled with a test-only cfg (if you introduce a dedicated test binary or build profile that sets such a cfg). |
| 37 | +- In production code paths, ignore `PACSEA_TEST_SUDO_PASSWORDLESS` so that the only way to enable passwordless sudo is via `use_passwordless_sudo` in settings. |
| 38 | + |
| 39 | +### 2.2 Password handling |
| 40 | + |
| 41 | +**Location:** `src/logic/password.rs` — `validate_sudo_password()`. |
| 42 | + |
| 43 | +**Finding:** |
| 44 | +- Password is escaped with `shell_single_quote()` before being passed to the shell command. |
| 45 | +- No password is written to logs (e.g. in `args/update.rs`, the log uses a shape that omits the password). |
| 46 | + |
| 47 | +**Suggestion:** |
| 48 | +- Keep avoiding any logging or tracing of password content. |
| 49 | +- If you add more code paths that build shell commands with the password, consistently use the same escaping helper and avoid building commands via string concatenation with user input. |
| 50 | + |
| 51 | +### 2.3 Remove always requires password |
| 52 | + |
| 53 | +**Location:** `src/install/direct.rs` — `start_integrated_remove_all()`. |
| 54 | + |
| 55 | +**Finding:** |
| 56 | +Remove operations always show `PasswordPrompt`; there is no branch that skips it based on passwordless sudo. This matches the design (remove always requires authentication). |
| 57 | + |
| 58 | +**Suggestion:** |
| 59 | +None; behavior is correct. Optionally add a short comment in code that remove is intentionally excluded from passwordless sudo for safety. |
| 60 | + |
| 61 | +### 2.4 CLI update vs settings |
| 62 | + |
| 63 | +**Location:** `src/args/update.rs` — `prompt_and_validate_password()`. |
| 64 | + |
| 65 | +**Finding:** |
| 66 | +The CLI update path checks passwordless sudo with `sudo -n true` and skips the password prompt if that succeeds. It does **not** read `use_passwordless_sudo` from settings. So: |
| 67 | + |
| 68 | +- **TUI:** Respects `use_passwordless_sudo` (opt-in). |
| 69 | +- **CLI update:** Uses passwordless sudo whenever the system allows it, regardless of config. |
| 70 | + |
| 71 | +**Suggestion:** |
| 72 | +- Decide intended behavior: either (a) CLI update should also respect `use_passwordless_sudo` for consistency, or (b) document that CLI update always tries passwordless sudo when available. |
| 73 | +- If (a): load settings (or at least the flag) in the CLI update path and only skip the password prompt when both `sudo -n true` succeeds and `use_passwordless_sudo` is true. |
| 74 | + |
| 75 | +--- |
| 76 | + |
| 77 | +## 3. Code quality and project standards |
| 78 | + |
| 79 | +### 3.1 CONTRIBUTING.md / AGENTS.md |
| 80 | + |
| 81 | +- **Rust docs (What, Inputs, Output, Details):** Present and consistent in `password.rs`, `direct.rs`, theme types, and parse_settings. |
| 82 | +- **No `unwrap()` / `expect()` in non-test code:** The reviewed code uses `Result` and `unwrap_or_else` for defaults (e.g. `USER`); no inappropriate unwraps. |
| 83 | +- **Clippy:** Not re-run as part of this review; the PR checklist states it was run. |
| 84 | +- **Tests:** Integration tests in `tests/passwordless_sudo/` cover install (single/multiple, official/AUR), remove (always password), update, downgrade, filesync, and env var behavior. |
| 85 | +- **Complexity:** New functions in `password.rs` and `direct.rs` are short and linear; no obvious cyclomatic/complexity concerns. |
| 86 | + |
| 87 | +### 3.2 Configuration |
| 88 | + |
| 89 | +- **Default:** `use_passwordless_sudo: false` in `Settings::default()` — correct. |
| 90 | +- **Parsing:** `use_passwordless_sudo` and aliases (`passwordless_sudo`, `allow_passwordless_sudo`) in `parse_misc_settings` — consistent. |
| 91 | +- **Example config:** `config/settings.conf` documents the option and safety implications. |
| 92 | + |
| 93 | +### 3.3 Minor documentation improvements |
| 94 | + |
| 95 | +- In `password.rs`, the **Testing** paragraphs for the env var could state explicitly that this override must not be honored in production builds (once you restrict it as in 2.1). |
| 96 | +- In `direct.rs`, the docstrings for install flows already mention passwordless sudo; you could add one sentence that remove is intentionally always gated by password prompt. |
| 97 | + |
| 98 | +--- |
| 99 | + |
| 100 | +## 4. Suggestions for improvements (no code changes applied) |
| 101 | + |
| 102 | +### 4.1 Security |
| 103 | + |
| 104 | +| # | Suggestion | Priority | |
| 105 | +|---|------------|----------| |
| 106 | +| 1 | Restrict `PACSEA_TEST_SUDO_PASSWORDLESS` to test-only contexts (e.g. only when another test-only env var is set) so production builds never honor it. | High | |
| 107 | +| 2 | Align CLI update with TUI: either make CLI update respect `use_passwordless_sudo`, or document that CLI update always uses passwordless sudo when available. | Medium | |
| 108 | + |
| 109 | +### 4.2 Robustness and clarity |
| 110 | + |
| 111 | +| # | Suggestion | Priority | |
| 112 | +|---|------------|----------| |
| 113 | +| 3 | Add a one-line comment in `start_integrated_remove_all` that remove is intentionally never passwordless for safety. | Low | |
| 114 | +| 4 | In rustdoc for the test env var, clarify that the override is (or will be) disabled in production. | Low | |
| 115 | + |
| 116 | +### 4.3 Tests |
| 117 | + |
| 118 | +| # | Suggestion | Priority | |
| 119 | +|---|------------|----------| |
| 120 | +| 5 | Add an integration test that, when `PACSEA_TEST_SUDO_PASSWORDLESS` is unset (or not honored), install path shows password prompt when `use_passwordless_sudo` is false, even if the system has passwordless sudo. | Medium | |
| 121 | +| 6 | If CLI update is changed to respect settings, add a test (or doc example) that CLI update still prompts when `use_passwordless_sudo` is false. | Low | |
| 122 | + |
| 123 | +### 4.4 Documentation and PR |
| 124 | + |
| 125 | +| # | Suggestion | Priority | |
| 126 | +|---|------------|----------| |
| 127 | +| 7 | In the PR description or wiki, briefly document that remove operations always require a password, regardless of `use_passwordless_sudo`. | Low | |
| 128 | +| 8 | If you keep the test env var for integration tests, add a note in CONTRIBUTING or the test README that `PACSEA_TEST_SUDO_PASSWORDLESS` is for tests only and must not be set in production. | Low | |
| 129 | + |
| 130 | +--- |
| 131 | + |
| 132 | +## 5. Checklist vs review |
| 133 | + |
| 134 | +| PR checklist item | Review note | |
| 135 | +|-------------------|------------| |
| 136 | +| Code compiles, fmt, clippy, tests | Not re-run; PR states they pass. | |
| 137 | +| Complexity checks | New code appears within limits. | |
| 138 | +| Rust docs (What, Inputs, Output, Details) | Present on new/updated public API. | |
| 139 | +| No `unwrap()`/`expect()` in non-test code | Confirmed in reviewed files. | |
| 140 | +| Integration tests | 34 tests; cover main flows and remove-always-password. | |
| 141 | +| Config examples updated | `config/settings.conf` updated. | |
| 142 | +| Respects `--dry-run` | Not re-verified; PR states yes. | |
| 143 | +| Graceful degradation | Passwordless check failures fall back to password prompt. | |
| 144 | +| No breaking changes | Opt-in, default off; no breaking change. | |
| 145 | + |
| 146 | +--- |
| 147 | + |
| 148 | +## 6. Conclusion |
| 149 | + |
| 150 | +The feature is implemented in line with the plan: opt-in, default off, install/update can use passwordless sudo when enabled and available, remove always requires a password. The main improvement is to ensure the test-only env var cannot affect production behavior. Aligning CLI update with the TUI setting (or documenting the difference) will make behavior clearer and more consistent. |
| 151 | + |
| 152 | +**Recommended before merge:** Address the high-priority item (restrict `PACSEA_TEST_SUDO_PASSWORDLESS` to test context). The rest can be done in this PR or in follow-ups. |
0 commit comments