claude-warden 1.2.1 → 1.4.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/plugin.json +1 -1
- package/README.md +2 -2
- package/config/warden.default.yaml +23 -7
- package/dist/index.cjs +267 -43
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-warden",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.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
|
@@ -127,14 +127,14 @@ rules:
|
|
|
127
127
|
description: Read-only docker commands
|
|
128
128
|
```
|
|
129
129
|
|
|
130
|
-
## Feedback and `/warden-allow`
|
|
130
|
+
## Feedback and `/claude-warden:warden-allow`
|
|
131
131
|
|
|
132
132
|
When Warden blocks or flags a command, it includes a system message explaining:
|
|
133
133
|
|
|
134
134
|
1. **Why** the command was blocked/flagged (per-command reasons)
|
|
135
135
|
2. **How to allow it** — a ready-to-use YAML snippet for your config
|
|
136
136
|
|
|
137
|
-
Use the `/warden-allow` slash command to apply the suggested config change. It will ask which scope (project or user) to use.
|
|
137
|
+
Use the `/claude-warden:warden-allow` slash command to apply the suggested config change. It will ask which scope (project or user) to use.
|
|
138
138
|
|
|
139
139
|
## Built-in defaults
|
|
140
140
|
|
|
@@ -27,29 +27,45 @@ askOnSubshell: true
|
|
|
27
27
|
# Trusted SSH hosts — ssh/scp/rsync to these hosts are auto-allowed.
|
|
28
28
|
# Remote commands on trusted hosts are recursively evaluated through warden rules.
|
|
29
29
|
# Supports glob patterns (* wildcards).
|
|
30
|
+
# Entries can be strings (use global overrides) or objects with per-target settings.
|
|
30
31
|
# trustedSSHHosts:
|
|
31
|
-
# - devserver
|
|
32
|
+
# - devserver # string → uses global overrides only
|
|
32
33
|
# - staging-*
|
|
33
34
|
# - "*.internal.company.com"
|
|
34
|
-
# -
|
|
35
|
+
# - name: prod-bastion # object with per-target overrides
|
|
36
|
+
# overrides:
|
|
37
|
+
# alwaysAllow: [systemctl]
|
|
35
38
|
|
|
36
39
|
# Trusted Docker containers — docker exec to these containers are auto-allowed.
|
|
37
40
|
# Remote commands are recursively evaluated through warden rules.
|
|
38
41
|
# trustedDockerContainers:
|
|
39
|
-
# - my-app
|
|
40
|
-
# - dev
|
|
42
|
+
# - my-app # string → uses global overrides only
|
|
43
|
+
# - name: dev-container # object with allowAll (skip all checks)
|
|
44
|
+
# allowAll: true
|
|
45
|
+
# - name: staging-* # object with per-target overrides
|
|
46
|
+
# overrides:
|
|
47
|
+
# alwaysAllow: [sudo, apt]
|
|
41
48
|
|
|
42
49
|
# Trusted kubectl contexts — kubectl exec in these contexts are auto-allowed.
|
|
43
50
|
# Remote commands (after --) are recursively evaluated through warden rules.
|
|
44
51
|
# trustedKubectlContexts:
|
|
45
52
|
# - minikube
|
|
46
|
-
# - dev-cluster-*
|
|
53
|
+
# - name: dev-cluster-*
|
|
54
|
+
# overrides:
|
|
55
|
+
# alwaysAllow: [sudo]
|
|
56
|
+
# - name: prod-cluster
|
|
57
|
+
# overrides:
|
|
58
|
+
# alwaysDeny: [rm]
|
|
47
59
|
|
|
48
60
|
# Trusted Sprites — sprite exec/console to these sprites are auto-allowed.
|
|
49
61
|
# Remote commands are recursively evaluated through warden rules.
|
|
50
62
|
# trustedSprites:
|
|
51
|
-
# - my-sprite
|
|
52
|
-
# -
|
|
63
|
+
# - my-sprite # string → uses global overrides only
|
|
64
|
+
# - name: yudu-claw # allowAll: skip all checks (disposable env)
|
|
65
|
+
# allowAll: true
|
|
66
|
+
# - name: dev-* # per-target overrides
|
|
67
|
+
# overrides:
|
|
68
|
+
# alwaysAllow: [sudo, apt]
|
|
53
69
|
|
|
54
70
|
# Override rules when evaluating commands inside trusted remote contexts
|
|
55
71
|
# (docker exec, kubectl exec, ssh, sprite exec). These overrides are applied
|
package/dist/index.cjs
CHANGED
|
@@ -18515,8 +18515,8 @@ function globToRegex(pattern) {
|
|
|
18515
18515
|
}
|
|
18516
18516
|
return new RegExp(`^${regex}$`);
|
|
18517
18517
|
}
|
|
18518
|
-
function
|
|
18519
|
-
return
|
|
18518
|
+
function findMatchingTarget(value, targets) {
|
|
18519
|
+
return targets.find((t) => globToRegex(t.name).test(value)) || null;
|
|
18520
18520
|
}
|
|
18521
18521
|
function parseSSHArgs(args2) {
|
|
18522
18522
|
let host = null;
|
|
@@ -18560,19 +18560,21 @@ function evaluateSSHCommand(cmd, config) {
|
|
|
18560
18560
|
const trustedHosts = config.trustedSSHHosts || [];
|
|
18561
18561
|
if (command === "scp" || command === "rsync") {
|
|
18562
18562
|
const host2 = extractHostFromRemotePath(args2);
|
|
18563
|
-
if (host2
|
|
18564
|
-
|
|
18565
|
-
|
|
18566
|
-
|
|
18567
|
-
|
|
18568
|
-
|
|
18569
|
-
|
|
18570
|
-
}
|
|
18571
|
-
|
|
18572
|
-
|
|
18563
|
+
if (!host2) return null;
|
|
18564
|
+
const target2 = findMatchingTarget(host2, trustedHosts);
|
|
18565
|
+
if (!target2) return null;
|
|
18566
|
+
return {
|
|
18567
|
+
command,
|
|
18568
|
+
args: args2,
|
|
18569
|
+
decision: "allow",
|
|
18570
|
+
reason: `Trusted SSH host "${host2}"`,
|
|
18571
|
+
matchedRule: "trustedSSHHosts"
|
|
18572
|
+
};
|
|
18573
18573
|
}
|
|
18574
18574
|
const { host, remoteCommand } = parseSSHArgs(args2);
|
|
18575
|
-
if (!host
|
|
18575
|
+
if (!host) return null;
|
|
18576
|
+
const target = findMatchingTarget(host, trustedHosts);
|
|
18577
|
+
if (!target) return null;
|
|
18576
18578
|
if (!remoteCommand) {
|
|
18577
18579
|
return {
|
|
18578
18580
|
command,
|
|
@@ -18582,8 +18584,17 @@ function evaluateSSHCommand(cmd, config) {
|
|
|
18582
18584
|
matchedRule: "trustedSSHHosts"
|
|
18583
18585
|
};
|
|
18584
18586
|
}
|
|
18587
|
+
if (target.allowAll) {
|
|
18588
|
+
return {
|
|
18589
|
+
command,
|
|
18590
|
+
args: args2,
|
|
18591
|
+
decision: "allow",
|
|
18592
|
+
reason: `Trusted SSH host "${host}" (allowAll)`,
|
|
18593
|
+
matchedRule: "trustedSSHHosts"
|
|
18594
|
+
};
|
|
18595
|
+
}
|
|
18585
18596
|
const parsed = parseCommand(remoteCommand);
|
|
18586
|
-
const result = evaluate(parsed, configWithContextOverrides(config));
|
|
18597
|
+
const result = evaluate(parsed, configWithContextOverrides(config, target));
|
|
18587
18598
|
return {
|
|
18588
18599
|
command,
|
|
18589
18600
|
args: args2,
|
|
@@ -18603,15 +18614,21 @@ var DOCKER_EXEC_FLAGS_WITH_VALUE = /* @__PURE__ */ new Set([
|
|
|
18603
18614
|
"--detach-keys"
|
|
18604
18615
|
]);
|
|
18605
18616
|
var INTERACTIVE_SHELLS = /* @__PURE__ */ new Set(["bash", "sh", "zsh"]);
|
|
18606
|
-
function configWithContextOverrides(config) {
|
|
18607
|
-
|
|
18617
|
+
function configWithContextOverrides(config, target) {
|
|
18618
|
+
const overrideLayers = [];
|
|
18619
|
+
if (target?.overrides) overrideLayers.push(target.overrides);
|
|
18620
|
+
if (config.trustedContextOverrides) overrideLayers.push(config.trustedContextOverrides);
|
|
18621
|
+
if (overrideLayers.length === 0) return config;
|
|
18608
18622
|
return {
|
|
18609
18623
|
...config,
|
|
18610
|
-
layers: [
|
|
18624
|
+
layers: [...overrideLayers, ...config.layers]
|
|
18611
18625
|
};
|
|
18612
18626
|
}
|
|
18613
|
-
function evaluateRemoteCommand(remoteArgs, config) {
|
|
18614
|
-
|
|
18627
|
+
function evaluateRemoteCommand(remoteArgs, config, target) {
|
|
18628
|
+
if (target?.allowAll) {
|
|
18629
|
+
return { decision: "allow", reason: "allowAll target", details: [] };
|
|
18630
|
+
}
|
|
18631
|
+
const overriddenConfig = configWithContextOverrides(config, target);
|
|
18615
18632
|
if (remoteArgs.length === 0) {
|
|
18616
18633
|
return { decision: "allow", reason: "interactive", details: [] };
|
|
18617
18634
|
}
|
|
@@ -18625,9 +18642,10 @@ function evaluateRemoteCommand(remoteArgs, config) {
|
|
|
18625
18642
|
return evaluate(parsed2, overriddenConfig);
|
|
18626
18643
|
}
|
|
18627
18644
|
const parsed = {
|
|
18628
|
-
commands: [{ command: remoteCmd, args: remoteArgs.slice(1) }],
|
|
18645
|
+
commands: [{ command: remoteCmd, args: remoteArgs.slice(1), envPrefixes: [], raw: remoteArgs.join(" ") }],
|
|
18629
18646
|
hasSubshell: false,
|
|
18630
|
-
subshellCommands: []
|
|
18647
|
+
subshellCommands: [],
|
|
18648
|
+
parseError: false
|
|
18631
18649
|
};
|
|
18632
18650
|
return evaluate(parsed, overriddenConfig);
|
|
18633
18651
|
}
|
|
@@ -18661,14 +18679,16 @@ function parseDockerExecArgs(args2) {
|
|
|
18661
18679
|
function evaluateDockerExec(cmd, config) {
|
|
18662
18680
|
const { command, args: args2 } = cmd;
|
|
18663
18681
|
if (args2[0] !== "exec") return null;
|
|
18664
|
-
const { target, remoteArgs } = parseDockerExecArgs(args2.slice(1));
|
|
18665
|
-
if (!
|
|
18666
|
-
const
|
|
18682
|
+
const { target: containerName, remoteArgs } = parseDockerExecArgs(args2.slice(1));
|
|
18683
|
+
if (!containerName) return null;
|
|
18684
|
+
const matched = findMatchingTarget(containerName, config.trustedDockerContainers || []);
|
|
18685
|
+
if (!matched) return null;
|
|
18686
|
+
const result = evaluateRemoteCommand(remoteArgs, config, matched);
|
|
18667
18687
|
return {
|
|
18668
18688
|
command,
|
|
18669
18689
|
args: args2,
|
|
18670
18690
|
decision: result.decision,
|
|
18671
|
-
reason: `Trusted Docker container "${
|
|
18691
|
+
reason: `Trusted Docker container "${containerName}" (${result.reason})`,
|
|
18672
18692
|
matchedRule: "trustedDockerContainers"
|
|
18673
18693
|
};
|
|
18674
18694
|
}
|
|
@@ -18740,9 +18760,10 @@ function evaluateKubectlExec(cmd, config) {
|
|
|
18740
18760
|
const { command, args: args2 } = cmd;
|
|
18741
18761
|
if (args2[0] !== "exec") return null;
|
|
18742
18762
|
const { context, pod, remoteArgs } = parseKubectlExecArgs(args2.slice(1));
|
|
18743
|
-
|
|
18744
|
-
|
|
18745
|
-
|
|
18763
|
+
if (!context) return null;
|
|
18764
|
+
const matched = findMatchingTarget(context, config.trustedKubectlContexts || []);
|
|
18765
|
+
if (!matched) return null;
|
|
18766
|
+
const result = evaluateRemoteCommand(remoteArgs, config, matched);
|
|
18746
18767
|
return {
|
|
18747
18768
|
command,
|
|
18748
18769
|
args: args2,
|
|
@@ -18805,9 +18826,10 @@ function parseSpriteExecArgs(args2) {
|
|
|
18805
18826
|
function evaluateSpriteExec(cmd, config) {
|
|
18806
18827
|
const { command, args: args2 } = cmd;
|
|
18807
18828
|
const { spriteName, remoteArgs } = parseSpriteExecArgs(args2);
|
|
18808
|
-
|
|
18809
|
-
|
|
18810
|
-
|
|
18829
|
+
if (!spriteName) return null;
|
|
18830
|
+
const matched = findMatchingTarget(spriteName, config.trustedSprites || []);
|
|
18831
|
+
if (!matched) return null;
|
|
18832
|
+
const result = evaluateRemoteCommand(remoteArgs, config, matched);
|
|
18811
18833
|
return {
|
|
18812
18834
|
command,
|
|
18813
18835
|
args: args2,
|
|
@@ -19058,6 +19080,19 @@ var DEFAULT_CONFIG = {
|
|
|
19058
19080
|
"yq",
|
|
19059
19081
|
"xargs",
|
|
19060
19082
|
"seq",
|
|
19083
|
+
// Network diagnostics (read-only)
|
|
19084
|
+
"nslookup",
|
|
19085
|
+
"dig",
|
|
19086
|
+
"host",
|
|
19087
|
+
"ping",
|
|
19088
|
+
"traceroute",
|
|
19089
|
+
"mtr",
|
|
19090
|
+
"netstat",
|
|
19091
|
+
"ss",
|
|
19092
|
+
"ifconfig",
|
|
19093
|
+
"ip",
|
|
19094
|
+
"nmap",
|
|
19095
|
+
"arp",
|
|
19061
19096
|
// Pagers and formatters
|
|
19062
19097
|
"bat",
|
|
19063
19098
|
"pygmentize",
|
|
@@ -19072,6 +19107,74 @@ var DEFAULT_CONFIG = {
|
|
|
19072
19107
|
"tput",
|
|
19073
19108
|
"reset",
|
|
19074
19109
|
"clear",
|
|
19110
|
+
// System/hardware info
|
|
19111
|
+
"lscpu",
|
|
19112
|
+
"lsblk",
|
|
19113
|
+
"lsusb",
|
|
19114
|
+
"lspci",
|
|
19115
|
+
"lsmod",
|
|
19116
|
+
"dmesg",
|
|
19117
|
+
"sysctl",
|
|
19118
|
+
"sw_vers",
|
|
19119
|
+
"system_profiler",
|
|
19120
|
+
"hostinfo",
|
|
19121
|
+
"lsb_release",
|
|
19122
|
+
"hostnamectl",
|
|
19123
|
+
"arch",
|
|
19124
|
+
"getconf",
|
|
19125
|
+
// User/group info
|
|
19126
|
+
"groups",
|
|
19127
|
+
"getent",
|
|
19128
|
+
"w",
|
|
19129
|
+
"last",
|
|
19130
|
+
"lastlog",
|
|
19131
|
+
"finger",
|
|
19132
|
+
"users",
|
|
19133
|
+
// Process info
|
|
19134
|
+
"pgrep",
|
|
19135
|
+
"pidof",
|
|
19136
|
+
"jobs",
|
|
19137
|
+
// Compression/archive
|
|
19138
|
+
"tar",
|
|
19139
|
+
"gzip",
|
|
19140
|
+
"gunzip",
|
|
19141
|
+
"bzip2",
|
|
19142
|
+
"bunzip2",
|
|
19143
|
+
"xz",
|
|
19144
|
+
"unxz",
|
|
19145
|
+
"zip",
|
|
19146
|
+
"unzip",
|
|
19147
|
+
"7z",
|
|
19148
|
+
"zcat",
|
|
19149
|
+
"bzcat",
|
|
19150
|
+
"xzcat",
|
|
19151
|
+
"zless",
|
|
19152
|
+
"zmore",
|
|
19153
|
+
"zgrep",
|
|
19154
|
+
// Clipboard
|
|
19155
|
+
"pbcopy",
|
|
19156
|
+
"pbpaste",
|
|
19157
|
+
"xclip",
|
|
19158
|
+
"xsel",
|
|
19159
|
+
"wl-copy",
|
|
19160
|
+
"wl-paste",
|
|
19161
|
+
// Binary analysis
|
|
19162
|
+
"strings",
|
|
19163
|
+
"nm",
|
|
19164
|
+
"objdump",
|
|
19165
|
+
"readelf",
|
|
19166
|
+
"ldd",
|
|
19167
|
+
"otool",
|
|
19168
|
+
"size",
|
|
19169
|
+
// macOS utilities (read-only)
|
|
19170
|
+
"mdfind",
|
|
19171
|
+
"mdls",
|
|
19172
|
+
"mdutil",
|
|
19173
|
+
"plutil",
|
|
19174
|
+
"sips",
|
|
19175
|
+
"xcode-select",
|
|
19176
|
+
"xcrun",
|
|
19177
|
+
"xcodebuild",
|
|
19075
19178
|
// Misc safe
|
|
19076
19179
|
"cd",
|
|
19077
19180
|
"pushd",
|
|
@@ -19089,7 +19192,18 @@ var DEFAULT_CONFIG = {
|
|
|
19089
19192
|
"shasum",
|
|
19090
19193
|
"cksum",
|
|
19091
19194
|
"base64",
|
|
19092
|
-
"openssl"
|
|
19195
|
+
"openssl",
|
|
19196
|
+
"watch",
|
|
19197
|
+
"timeout",
|
|
19198
|
+
"nohup",
|
|
19199
|
+
"nice",
|
|
19200
|
+
"iconv",
|
|
19201
|
+
"locale",
|
|
19202
|
+
"localedef",
|
|
19203
|
+
"numfmt",
|
|
19204
|
+
"factor",
|
|
19205
|
+
"bc",
|
|
19206
|
+
"dc"
|
|
19093
19207
|
],
|
|
19094
19208
|
alwaysDeny: [
|
|
19095
19209
|
"sudo",
|
|
@@ -19113,7 +19227,9 @@ var DEFAULT_CONFIG = {
|
|
|
19113
19227
|
"crontab",
|
|
19114
19228
|
"systemctl",
|
|
19115
19229
|
"service",
|
|
19116
|
-
"launchctl"
|
|
19230
|
+
"launchctl",
|
|
19231
|
+
"wipefs",
|
|
19232
|
+
"shred"
|
|
19117
19233
|
],
|
|
19118
19234
|
rules: [
|
|
19119
19235
|
// --- CLI tools ---
|
|
@@ -19228,7 +19344,15 @@ var DEFAULT_CONFIG = {
|
|
|
19228
19344
|
]
|
|
19229
19345
|
},
|
|
19230
19346
|
{ command: "docker-compose", default: "ask" },
|
|
19231
|
-
{
|
|
19347
|
+
{
|
|
19348
|
+
command: "kubectl",
|
|
19349
|
+
default: "ask",
|
|
19350
|
+
argPatterns: [
|
|
19351
|
+
{ match: { anyArgMatches: ["^(get|describe|logs|top|explain|api-resources|api-versions|version|config|cluster-info)$"] }, decision: "allow", description: "Read-only kubectl commands" },
|
|
19352
|
+
{ match: { anyArgMatches: ["^(delete|drain|cordon|taint)$"] }, decision: "ask", reason: "Destructive kubectl operation" },
|
|
19353
|
+
VERSION_HELP_FLAGS
|
|
19354
|
+
]
|
|
19355
|
+
},
|
|
19232
19356
|
// --- File operations ---
|
|
19233
19357
|
{
|
|
19234
19358
|
command: "rm",
|
|
@@ -19268,7 +19392,92 @@ var DEFAULT_CONFIG = {
|
|
|
19268
19392
|
// --- Terraform / IaC ---
|
|
19269
19393
|
{ command: "terraform", default: "ask", argPatterns: [
|
|
19270
19394
|
{ match: { anyArgMatches: ["^(plan|validate|fmt|show|state|output|providers|version|graph|console)$"] }, decision: "allow", description: "Read-only terraform commands" }
|
|
19271
|
-
] }
|
|
19395
|
+
] },
|
|
19396
|
+
// --- macOS open ---
|
|
19397
|
+
{ command: "open", default: "ask" },
|
|
19398
|
+
// --- Text editors ---
|
|
19399
|
+
...["vi", "vim", "nvim", "nano", "emacs"].map((cmd) => ({
|
|
19400
|
+
command: cmd,
|
|
19401
|
+
default: "ask",
|
|
19402
|
+
argPatterns: [VERSION_HELP_FLAGS]
|
|
19403
|
+
})),
|
|
19404
|
+
// --- Scripting languages ---
|
|
19405
|
+
...["ruby", "perl", "php"].map((cmd) => ({
|
|
19406
|
+
command: cmd,
|
|
19407
|
+
default: "ask",
|
|
19408
|
+
argPatterns: [
|
|
19409
|
+
{ match: { anyArgMatches: ["^-e$", "^--eval"] }, decision: "ask", reason: "Inline code execution" },
|
|
19410
|
+
VERSION_HELP_FLAGS
|
|
19411
|
+
]
|
|
19412
|
+
})),
|
|
19413
|
+
// --- Java ecosystem ---
|
|
19414
|
+
{ command: "java", default: "ask", argPatterns: [VERSION_HELP_FLAGS] },
|
|
19415
|
+
{ command: "javac", default: "allow" },
|
|
19416
|
+
// --- Swift / Zig / Dotnet ---
|
|
19417
|
+
{ command: "swift", default: "allow", argPatterns: [
|
|
19418
|
+
{ match: { anyArgMatches: ["^(build|test|run|package)$"] }, decision: "allow" }
|
|
19419
|
+
] },
|
|
19420
|
+
{ command: "swiftc", default: "allow" },
|
|
19421
|
+
{ command: "zig", default: "allow" },
|
|
19422
|
+
{ command: "dotnet", default: "allow", argPatterns: [
|
|
19423
|
+
{ match: { anyArgMatches: ["^(publish|nuget)$"] }, decision: "ask", reason: "Publishing" }
|
|
19424
|
+
] },
|
|
19425
|
+
// --- Database CLIs ---
|
|
19426
|
+
...["psql", "mysql", "mariadb", "sqlite3", "redis-cli", "mongosh"].map((cmd) => ({
|
|
19427
|
+
command: cmd,
|
|
19428
|
+
default: "ask",
|
|
19429
|
+
argPatterns: [VERSION_HELP_FLAGS]
|
|
19430
|
+
})),
|
|
19431
|
+
// --- Cloud CLIs ---
|
|
19432
|
+
{ command: "gcloud", default: "ask", argPatterns: [
|
|
19433
|
+
{ match: { anyArgMatches: ["^(info|version|help|config|components)$"] }, decision: "allow", description: "Config/info" },
|
|
19434
|
+
{ match: { anyArgMatches: ["^(list|describe|get-iam-policy|get)$"] }, decision: "allow", description: "Read-only ops" },
|
|
19435
|
+
VERSION_HELP_FLAGS
|
|
19436
|
+
] },
|
|
19437
|
+
{ command: "az", default: "ask", argPatterns: [
|
|
19438
|
+
{ match: { anyArgMatches: ["^(list|show|get)$"] }, decision: "allow", description: "Read-only ops" },
|
|
19439
|
+
VERSION_HELP_FLAGS
|
|
19440
|
+
] },
|
|
19441
|
+
{ command: "aws", default: "ask", argPatterns: [
|
|
19442
|
+
{ match: { anyArgMatches: ["^(describe|list|get|sts)$"] }, decision: "allow", description: "Read-only ops" },
|
|
19443
|
+
VERSION_HELP_FLAGS
|
|
19444
|
+
] },
|
|
19445
|
+
// --- Helm ---
|
|
19446
|
+
{ command: "helm", default: "ask", argPatterns: [
|
|
19447
|
+
{ match: { anyArgMatches: ["^(list|search|show|status|get|template|version|env|history)$"] }, decision: "allow", description: "Read-only helm commands" },
|
|
19448
|
+
VERSION_HELP_FLAGS
|
|
19449
|
+
] },
|
|
19450
|
+
// --- Screen/tmux ---
|
|
19451
|
+
...["screen", "tmux"].map((cmd) => ({
|
|
19452
|
+
command: cmd,
|
|
19453
|
+
default: "ask",
|
|
19454
|
+
argPatterns: [
|
|
19455
|
+
{ match: { anyArgMatches: ["^(list-sessions|ls|list)$"] }, decision: "allow", description: "List sessions" },
|
|
19456
|
+
VERSION_HELP_FLAGS
|
|
19457
|
+
]
|
|
19458
|
+
})),
|
|
19459
|
+
// --- GPG ---
|
|
19460
|
+
{ command: "gpg", default: "ask", argPatterns: [
|
|
19461
|
+
{ match: { anyArgMatches: ["^(--verify|--list-keys|--list-secret-keys|--fingerprint)$"] }, decision: "allow", description: "Read-only gpg" },
|
|
19462
|
+
VERSION_HELP_FLAGS
|
|
19463
|
+
] },
|
|
19464
|
+
// --- macOS-specific ---
|
|
19465
|
+
{ command: "defaults", default: "ask", argPatterns: [
|
|
19466
|
+
{ match: { anyArgMatches: ["^(read|read-type|find|domains)$"] }, decision: "allow", description: "Read-only defaults operations" }
|
|
19467
|
+
] },
|
|
19468
|
+
{ command: "diskutil", default: "ask", argPatterns: [
|
|
19469
|
+
{ match: { anyArgMatches: ["^(list|info|apfs|cs|appleRAID)$"] }, decision: "allow", description: "Read-only diskutil" }
|
|
19470
|
+
] },
|
|
19471
|
+
{ command: "codesign", default: "ask", argPatterns: [
|
|
19472
|
+
{ match: { anyArgMatches: ["^(-vv|--verify|--display|-d)$"] }, decision: "allow", description: "Verify codesign" }
|
|
19473
|
+
] },
|
|
19474
|
+
{ command: "osascript", default: "ask" },
|
|
19475
|
+
{ command: "say", default: "ask" },
|
|
19476
|
+
// --- Process management ---
|
|
19477
|
+
{ command: "kill", default: "ask" },
|
|
19478
|
+
{ command: "killall", default: "ask" },
|
|
19479
|
+
{ command: "pkill", default: "ask" },
|
|
19480
|
+
{ command: "renice", default: "ask" }
|
|
19272
19481
|
]
|
|
19273
19482
|
}]
|
|
19274
19483
|
};
|
|
@@ -19335,18 +19544,33 @@ function extractLayer(raw) {
|
|
|
19335
19544
|
rules: Array.isArray(raw.rules) ? raw.rules : []
|
|
19336
19545
|
};
|
|
19337
19546
|
}
|
|
19547
|
+
function parseTrustedList(raw) {
|
|
19548
|
+
return raw.map((entry) => {
|
|
19549
|
+
if (typeof entry === "string") return { name: entry };
|
|
19550
|
+
if (entry && typeof entry === "object" && "name" in entry) {
|
|
19551
|
+
const obj = entry;
|
|
19552
|
+
const target = { name: String(obj.name) };
|
|
19553
|
+
if (obj.allowAll === true) target.allowAll = true;
|
|
19554
|
+
if (obj.overrides && typeof obj.overrides === "object") {
|
|
19555
|
+
target.overrides = extractLayer(obj.overrides);
|
|
19556
|
+
}
|
|
19557
|
+
return target;
|
|
19558
|
+
}
|
|
19559
|
+
return null;
|
|
19560
|
+
}).filter((t) => t !== null);
|
|
19561
|
+
}
|
|
19338
19562
|
function mergeNonLayerFields(config, raw) {
|
|
19339
19563
|
if (Array.isArray(raw.trustedSSHHosts)) {
|
|
19340
|
-
config.trustedSSHHosts = [...config.trustedSSHHosts || [], ...raw.trustedSSHHosts];
|
|
19564
|
+
config.trustedSSHHosts = [...config.trustedSSHHosts || [], ...parseTrustedList(raw.trustedSSHHosts)];
|
|
19341
19565
|
}
|
|
19342
19566
|
if (Array.isArray(raw.trustedDockerContainers)) {
|
|
19343
|
-
config.trustedDockerContainers = [...config.trustedDockerContainers || [], ...raw.trustedDockerContainers];
|
|
19567
|
+
config.trustedDockerContainers = [...config.trustedDockerContainers || [], ...parseTrustedList(raw.trustedDockerContainers)];
|
|
19344
19568
|
}
|
|
19345
19569
|
if (Array.isArray(raw.trustedKubectlContexts)) {
|
|
19346
|
-
config.trustedKubectlContexts = [...config.trustedKubectlContexts || [], ...raw.trustedKubectlContexts];
|
|
19570
|
+
config.trustedKubectlContexts = [...config.trustedKubectlContexts || [], ...parseTrustedList(raw.trustedKubectlContexts)];
|
|
19347
19571
|
}
|
|
19348
19572
|
if (Array.isArray(raw.trustedSprites)) {
|
|
19349
|
-
config.trustedSprites = [...config.trustedSprites || [], ...raw.trustedSprites];
|
|
19573
|
+
config.trustedSprites = [...config.trustedSprites || [], ...parseTrustedList(raw.trustedSprites)];
|
|
19350
19574
|
}
|
|
19351
19575
|
if (typeof raw.defaultDecision === "string") {
|
|
19352
19576
|
config.defaultDecision = raw.defaultDecision;
|
|
@@ -19408,15 +19632,15 @@ function formatSystemMessage(decision, rawCommand, details) {
|
|
|
19408
19632
|
const header = `[warden] ${parts.join(" | ")}`;
|
|
19409
19633
|
const subcommandHints = relevant.filter((d) => d.args.length > 0).map((d) => {
|
|
19410
19634
|
const sub = d.args[0];
|
|
19411
|
-
return ` Option A: Allow all \`${d.command}\` \u2192 \`/warden-allow ${d.command}\`
|
|
19412
|
-
Option B: Allow only \`${d.command} ${sub}\` \u2192 \`/warden-allow ${d.command} ${sub}\``;
|
|
19635
|
+
return ` Option A: Allow all \`${d.command}\` \u2192 \`/claude-warden:warden-allow ${d.command}\`
|
|
19636
|
+
Option B: Allow only \`${d.command} ${sub}\` \u2192 \`/claude-warden:warden-allow ${d.command} ${sub}\``;
|
|
19413
19637
|
});
|
|
19414
19638
|
if (subcommandHints.length > 0) {
|
|
19415
19639
|
return `${header}
|
|
19416
19640
|
${subcommandHints.join("\n")}
|
|
19417
|
-
See /warden-allow`;
|
|
19641
|
+
See /claude-warden:warden-allow`;
|
|
19418
19642
|
}
|
|
19419
|
-
return `${header} \u2014 To auto-allow, see /warden-allow`;
|
|
19643
|
+
return `${header} \u2014 To auto-allow, see /claude-warden:warden-allow`;
|
|
19420
19644
|
}
|
|
19421
19645
|
const lines = ["[warden] Command blocked", ""];
|
|
19422
19646
|
if (relevant.length > 0) {
|