opencode-polkit 0.1.3 → 0.1.5

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 CHANGED
@@ -6,8 +6,12 @@ instead of requiring a terminal for password input.
6
6
 
7
7
  Like CachyOS Hello, the plugin does not check for a polkit agent up front:
8
8
  `sudo` is always redirected to `pkexec` at execution time, and polkitd routes
9
- the request to whatever agent is currently registered. If no agent is
10
- available, `pkexec` fails with its own clear error message.
9
+ the request to whatever agent is currently registered. Without an agent,
10
+ `pkexec` fails fast with `Error creating textual authentication agent`
11
+ (no TTY); the plugin reports that as a clear denial. A hang (dialog never
12
+ appears) is bounded by the bash tool's own timeout (default 2 min,
13
+ configurable up to 10 min) and left untranslated — it cannot be told
14
+ apart from a long-running command.
11
15
 
12
16
  ## Install
13
17
 
@@ -33,15 +37,44 @@ For local development, point opencode at the project directory instead:
33
37
 
34
38
  ## Behavior
35
39
 
36
- | Command | result |
37
- |-----------------|--------------------------------------------|
38
- | `sudo xxx` | redirects to `pkexec xxx` |
39
- | `doas xxx` | redirects to `pkexec xxx` |
40
- | `pkexec xxx` | passes through |
41
- | `sudoedit` | blocked |
42
- | `visudo` | blocked |
43
-
44
- When a user denies the polkit authentication dialog, a clear error message is shown.
40
+ | Command | result |
41
+ |-----------------------|-------------------------------------------------------|
42
+ | `sudo xxx` | redirects to `pkexec xxx` |
43
+ | `doas xxx` | redirects to `pkexec xxx` |
44
+ | `sudo -n xxx` | blocked: pkexec has no short options (unclear failure)|
45
+ | `cat x \| sudo tee y` | redirects to `cat x \| pkexec tee y` (mid-command) |
46
+ | `pkexec xxx` | passes through |
47
+ | `sudoedit` / `visudo` | blocked |
48
+
49
+ ### Minimal intervention
50
+
51
+ The command is rewritten **only** by replacing `sudo`/`doas` with
52
+ `pkexec` — its shape is otherwise untouched, so the agent always sees a
53
+ command that behaves like the one it wrote. Privilege keywords are found
54
+ by a lexical scanner (quote/escape/heredoc aware): `sudo` inside string
55
+ literals, comments or heredocs is ignored; `sudo` in any executable
56
+ position (leading, after `&&`/`||`/`|`, in `$(...)` or subshells, after
57
+ an env assignment like `FOO=1 sudo x`) is rewritten, while the same word
58
+ in argument position (`--name sudo bash`) is left alone. `sudo a && sudo b`
59
+ rewrites both.
60
+
61
+ ### Failures
62
+
63
+ Unambiguous authentication failures are reported as clear errors and the
64
+ command is remembered so a retry is rejected without prompting again
65
+ (cleared when opencode restarts): `Not authorized`, `Error executing
66
+ command as another user`, `Error creating textual authentication agent`
67
+ (no polkit agent + no TTY). A hang (dialog never appears) is bounded by
68
+ the bash tool's own timeout (default 2 min, configurable up to 10 min)
69
+ and is left untranslated — it cannot be told apart from a long-running
70
+ command.
71
+
72
+ Options pkexec does not accept (all short options, plus any long option
73
+ outside `--user`, `--keep-cwd`, `--disable-internal-agent`, `--help`,
74
+ `--version`) are rejected before execution with a clear message, since
75
+ the rewrite would otherwise surface pkexec's own confusing
76
+ `Cannot run program -n` error. `sudo --` and options after the program
77
+ name are left alone.
45
78
 
46
79
  ## i18n
47
80
 
@@ -0,0 +1,3 @@
1
+ import type { Plugin } from "@opencode-ai/plugin";
2
+ export declare const PolkitPlugin: Plugin;
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAe,MAAM,qBAAqB,CAAA;AA2H9D,eAAO,MAAM,YAAY,EAAE,MAgD1B,CAAA"}
package/dist/index.js CHANGED
@@ -1,48 +1,227 @@
1
- const MATCH = /(?<![-\/.\w])(sudo|pkexec|doas|sudoedit|visudo)(?![-\/.\w])/i;
1
+ /** Long options pkexec accepts (all of them; pkexec has no short options). */
2
+ const PKEXEC_OPTIONS = new Set([
3
+ "--version",
4
+ "--help",
5
+ "--disable-internal-agent",
6
+ "--keep-cwd",
7
+ "--user",
8
+ ]);
9
+ /**
10
+ * Lexical scan for privilege-escalation keywords OUTSIDE quotes.
11
+ *
12
+ * Shell commands may contain `sudo` anywhere a command starts (pipes,
13
+ * `&&`/`||`, subshells, command substitution), and string literals /
14
+ * comments may contain the same words spuriously. A plain regex cannot
15
+ * tell those apart; this scanner tracks quote state (' " and backslash
16
+ * escapes) and only reports keywords in executable position.
17
+ *
18
+ * - `node -e "…sudo…"` → no hit (inside quotes)
19
+ * - `cat x | sudo tee y` → hit at index 8 (command boundary)
20
+ * - `cd /tmp && sudo ./x` → hit (after `&&`)
21
+ * - `--name sudo bash` → no hit (argument position)
22
+ * - `echo x; # sudo y` → no hit (comment)
23
+ */
24
+ function scanPrivileged(command) {
25
+ const hits = [];
26
+ let inSingle = false;
27
+ let inDouble = false;
28
+ let escaped = false;
29
+ // True right after a command boundary (`;`, `&&`, `||`, `|`, `(`, start).
30
+ let atCommandStart = true;
31
+ // Heredoc delimiters waiting to close (stack; multiple << are legal).
32
+ const heredocs = [];
33
+ for (let i = 0; i < command.length; i++) {
34
+ const ch = command[i];
35
+ // Inside a heredoc body: only a line consisting of the delimiter ends
36
+ // it. Content there is a string literal, never a command. Pop the
37
+ // matching delimiter (nested heredocs close in any order).
38
+ if (heredocs.length > 0) {
39
+ const lineEnd = command.indexOf("\n", i);
40
+ const line = lineEnd === -1 ? command.slice(i) : command.slice(i, lineEnd);
41
+ const idx = heredocs.lastIndexOf(line);
42
+ if (idx !== -1) {
43
+ heredocs.splice(idx);
44
+ // The line after the delimiter starts a new command position.
45
+ atCommandStart = true;
46
+ }
47
+ i = lineEnd === -1 ? command.length : lineEnd;
48
+ continue;
49
+ }
50
+ if (escaped) {
51
+ escaped = false;
52
+ continue;
53
+ }
54
+ if (ch === "\\" && !inSingle) {
55
+ escaped = true;
56
+ continue;
57
+ }
58
+ if (ch === "'" && !inDouble) {
59
+ inSingle = !inSingle;
60
+ continue;
61
+ }
62
+ if (ch === '"' && !inDouble) {
63
+ inDouble = !inDouble;
64
+ continue;
65
+ }
66
+ if (inSingle || inDouble)
67
+ continue;
68
+ // Heredoc start: `<<[-]DELIM` (delim may be quoted or unquoted).
69
+ if (ch === "<" && command[i + 1] === "<") {
70
+ let j = i + 2;
71
+ if (command[j] === "-")
72
+ j++;
73
+ while (j < command.length && /\s/.test(command[j]))
74
+ j++;
75
+ if (j < command.length && (command[j] === "'" || command[j] === '"')) {
76
+ const q = command[j];
77
+ const end = command.indexOf(q, j + 1);
78
+ if (end !== -1) {
79
+ heredocs.push(command.slice(j + 1, end));
80
+ i = end;
81
+ continue;
82
+ }
83
+ }
84
+ else {
85
+ const m = /^[^\s|;&<>()]+/.exec(command.slice(j));
86
+ if (m) {
87
+ heredocs.push(m[0]);
88
+ i = j + m[0].length - 1;
89
+ continue;
90
+ }
91
+ }
92
+ }
93
+ // Command boundaries open a new executable position.
94
+ if (ch === ";" || ch === "|" || ch === "&" || ch === "(" || ch === "\n") {
95
+ atCommandStart = true;
96
+ continue;
97
+ }
98
+ // `#` at a word start begins a comment that runs to end of line.
99
+ if (ch === "#") {
100
+ const prev = command[i - 1] ?? "";
101
+ if (i === 0 || /\s/.test(prev) || /[;|&(]/.test(prev)) {
102
+ const nl = command.indexOf("\n", i);
103
+ i = nl === -1 ? command.length : nl;
104
+ continue;
105
+ }
106
+ }
107
+ if (/\s/.test(ch))
108
+ continue;
109
+ // An env assignment (`FOO=1 sudo x`) still starts a command; any other
110
+ // word in argument position (`--name sudo`) does not.
111
+ let isCommandPos = atCommandStart;
112
+ if (!isCommandPos) {
113
+ let j = i - 1;
114
+ while (j >= 0 && /\s/.test(command[j]))
115
+ j--;
116
+ while (j >= 0 && !/[\s;|&()]/.test(command[j]))
117
+ j--;
118
+ const token = command.slice(j + 1, i);
119
+ if (token.includes("="))
120
+ isCommandPos = true;
121
+ }
122
+ atCommandStart = false;
123
+ if (!isCommandPos)
124
+ continue;
125
+ for (const kw of ["sudoedit", "visudo", "sudo", "doas", "pkexec"]) {
126
+ if (command.startsWith(kw, i)) {
127
+ const next = command[i + kw.length] ?? "";
128
+ if (!/[-\/.\w]/.test(next)) {
129
+ hits.push({ index: i, kw });
130
+ i += kw.length - 1;
131
+ break;
132
+ }
133
+ }
134
+ }
135
+ }
136
+ return hits;
137
+ }
138
+ /**
139
+ * First option token after a privilege keyword that pkexec does not
140
+ * accept, or null when the command's options are pkexec-compatible.
141
+ * Scanning stops at the program name (`--` also terminates options, as
142
+ * in sudo); tokens after it belong to the program, not to pkexec.
143
+ *
144
+ * - `sudo -n true` → `-n` (pkexec has no short options)
145
+ * - `sudo --non-interactive x` → `--non-interactive`
146
+ * - `sudo --user root x` → null (compatible)
147
+ * - `sudo -- x -n` → null (`--` ends sudo options)
148
+ */
149
+ function findBadOption(command, hit) {
150
+ let i = hit.index + hit.kw.length;
151
+ while (i < command.length && /\s/.test(command[i]))
152
+ i++;
153
+ while (i < command.length && command[i] === "-") {
154
+ let end = i + 1;
155
+ while (end < command.length && !/\s/.test(command[end]) && !/[;|&()]/.test(command[end]))
156
+ end++;
157
+ const token = command.slice(i, end);
158
+ if (token === "--")
159
+ break;
160
+ if (!token.startsWith("--"))
161
+ return token;
162
+ if (!PKEXEC_OPTIONS.has(token.split("=")[0]))
163
+ return token;
164
+ i = end;
165
+ while (i < command.length && /\s/.test(command[i]))
166
+ i++;
167
+ }
168
+ return null;
169
+ }
2
170
  const translations = {
3
171
  en: {
4
172
  blocked: "Privilege escalation command blocked by plugin",
5
173
  polkitDenied: "Polkit authentication denied by user",
174
+ badOption: 'Option "{opt}" is not supported by pkexec. Remove it or use a pkexec-compatible one (--user, --keep-cwd, --disable-internal-agent).',
6
175
  },
7
176
  zh: {
8
177
  blocked: "权限提升命令已被插件拦截",
9
178
  polkitDenied: "Polkit 认证已被用户拒绝",
179
+ badOption: '选项 "{opt}" 不被 pkexec 支持,请移除或改用 pkexec 兼容选项(--user、--keep-cwd、--disable-internal-agent)。',
10
180
  },
11
181
  ja: {
12
182
  blocked: "特権昇格コマンドはプラグインによりブロックされました",
13
183
  polkitDenied: "Polkit 認証がユーザーによって拒否されました",
184
+ badOption: 'オプション "{opt}" は pkexec ではサポートされていません。削除するか、pkexec 互換オプション(--user、--keep-cwd、--disable-internal-agent)を使用してください。',
14
185
  },
15
186
  ko: {
16
187
  blocked: "권한 상승 명령이 플러그인에 의해 차단되었습니다",
17
188
  polkitDenied: "Polkit 인증이 사용자에 의해 거부되었습니다",
189
+ badOption: '옵션 "{opt}"은(는) pkexec에서 지원되지 않습니다. 제거하거나 pkexec 호환 옵션(--user, --keep-cwd, --disable-internal-agent)을 사용하세요.',
18
190
  },
19
191
  de: {
20
192
  blocked: "Berechtigungseskalation vom Plugin blockiert",
21
193
  polkitDenied: "Polkit-Authentifizierung vom Benutzer abgelehnt",
194
+ badOption: 'Option "{opt}" wird von pkexec nicht unterstützt. Entfernen Sie sie oder verwenden Sie eine pkexec-kompatible Option (--user, --keep-cwd, --disable-internal-agent).',
22
195
  },
23
196
  fr: {
24
197
  blocked: "Commande d'élévation de privilèges bloquée par le plugin",
25
198
  polkitDenied: "Authentification polkit refusée par l'utilisateur",
199
+ badOption: 'Option "{opt}" non prise en charge par pkexec. Supprimez-la ou utilisez une option compatible pkexec (--user, --keep-cwd, --disable-internal-agent).',
26
200
  },
27
201
  es: {
28
202
  blocked: "Comando de elevación de privilegios bloqueado por el plugin",
29
203
  polkitDenied: "Autenticación polkit denegada por el usuario",
204
+ badOption: 'Opción "{opt}" no admitida por pkexec. Elimínela o use una opción compatible con pkexec (--user, --keep-cwd, --disable-internal-agent).',
30
205
  },
31
206
  pt: {
32
207
  blocked: "Comando de elevação de privilégios bloqueado pelo plugin",
33
208
  polkitDenied: "Autenticação polkit negada pelo usuário",
209
+ badOption: 'Opção "{opt}" não suportada pelo pkexec. Remova-a ou use uma opção compatível com pkexec (--user, --keep-cwd, --disable-internal-agent).',
34
210
  },
35
211
  ru: {
36
212
  blocked: "Команда повышения привилегий заблокирована плагином",
37
213
  polkitDenied: "Аутентификация polkit отклонена пользователем",
214
+ badOption: 'Параметр "{opt}" не поддерживается pkexec. Удалите его или используйте совместимый параметр (--user, --keep-cwd, --disable-internal-agent).',
38
215
  },
39
216
  tr: {
40
217
  blocked: "Yetki yükseltme komutu eklenti tarafından engellendi",
41
218
  polkitDenied: "Polkit kimlik doğrulaması kullanıcı tarafından reddedildi",
219
+ badOption: '"{opt}" seçeneği pkexec tarafından desteklenmiyor. Kaldırın veya pkexec uyumlu bir seçenek kullanın (--user, --keep-cwd, --disable-internal-agent).',
42
220
  },
43
221
  uk: {
44
222
  blocked: "Команду підвищення привілеїв заблоковано плагіном",
45
223
  polkitDenied: "Автентифікацію polkit відхилено користувачем",
224
+ badOption: 'Параметр "{opt}" не підтримується pkexec. Видаліть його або використайте сумісний параметр (--user, --keep-cwd, --disable-internal-agent).',
46
225
  },
47
226
  };
48
227
  function detectLocale() {
@@ -62,29 +241,63 @@ export const PolkitPlugin = async (_input) => {
62
241
  if (hookInput.tool !== "bash")
63
242
  return;
64
243
  const command = hookOutput?.args?.command ?? "";
65
- if (!MATCH.test(command))
244
+ const hits = scanPrivileged(command);
245
+ if (hits.length === 0)
66
246
  return;
67
247
  if (deniedCommands.has(command)) {
68
248
  throw new Error(MSG.polkitDenied);
69
249
  }
70
- if (/^pkexec(?![-\/.\w])/.test(command.trim())) {
71
- return;
72
- }
73
- if (/(?<![-\/.\w])(sudoedit|visudo)(?![-\/.\w])/.test(command)) {
250
+ if (hits.some((h) => h.kw === "sudoedit" || h.kw === "visudo")) {
74
251
  throw new Error(MSG.blocked);
75
252
  }
76
- hookOutput.args.command = command.replace(/(?<![-\/.\w])(sudo|doas)(?![-\/.\w])/, "pkexec");
253
+ // Rewrite would produce `pkexec <bad option>`: fail with a clear
254
+ // message instead of a confusing `Cannot run program` error.
255
+ for (const h of hits) {
256
+ if (h.kw === "sudo" || h.kw === "doas" || h.kw === "pkexec") {
257
+ const bad = findBadOption(command, h);
258
+ if (bad)
259
+ throw new Error(MSG.badOption.replace("{opt}", bad));
260
+ }
261
+ }
262
+ // Already pkexec (leading or mid-command): pass through untouched.
263
+ if (hits.every((h) => h.kw === "pkexec"))
264
+ return;
265
+ // Rewrite every in-command sudo/doas to pkexec (back to front so
266
+ // indices stay valid): `cat x | sudo tee y` -> `cat x | pkexec tee y`.
267
+ // No other rewriting: the command keeps its exact shape so the agent
268
+ // sees only the minimal change (sudo -> pkexec).
269
+ let rewritten = command;
270
+ for (const h of [...hits].reverse()) {
271
+ if (h.kw === "sudo" || h.kw === "doas") {
272
+ rewritten =
273
+ rewritten.slice(0, h.index) + "pkexec" + rewritten.slice(h.index + h.kw.length);
274
+ }
275
+ }
276
+ hookOutput.args.command = rewritten;
77
277
  },
78
278
  "tool.execute.after": async (hookInput, hookOutput) => {
79
279
  if (hookInput.tool !== "bash")
80
280
  return;
81
281
  const command = hookInput.args?.command ?? "";
82
- if (!MATCH.test(command))
282
+ const hits = scanPrivileged(command);
283
+ if (hits.length === 0)
83
284
  return;
84
- const originalCommand = command.replace(/(?<![-\/.\w])pkexec(?![-\/.\w])/, "sudo");
285
+ // Reconstruct the user's original command for the deny list: map
286
+ // pkexec back to sudo.
287
+ let original = command;
288
+ for (const h of [...scanPrivileged(original)].reverse()) {
289
+ if (h.kw === "pkexec") {
290
+ original = original.slice(0, h.index) + "sudo" + original.slice(h.index + 6);
291
+ }
292
+ }
293
+ // Only unambiguous authentication failures are reported and deny
294
+ // listed. A hang (dialog never appears) is bounded by the bash tool's
295
+ // own timeout (default 2 min) and is NOT translated here: it cannot
296
+ // be told apart from a long-running command.
85
297
  if (/\bNot authorized\b/.test(hookOutput.output) ||
86
- /\bError executing command as another user\b/.test(hookOutput.output)) {
87
- deniedCommands.add(originalCommand);
298
+ /\bError executing command as another user\b/.test(hookOutput.output) ||
299
+ /\bError creating textual authentication agent\b/.test(hookOutput.output)) {
300
+ deniedCommands.add(original);
88
301
  throw new Error(MSG.polkitDenied);
89
302
  }
90
303
  },
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-polkit",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Redirect sudo/doas to pkexec in OpenCode — uses system polkit agent for native auth dialogs",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",