claude-warden 2.7.0 → 2.8.1
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/config/warden.default.yaml +20 -0
- package/dist/cli.cjs +114 -9
- package/dist/codex-export.cjs +114 -9
- package/dist/copilot.cjs +114 -9
- package/dist/index.cjs +130 -9
- package/hooks/hooks.json +11 -0
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "warden",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.8.1",
|
|
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"
|
|
@@ -19,6 +19,26 @@ askOnSubshell: true
|
|
|
19
19
|
notifyOnAsk: true
|
|
20
20
|
notifyOnDeny: true
|
|
21
21
|
|
|
22
|
+
# Guidance injected into every Claude Code session via the SessionStart hook.
|
|
23
|
+
# Claude sees this as a system message, so it can shape tool choice *before*
|
|
24
|
+
# warden needs to ask or deny. Keep it short — it competes for context.
|
|
25
|
+
#
|
|
26
|
+
# - Omit the key to use the built-in default (prefer jq, save temp scripts to
|
|
27
|
+
# tempScriptDir below, read deny reasons, mention /warden:allow and /warden:yolo).
|
|
28
|
+
# - Set to a string to override with your own guidance.
|
|
29
|
+
# - Set to `false` to disable injection entirely.
|
|
30
|
+
#
|
|
31
|
+
# sessionGuidance: |
|
|
32
|
+
# Warden is active. Prefer allow-listed tools (e.g. jq for JSON). For
|
|
33
|
+
# multi-line logic, save a temp script under /tmp/ instead of using
|
|
34
|
+
# inline `bash -c` / `node -e`.
|
|
35
|
+
|
|
36
|
+
# Directory the built-in guidance tells Claude to save throwaway multi-line
|
|
37
|
+
# scripts to. Defaults to `/tmp` so scripts don't pollute the repo. Point at
|
|
38
|
+
# another location (e.g. `.warden-scratch`) if you want them tracked per-project.
|
|
39
|
+
# Only used when `sessionGuidance` is unset.
|
|
40
|
+
# tempScriptDir: /tmp
|
|
41
|
+
|
|
22
42
|
# Additional commands to always allow (checked after alwaysDeny within this scope)
|
|
23
43
|
# alwaysAllow:
|
|
24
44
|
# - terraform
|
package/dist/cli.cjs
CHANGED
|
@@ -18860,6 +18860,91 @@ function registryOpsPattern() {
|
|
|
18860
18860
|
reason: "Registry modification"
|
|
18861
18861
|
};
|
|
18862
18862
|
}
|
|
18863
|
+
var INLINE_LANG_CONFIG = {
|
|
18864
|
+
Python: {
|
|
18865
|
+
ext: "py",
|
|
18866
|
+
patterns: [
|
|
18867
|
+
"os\\.system",
|
|
18868
|
+
"subprocess",
|
|
18869
|
+
"commands\\.",
|
|
18870
|
+
"pty\\.",
|
|
18871
|
+
`__import__\\s*\\(\\s*['"](?:os|subprocess|socket)`,
|
|
18872
|
+
"\\bexec\\s*\\(",
|
|
18873
|
+
"\\beval\\s*\\(",
|
|
18874
|
+
`open\\s*\\([^)]*['"][wax+]`,
|
|
18875
|
+
"\\bsocket\\b",
|
|
18876
|
+
"urllib",
|
|
18877
|
+
"requests\\.",
|
|
18878
|
+
"http\\.client"
|
|
18879
|
+
]
|
|
18880
|
+
},
|
|
18881
|
+
JavaScript: {
|
|
18882
|
+
ext: "js",
|
|
18883
|
+
patterns: [
|
|
18884
|
+
"child[_]process",
|
|
18885
|
+
`require\\s*\\(\\s*['"]child[_]process`,
|
|
18886
|
+
"\\.(?:writeFile|appendFile|createWriteStream|writeFileSync|appendFileSync)\\s*\\(",
|
|
18887
|
+
"http\\.request",
|
|
18888
|
+
"https\\.request",
|
|
18889
|
+
"net\\.(?:connect|createConnection)",
|
|
18890
|
+
"fetch\\s*\\("
|
|
18891
|
+
]
|
|
18892
|
+
},
|
|
18893
|
+
Ruby: {
|
|
18894
|
+
ext: "rb",
|
|
18895
|
+
patterns: [
|
|
18896
|
+
"`",
|
|
18897
|
+
"%x[\\(\\{\\[]",
|
|
18898
|
+
"\\bsystem\\s*\\(",
|
|
18899
|
+
"\\bexec\\s*\\(",
|
|
18900
|
+
"IO\\.popen",
|
|
18901
|
+
"Kernel\\.",
|
|
18902
|
+
"\\bspawn\\s*\\(",
|
|
18903
|
+
`File\\.open\\s*\\([^)]*['"][wax+]`,
|
|
18904
|
+
"File\\.write",
|
|
18905
|
+
"open-uri",
|
|
18906
|
+
"Net::HTTP"
|
|
18907
|
+
]
|
|
18908
|
+
},
|
|
18909
|
+
Perl: {
|
|
18910
|
+
ext: "pl",
|
|
18911
|
+
patterns: [
|
|
18912
|
+
"`",
|
|
18913
|
+
"qx[\\(\\{\\[/]",
|
|
18914
|
+
"\\bsystem\\s*\\(",
|
|
18915
|
+
"\\bexec\\s*\\(",
|
|
18916
|
+
`open\\s*\\([^)]*['"][>|+]`
|
|
18917
|
+
]
|
|
18918
|
+
},
|
|
18919
|
+
PHP: {
|
|
18920
|
+
ext: "php",
|
|
18921
|
+
patterns: [
|
|
18922
|
+
"`",
|
|
18923
|
+
"shell_exec",
|
|
18924
|
+
"\\b(?:system|passthru|popen|proc_open)\\s*\\(",
|
|
18925
|
+
"\\bexec\\s*\\(",
|
|
18926
|
+
"file_put_contents",
|
|
18927
|
+
"fwrite",
|
|
18928
|
+
`fopen\\s*\\([^)]*['"][wax+]`,
|
|
18929
|
+
"curl_exec",
|
|
18930
|
+
"fsockopen"
|
|
18931
|
+
]
|
|
18932
|
+
}
|
|
18933
|
+
};
|
|
18934
|
+
function inlineExecPatterns(lang, flags) {
|
|
18935
|
+
const { ext, patterns } = INLINE_LANG_CONFIG[lang];
|
|
18936
|
+
const reason = `Inline ${lang} is hard to audit. For JSON, prefer \`jq\`. For reuse, save to scripts/*.${ext} and run it.`;
|
|
18937
|
+
const flagAlt = flags.map((f) => f.replace(/^\^/, "").replace(/\$$/, "")).join("|");
|
|
18938
|
+
const compound = `(?:^|\\s)(?:${flagAlt})[\\s=][^\\n]{0,16000}?(?:${patterns.join("|")})`;
|
|
18939
|
+
return [
|
|
18940
|
+
{ match: { argsMatch: [compound] }, decision: "ask", reason },
|
|
18941
|
+
{
|
|
18942
|
+
match: { anyArgMatches: flags },
|
|
18943
|
+
decision: "allow",
|
|
18944
|
+
description: `Plausibly read-only inline ${lang} script`
|
|
18945
|
+
}
|
|
18946
|
+
];
|
|
18947
|
+
}
|
|
18863
18948
|
function pkgManagerRule(command, extraSafeCmds = []) {
|
|
18864
18949
|
const safeCmds = [...SAFE_PKG_MANAGER_CMDS, ...extraSafeCmds];
|
|
18865
18950
|
return {
|
|
@@ -18933,6 +19018,18 @@ var DEFAULT_SKILL_RULES = {
|
|
|
18933
19018
|
rules: []
|
|
18934
19019
|
}]
|
|
18935
19020
|
};
|
|
19021
|
+
var DEFAULT_TEMP_SCRIPT_DIR = "/tmp";
|
|
19022
|
+
function buildDefaultSessionGuidance(tempScriptDir) {
|
|
19023
|
+
return [
|
|
19024
|
+
"Claude Warden is active. It filters Bash commands against safety rules and may ask or deny.",
|
|
19025
|
+
"",
|
|
19026
|
+
"- For JSON in shell pipelines, prefer `jq` (auto-allowed) over `python3 -c` / `node -e`.",
|
|
19027
|
+
`- For multi-line logic, save a temp script under \`${tempScriptDir}/\` (e.g. \`${tempScriptDir}/warden-task.sh\`) or add a \`package.json\` script rather than inline \`bash -c\` / \`node -e\`. Avoid polluting the repo with throwaway scripts.`,
|
|
19028
|
+
"- When Warden denies or asks, read the reason \u2014 it often names the preferred alternative.",
|
|
19029
|
+
"- To permanently allow a specific command, run `/warden:allow <cmd>`. To temporarily bypass filtering, `/warden:yolo`."
|
|
19030
|
+
].join("\n");
|
|
19031
|
+
}
|
|
19032
|
+
var DEFAULT_SESSION_GUIDANCE = buildDefaultSessionGuidance(DEFAULT_TEMP_SCRIPT_DIR);
|
|
18936
19033
|
var DEFAULT_CONFIG = {
|
|
18937
19034
|
defaultDecision: "ask",
|
|
18938
19035
|
askOnSubshell: true,
|
|
@@ -19231,7 +19328,7 @@ var DEFAULT_CONFIG = {
|
|
|
19231
19328
|
command: "node",
|
|
19232
19329
|
default: "ask",
|
|
19233
19330
|
argPatterns: [
|
|
19234
|
-
|
|
19331
|
+
...inlineExecPatterns("JavaScript", ["^-e$", "^--eval", "^-p$", "^--print"]),
|
|
19235
19332
|
{ match: { anyArgMatches: ["^--(version|help)$", "^-[vh]$"] }, decision: "allow", description: "Version/help flags" },
|
|
19236
19333
|
{ match: { noArgs: true }, decision: "ask", reason: "Interactive REPL" }
|
|
19237
19334
|
]
|
|
@@ -19260,6 +19357,7 @@ var DEFAULT_CONFIG = {
|
|
|
19260
19357
|
command: cmd,
|
|
19261
19358
|
default: "ask",
|
|
19262
19359
|
argPatterns: [
|
|
19360
|
+
...inlineExecPatterns("Python", ["^-c$"]),
|
|
19263
19361
|
{ match: { anyArgMatches: ["^--(version|help)$", "^-V$"] }, decision: "allow" }
|
|
19264
19362
|
]
|
|
19265
19363
|
})),
|
|
@@ -19418,14 +19516,9 @@ var DEFAULT_CONFIG = {
|
|
|
19418
19516
|
argPatterns: [VERSION_HELP_FLAGS]
|
|
19419
19517
|
})),
|
|
19420
19518
|
// --- Scripting languages ---
|
|
19421
|
-
|
|
19422
|
-
|
|
19423
|
-
|
|
19424
|
-
argPatterns: [
|
|
19425
|
-
{ match: { anyArgMatches: ["^-e$", "^--eval"] }, decision: "ask", reason: "Inline code execution" },
|
|
19426
|
-
VERSION_HELP_FLAGS
|
|
19427
|
-
]
|
|
19428
|
-
})),
|
|
19519
|
+
{ command: "ruby", default: "ask", argPatterns: [...inlineExecPatterns("Ruby", ["^-e$", "^--eval"]), VERSION_HELP_FLAGS] },
|
|
19520
|
+
{ command: "perl", default: "ask", argPatterns: [...inlineExecPatterns("Perl", ["^-e$", "^-E$"]), VERSION_HELP_FLAGS] },
|
|
19521
|
+
{ command: "php", default: "ask", argPatterns: [...inlineExecPatterns("PHP", ["^-r$"]), VERSION_HELP_FLAGS] },
|
|
19429
19522
|
// --- Java ecosystem ---
|
|
19430
19523
|
{ command: "java", default: "ask", argPatterns: [VERSION_HELP_FLAGS] },
|
|
19431
19524
|
{ command: "javac", default: "allow" },
|
|
@@ -19809,6 +19902,18 @@ function mergeNonLayerFields(config, raw) {
|
|
|
19809
19902
|
if (typeof raw.notifyOnDeny === "boolean") {
|
|
19810
19903
|
config.notifyOnDeny = raw.notifyOnDeny;
|
|
19811
19904
|
}
|
|
19905
|
+
if (typeof raw.sessionGuidance === "string" || raw.sessionGuidance === false) {
|
|
19906
|
+
config.sessionGuidance = raw.sessionGuidance;
|
|
19907
|
+
} else if (raw.sessionGuidance !== void 0) {
|
|
19908
|
+
warn(`[warden] Warning: invalid sessionGuidance (expected string or false), ignoring
|
|
19909
|
+
`);
|
|
19910
|
+
}
|
|
19911
|
+
if (typeof raw.tempScriptDir === "string" && raw.tempScriptDir.length > 0) {
|
|
19912
|
+
config.tempScriptDir = raw.tempScriptDir;
|
|
19913
|
+
} else if (raw.tempScriptDir !== void 0) {
|
|
19914
|
+
warn(`[warden] Warning: invalid tempScriptDir (expected non-empty string), ignoring
|
|
19915
|
+
`);
|
|
19916
|
+
}
|
|
19812
19917
|
if (raw.skills && typeof raw.skills === "object") {
|
|
19813
19918
|
const skills = raw.skills;
|
|
19814
19919
|
if (typeof skills.defaultDecision === "string") {
|
package/dist/codex-export.cjs
CHANGED
|
@@ -18864,6 +18864,91 @@ function registryOpsPattern() {
|
|
|
18864
18864
|
reason: "Registry modification"
|
|
18865
18865
|
};
|
|
18866
18866
|
}
|
|
18867
|
+
var INLINE_LANG_CONFIG = {
|
|
18868
|
+
Python: {
|
|
18869
|
+
ext: "py",
|
|
18870
|
+
patterns: [
|
|
18871
|
+
"os\\.system",
|
|
18872
|
+
"subprocess",
|
|
18873
|
+
"commands\\.",
|
|
18874
|
+
"pty\\.",
|
|
18875
|
+
`__import__\\s*\\(\\s*['"](?:os|subprocess|socket)`,
|
|
18876
|
+
"\\bexec\\s*\\(",
|
|
18877
|
+
"\\beval\\s*\\(",
|
|
18878
|
+
`open\\s*\\([^)]*['"][wax+]`,
|
|
18879
|
+
"\\bsocket\\b",
|
|
18880
|
+
"urllib",
|
|
18881
|
+
"requests\\.",
|
|
18882
|
+
"http\\.client"
|
|
18883
|
+
]
|
|
18884
|
+
},
|
|
18885
|
+
JavaScript: {
|
|
18886
|
+
ext: "js",
|
|
18887
|
+
patterns: [
|
|
18888
|
+
"child[_]process",
|
|
18889
|
+
`require\\s*\\(\\s*['"]child[_]process`,
|
|
18890
|
+
"\\.(?:writeFile|appendFile|createWriteStream|writeFileSync|appendFileSync)\\s*\\(",
|
|
18891
|
+
"http\\.request",
|
|
18892
|
+
"https\\.request",
|
|
18893
|
+
"net\\.(?:connect|createConnection)",
|
|
18894
|
+
"fetch\\s*\\("
|
|
18895
|
+
]
|
|
18896
|
+
},
|
|
18897
|
+
Ruby: {
|
|
18898
|
+
ext: "rb",
|
|
18899
|
+
patterns: [
|
|
18900
|
+
"`",
|
|
18901
|
+
"%x[\\(\\{\\[]",
|
|
18902
|
+
"\\bsystem\\s*\\(",
|
|
18903
|
+
"\\bexec\\s*\\(",
|
|
18904
|
+
"IO\\.popen",
|
|
18905
|
+
"Kernel\\.",
|
|
18906
|
+
"\\bspawn\\s*\\(",
|
|
18907
|
+
`File\\.open\\s*\\([^)]*['"][wax+]`,
|
|
18908
|
+
"File\\.write",
|
|
18909
|
+
"open-uri",
|
|
18910
|
+
"Net::HTTP"
|
|
18911
|
+
]
|
|
18912
|
+
},
|
|
18913
|
+
Perl: {
|
|
18914
|
+
ext: "pl",
|
|
18915
|
+
patterns: [
|
|
18916
|
+
"`",
|
|
18917
|
+
"qx[\\(\\{\\[/]",
|
|
18918
|
+
"\\bsystem\\s*\\(",
|
|
18919
|
+
"\\bexec\\s*\\(",
|
|
18920
|
+
`open\\s*\\([^)]*['"][>|+]`
|
|
18921
|
+
]
|
|
18922
|
+
},
|
|
18923
|
+
PHP: {
|
|
18924
|
+
ext: "php",
|
|
18925
|
+
patterns: [
|
|
18926
|
+
"`",
|
|
18927
|
+
"shell_exec",
|
|
18928
|
+
"\\b(?:system|passthru|popen|proc_open)\\s*\\(",
|
|
18929
|
+
"\\bexec\\s*\\(",
|
|
18930
|
+
"file_put_contents",
|
|
18931
|
+
"fwrite",
|
|
18932
|
+
`fopen\\s*\\([^)]*['"][wax+]`,
|
|
18933
|
+
"curl_exec",
|
|
18934
|
+
"fsockopen"
|
|
18935
|
+
]
|
|
18936
|
+
}
|
|
18937
|
+
};
|
|
18938
|
+
function inlineExecPatterns(lang, flags) {
|
|
18939
|
+
const { ext, patterns } = INLINE_LANG_CONFIG[lang];
|
|
18940
|
+
const reason = `Inline ${lang} is hard to audit. For JSON, prefer \`jq\`. For reuse, save to scripts/*.${ext} and run it.`;
|
|
18941
|
+
const flagAlt = flags.map((f) => f.replace(/^\^/, "").replace(/\$$/, "")).join("|");
|
|
18942
|
+
const compound = `(?:^|\\s)(?:${flagAlt})[\\s=][^\\n]{0,16000}?(?:${patterns.join("|")})`;
|
|
18943
|
+
return [
|
|
18944
|
+
{ match: { argsMatch: [compound] }, decision: "ask", reason },
|
|
18945
|
+
{
|
|
18946
|
+
match: { anyArgMatches: flags },
|
|
18947
|
+
decision: "allow",
|
|
18948
|
+
description: `Plausibly read-only inline ${lang} script`
|
|
18949
|
+
}
|
|
18950
|
+
];
|
|
18951
|
+
}
|
|
18867
18952
|
function pkgManagerRule(command, extraSafeCmds = []) {
|
|
18868
18953
|
const safeCmds = [...SAFE_PKG_MANAGER_CMDS, ...extraSafeCmds];
|
|
18869
18954
|
return {
|
|
@@ -18937,6 +19022,18 @@ var DEFAULT_SKILL_RULES = {
|
|
|
18937
19022
|
rules: []
|
|
18938
19023
|
}]
|
|
18939
19024
|
};
|
|
19025
|
+
var DEFAULT_TEMP_SCRIPT_DIR = "/tmp";
|
|
19026
|
+
function buildDefaultSessionGuidance(tempScriptDir) {
|
|
19027
|
+
return [
|
|
19028
|
+
"Claude Warden is active. It filters Bash commands against safety rules and may ask or deny.",
|
|
19029
|
+
"",
|
|
19030
|
+
"- For JSON in shell pipelines, prefer `jq` (auto-allowed) over `python3 -c` / `node -e`.",
|
|
19031
|
+
`- For multi-line logic, save a temp script under \`${tempScriptDir}/\` (e.g. \`${tempScriptDir}/warden-task.sh\`) or add a \`package.json\` script rather than inline \`bash -c\` / \`node -e\`. Avoid polluting the repo with throwaway scripts.`,
|
|
19032
|
+
"- When Warden denies or asks, read the reason \u2014 it often names the preferred alternative.",
|
|
19033
|
+
"- To permanently allow a specific command, run `/warden:allow <cmd>`. To temporarily bypass filtering, `/warden:yolo`."
|
|
19034
|
+
].join("\n");
|
|
19035
|
+
}
|
|
19036
|
+
var DEFAULT_SESSION_GUIDANCE = buildDefaultSessionGuidance(DEFAULT_TEMP_SCRIPT_DIR);
|
|
18940
19037
|
var DEFAULT_CONFIG = {
|
|
18941
19038
|
defaultDecision: "ask",
|
|
18942
19039
|
askOnSubshell: true,
|
|
@@ -19235,7 +19332,7 @@ var DEFAULT_CONFIG = {
|
|
|
19235
19332
|
command: "node",
|
|
19236
19333
|
default: "ask",
|
|
19237
19334
|
argPatterns: [
|
|
19238
|
-
|
|
19335
|
+
...inlineExecPatterns("JavaScript", ["^-e$", "^--eval", "^-p$", "^--print"]),
|
|
19239
19336
|
{ match: { anyArgMatches: ["^--(version|help)$", "^-[vh]$"] }, decision: "allow", description: "Version/help flags" },
|
|
19240
19337
|
{ match: { noArgs: true }, decision: "ask", reason: "Interactive REPL" }
|
|
19241
19338
|
]
|
|
@@ -19264,6 +19361,7 @@ var DEFAULT_CONFIG = {
|
|
|
19264
19361
|
command: cmd,
|
|
19265
19362
|
default: "ask",
|
|
19266
19363
|
argPatterns: [
|
|
19364
|
+
...inlineExecPatterns("Python", ["^-c$"]),
|
|
19267
19365
|
{ match: { anyArgMatches: ["^--(version|help)$", "^-V$"] }, decision: "allow" }
|
|
19268
19366
|
]
|
|
19269
19367
|
})),
|
|
@@ -19422,14 +19520,9 @@ var DEFAULT_CONFIG = {
|
|
|
19422
19520
|
argPatterns: [VERSION_HELP_FLAGS]
|
|
19423
19521
|
})),
|
|
19424
19522
|
// --- Scripting languages ---
|
|
19425
|
-
|
|
19426
|
-
|
|
19427
|
-
|
|
19428
|
-
argPatterns: [
|
|
19429
|
-
{ match: { anyArgMatches: ["^-e$", "^--eval"] }, decision: "ask", reason: "Inline code execution" },
|
|
19430
|
-
VERSION_HELP_FLAGS
|
|
19431
|
-
]
|
|
19432
|
-
})),
|
|
19523
|
+
{ command: "ruby", default: "ask", argPatterns: [...inlineExecPatterns("Ruby", ["^-e$", "^--eval"]), VERSION_HELP_FLAGS] },
|
|
19524
|
+
{ command: "perl", default: "ask", argPatterns: [...inlineExecPatterns("Perl", ["^-e$", "^-E$"]), VERSION_HELP_FLAGS] },
|
|
19525
|
+
{ command: "php", default: "ask", argPatterns: [...inlineExecPatterns("PHP", ["^-r$"]), VERSION_HELP_FLAGS] },
|
|
19433
19526
|
// --- Java ecosystem ---
|
|
19434
19527
|
{ command: "java", default: "ask", argPatterns: [VERSION_HELP_FLAGS] },
|
|
19435
19528
|
{ command: "javac", default: "allow" },
|
|
@@ -19813,6 +19906,18 @@ function mergeNonLayerFields(config, raw) {
|
|
|
19813
19906
|
if (typeof raw.notifyOnDeny === "boolean") {
|
|
19814
19907
|
config.notifyOnDeny = raw.notifyOnDeny;
|
|
19815
19908
|
}
|
|
19909
|
+
if (typeof raw.sessionGuidance === "string" || raw.sessionGuidance === false) {
|
|
19910
|
+
config.sessionGuidance = raw.sessionGuidance;
|
|
19911
|
+
} else if (raw.sessionGuidance !== void 0) {
|
|
19912
|
+
warn(`[warden] Warning: invalid sessionGuidance (expected string or false), ignoring
|
|
19913
|
+
`);
|
|
19914
|
+
}
|
|
19915
|
+
if (typeof raw.tempScriptDir === "string" && raw.tempScriptDir.length > 0) {
|
|
19916
|
+
config.tempScriptDir = raw.tempScriptDir;
|
|
19917
|
+
} else if (raw.tempScriptDir !== void 0) {
|
|
19918
|
+
warn(`[warden] Warning: invalid tempScriptDir (expected non-empty string), ignoring
|
|
19919
|
+
`);
|
|
19920
|
+
}
|
|
19816
19921
|
if (raw.skills && typeof raw.skills === "object") {
|
|
19817
19922
|
const skills = raw.skills;
|
|
19818
19923
|
if (typeof skills.defaultDecision === "string") {
|
package/dist/copilot.cjs
CHANGED
|
@@ -18860,6 +18860,91 @@ function registryOpsPattern() {
|
|
|
18860
18860
|
reason: "Registry modification"
|
|
18861
18861
|
};
|
|
18862
18862
|
}
|
|
18863
|
+
var INLINE_LANG_CONFIG = {
|
|
18864
|
+
Python: {
|
|
18865
|
+
ext: "py",
|
|
18866
|
+
patterns: [
|
|
18867
|
+
"os\\.system",
|
|
18868
|
+
"subprocess",
|
|
18869
|
+
"commands\\.",
|
|
18870
|
+
"pty\\.",
|
|
18871
|
+
`__import__\\s*\\(\\s*['"](?:os|subprocess|socket)`,
|
|
18872
|
+
"\\bexec\\s*\\(",
|
|
18873
|
+
"\\beval\\s*\\(",
|
|
18874
|
+
`open\\s*\\([^)]*['"][wax+]`,
|
|
18875
|
+
"\\bsocket\\b",
|
|
18876
|
+
"urllib",
|
|
18877
|
+
"requests\\.",
|
|
18878
|
+
"http\\.client"
|
|
18879
|
+
]
|
|
18880
|
+
},
|
|
18881
|
+
JavaScript: {
|
|
18882
|
+
ext: "js",
|
|
18883
|
+
patterns: [
|
|
18884
|
+
"child[_]process",
|
|
18885
|
+
`require\\s*\\(\\s*['"]child[_]process`,
|
|
18886
|
+
"\\.(?:writeFile|appendFile|createWriteStream|writeFileSync|appendFileSync)\\s*\\(",
|
|
18887
|
+
"http\\.request",
|
|
18888
|
+
"https\\.request",
|
|
18889
|
+
"net\\.(?:connect|createConnection)",
|
|
18890
|
+
"fetch\\s*\\("
|
|
18891
|
+
]
|
|
18892
|
+
},
|
|
18893
|
+
Ruby: {
|
|
18894
|
+
ext: "rb",
|
|
18895
|
+
patterns: [
|
|
18896
|
+
"`",
|
|
18897
|
+
"%x[\\(\\{\\[]",
|
|
18898
|
+
"\\bsystem\\s*\\(",
|
|
18899
|
+
"\\bexec\\s*\\(",
|
|
18900
|
+
"IO\\.popen",
|
|
18901
|
+
"Kernel\\.",
|
|
18902
|
+
"\\bspawn\\s*\\(",
|
|
18903
|
+
`File\\.open\\s*\\([^)]*['"][wax+]`,
|
|
18904
|
+
"File\\.write",
|
|
18905
|
+
"open-uri",
|
|
18906
|
+
"Net::HTTP"
|
|
18907
|
+
]
|
|
18908
|
+
},
|
|
18909
|
+
Perl: {
|
|
18910
|
+
ext: "pl",
|
|
18911
|
+
patterns: [
|
|
18912
|
+
"`",
|
|
18913
|
+
"qx[\\(\\{\\[/]",
|
|
18914
|
+
"\\bsystem\\s*\\(",
|
|
18915
|
+
"\\bexec\\s*\\(",
|
|
18916
|
+
`open\\s*\\([^)]*['"][>|+]`
|
|
18917
|
+
]
|
|
18918
|
+
},
|
|
18919
|
+
PHP: {
|
|
18920
|
+
ext: "php",
|
|
18921
|
+
patterns: [
|
|
18922
|
+
"`",
|
|
18923
|
+
"shell_exec",
|
|
18924
|
+
"\\b(?:system|passthru|popen|proc_open)\\s*\\(",
|
|
18925
|
+
"\\bexec\\s*\\(",
|
|
18926
|
+
"file_put_contents",
|
|
18927
|
+
"fwrite",
|
|
18928
|
+
`fopen\\s*\\([^)]*['"][wax+]`,
|
|
18929
|
+
"curl_exec",
|
|
18930
|
+
"fsockopen"
|
|
18931
|
+
]
|
|
18932
|
+
}
|
|
18933
|
+
};
|
|
18934
|
+
function inlineExecPatterns(lang, flags) {
|
|
18935
|
+
const { ext, patterns } = INLINE_LANG_CONFIG[lang];
|
|
18936
|
+
const reason = `Inline ${lang} is hard to audit. For JSON, prefer \`jq\`. For reuse, save to scripts/*.${ext} and run it.`;
|
|
18937
|
+
const flagAlt = flags.map((f) => f.replace(/^\^/, "").replace(/\$$/, "")).join("|");
|
|
18938
|
+
const compound = `(?:^|\\s)(?:${flagAlt})[\\s=][^\\n]{0,16000}?(?:${patterns.join("|")})`;
|
|
18939
|
+
return [
|
|
18940
|
+
{ match: { argsMatch: [compound] }, decision: "ask", reason },
|
|
18941
|
+
{
|
|
18942
|
+
match: { anyArgMatches: flags },
|
|
18943
|
+
decision: "allow",
|
|
18944
|
+
description: `Plausibly read-only inline ${lang} script`
|
|
18945
|
+
}
|
|
18946
|
+
];
|
|
18947
|
+
}
|
|
18863
18948
|
function pkgManagerRule(command, extraSafeCmds = []) {
|
|
18864
18949
|
const safeCmds = [...SAFE_PKG_MANAGER_CMDS, ...extraSafeCmds];
|
|
18865
18950
|
return {
|
|
@@ -18933,6 +19018,18 @@ var DEFAULT_SKILL_RULES = {
|
|
|
18933
19018
|
rules: []
|
|
18934
19019
|
}]
|
|
18935
19020
|
};
|
|
19021
|
+
var DEFAULT_TEMP_SCRIPT_DIR = "/tmp";
|
|
19022
|
+
function buildDefaultSessionGuidance(tempScriptDir) {
|
|
19023
|
+
return [
|
|
19024
|
+
"Claude Warden is active. It filters Bash commands against safety rules and may ask or deny.",
|
|
19025
|
+
"",
|
|
19026
|
+
"- For JSON in shell pipelines, prefer `jq` (auto-allowed) over `python3 -c` / `node -e`.",
|
|
19027
|
+
`- For multi-line logic, save a temp script under \`${tempScriptDir}/\` (e.g. \`${tempScriptDir}/warden-task.sh\`) or add a \`package.json\` script rather than inline \`bash -c\` / \`node -e\`. Avoid polluting the repo with throwaway scripts.`,
|
|
19028
|
+
"- When Warden denies or asks, read the reason \u2014 it often names the preferred alternative.",
|
|
19029
|
+
"- To permanently allow a specific command, run `/warden:allow <cmd>`. To temporarily bypass filtering, `/warden:yolo`."
|
|
19030
|
+
].join("\n");
|
|
19031
|
+
}
|
|
19032
|
+
var DEFAULT_SESSION_GUIDANCE = buildDefaultSessionGuidance(DEFAULT_TEMP_SCRIPT_DIR);
|
|
18936
19033
|
var DEFAULT_CONFIG = {
|
|
18937
19034
|
defaultDecision: "ask",
|
|
18938
19035
|
askOnSubshell: true,
|
|
@@ -19231,7 +19328,7 @@ var DEFAULT_CONFIG = {
|
|
|
19231
19328
|
command: "node",
|
|
19232
19329
|
default: "ask",
|
|
19233
19330
|
argPatterns: [
|
|
19234
|
-
|
|
19331
|
+
...inlineExecPatterns("JavaScript", ["^-e$", "^--eval", "^-p$", "^--print"]),
|
|
19235
19332
|
{ match: { anyArgMatches: ["^--(version|help)$", "^-[vh]$"] }, decision: "allow", description: "Version/help flags" },
|
|
19236
19333
|
{ match: { noArgs: true }, decision: "ask", reason: "Interactive REPL" }
|
|
19237
19334
|
]
|
|
@@ -19260,6 +19357,7 @@ var DEFAULT_CONFIG = {
|
|
|
19260
19357
|
command: cmd,
|
|
19261
19358
|
default: "ask",
|
|
19262
19359
|
argPatterns: [
|
|
19360
|
+
...inlineExecPatterns("Python", ["^-c$"]),
|
|
19263
19361
|
{ match: { anyArgMatches: ["^--(version|help)$", "^-V$"] }, decision: "allow" }
|
|
19264
19362
|
]
|
|
19265
19363
|
})),
|
|
@@ -19418,14 +19516,9 @@ var DEFAULT_CONFIG = {
|
|
|
19418
19516
|
argPatterns: [VERSION_HELP_FLAGS]
|
|
19419
19517
|
})),
|
|
19420
19518
|
// --- Scripting languages ---
|
|
19421
|
-
|
|
19422
|
-
|
|
19423
|
-
|
|
19424
|
-
argPatterns: [
|
|
19425
|
-
{ match: { anyArgMatches: ["^-e$", "^--eval"] }, decision: "ask", reason: "Inline code execution" },
|
|
19426
|
-
VERSION_HELP_FLAGS
|
|
19427
|
-
]
|
|
19428
|
-
})),
|
|
19519
|
+
{ command: "ruby", default: "ask", argPatterns: [...inlineExecPatterns("Ruby", ["^-e$", "^--eval"]), VERSION_HELP_FLAGS] },
|
|
19520
|
+
{ command: "perl", default: "ask", argPatterns: [...inlineExecPatterns("Perl", ["^-e$", "^-E$"]), VERSION_HELP_FLAGS] },
|
|
19521
|
+
{ command: "php", default: "ask", argPatterns: [...inlineExecPatterns("PHP", ["^-r$"]), VERSION_HELP_FLAGS] },
|
|
19429
19522
|
// --- Java ecosystem ---
|
|
19430
19523
|
{ command: "java", default: "ask", argPatterns: [VERSION_HELP_FLAGS] },
|
|
19431
19524
|
{ command: "javac", default: "allow" },
|
|
@@ -19806,6 +19899,18 @@ function mergeNonLayerFields(config, raw) {
|
|
|
19806
19899
|
if (typeof raw.notifyOnDeny === "boolean") {
|
|
19807
19900
|
config.notifyOnDeny = raw.notifyOnDeny;
|
|
19808
19901
|
}
|
|
19902
|
+
if (typeof raw.sessionGuidance === "string" || raw.sessionGuidance === false) {
|
|
19903
|
+
config.sessionGuidance = raw.sessionGuidance;
|
|
19904
|
+
} else if (raw.sessionGuidance !== void 0) {
|
|
19905
|
+
warn(`[warden] Warning: invalid sessionGuidance (expected string or false), ignoring
|
|
19906
|
+
`);
|
|
19907
|
+
}
|
|
19908
|
+
if (typeof raw.tempScriptDir === "string" && raw.tempScriptDir.length > 0) {
|
|
19909
|
+
config.tempScriptDir = raw.tempScriptDir;
|
|
19910
|
+
} else if (raw.tempScriptDir !== void 0) {
|
|
19911
|
+
warn(`[warden] Warning: invalid tempScriptDir (expected non-empty string), ignoring
|
|
19912
|
+
`);
|
|
19913
|
+
}
|
|
19809
19914
|
if (raw.skills && typeof raw.skills === "object") {
|
|
19810
19915
|
const skills = raw.skills;
|
|
19811
19916
|
if (typeof skills.defaultDecision === "string") {
|
package/dist/index.cjs
CHANGED
|
@@ -18860,6 +18860,91 @@ function registryOpsPattern() {
|
|
|
18860
18860
|
reason: "Registry modification"
|
|
18861
18861
|
};
|
|
18862
18862
|
}
|
|
18863
|
+
var INLINE_LANG_CONFIG = {
|
|
18864
|
+
Python: {
|
|
18865
|
+
ext: "py",
|
|
18866
|
+
patterns: [
|
|
18867
|
+
"os\\.system",
|
|
18868
|
+
"subprocess",
|
|
18869
|
+
"commands\\.",
|
|
18870
|
+
"pty\\.",
|
|
18871
|
+
`__import__\\s*\\(\\s*['"](?:os|subprocess|socket)`,
|
|
18872
|
+
"\\bexec\\s*\\(",
|
|
18873
|
+
"\\beval\\s*\\(",
|
|
18874
|
+
`open\\s*\\([^)]*['"][wax+]`,
|
|
18875
|
+
"\\bsocket\\b",
|
|
18876
|
+
"urllib",
|
|
18877
|
+
"requests\\.",
|
|
18878
|
+
"http\\.client"
|
|
18879
|
+
]
|
|
18880
|
+
},
|
|
18881
|
+
JavaScript: {
|
|
18882
|
+
ext: "js",
|
|
18883
|
+
patterns: [
|
|
18884
|
+
"child[_]process",
|
|
18885
|
+
`require\\s*\\(\\s*['"]child[_]process`,
|
|
18886
|
+
"\\.(?:writeFile|appendFile|createWriteStream|writeFileSync|appendFileSync)\\s*\\(",
|
|
18887
|
+
"http\\.request",
|
|
18888
|
+
"https\\.request",
|
|
18889
|
+
"net\\.(?:connect|createConnection)",
|
|
18890
|
+
"fetch\\s*\\("
|
|
18891
|
+
]
|
|
18892
|
+
},
|
|
18893
|
+
Ruby: {
|
|
18894
|
+
ext: "rb",
|
|
18895
|
+
patterns: [
|
|
18896
|
+
"`",
|
|
18897
|
+
"%x[\\(\\{\\[]",
|
|
18898
|
+
"\\bsystem\\s*\\(",
|
|
18899
|
+
"\\bexec\\s*\\(",
|
|
18900
|
+
"IO\\.popen",
|
|
18901
|
+
"Kernel\\.",
|
|
18902
|
+
"\\bspawn\\s*\\(",
|
|
18903
|
+
`File\\.open\\s*\\([^)]*['"][wax+]`,
|
|
18904
|
+
"File\\.write",
|
|
18905
|
+
"open-uri",
|
|
18906
|
+
"Net::HTTP"
|
|
18907
|
+
]
|
|
18908
|
+
},
|
|
18909
|
+
Perl: {
|
|
18910
|
+
ext: "pl",
|
|
18911
|
+
patterns: [
|
|
18912
|
+
"`",
|
|
18913
|
+
"qx[\\(\\{\\[/]",
|
|
18914
|
+
"\\bsystem\\s*\\(",
|
|
18915
|
+
"\\bexec\\s*\\(",
|
|
18916
|
+
`open\\s*\\([^)]*['"][>|+]`
|
|
18917
|
+
]
|
|
18918
|
+
},
|
|
18919
|
+
PHP: {
|
|
18920
|
+
ext: "php",
|
|
18921
|
+
patterns: [
|
|
18922
|
+
"`",
|
|
18923
|
+
"shell_exec",
|
|
18924
|
+
"\\b(?:system|passthru|popen|proc_open)\\s*\\(",
|
|
18925
|
+
"\\bexec\\s*\\(",
|
|
18926
|
+
"file_put_contents",
|
|
18927
|
+
"fwrite",
|
|
18928
|
+
`fopen\\s*\\([^)]*['"][wax+]`,
|
|
18929
|
+
"curl_exec",
|
|
18930
|
+
"fsockopen"
|
|
18931
|
+
]
|
|
18932
|
+
}
|
|
18933
|
+
};
|
|
18934
|
+
function inlineExecPatterns(lang, flags) {
|
|
18935
|
+
const { ext, patterns } = INLINE_LANG_CONFIG[lang];
|
|
18936
|
+
const reason = `Inline ${lang} is hard to audit. For JSON, prefer \`jq\`. For reuse, save to scripts/*.${ext} and run it.`;
|
|
18937
|
+
const flagAlt = flags.map((f) => f.replace(/^\^/, "").replace(/\$$/, "")).join("|");
|
|
18938
|
+
const compound = `(?:^|\\s)(?:${flagAlt})[\\s=][^\\n]{0,16000}?(?:${patterns.join("|")})`;
|
|
18939
|
+
return [
|
|
18940
|
+
{ match: { argsMatch: [compound] }, decision: "ask", reason },
|
|
18941
|
+
{
|
|
18942
|
+
match: { anyArgMatches: flags },
|
|
18943
|
+
decision: "allow",
|
|
18944
|
+
description: `Plausibly read-only inline ${lang} script`
|
|
18945
|
+
}
|
|
18946
|
+
];
|
|
18947
|
+
}
|
|
18863
18948
|
function pkgManagerRule(command, extraSafeCmds = []) {
|
|
18864
18949
|
const safeCmds = [...SAFE_PKG_MANAGER_CMDS, ...extraSafeCmds];
|
|
18865
18950
|
return {
|
|
@@ -18933,6 +19018,18 @@ var DEFAULT_SKILL_RULES = {
|
|
|
18933
19018
|
rules: []
|
|
18934
19019
|
}]
|
|
18935
19020
|
};
|
|
19021
|
+
var DEFAULT_TEMP_SCRIPT_DIR = "/tmp";
|
|
19022
|
+
function buildDefaultSessionGuidance(tempScriptDir) {
|
|
19023
|
+
return [
|
|
19024
|
+
"Claude Warden is active. It filters Bash commands against safety rules and may ask or deny.",
|
|
19025
|
+
"",
|
|
19026
|
+
"- For JSON in shell pipelines, prefer `jq` (auto-allowed) over `python3 -c` / `node -e`.",
|
|
19027
|
+
`- For multi-line logic, save a temp script under \`${tempScriptDir}/\` (e.g. \`${tempScriptDir}/warden-task.sh\`) or add a \`package.json\` script rather than inline \`bash -c\` / \`node -e\`. Avoid polluting the repo with throwaway scripts.`,
|
|
19028
|
+
"- When Warden denies or asks, read the reason \u2014 it often names the preferred alternative.",
|
|
19029
|
+
"- To permanently allow a specific command, run `/warden:allow <cmd>`. To temporarily bypass filtering, `/warden:yolo`."
|
|
19030
|
+
].join("\n");
|
|
19031
|
+
}
|
|
19032
|
+
var DEFAULT_SESSION_GUIDANCE = buildDefaultSessionGuidance(DEFAULT_TEMP_SCRIPT_DIR);
|
|
18936
19033
|
var DEFAULT_CONFIG = {
|
|
18937
19034
|
defaultDecision: "ask",
|
|
18938
19035
|
askOnSubshell: true,
|
|
@@ -19231,7 +19328,7 @@ var DEFAULT_CONFIG = {
|
|
|
19231
19328
|
command: "node",
|
|
19232
19329
|
default: "ask",
|
|
19233
19330
|
argPatterns: [
|
|
19234
|
-
|
|
19331
|
+
...inlineExecPatterns("JavaScript", ["^-e$", "^--eval", "^-p$", "^--print"]),
|
|
19235
19332
|
{ match: { anyArgMatches: ["^--(version|help)$", "^-[vh]$"] }, decision: "allow", description: "Version/help flags" },
|
|
19236
19333
|
{ match: { noArgs: true }, decision: "ask", reason: "Interactive REPL" }
|
|
19237
19334
|
]
|
|
@@ -19260,6 +19357,7 @@ var DEFAULT_CONFIG = {
|
|
|
19260
19357
|
command: cmd,
|
|
19261
19358
|
default: "ask",
|
|
19262
19359
|
argPatterns: [
|
|
19360
|
+
...inlineExecPatterns("Python", ["^-c$"]),
|
|
19263
19361
|
{ match: { anyArgMatches: ["^--(version|help)$", "^-V$"] }, decision: "allow" }
|
|
19264
19362
|
]
|
|
19265
19363
|
})),
|
|
@@ -19418,14 +19516,9 @@ var DEFAULT_CONFIG = {
|
|
|
19418
19516
|
argPatterns: [VERSION_HELP_FLAGS]
|
|
19419
19517
|
})),
|
|
19420
19518
|
// --- Scripting languages ---
|
|
19421
|
-
|
|
19422
|
-
|
|
19423
|
-
|
|
19424
|
-
argPatterns: [
|
|
19425
|
-
{ match: { anyArgMatches: ["^-e$", "^--eval"] }, decision: "ask", reason: "Inline code execution" },
|
|
19426
|
-
VERSION_HELP_FLAGS
|
|
19427
|
-
]
|
|
19428
|
-
})),
|
|
19519
|
+
{ command: "ruby", default: "ask", argPatterns: [...inlineExecPatterns("Ruby", ["^-e$", "^--eval"]), VERSION_HELP_FLAGS] },
|
|
19520
|
+
{ command: "perl", default: "ask", argPatterns: [...inlineExecPatterns("Perl", ["^-e$", "^-E$"]), VERSION_HELP_FLAGS] },
|
|
19521
|
+
{ command: "php", default: "ask", argPatterns: [...inlineExecPatterns("PHP", ["^-r$"]), VERSION_HELP_FLAGS] },
|
|
19429
19522
|
// --- Java ecosystem ---
|
|
19430
19523
|
{ command: "java", default: "ask", argPatterns: [VERSION_HELP_FLAGS] },
|
|
19431
19524
|
{ command: "javac", default: "allow" },
|
|
@@ -19806,6 +19899,18 @@ function mergeNonLayerFields(config, raw) {
|
|
|
19806
19899
|
if (typeof raw.notifyOnDeny === "boolean") {
|
|
19807
19900
|
config.notifyOnDeny = raw.notifyOnDeny;
|
|
19808
19901
|
}
|
|
19902
|
+
if (typeof raw.sessionGuidance === "string" || raw.sessionGuidance === false) {
|
|
19903
|
+
config.sessionGuidance = raw.sessionGuidance;
|
|
19904
|
+
} else if (raw.sessionGuidance !== void 0) {
|
|
19905
|
+
warn(`[warden] Warning: invalid sessionGuidance (expected string or false), ignoring
|
|
19906
|
+
`);
|
|
19907
|
+
}
|
|
19908
|
+
if (typeof raw.tempScriptDir === "string" && raw.tempScriptDir.length > 0) {
|
|
19909
|
+
config.tempScriptDir = raw.tempScriptDir;
|
|
19910
|
+
} else if (raw.tempScriptDir !== void 0) {
|
|
19911
|
+
warn(`[warden] Warning: invalid tempScriptDir (expected non-empty string), ignoring
|
|
19912
|
+
`);
|
|
19913
|
+
}
|
|
19809
19914
|
if (raw.skills && typeof raw.skills === "object") {
|
|
19810
19915
|
const skills = raw.skills;
|
|
19811
19916
|
if (typeof skills.defaultDecision === "string") {
|
|
@@ -20990,6 +21095,18 @@ function emitDecision(decision, reason, stderrMessage) {
|
|
|
20990
21095
|
}
|
|
20991
21096
|
process.exit(0);
|
|
20992
21097
|
}
|
|
21098
|
+
function handleSessionStart(config) {
|
|
21099
|
+
if (config.sessionGuidance === false) process.exit(0);
|
|
21100
|
+
const text = config.sessionGuidance ?? buildDefaultSessionGuidance(config.tempScriptDir ?? DEFAULT_TEMP_SCRIPT_DIR);
|
|
21101
|
+
const output = {
|
|
21102
|
+
hookSpecificOutput: {
|
|
21103
|
+
hookEventName: "SessionStart",
|
|
21104
|
+
additionalContext: text
|
|
21105
|
+
}
|
|
21106
|
+
};
|
|
21107
|
+
process.stdout.write(JSON.stringify(output));
|
|
21108
|
+
process.exit(0);
|
|
21109
|
+
}
|
|
20993
21110
|
function handleYoloMode(sessionId, result) {
|
|
20994
21111
|
const yoloState = getYoloState(sessionId);
|
|
20995
21112
|
if (!yoloState) return;
|
|
@@ -21011,6 +21128,10 @@ async function main() {
|
|
|
21011
21128
|
} catch {
|
|
21012
21129
|
process.exit(0);
|
|
21013
21130
|
}
|
|
21131
|
+
if (input.hook_event_name === "SessionStart") {
|
|
21132
|
+
const config2 = loadConfig(input.cwd);
|
|
21133
|
+
handleSessionStart(config2);
|
|
21134
|
+
}
|
|
21014
21135
|
if (input.tool_name !== "Bash" && input.tool_name !== "Skill") {
|
|
21015
21136
|
process.exit(0);
|
|
21016
21137
|
}
|
package/hooks/hooks.json
CHANGED