claude-warden 2.8.0 → 2.9.0
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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +62 -1
- package/dist/cli.cjs +92 -9
- package/dist/codex-export.cjs +92 -9
- package/dist/copilot.cjs +92 -9
- package/dist/index.cjs +92 -9
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "warden",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.9.0",
|
|
4
4
|
"description": "Smart command safety filter for Claude Code — parses shell pipelines and evaluates per-command safety rules to auto-approve safe commands and block dangerous ones",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "banyudu"
|
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
[](https://github.com/banyudu/claude-warden/stargazers)
|
|
7
7
|
[](https://github.com/banyudu/claude-warden/actions)
|
|
8
8
|
|
|
9
|
-
Smart command safety filter for [Claude Code](https://claude.ai/code), [GitHub Copilot CLI](https://docs.github.com/en/copilot/how-tos/customize-copilot-cli/use-hooks), and other AI coding agents. Parses shell commands, evaluates each against configurable safety rules, and returns allow/deny/ask decisions — eliminating unnecessary permission prompts while blocking dangerous commands.
|
|
9
|
+
Smart command safety filter for [Claude Code](https://claude.ai/code), [OpenAI Codex CLI](https://developers.openai.com/codex/hooks), [GitHub Copilot CLI](https://docs.github.com/en/copilot/how-tos/customize-copilot-cli/use-hooks), and other AI coding agents. Parses shell commands, evaluates each against configurable safety rules, and returns allow/deny/ask decisions — eliminating unnecessary permission prompts while blocking dangerous commands.
|
|
10
10
|
|
|
11
11
|
## The problem
|
|
12
12
|
|
|
@@ -283,8 +283,69 @@ rules:
|
|
|
283
283
|
anyArgMatches: ['^(ps|images|logs)$']
|
|
284
284
|
decision: allow
|
|
285
285
|
description: Read-only docker commands
|
|
286
|
+
|
|
287
|
+
# Skill (slash command) filtering — gate Claude Code skill invocations.
|
|
288
|
+
# Skill names use the short form ("commit", not "/commit"). Glob patterns
|
|
289
|
+
# are supported so you can whitelist an entire plugin namespace.
|
|
290
|
+
skills:
|
|
291
|
+
defaultDecision: ask
|
|
292
|
+
alwaysAllow:
|
|
293
|
+
- commit
|
|
294
|
+
- review
|
|
295
|
+
- simplify
|
|
296
|
+
- "plugin-dev:*" # allow every skill in the "plugin-dev" plugin
|
|
297
|
+
alwaysDeny:
|
|
298
|
+
- deploy
|
|
299
|
+
rules:
|
|
300
|
+
- skill: release
|
|
301
|
+
default: ask
|
|
302
|
+
argPatterns:
|
|
303
|
+
- match:
|
|
304
|
+
argsMatch: ["--dry-run"]
|
|
305
|
+
decision: allow
|
|
306
|
+
description: Dry-run release is safe
|
|
286
307
|
```
|
|
287
308
|
|
|
309
|
+
## Skill (slash command) filtering
|
|
310
|
+
|
|
311
|
+
Warden also intercepts Claude Code's `Skill` tool (the mechanism behind `/slash-command` invocations) using the same layered rule engine as shell commands. This lets you whitelist safe skills (read-only helpers, code review, summarization) while still prompting for anything that could modify state.
|
|
312
|
+
|
|
313
|
+
Skill names are the identifier Claude Code uses internally — **without the leading `/`**. Built-in skills use a bare name (`commit`, `review`), plugin skills use `<plugin>:<skill>` (e.g. `plugin-dev:agent-development`, `code-review:code-review`). Glob patterns `*`, `?`, `[...]`, `{a,b,c}` are supported, so `"plugin-dev:*"` matches every skill in that plugin.
|
|
314
|
+
|
|
315
|
+
### Configure
|
|
316
|
+
|
|
317
|
+
```yaml
|
|
318
|
+
skills:
|
|
319
|
+
# Default for skills with no matching rule: allow | deny | ask
|
|
320
|
+
defaultDecision: ask
|
|
321
|
+
|
|
322
|
+
# Auto-allow these skills (scoped to this config layer)
|
|
323
|
+
alwaysAllow:
|
|
324
|
+
- commit
|
|
325
|
+
- review
|
|
326
|
+
- "plugin-dev:*"
|
|
327
|
+
|
|
328
|
+
# Auto-deny these skills
|
|
329
|
+
alwaysDeny:
|
|
330
|
+
- deploy
|
|
331
|
+
|
|
332
|
+
# Per-skill rules with argument-aware matching
|
|
333
|
+
rules:
|
|
334
|
+
- skill: release
|
|
335
|
+
default: ask
|
|
336
|
+
argPatterns:
|
|
337
|
+
- match:
|
|
338
|
+
argsMatch: ["--dry-run"]
|
|
339
|
+
decision: allow
|
|
340
|
+
description: Dry-run release is safe
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
Layering follows the same **project > user > default** priority as shell rules (see [Config priority](#config-priority-scoped-layers)).
|
|
344
|
+
|
|
345
|
+
### Built-in skill defaults
|
|
346
|
+
|
|
347
|
+
Warden ships with a curated allow-list of skills that are read-only or informational — review tools (`review`, `security-review`, `code-review:code-review`), search/summarization helpers (`promptfolio-*`, `slack:find-discussions`, `slack:summarize-channel`), plugin-development guidance (`plugin-dev:*-development`), and `*-usage` docs skills. Everything else falls through to `defaultDecision: ask`.
|
|
348
|
+
|
|
288
349
|
## YOLO mode
|
|
289
350
|
|
|
290
351
|
Need to temporarily bypass all permission prompts? YOLO mode auto-allows all commands for a limited time or the full session — while still blocking always-deny commands (like `sudo`, `shutdown`) for safety.
|
package/dist/cli.cjs
CHANGED
|
@@ -18740,6 +18740,7 @@ var SAFE_DEV_TOOLS = [
|
|
|
18740
18740
|
"jest",
|
|
18741
18741
|
"vitest",
|
|
18742
18742
|
"tsc",
|
|
18743
|
+
"tsgo",
|
|
18743
18744
|
"eslint",
|
|
18744
18745
|
"prettier",
|
|
18745
18746
|
"mkdirp",
|
|
@@ -18860,6 +18861,91 @@ function registryOpsPattern() {
|
|
|
18860
18861
|
reason: "Registry modification"
|
|
18861
18862
|
};
|
|
18862
18863
|
}
|
|
18864
|
+
var INLINE_LANG_CONFIG = {
|
|
18865
|
+
Python: {
|
|
18866
|
+
ext: "py",
|
|
18867
|
+
patterns: [
|
|
18868
|
+
"os\\.system",
|
|
18869
|
+
"subprocess",
|
|
18870
|
+
"commands\\.",
|
|
18871
|
+
"pty\\.",
|
|
18872
|
+
`__import__\\s*\\(\\s*['"](?:os|subprocess|socket)`,
|
|
18873
|
+
"\\bexec\\s*\\(",
|
|
18874
|
+
"\\beval\\s*\\(",
|
|
18875
|
+
`open\\s*\\([^)]*['"][wax+]`,
|
|
18876
|
+
"\\bsocket\\b",
|
|
18877
|
+
"urllib",
|
|
18878
|
+
"requests\\.",
|
|
18879
|
+
"http\\.client"
|
|
18880
|
+
]
|
|
18881
|
+
},
|
|
18882
|
+
JavaScript: {
|
|
18883
|
+
ext: "js",
|
|
18884
|
+
patterns: [
|
|
18885
|
+
"child[_]process",
|
|
18886
|
+
`require\\s*\\(\\s*['"]child[_]process`,
|
|
18887
|
+
"\\.(?:writeFile|appendFile|createWriteStream|writeFileSync|appendFileSync)\\s*\\(",
|
|
18888
|
+
"http\\.request",
|
|
18889
|
+
"https\\.request",
|
|
18890
|
+
"net\\.(?:connect|createConnection)",
|
|
18891
|
+
"fetch\\s*\\("
|
|
18892
|
+
]
|
|
18893
|
+
},
|
|
18894
|
+
Ruby: {
|
|
18895
|
+
ext: "rb",
|
|
18896
|
+
patterns: [
|
|
18897
|
+
"`",
|
|
18898
|
+
"%x[\\(\\{\\[]",
|
|
18899
|
+
"\\bsystem\\s*\\(",
|
|
18900
|
+
"\\bexec\\s*\\(",
|
|
18901
|
+
"IO\\.popen",
|
|
18902
|
+
"Kernel\\.",
|
|
18903
|
+
"\\bspawn\\s*\\(",
|
|
18904
|
+
`File\\.open\\s*\\([^)]*['"][wax+]`,
|
|
18905
|
+
"File\\.write",
|
|
18906
|
+
"open-uri",
|
|
18907
|
+
"Net::HTTP"
|
|
18908
|
+
]
|
|
18909
|
+
},
|
|
18910
|
+
Perl: {
|
|
18911
|
+
ext: "pl",
|
|
18912
|
+
patterns: [
|
|
18913
|
+
"`",
|
|
18914
|
+
"qx[\\(\\{\\[/]",
|
|
18915
|
+
"\\bsystem\\s*\\(",
|
|
18916
|
+
"\\bexec\\s*\\(",
|
|
18917
|
+
`open\\s*\\([^)]*['"][>|+]`
|
|
18918
|
+
]
|
|
18919
|
+
},
|
|
18920
|
+
PHP: {
|
|
18921
|
+
ext: "php",
|
|
18922
|
+
patterns: [
|
|
18923
|
+
"`",
|
|
18924
|
+
"shell_exec",
|
|
18925
|
+
"\\b(?:system|passthru|popen|proc_open)\\s*\\(",
|
|
18926
|
+
"\\bexec\\s*\\(",
|
|
18927
|
+
"file_put_contents",
|
|
18928
|
+
"fwrite",
|
|
18929
|
+
`fopen\\s*\\([^)]*['"][wax+]`,
|
|
18930
|
+
"curl_exec",
|
|
18931
|
+
"fsockopen"
|
|
18932
|
+
]
|
|
18933
|
+
}
|
|
18934
|
+
};
|
|
18935
|
+
function inlineExecPatterns(lang, flags) {
|
|
18936
|
+
const { ext, patterns } = INLINE_LANG_CONFIG[lang];
|
|
18937
|
+
const reason = `Inline ${lang} is hard to audit. For JSON, prefer \`jq\`. For reuse, save to scripts/*.${ext} and run it.`;
|
|
18938
|
+
const flagAlt = flags.map((f) => f.replace(/^\^/, "").replace(/\$$/, "")).join("|");
|
|
18939
|
+
const compound = `(?:^|\\s)(?:${flagAlt})[\\s=][^\\n]{0,16000}?(?:${patterns.join("|")})`;
|
|
18940
|
+
return [
|
|
18941
|
+
{ match: { argsMatch: [compound] }, decision: "ask", reason },
|
|
18942
|
+
{
|
|
18943
|
+
match: { anyArgMatches: flags },
|
|
18944
|
+
decision: "allow",
|
|
18945
|
+
description: `Plausibly read-only inline ${lang} script`
|
|
18946
|
+
}
|
|
18947
|
+
];
|
|
18948
|
+
}
|
|
18863
18949
|
function pkgManagerRule(command, extraSafeCmds = []) {
|
|
18864
18950
|
const safeCmds = [...SAFE_PKG_MANAGER_CMDS, ...extraSafeCmds];
|
|
18865
18951
|
return {
|
|
@@ -19243,7 +19329,7 @@ var DEFAULT_CONFIG = {
|
|
|
19243
19329
|
command: "node",
|
|
19244
19330
|
default: "ask",
|
|
19245
19331
|
argPatterns: [
|
|
19246
|
-
|
|
19332
|
+
...inlineExecPatterns("JavaScript", ["^-e$", "^--eval", "^-p$", "^--print"]),
|
|
19247
19333
|
{ match: { anyArgMatches: ["^--(version|help)$", "^-[vh]$"] }, decision: "allow", description: "Version/help flags" },
|
|
19248
19334
|
{ match: { noArgs: true }, decision: "ask", reason: "Interactive REPL" }
|
|
19249
19335
|
]
|
|
@@ -19272,6 +19358,7 @@ var DEFAULT_CONFIG = {
|
|
|
19272
19358
|
command: cmd,
|
|
19273
19359
|
default: "ask",
|
|
19274
19360
|
argPatterns: [
|
|
19361
|
+
...inlineExecPatterns("Python", ["^-c$"]),
|
|
19275
19362
|
{ match: { anyArgMatches: ["^--(version|help)$", "^-V$"] }, decision: "allow" }
|
|
19276
19363
|
]
|
|
19277
19364
|
})),
|
|
@@ -19321,6 +19408,7 @@ var DEFAULT_CONFIG = {
|
|
|
19321
19408
|
},
|
|
19322
19409
|
{ command: "rustup", default: "allow" },
|
|
19323
19410
|
{ command: "tsc", default: "allow" },
|
|
19411
|
+
{ command: "tsgo", default: "allow" },
|
|
19324
19412
|
{ command: "turbo", default: "allow" },
|
|
19325
19413
|
{ command: "nx", default: "allow" },
|
|
19326
19414
|
{ command: "lerna", default: "allow" },
|
|
@@ -19430,14 +19518,9 @@ var DEFAULT_CONFIG = {
|
|
|
19430
19518
|
argPatterns: [VERSION_HELP_FLAGS]
|
|
19431
19519
|
})),
|
|
19432
19520
|
// --- Scripting languages ---
|
|
19433
|
-
|
|
19434
|
-
|
|
19435
|
-
|
|
19436
|
-
argPatterns: [
|
|
19437
|
-
{ match: { anyArgMatches: ["^-e$", "^--eval"] }, decision: "ask", reason: "Inline code execution" },
|
|
19438
|
-
VERSION_HELP_FLAGS
|
|
19439
|
-
]
|
|
19440
|
-
})),
|
|
19521
|
+
{ command: "ruby", default: "ask", argPatterns: [...inlineExecPatterns("Ruby", ["^-e$", "^--eval"]), VERSION_HELP_FLAGS] },
|
|
19522
|
+
{ command: "perl", default: "ask", argPatterns: [...inlineExecPatterns("Perl", ["^-e$", "^-E$"]), VERSION_HELP_FLAGS] },
|
|
19523
|
+
{ command: "php", default: "ask", argPatterns: [...inlineExecPatterns("PHP", ["^-r$"]), VERSION_HELP_FLAGS] },
|
|
19441
19524
|
// --- Java ecosystem ---
|
|
19442
19525
|
{ command: "java", default: "ask", argPatterns: [VERSION_HELP_FLAGS] },
|
|
19443
19526
|
{ command: "javac", default: "allow" },
|
package/dist/codex-export.cjs
CHANGED
|
@@ -18744,6 +18744,7 @@ var SAFE_DEV_TOOLS = [
|
|
|
18744
18744
|
"jest",
|
|
18745
18745
|
"vitest",
|
|
18746
18746
|
"tsc",
|
|
18747
|
+
"tsgo",
|
|
18747
18748
|
"eslint",
|
|
18748
18749
|
"prettier",
|
|
18749
18750
|
"mkdirp",
|
|
@@ -18864,6 +18865,91 @@ function registryOpsPattern() {
|
|
|
18864
18865
|
reason: "Registry modification"
|
|
18865
18866
|
};
|
|
18866
18867
|
}
|
|
18868
|
+
var INLINE_LANG_CONFIG = {
|
|
18869
|
+
Python: {
|
|
18870
|
+
ext: "py",
|
|
18871
|
+
patterns: [
|
|
18872
|
+
"os\\.system",
|
|
18873
|
+
"subprocess",
|
|
18874
|
+
"commands\\.",
|
|
18875
|
+
"pty\\.",
|
|
18876
|
+
`__import__\\s*\\(\\s*['"](?:os|subprocess|socket)`,
|
|
18877
|
+
"\\bexec\\s*\\(",
|
|
18878
|
+
"\\beval\\s*\\(",
|
|
18879
|
+
`open\\s*\\([^)]*['"][wax+]`,
|
|
18880
|
+
"\\bsocket\\b",
|
|
18881
|
+
"urllib",
|
|
18882
|
+
"requests\\.",
|
|
18883
|
+
"http\\.client"
|
|
18884
|
+
]
|
|
18885
|
+
},
|
|
18886
|
+
JavaScript: {
|
|
18887
|
+
ext: "js",
|
|
18888
|
+
patterns: [
|
|
18889
|
+
"child[_]process",
|
|
18890
|
+
`require\\s*\\(\\s*['"]child[_]process`,
|
|
18891
|
+
"\\.(?:writeFile|appendFile|createWriteStream|writeFileSync|appendFileSync)\\s*\\(",
|
|
18892
|
+
"http\\.request",
|
|
18893
|
+
"https\\.request",
|
|
18894
|
+
"net\\.(?:connect|createConnection)",
|
|
18895
|
+
"fetch\\s*\\("
|
|
18896
|
+
]
|
|
18897
|
+
},
|
|
18898
|
+
Ruby: {
|
|
18899
|
+
ext: "rb",
|
|
18900
|
+
patterns: [
|
|
18901
|
+
"`",
|
|
18902
|
+
"%x[\\(\\{\\[]",
|
|
18903
|
+
"\\bsystem\\s*\\(",
|
|
18904
|
+
"\\bexec\\s*\\(",
|
|
18905
|
+
"IO\\.popen",
|
|
18906
|
+
"Kernel\\.",
|
|
18907
|
+
"\\bspawn\\s*\\(",
|
|
18908
|
+
`File\\.open\\s*\\([^)]*['"][wax+]`,
|
|
18909
|
+
"File\\.write",
|
|
18910
|
+
"open-uri",
|
|
18911
|
+
"Net::HTTP"
|
|
18912
|
+
]
|
|
18913
|
+
},
|
|
18914
|
+
Perl: {
|
|
18915
|
+
ext: "pl",
|
|
18916
|
+
patterns: [
|
|
18917
|
+
"`",
|
|
18918
|
+
"qx[\\(\\{\\[/]",
|
|
18919
|
+
"\\bsystem\\s*\\(",
|
|
18920
|
+
"\\bexec\\s*\\(",
|
|
18921
|
+
`open\\s*\\([^)]*['"][>|+]`
|
|
18922
|
+
]
|
|
18923
|
+
},
|
|
18924
|
+
PHP: {
|
|
18925
|
+
ext: "php",
|
|
18926
|
+
patterns: [
|
|
18927
|
+
"`",
|
|
18928
|
+
"shell_exec",
|
|
18929
|
+
"\\b(?:system|passthru|popen|proc_open)\\s*\\(",
|
|
18930
|
+
"\\bexec\\s*\\(",
|
|
18931
|
+
"file_put_contents",
|
|
18932
|
+
"fwrite",
|
|
18933
|
+
`fopen\\s*\\([^)]*['"][wax+]`,
|
|
18934
|
+
"curl_exec",
|
|
18935
|
+
"fsockopen"
|
|
18936
|
+
]
|
|
18937
|
+
}
|
|
18938
|
+
};
|
|
18939
|
+
function inlineExecPatterns(lang, flags) {
|
|
18940
|
+
const { ext, patterns } = INLINE_LANG_CONFIG[lang];
|
|
18941
|
+
const reason = `Inline ${lang} is hard to audit. For JSON, prefer \`jq\`. For reuse, save to scripts/*.${ext} and run it.`;
|
|
18942
|
+
const flagAlt = flags.map((f) => f.replace(/^\^/, "").replace(/\$$/, "")).join("|");
|
|
18943
|
+
const compound = `(?:^|\\s)(?:${flagAlt})[\\s=][^\\n]{0,16000}?(?:${patterns.join("|")})`;
|
|
18944
|
+
return [
|
|
18945
|
+
{ match: { argsMatch: [compound] }, decision: "ask", reason },
|
|
18946
|
+
{
|
|
18947
|
+
match: { anyArgMatches: flags },
|
|
18948
|
+
decision: "allow",
|
|
18949
|
+
description: `Plausibly read-only inline ${lang} script`
|
|
18950
|
+
}
|
|
18951
|
+
];
|
|
18952
|
+
}
|
|
18867
18953
|
function pkgManagerRule(command, extraSafeCmds = []) {
|
|
18868
18954
|
const safeCmds = [...SAFE_PKG_MANAGER_CMDS, ...extraSafeCmds];
|
|
18869
18955
|
return {
|
|
@@ -19247,7 +19333,7 @@ var DEFAULT_CONFIG = {
|
|
|
19247
19333
|
command: "node",
|
|
19248
19334
|
default: "ask",
|
|
19249
19335
|
argPatterns: [
|
|
19250
|
-
|
|
19336
|
+
...inlineExecPatterns("JavaScript", ["^-e$", "^--eval", "^-p$", "^--print"]),
|
|
19251
19337
|
{ match: { anyArgMatches: ["^--(version|help)$", "^-[vh]$"] }, decision: "allow", description: "Version/help flags" },
|
|
19252
19338
|
{ match: { noArgs: true }, decision: "ask", reason: "Interactive REPL" }
|
|
19253
19339
|
]
|
|
@@ -19276,6 +19362,7 @@ var DEFAULT_CONFIG = {
|
|
|
19276
19362
|
command: cmd,
|
|
19277
19363
|
default: "ask",
|
|
19278
19364
|
argPatterns: [
|
|
19365
|
+
...inlineExecPatterns("Python", ["^-c$"]),
|
|
19279
19366
|
{ match: { anyArgMatches: ["^--(version|help)$", "^-V$"] }, decision: "allow" }
|
|
19280
19367
|
]
|
|
19281
19368
|
})),
|
|
@@ -19325,6 +19412,7 @@ var DEFAULT_CONFIG = {
|
|
|
19325
19412
|
},
|
|
19326
19413
|
{ command: "rustup", default: "allow" },
|
|
19327
19414
|
{ command: "tsc", default: "allow" },
|
|
19415
|
+
{ command: "tsgo", default: "allow" },
|
|
19328
19416
|
{ command: "turbo", default: "allow" },
|
|
19329
19417
|
{ command: "nx", default: "allow" },
|
|
19330
19418
|
{ command: "lerna", default: "allow" },
|
|
@@ -19434,14 +19522,9 @@ var DEFAULT_CONFIG = {
|
|
|
19434
19522
|
argPatterns: [VERSION_HELP_FLAGS]
|
|
19435
19523
|
})),
|
|
19436
19524
|
// --- Scripting languages ---
|
|
19437
|
-
|
|
19438
|
-
|
|
19439
|
-
|
|
19440
|
-
argPatterns: [
|
|
19441
|
-
{ match: { anyArgMatches: ["^-e$", "^--eval"] }, decision: "ask", reason: "Inline code execution" },
|
|
19442
|
-
VERSION_HELP_FLAGS
|
|
19443
|
-
]
|
|
19444
|
-
})),
|
|
19525
|
+
{ command: "ruby", default: "ask", argPatterns: [...inlineExecPatterns("Ruby", ["^-e$", "^--eval"]), VERSION_HELP_FLAGS] },
|
|
19526
|
+
{ command: "perl", default: "ask", argPatterns: [...inlineExecPatterns("Perl", ["^-e$", "^-E$"]), VERSION_HELP_FLAGS] },
|
|
19527
|
+
{ command: "php", default: "ask", argPatterns: [...inlineExecPatterns("PHP", ["^-r$"]), VERSION_HELP_FLAGS] },
|
|
19445
19528
|
// --- Java ecosystem ---
|
|
19446
19529
|
{ command: "java", default: "ask", argPatterns: [VERSION_HELP_FLAGS] },
|
|
19447
19530
|
{ command: "javac", default: "allow" },
|
package/dist/copilot.cjs
CHANGED
|
@@ -18740,6 +18740,7 @@ var SAFE_DEV_TOOLS = [
|
|
|
18740
18740
|
"jest",
|
|
18741
18741
|
"vitest",
|
|
18742
18742
|
"tsc",
|
|
18743
|
+
"tsgo",
|
|
18743
18744
|
"eslint",
|
|
18744
18745
|
"prettier",
|
|
18745
18746
|
"mkdirp",
|
|
@@ -18860,6 +18861,91 @@ function registryOpsPattern() {
|
|
|
18860
18861
|
reason: "Registry modification"
|
|
18861
18862
|
};
|
|
18862
18863
|
}
|
|
18864
|
+
var INLINE_LANG_CONFIG = {
|
|
18865
|
+
Python: {
|
|
18866
|
+
ext: "py",
|
|
18867
|
+
patterns: [
|
|
18868
|
+
"os\\.system",
|
|
18869
|
+
"subprocess",
|
|
18870
|
+
"commands\\.",
|
|
18871
|
+
"pty\\.",
|
|
18872
|
+
`__import__\\s*\\(\\s*['"](?:os|subprocess|socket)`,
|
|
18873
|
+
"\\bexec\\s*\\(",
|
|
18874
|
+
"\\beval\\s*\\(",
|
|
18875
|
+
`open\\s*\\([^)]*['"][wax+]`,
|
|
18876
|
+
"\\bsocket\\b",
|
|
18877
|
+
"urllib",
|
|
18878
|
+
"requests\\.",
|
|
18879
|
+
"http\\.client"
|
|
18880
|
+
]
|
|
18881
|
+
},
|
|
18882
|
+
JavaScript: {
|
|
18883
|
+
ext: "js",
|
|
18884
|
+
patterns: [
|
|
18885
|
+
"child[_]process",
|
|
18886
|
+
`require\\s*\\(\\s*['"]child[_]process`,
|
|
18887
|
+
"\\.(?:writeFile|appendFile|createWriteStream|writeFileSync|appendFileSync)\\s*\\(",
|
|
18888
|
+
"http\\.request",
|
|
18889
|
+
"https\\.request",
|
|
18890
|
+
"net\\.(?:connect|createConnection)",
|
|
18891
|
+
"fetch\\s*\\("
|
|
18892
|
+
]
|
|
18893
|
+
},
|
|
18894
|
+
Ruby: {
|
|
18895
|
+
ext: "rb",
|
|
18896
|
+
patterns: [
|
|
18897
|
+
"`",
|
|
18898
|
+
"%x[\\(\\{\\[]",
|
|
18899
|
+
"\\bsystem\\s*\\(",
|
|
18900
|
+
"\\bexec\\s*\\(",
|
|
18901
|
+
"IO\\.popen",
|
|
18902
|
+
"Kernel\\.",
|
|
18903
|
+
"\\bspawn\\s*\\(",
|
|
18904
|
+
`File\\.open\\s*\\([^)]*['"][wax+]`,
|
|
18905
|
+
"File\\.write",
|
|
18906
|
+
"open-uri",
|
|
18907
|
+
"Net::HTTP"
|
|
18908
|
+
]
|
|
18909
|
+
},
|
|
18910
|
+
Perl: {
|
|
18911
|
+
ext: "pl",
|
|
18912
|
+
patterns: [
|
|
18913
|
+
"`",
|
|
18914
|
+
"qx[\\(\\{\\[/]",
|
|
18915
|
+
"\\bsystem\\s*\\(",
|
|
18916
|
+
"\\bexec\\s*\\(",
|
|
18917
|
+
`open\\s*\\([^)]*['"][>|+]`
|
|
18918
|
+
]
|
|
18919
|
+
},
|
|
18920
|
+
PHP: {
|
|
18921
|
+
ext: "php",
|
|
18922
|
+
patterns: [
|
|
18923
|
+
"`",
|
|
18924
|
+
"shell_exec",
|
|
18925
|
+
"\\b(?:system|passthru|popen|proc_open)\\s*\\(",
|
|
18926
|
+
"\\bexec\\s*\\(",
|
|
18927
|
+
"file_put_contents",
|
|
18928
|
+
"fwrite",
|
|
18929
|
+
`fopen\\s*\\([^)]*['"][wax+]`,
|
|
18930
|
+
"curl_exec",
|
|
18931
|
+
"fsockopen"
|
|
18932
|
+
]
|
|
18933
|
+
}
|
|
18934
|
+
};
|
|
18935
|
+
function inlineExecPatterns(lang, flags) {
|
|
18936
|
+
const { ext, patterns } = INLINE_LANG_CONFIG[lang];
|
|
18937
|
+
const reason = `Inline ${lang} is hard to audit. For JSON, prefer \`jq\`. For reuse, save to scripts/*.${ext} and run it.`;
|
|
18938
|
+
const flagAlt = flags.map((f) => f.replace(/^\^/, "").replace(/\$$/, "")).join("|");
|
|
18939
|
+
const compound = `(?:^|\\s)(?:${flagAlt})[\\s=][^\\n]{0,16000}?(?:${patterns.join("|")})`;
|
|
18940
|
+
return [
|
|
18941
|
+
{ match: { argsMatch: [compound] }, decision: "ask", reason },
|
|
18942
|
+
{
|
|
18943
|
+
match: { anyArgMatches: flags },
|
|
18944
|
+
decision: "allow",
|
|
18945
|
+
description: `Plausibly read-only inline ${lang} script`
|
|
18946
|
+
}
|
|
18947
|
+
];
|
|
18948
|
+
}
|
|
18863
18949
|
function pkgManagerRule(command, extraSafeCmds = []) {
|
|
18864
18950
|
const safeCmds = [...SAFE_PKG_MANAGER_CMDS, ...extraSafeCmds];
|
|
18865
18951
|
return {
|
|
@@ -19243,7 +19329,7 @@ var DEFAULT_CONFIG = {
|
|
|
19243
19329
|
command: "node",
|
|
19244
19330
|
default: "ask",
|
|
19245
19331
|
argPatterns: [
|
|
19246
|
-
|
|
19332
|
+
...inlineExecPatterns("JavaScript", ["^-e$", "^--eval", "^-p$", "^--print"]),
|
|
19247
19333
|
{ match: { anyArgMatches: ["^--(version|help)$", "^-[vh]$"] }, decision: "allow", description: "Version/help flags" },
|
|
19248
19334
|
{ match: { noArgs: true }, decision: "ask", reason: "Interactive REPL" }
|
|
19249
19335
|
]
|
|
@@ -19272,6 +19358,7 @@ var DEFAULT_CONFIG = {
|
|
|
19272
19358
|
command: cmd,
|
|
19273
19359
|
default: "ask",
|
|
19274
19360
|
argPatterns: [
|
|
19361
|
+
...inlineExecPatterns("Python", ["^-c$"]),
|
|
19275
19362
|
{ match: { anyArgMatches: ["^--(version|help)$", "^-V$"] }, decision: "allow" }
|
|
19276
19363
|
]
|
|
19277
19364
|
})),
|
|
@@ -19321,6 +19408,7 @@ var DEFAULT_CONFIG = {
|
|
|
19321
19408
|
},
|
|
19322
19409
|
{ command: "rustup", default: "allow" },
|
|
19323
19410
|
{ command: "tsc", default: "allow" },
|
|
19411
|
+
{ command: "tsgo", default: "allow" },
|
|
19324
19412
|
{ command: "turbo", default: "allow" },
|
|
19325
19413
|
{ command: "nx", default: "allow" },
|
|
19326
19414
|
{ command: "lerna", default: "allow" },
|
|
@@ -19430,14 +19518,9 @@ var DEFAULT_CONFIG = {
|
|
|
19430
19518
|
argPatterns: [VERSION_HELP_FLAGS]
|
|
19431
19519
|
})),
|
|
19432
19520
|
// --- Scripting languages ---
|
|
19433
|
-
|
|
19434
|
-
|
|
19435
|
-
|
|
19436
|
-
argPatterns: [
|
|
19437
|
-
{ match: { anyArgMatches: ["^-e$", "^--eval"] }, decision: "ask", reason: "Inline code execution" },
|
|
19438
|
-
VERSION_HELP_FLAGS
|
|
19439
|
-
]
|
|
19440
|
-
})),
|
|
19521
|
+
{ command: "ruby", default: "ask", argPatterns: [...inlineExecPatterns("Ruby", ["^-e$", "^--eval"]), VERSION_HELP_FLAGS] },
|
|
19522
|
+
{ command: "perl", default: "ask", argPatterns: [...inlineExecPatterns("Perl", ["^-e$", "^-E$"]), VERSION_HELP_FLAGS] },
|
|
19523
|
+
{ command: "php", default: "ask", argPatterns: [...inlineExecPatterns("PHP", ["^-r$"]), VERSION_HELP_FLAGS] },
|
|
19441
19524
|
// --- Java ecosystem ---
|
|
19442
19525
|
{ command: "java", default: "ask", argPatterns: [VERSION_HELP_FLAGS] },
|
|
19443
19526
|
{ command: "javac", default: "allow" },
|
package/dist/index.cjs
CHANGED
|
@@ -18740,6 +18740,7 @@ var SAFE_DEV_TOOLS = [
|
|
|
18740
18740
|
"jest",
|
|
18741
18741
|
"vitest",
|
|
18742
18742
|
"tsc",
|
|
18743
|
+
"tsgo",
|
|
18743
18744
|
"eslint",
|
|
18744
18745
|
"prettier",
|
|
18745
18746
|
"mkdirp",
|
|
@@ -18860,6 +18861,91 @@ function registryOpsPattern() {
|
|
|
18860
18861
|
reason: "Registry modification"
|
|
18861
18862
|
};
|
|
18862
18863
|
}
|
|
18864
|
+
var INLINE_LANG_CONFIG = {
|
|
18865
|
+
Python: {
|
|
18866
|
+
ext: "py",
|
|
18867
|
+
patterns: [
|
|
18868
|
+
"os\\.system",
|
|
18869
|
+
"subprocess",
|
|
18870
|
+
"commands\\.",
|
|
18871
|
+
"pty\\.",
|
|
18872
|
+
`__import__\\s*\\(\\s*['"](?:os|subprocess|socket)`,
|
|
18873
|
+
"\\bexec\\s*\\(",
|
|
18874
|
+
"\\beval\\s*\\(",
|
|
18875
|
+
`open\\s*\\([^)]*['"][wax+]`,
|
|
18876
|
+
"\\bsocket\\b",
|
|
18877
|
+
"urllib",
|
|
18878
|
+
"requests\\.",
|
|
18879
|
+
"http\\.client"
|
|
18880
|
+
]
|
|
18881
|
+
},
|
|
18882
|
+
JavaScript: {
|
|
18883
|
+
ext: "js",
|
|
18884
|
+
patterns: [
|
|
18885
|
+
"child[_]process",
|
|
18886
|
+
`require\\s*\\(\\s*['"]child[_]process`,
|
|
18887
|
+
"\\.(?:writeFile|appendFile|createWriteStream|writeFileSync|appendFileSync)\\s*\\(",
|
|
18888
|
+
"http\\.request",
|
|
18889
|
+
"https\\.request",
|
|
18890
|
+
"net\\.(?:connect|createConnection)",
|
|
18891
|
+
"fetch\\s*\\("
|
|
18892
|
+
]
|
|
18893
|
+
},
|
|
18894
|
+
Ruby: {
|
|
18895
|
+
ext: "rb",
|
|
18896
|
+
patterns: [
|
|
18897
|
+
"`",
|
|
18898
|
+
"%x[\\(\\{\\[]",
|
|
18899
|
+
"\\bsystem\\s*\\(",
|
|
18900
|
+
"\\bexec\\s*\\(",
|
|
18901
|
+
"IO\\.popen",
|
|
18902
|
+
"Kernel\\.",
|
|
18903
|
+
"\\bspawn\\s*\\(",
|
|
18904
|
+
`File\\.open\\s*\\([^)]*['"][wax+]`,
|
|
18905
|
+
"File\\.write",
|
|
18906
|
+
"open-uri",
|
|
18907
|
+
"Net::HTTP"
|
|
18908
|
+
]
|
|
18909
|
+
},
|
|
18910
|
+
Perl: {
|
|
18911
|
+
ext: "pl",
|
|
18912
|
+
patterns: [
|
|
18913
|
+
"`",
|
|
18914
|
+
"qx[\\(\\{\\[/]",
|
|
18915
|
+
"\\bsystem\\s*\\(",
|
|
18916
|
+
"\\bexec\\s*\\(",
|
|
18917
|
+
`open\\s*\\([^)]*['"][>|+]`
|
|
18918
|
+
]
|
|
18919
|
+
},
|
|
18920
|
+
PHP: {
|
|
18921
|
+
ext: "php",
|
|
18922
|
+
patterns: [
|
|
18923
|
+
"`",
|
|
18924
|
+
"shell_exec",
|
|
18925
|
+
"\\b(?:system|passthru|popen|proc_open)\\s*\\(",
|
|
18926
|
+
"\\bexec\\s*\\(",
|
|
18927
|
+
"file_put_contents",
|
|
18928
|
+
"fwrite",
|
|
18929
|
+
`fopen\\s*\\([^)]*['"][wax+]`,
|
|
18930
|
+
"curl_exec",
|
|
18931
|
+
"fsockopen"
|
|
18932
|
+
]
|
|
18933
|
+
}
|
|
18934
|
+
};
|
|
18935
|
+
function inlineExecPatterns(lang, flags) {
|
|
18936
|
+
const { ext, patterns } = INLINE_LANG_CONFIG[lang];
|
|
18937
|
+
const reason = `Inline ${lang} is hard to audit. For JSON, prefer \`jq\`. For reuse, save to scripts/*.${ext} and run it.`;
|
|
18938
|
+
const flagAlt = flags.map((f) => f.replace(/^\^/, "").replace(/\$$/, "")).join("|");
|
|
18939
|
+
const compound = `(?:^|\\s)(?:${flagAlt})[\\s=][^\\n]{0,16000}?(?:${patterns.join("|")})`;
|
|
18940
|
+
return [
|
|
18941
|
+
{ match: { argsMatch: [compound] }, decision: "ask", reason },
|
|
18942
|
+
{
|
|
18943
|
+
match: { anyArgMatches: flags },
|
|
18944
|
+
decision: "allow",
|
|
18945
|
+
description: `Plausibly read-only inline ${lang} script`
|
|
18946
|
+
}
|
|
18947
|
+
];
|
|
18948
|
+
}
|
|
18863
18949
|
function pkgManagerRule(command, extraSafeCmds = []) {
|
|
18864
18950
|
const safeCmds = [...SAFE_PKG_MANAGER_CMDS, ...extraSafeCmds];
|
|
18865
18951
|
return {
|
|
@@ -19243,7 +19329,7 @@ var DEFAULT_CONFIG = {
|
|
|
19243
19329
|
command: "node",
|
|
19244
19330
|
default: "ask",
|
|
19245
19331
|
argPatterns: [
|
|
19246
|
-
|
|
19332
|
+
...inlineExecPatterns("JavaScript", ["^-e$", "^--eval", "^-p$", "^--print"]),
|
|
19247
19333
|
{ match: { anyArgMatches: ["^--(version|help)$", "^-[vh]$"] }, decision: "allow", description: "Version/help flags" },
|
|
19248
19334
|
{ match: { noArgs: true }, decision: "ask", reason: "Interactive REPL" }
|
|
19249
19335
|
]
|
|
@@ -19272,6 +19358,7 @@ var DEFAULT_CONFIG = {
|
|
|
19272
19358
|
command: cmd,
|
|
19273
19359
|
default: "ask",
|
|
19274
19360
|
argPatterns: [
|
|
19361
|
+
...inlineExecPatterns("Python", ["^-c$"]),
|
|
19275
19362
|
{ match: { anyArgMatches: ["^--(version|help)$", "^-V$"] }, decision: "allow" }
|
|
19276
19363
|
]
|
|
19277
19364
|
})),
|
|
@@ -19321,6 +19408,7 @@ var DEFAULT_CONFIG = {
|
|
|
19321
19408
|
},
|
|
19322
19409
|
{ command: "rustup", default: "allow" },
|
|
19323
19410
|
{ command: "tsc", default: "allow" },
|
|
19411
|
+
{ command: "tsgo", default: "allow" },
|
|
19324
19412
|
{ command: "turbo", default: "allow" },
|
|
19325
19413
|
{ command: "nx", default: "allow" },
|
|
19326
19414
|
{ command: "lerna", default: "allow" },
|
|
@@ -19430,14 +19518,9 @@ var DEFAULT_CONFIG = {
|
|
|
19430
19518
|
argPatterns: [VERSION_HELP_FLAGS]
|
|
19431
19519
|
})),
|
|
19432
19520
|
// --- Scripting languages ---
|
|
19433
|
-
|
|
19434
|
-
|
|
19435
|
-
|
|
19436
|
-
argPatterns: [
|
|
19437
|
-
{ match: { anyArgMatches: ["^-e$", "^--eval"] }, decision: "ask", reason: "Inline code execution" },
|
|
19438
|
-
VERSION_HELP_FLAGS
|
|
19439
|
-
]
|
|
19440
|
-
})),
|
|
19521
|
+
{ command: "ruby", default: "ask", argPatterns: [...inlineExecPatterns("Ruby", ["^-e$", "^--eval"]), VERSION_HELP_FLAGS] },
|
|
19522
|
+
{ command: "perl", default: "ask", argPatterns: [...inlineExecPatterns("Perl", ["^-e$", "^-E$"]), VERSION_HELP_FLAGS] },
|
|
19523
|
+
{ command: "php", default: "ask", argPatterns: [...inlineExecPatterns("PHP", ["^-r$"]), VERSION_HELP_FLAGS] },
|
|
19441
19524
|
// --- Java ecosystem ---
|
|
19442
19525
|
{ command: "java", default: "ask", argPatterns: [VERSION_HELP_FLAGS] },
|
|
19443
19526
|
{ command: "javac", default: "allow" },
|