claude-warden 1.1.0 → 1.1.4
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 +3 -3
- package/dist/index.cjs +55 -5
- package/package.json +10 -11
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@ Warden hooks into Claude Code's `PreToolUse` event and **parses every shell comm
|
|
|
15
15
|
This AST-based approach enables:
|
|
16
16
|
|
|
17
17
|
- **Pipe and chain decomposition**: `cat file | grep pattern | wc -l` is parsed into three commands, each evaluated separately. All safe → auto-allow. One dangerous → deny the whole pipeline.
|
|
18
|
-
- **Argument-aware rules**: `git status` → allow, `git push --force` → prompt. `rm temp.txt` → allow, `rm -rf /` →
|
|
18
|
+
- **Argument-aware rules**: `git status` → allow, `git push --force` → prompt. `rm temp.txt` → allow, `rm -rf /` → prompt. The evaluator matches against argument patterns, not just command names.
|
|
19
19
|
- **Recursive evaluation of remote commands**: `ssh devserver 'cat /etc/hosts'` → Warden extracts the remote command, parses it through the same pipeline, and allows it. `ssh devserver 'sudo rm -rf /'` → denied. Same for `docker exec`, `kubectl exec`, and `sprite exec`.
|
|
20
20
|
- **Shell wrapper unwrapping**: `sh -c "npm run build && npm test"` → the inner command is extracted and recursively parsed/evaluated, not treated as an opaque string.
|
|
21
21
|
- **Env prefix handling**: `NODE_ENV=production npm run build` → correctly evaluates `npm run build`, ignoring the env prefix.
|
|
@@ -32,7 +32,7 @@ The result: **100+ common dev commands auto-approved**, dangerous commands auto-
|
|
|
32
32
|
| `cat file \| grep pattern \| wc -l` | Prompted | Auto-allowed (3 safe commands) |
|
|
33
33
|
| `npm run build && npm test` | Prompted | Auto-allowed |
|
|
34
34
|
| `git push --force origin main` | Prompted | Prompted (force push is risky) |
|
|
35
|
-
| `sudo rm -rf /` | Prompted | Auto-denied |
|
|
35
|
+
| `sudo rm -rf /` | Prompted | Auto-denied (sudo is blocked) |
|
|
36
36
|
| `ssh devserver cat /etc/hosts` | Prompted | Auto-allowed (trusted host + safe cmd) |
|
|
37
37
|
| `ssh devserver sudo rm -rf /` | Prompted | Auto-denied (trusted host + dangerous cmd) |
|
|
38
38
|
|
|
@@ -147,7 +147,7 @@ File readers (`cat`, `head`, `tail`, `less`), search tools (`grep`, `rg`, `find`
|
|
|
147
147
|
### Conditional rules
|
|
148
148
|
Commands like `node`, `npx`, `docker`, `ssh`, `git push --force`, `rm`, `chmod` have argument-aware rules. For example:
|
|
149
149
|
- `git` is allowed but `git push --force` triggers a prompt
|
|
150
|
-
- `rm temp.txt` is allowed but `rm -rf /` is
|
|
150
|
+
- `rm temp.txt` is allowed but `rm -rf /` is prompted
|
|
151
151
|
- `chmod 644 file` prompts but `chmod -R 777 /var` is denied
|
|
152
152
|
|
|
153
153
|
### Trusted remote targets
|
package/dist/index.cjs
CHANGED
|
@@ -18888,6 +18888,11 @@ var DEFAULT_CONFIG = {
|
|
|
18888
18888
|
"fnm",
|
|
18889
18889
|
"rbenv",
|
|
18890
18890
|
"pyenv",
|
|
18891
|
+
// Terminal
|
|
18892
|
+
"stty",
|
|
18893
|
+
"tput",
|
|
18894
|
+
"reset",
|
|
18895
|
+
"clear",
|
|
18891
18896
|
// Misc safe
|
|
18892
18897
|
"cd",
|
|
18893
18898
|
"pushd",
|
|
@@ -18931,6 +18936,36 @@ var DEFAULT_CONFIG = {
|
|
|
18931
18936
|
"launchctl"
|
|
18932
18937
|
],
|
|
18933
18938
|
rules: [
|
|
18939
|
+
// --- CLI tools ---
|
|
18940
|
+
{
|
|
18941
|
+
command: "claude",
|
|
18942
|
+
default: "ask",
|
|
18943
|
+
argPatterns: [
|
|
18944
|
+
{ match: { anyArgMatches: ["^--(version|help)$", "^-[vh]$"] }, decision: "allow", description: "Version/help flags" }
|
|
18945
|
+
]
|
|
18946
|
+
},
|
|
18947
|
+
// --- Shell interpreters ---
|
|
18948
|
+
{
|
|
18949
|
+
command: "bash",
|
|
18950
|
+
default: "ask",
|
|
18951
|
+
argPatterns: [
|
|
18952
|
+
{ match: { anyArgMatches: ["^--(version|help)$"] }, decision: "allow", description: "Version/help flags" }
|
|
18953
|
+
]
|
|
18954
|
+
},
|
|
18955
|
+
{
|
|
18956
|
+
command: "sh",
|
|
18957
|
+
default: "ask",
|
|
18958
|
+
argPatterns: [
|
|
18959
|
+
{ match: { anyArgMatches: ["^--(version|help)$"] }, decision: "allow", description: "Version/help flags" }
|
|
18960
|
+
]
|
|
18961
|
+
},
|
|
18962
|
+
{
|
|
18963
|
+
command: "zsh",
|
|
18964
|
+
default: "ask",
|
|
18965
|
+
argPatterns: [
|
|
18966
|
+
{ match: { anyArgMatches: ["^--(version|help)$"] }, decision: "allow", description: "Version/help flags" }
|
|
18967
|
+
]
|
|
18968
|
+
},
|
|
18934
18969
|
// --- Node.js ecosystem ---
|
|
18935
18970
|
{
|
|
18936
18971
|
command: "node",
|
|
@@ -19075,7 +19110,7 @@ var DEFAULT_CONFIG = {
|
|
|
19075
19110
|
command: "rm",
|
|
19076
19111
|
default: "ask",
|
|
19077
19112
|
argPatterns: [
|
|
19078
|
-
{ match: { argsMatch: ["-[^\\s]*r[^\\s]*f|-[^\\s]*f[^\\s]*r"] }, decision: "
|
|
19113
|
+
{ match: { argsMatch: ["-[^\\s]*r[^\\s]*f|-[^\\s]*f[^\\s]*r"] }, decision: "ask", reason: "Recursive force delete (rm -rf)" },
|
|
19079
19114
|
{ match: { argsMatch: ["-[^\\s]*r"] }, decision: "ask", reason: "Recursive delete" },
|
|
19080
19115
|
{ match: { argCount: { max: 3 }, not: false }, decision: "allow", description: "Deleting a small number of non-recursive files" }
|
|
19081
19116
|
]
|
|
@@ -19230,9 +19265,12 @@ function generateAllowSnippet(details) {
|
|
|
19230
19265
|
return lines.join("\n");
|
|
19231
19266
|
}
|
|
19232
19267
|
function formatSystemMessage(decision, rawCommand, details) {
|
|
19233
|
-
const header = decision === "deny" ? "[warden] Command blocked" : "[warden] Command flagged for review";
|
|
19234
|
-
const lines = [header, ""];
|
|
19235
19268
|
const relevant = details.filter((d) => d.decision !== "allow");
|
|
19269
|
+
if (decision === "ask") {
|
|
19270
|
+
const parts = relevant.map((d) => `\`${d.command}\`: ${d.reason}`);
|
|
19271
|
+
return `[warden] ${parts.join(" | ")} \u2014 To auto-allow, see /warden-allow`;
|
|
19272
|
+
}
|
|
19273
|
+
const lines = ["[warden] Command blocked", ""];
|
|
19236
19274
|
if (relevant.length > 0) {
|
|
19237
19275
|
for (const d of relevant) {
|
|
19238
19276
|
lines.push(`- \`${d.command}\`: ${d.reason}`);
|
|
@@ -19291,14 +19329,26 @@ async function main() {
|
|
|
19291
19329
|
}
|
|
19292
19330
|
if (result.decision === "deny") {
|
|
19293
19331
|
const msg2 = formatSystemMessage("deny", command, result.details);
|
|
19294
|
-
const output2 = {
|
|
19332
|
+
const output2 = {
|
|
19333
|
+
hookSpecificOutput: {
|
|
19334
|
+
hookEventName: "PreToolUse",
|
|
19335
|
+
permissionDecision: "deny",
|
|
19336
|
+
permissionDecisionReason: msg2
|
|
19337
|
+
}
|
|
19338
|
+
};
|
|
19295
19339
|
process.stdout.write(JSON.stringify(output2));
|
|
19296
19340
|
process.stderr.write(`[warden] Blocked: ${result.reason}
|
|
19297
19341
|
`);
|
|
19298
19342
|
process.exit(2);
|
|
19299
19343
|
}
|
|
19300
19344
|
const msg = formatSystemMessage("ask", command, result.details);
|
|
19301
|
-
const output = {
|
|
19345
|
+
const output = {
|
|
19346
|
+
hookSpecificOutput: {
|
|
19347
|
+
hookEventName: "PreToolUse",
|
|
19348
|
+
permissionDecision: "ask",
|
|
19349
|
+
permissionDecisionReason: msg
|
|
19350
|
+
}
|
|
19351
|
+
};
|
|
19302
19352
|
process.stdout.write(JSON.stringify(output));
|
|
19303
19353
|
process.exit(0);
|
|
19304
19354
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-warden",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.4",
|
|
4
4
|
"description": "Smart command safety filter for Claude Code — auto-approves safe commands, blocks dangerous ones",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
@@ -28,15 +28,6 @@
|
|
|
28
28
|
"README.md",
|
|
29
29
|
"LICENSE"
|
|
30
30
|
],
|
|
31
|
-
"scripts": {
|
|
32
|
-
"build": "tsup",
|
|
33
|
-
"dev": "tsup --watch",
|
|
34
|
-
"test": "vitest run",
|
|
35
|
-
"test:watch": "vitest",
|
|
36
|
-
"typecheck": "tsc --noEmit",
|
|
37
|
-
"eval": "node dist/index.cjs",
|
|
38
|
-
"prepublishOnly": "pnpm run build && pnpm run test"
|
|
39
|
-
},
|
|
40
31
|
"devDependencies": {
|
|
41
32
|
"@types/node": "^20.0.0",
|
|
42
33
|
"bash-parser": "^0.5.0",
|
|
@@ -44,5 +35,13 @@
|
|
|
44
35
|
"typescript": "^5.4.0",
|
|
45
36
|
"vitest": "^1.6.0",
|
|
46
37
|
"yaml": "^2.4.0"
|
|
38
|
+
},
|
|
39
|
+
"scripts": {
|
|
40
|
+
"build": "tsup",
|
|
41
|
+
"dev": "tsup --watch",
|
|
42
|
+
"test": "vitest run",
|
|
43
|
+
"test:watch": "vitest",
|
|
44
|
+
"typecheck": "tsc --noEmit",
|
|
45
|
+
"eval": "node dist/index.cjs"
|
|
47
46
|
}
|
|
48
|
-
}
|
|
47
|
+
}
|