@pi-archimedes/sudo 2.5.0 → 2.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -27
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,66 +1,85 @@
|
|
|
1
1
|
# @pi-archimedes/sudo
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**A little more care with root access.**
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
- **`sudo_exec` tool** — runs a privileged command via `sudo -S`, showing the exact command and reason for confirmation before any credential is requested; on timeout/abort the kill applies to the command's entire process group, so privileged (root) descendants are killed too, not just the direct sudo process — except a command that intentionally detaches itself into its own session (`setsid`/daemonizing), which leaves the group by definition and is beyond any user-space kill (the same reach as `tmux kill-pane`): give such commands a managed lifecycle flag (e.g. `--foreground`) instead
|
|
8
|
-
- **Masked password prompt** — the password is entered only through a masked UI, cached in memory for the session, and passed to sudo via stdin only — never in argv, env, logs, or files
|
|
9
|
-
- **Defensive scrubbing** — command output lines containing the password are redacted before they appear in tool results
|
|
10
|
-
- **Credential lifecycle** — single in-memory cache with TTL (default 15 min, `ttlMs`); cleared on auth failure, `session_start`/`session_shutdown`, and `/sudo forget`
|
|
11
|
-
- **Headless sessions blocked** — subagent/headless sessions get a clear error from `sudo_exec` instead of a prompt; the masked prompt only ever appears in a human's TUI
|
|
12
|
-
- **Bash guard** — active `tool_call` veto (ADR 0010): interactive `sudo` through the built-in `bash` tool is blocked, funneling privileged execution through `sudo_exec`
|
|
13
|
-
- **`/sudo` + `/sudo forget`** — report the credential-cache state or clear it from memory
|
|
5
|
+
Interactive `sudo` inside an agent session is a mistake waiting to happen — it can deadlock the terminal and drag root credentials into the LLM's context. Sudo puts a deliberate step between the model and the password: the exact command and its reason for your eyes first, a masked prompt (never the chat) for the credential, and a guard that keeps the ordinary `bash` tool from driving interactive `sudo` at all.
|
|
14
6
|
|
|
15
7
|
## Install
|
|
16
8
|
|
|
9
|
+
Standalone:
|
|
10
|
+
|
|
17
11
|
```bash
|
|
18
12
|
pi install npm:@pi-archimedes/sudo
|
|
19
13
|
```
|
|
20
14
|
|
|
15
|
+
Or the full suite instead:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pi install npm:pi-archimedes
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
New to Pi? Pi itself is a one-time global install and needs Node.js ≥ 22.19.0:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install -g --ignore-scripts @earendil-works/pi-coding-agent
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
After installing Pi, choose one installation command above, then `cd` into your project and run `pi`. Inside the session, `/login` signs you in and `/model` picks a model — the [setup section](https://github.com/danielcherubini/pi-archimedes#setup) covers the first run. `/reload` picks the extension up in a running session.
|
|
28
|
+
|
|
29
|
+
## What you get
|
|
30
|
+
|
|
31
|
+
- **`sudo_exec` tool** — runs a privileged command via `sudo -S`, showing the exact command and a human-readable **reason** for confirmation before any credential prompt appears. A declined confirmation means nothing runs and no password is requested.
|
|
32
|
+
- **Masked password prompt** — the password is typed into a masked UI and passed to sudo via stdin only. It is never in argv, environment variables, command logs, or the LLM context.
|
|
33
|
+
- **Defensive output scrubbing** — command output lines that contain the password are redacted before they reach the tool result. That is a literal-substring scrub: it catches common cases, and it is **not** universal leak protection.
|
|
34
|
+
- **Credential cache** — a single in-memory cache with a TTL (15 minutes by default, `ttlMs`); cleared on authentication failure, at `session_start`/`session_shutdown`, and by `/sudo forget`.
|
|
35
|
+
- **Timeout/abort cleanup** — on timeout or abort, the tool attempts to kill the command's entire process group, falling back to the direct sudo process, so root children, not just the direct sudo process, are the target of the cleanup. Deliberately detached descendants (`setsid`, daemonising) leave the process group and are outside its scope — use a flag to keep the child a process in the group (e.g. `--foreground`).
|
|
36
|
+
- **Headless sessions refused** — `sudo_exec` requires an interactive (TUI) session; subagent and headless sessions get a clear error instead of a prompt. The masked prompt only ever appears in front of a human.
|
|
37
|
+
- **Active bash guard** — a `tool_call` veto on the built-in `bash` tool (per [ADR 0010](https://github.com/danielcherubini/pi-archimedes/blob/main/docs/adr/0010-archimedes-sudo-security.md)) blocks interactive `sudo`, funneling privileged execution toward `sudo_exec`.
|
|
38
|
+
|
|
21
39
|
## Usage
|
|
22
40
|
|
|
23
41
|
### The `sudo_exec` tool
|
|
24
42
|
|
|
25
43
|
```jsonc
|
|
26
44
|
{
|
|
27
|
-
"command": "apt install ripgrep",
|
|
28
|
-
"reason": "ripgrep is needed for the search tooling", // required — shown
|
|
29
|
-
"timeoutMs": 120000
|
|
45
|
+
"command": "apt install ripgrep", // exact argv string — no leading 'sudo'; no shell syntax (pipes, &&, redirects, env assignments)
|
|
46
|
+
"reason": "ripgrep is needed for the search tooling", // required — shown before execution
|
|
47
|
+
"timeoutMs": 120000 // optional override of config.defaultTimeoutMs
|
|
30
48
|
}
|
|
31
49
|
```
|
|
32
50
|
|
|
33
|
-
The tool uses pi's built-in `renderCall`/`renderResult`; command output is surfaced as plain text, scrubbed with the password masked.
|
|
34
|
-
|
|
35
51
|
### The bash guard
|
|
36
52
|
|
|
37
|
-
|
|
53
|
+
The scanned `bash` commands:
|
|
38
54
|
|
|
39
|
-
- **Blocked:** `sudo` in command position without a no-prompt flag — including through runner wrappers (`env`, `nohup`, `timeout`, `xargs`, …), nested shells (`bash -c`, `su -c`), `eval`, compound keywords, and heredoc bodies
|
|
40
|
-
- **Allowed:**
|
|
55
|
+
- **Blocked:** `sudo` in command position without a no-prompt flag — including through runner wrappers (`env`, `nohup`, `timeout`, `xargs`, …), nested shells (`bash -c`, `su -c`), `eval`, compound keywords, and heredoc bodies.
|
|
56
|
+
- **Allowed:** sudo occurrences that carry a no-prompt flag (`-n`, `-l`, `-v`, `-K`, `-k`, `--non-interactive`, or merged short flags composed solely of those) — the scanner's allow-list exception, mirroring the typical non-interactive usage.
|
|
41
57
|
|
|
42
|
-
The guard is a heuristic with accepted residual bypasses documented in the [ADR 0010 design notes](
|
|
58
|
+
The guard is a **heuristic with accepted residual bypasses** documented in the [ADR 0010 design notes](https://github.com/danielcherubini/pi-archimedes/blob/main/docs/adr/0010-archimedes-sudo-security.md) — for example cross-token variable indirection, and `sudo` inside `$(...)`/backtick interpolation the word-position model cannot see. Over-blocking is the safe direction; the tested no-prompt flag set is a stable contract of the scanner, **not** a guarantee that no prompt can occur.
|
|
43
59
|
|
|
44
60
|
## Commands
|
|
45
61
|
|
|
46
|
-
- `/sudo` — report whether a credential is cached
|
|
47
|
-
- `/sudo forget` —
|
|
62
|
+
- `/sudo` — report whether a credential is currently cached in memory.
|
|
63
|
+
- `/sudo forget` — flush the cached credential immediately.
|
|
48
64
|
|
|
49
65
|
## Settings
|
|
50
66
|
|
|
67
|
+
`~/.pi/agent/settings.json`, under `archimedes.sudo` — **JSON only**, no settings-panel UI in v1:
|
|
68
|
+
|
|
51
69
|
| Setting | Type | Default | Description |
|
|
52
70
|
|---------|------|---------|-------------|
|
|
53
71
|
| `ttlMs` | number | `900000` | Password cache TTL in milliseconds (default 15 minutes) |
|
|
54
72
|
| `defaultTimeoutMs` | number | `120000` | `sudo_exec` default command timeout in milliseconds (default 120 seconds) |
|
|
55
73
|
|
|
56
|
-
|
|
74
|
+
### Credential handling when sudo retains no verifiable ticket
|
|
57
75
|
|
|
58
|
-
|
|
76
|
+
On sudoers policies that retain no reusable credential ticket (e.g. `timestamp_timeout=0` with strict `Defaults`), an authenticated but failed command is indistinguishable from an authentication failure unless the ticket can be verified with `sudo -n -v`.
|
|
59
77
|
|
|
60
|
-
|
|
78
|
+
- A **recognized wrong password** (sudo's `incorrect password` output alongside its prompt) clears the credential **immediately**, on that failure.
|
|
79
|
+
- The **two-strike rule** applies to **ambiguous** failures where the ticket probe cannot verify the credential: the first strike keeps the cached password (with a visible one-more-attempt warning), the second consecutive strike clears it and re-prompts. Success resets the streak, and transport failures don't count as strikes.
|
|
61
80
|
|
|
62
|
-
##
|
|
81
|
+
## Part of the suite
|
|
63
82
|
|
|
64
|
-
|
|
83
|
+
In [pi-archimedes](https://github.com/danielcherubini/pi-archimedes), the package is registered by the plugin manifest; the bash guard and `sudo_exec` are loaded in the main session and in subagent children — the guard still vetoes there, while `sudo_exec` itself refuses to run in headless mode. Standalone works independently. On/off is managed by the suite: toggle via `/plugins` (`archimedes.sudo.enabled`, default on).
|
|
65
84
|
|
|
66
|
-
← Back to
|
|
85
|
+
← [Back to pi-archimedes](https://github.com/danielcherubini/pi-archimedes)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-archimedes/sudo",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package"
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"./guard": "./src/guard.ts"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@pi-archimedes/core": "2.
|
|
18
|
+
"@pi-archimedes/core": "2.6.2"
|
|
19
19
|
},
|
|
20
20
|
"peerDependencies": {
|
|
21
21
|
"@earendil-works/pi-coding-agent": ">=0.1.0",
|
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
"typebox": ">=1.1.0"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
|
-
"@earendil-works/pi-coding-agent": "^0.
|
|
27
|
-
"@earendil-works/pi-tui": "^0.
|
|
26
|
+
"@earendil-works/pi-coding-agent": "^0.85.1",
|
|
27
|
+
"@earendil-works/pi-tui": "^0.85.1",
|
|
28
28
|
"typebox": "^1.1.38",
|
|
29
29
|
"typescript": "^6.0.0"
|
|
30
30
|
},
|