dsh-perm-gate 2.1.0 → 2.6.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/CHANGELOG.ja.md +108 -0
- package/CHANGELOG.ko.md +104 -0
- package/CHANGELOG.md +347 -0
- package/INSTALL.ja.md +84 -8
- package/INSTALL.ko.md +80 -9
- package/INSTALL.md +83 -8
- package/INSTALL.zh.md +70 -7
- package/README.ja.md +130 -16
- package/README.ko.md +128 -17
- package/README.md +179 -25
- package/README.zh.md +121 -12
- package/assets/allow1.png +0 -0
- package/assets/allow2.png +0 -0
- package/assets/gateoff.png +0 -0
- package/assets/llms.png +0 -0
- package/assets/permlist.png +0 -0
- package/assets/setting-head.png +0 -0
- package/assets/setting-rules.png +0 -0
- package/cordis.patch.yml +37 -3
- package/docs/baseline-guard.md +56 -0
- package/docs/plan-rules-to-settings.md +217 -0
- package/docs/rules-format.en.md +294 -0
- package/docs/rules-format.md +279 -0
- package/docs/ui-gap-analysis-and-branch-permissions.md +338 -0
- package/dsh.plugin.json +22 -0
- package/examples/permissions.example.yaml +16 -1
- package/lib/agent-identity.d.ts +43 -0
- package/lib/agent-identity.js +95 -0
- package/lib/allowlist.d.ts +27 -0
- package/lib/allowlist.js +103 -1
- package/lib/cli.js +11 -14
- package/lib/client.js +598 -6
- package/lib/client.js.map +1 -1
- package/lib/command-dispatcher.d.ts +22 -0
- package/lib/command-dispatcher.js +97 -0
- package/lib/command-semantics.d.ts +62 -0
- package/lib/command-semantics.js +6 -0
- package/lib/compiler.d.ts +50 -0
- package/lib/compiler.js +122 -0
- package/lib/config.d.ts +161 -7
- package/lib/config.js +78 -11
- package/lib/dry-run.d.ts +87 -0
- package/lib/dry-run.js +110 -0
- package/lib/engine.js +61 -4
- package/lib/evaluate.d.ts +9 -0
- package/lib/evaluate.js +264 -1
- package/lib/events.d.ts +69 -2
- package/lib/events.js +123 -0
- package/lib/index.d.ts +1 -1
- package/lib/index.js +320 -11
- package/lib/network-lifecycle.d.ts +107 -0
- package/lib/network-lifecycle.js +180 -0
- package/lib/network.d.ts +109 -0
- package/lib/network.js +196 -0
- package/lib/parsers/git.d.ts +43 -0
- package/lib/parsers/git.js +404 -0
- package/lib/parsers/shell-cmds.d.ts +32 -0
- package/lib/parsers/shell-cmds.js +293 -0
- package/lib/preset.d.ts +13 -0
- package/lib/preset.js +17 -0
- package/lib/proxy.d.ts +160 -0
- package/lib/proxy.js +529 -0
- package/lib/risk.d.ts +17 -3
- package/lib/risk.js +19 -6
- package/lib/rule-chain.d.ts +39 -0
- package/lib/rule-chain.js +213 -0
- package/lib/rule-dims.d.ts +174 -0
- package/lib/rule-dims.js +230 -0
- package/lib/rule.d.ts +60 -0
- package/lib/rule.js +69 -7
- package/lib/rules-view.d.ts +52 -0
- package/lib/rules-view.js +126 -0
- package/lib/runtime.d.ts +208 -7
- package/lib/runtime.js +433 -27
- package/lib/session-sweep.d.ts +45 -0
- package/lib/session-sweep.js +153 -0
- package/lib/shadow.d.ts +34 -0
- package/lib/shadow.js +143 -0
- package/lib/shell.d.ts +14 -0
- package/lib/shell.js +17 -0
- package/lib/watch.d.ts +42 -0
- package/lib/watch.js +170 -0
- package/package.json +26 -3
- package/scripts/patch-permission-glyph.mjs +392 -0
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git command parser - extracts subcommand, branch, remote, flags, destructiveness.
|
|
3
|
+
* P0 priority - most critical for branch permissions.
|
|
4
|
+
*
|
|
5
|
+
* Handles:
|
|
6
|
+
* - git push/force push detection
|
|
7
|
+
* - git branch operations (delete, rename)
|
|
8
|
+
* - git checkout/switch with branch names
|
|
9
|
+
* - git merge/rebase
|
|
10
|
+
* - git reset (soft/hard/mixed)
|
|
11
|
+
* - git clean (destructive file deletion)
|
|
12
|
+
* - git stash operations
|
|
13
|
+
* - git refspec parsing (HEAD:main)
|
|
14
|
+
* - Remote vs branch name disambiguation
|
|
15
|
+
*/
|
|
16
|
+
/** Known protected branch patterns */
|
|
17
|
+
const PROTECTED_BRANCHES = /^(main|master|production|release|stable)$/i;
|
|
18
|
+
/** Known remote names (common defaults) */
|
|
19
|
+
const KNOWN_REMOTES = /^(origin|upstream|fork|origin-\w+)$/i;
|
|
20
|
+
/** Flags that increase destructiveness */
|
|
21
|
+
const DESTRUCTIVE_FLAGS = new Set([
|
|
22
|
+
'--force', '-f',
|
|
23
|
+
'--hard',
|
|
24
|
+
'--delete', '-d', '-D',
|
|
25
|
+
'--amend',
|
|
26
|
+
'--no-backup',
|
|
27
|
+
'-rf',
|
|
28
|
+
'--clean',
|
|
29
|
+
'--reset',
|
|
30
|
+
]);
|
|
31
|
+
export class GitParser {
|
|
32
|
+
name = 'git';
|
|
33
|
+
priority = 10;
|
|
34
|
+
canParse(command) {
|
|
35
|
+
const trimmed = command.trim();
|
|
36
|
+
// Direct git command
|
|
37
|
+
if (/^git\s+/.test(trimmed))
|
|
38
|
+
return true;
|
|
39
|
+
// Shell-wrapped: sh -c "git ...", bash -c git ..., etc.
|
|
40
|
+
if (/(?:sh|bash|pwsh|powershell)(?:\s+-c\s+['"]?)?.*?\bgit\s+/.test(trimmed))
|
|
41
|
+
return true;
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
parse(command) {
|
|
45
|
+
const trimmed = command.trim();
|
|
46
|
+
// Extract the git command portion (strip shell wrappers)
|
|
47
|
+
const gitMatch = trimmed.match(/(?:sh|bash|pwsh|powershell)(?:\s+-c\s+['"]?)?(\s+git\s+.+)/);
|
|
48
|
+
const gitPart = gitMatch ? gitMatch[1].trim() : trimmed;
|
|
49
|
+
// Parse git arguments
|
|
50
|
+
const parts = this.parseGitArgs(gitPart);
|
|
51
|
+
if (parts.length < 2)
|
|
52
|
+
return null;
|
|
53
|
+
// Skip 'git' keyword if present
|
|
54
|
+
const startIndex = parts[0] === 'git' ? 1 : 0;
|
|
55
|
+
if (parts.length - startIndex < 1)
|
|
56
|
+
return null;
|
|
57
|
+
const subcommand = parts[startIndex]?.toLowerCase();
|
|
58
|
+
// Get rest of arguments
|
|
59
|
+
const args = parts.slice(startIndex + 1);
|
|
60
|
+
return this.analyzeSubcommand(subcommand, args, trimmed);
|
|
61
|
+
}
|
|
62
|
+
analyzeSubcommand(subcommand, args, rawCommand) {
|
|
63
|
+
const flags = this.extractFlags(args);
|
|
64
|
+
const hasForce = flags.includes('--force') || flags.includes('-f') || flags.includes('--force-with-lease');
|
|
65
|
+
const hasDelete = flags.includes('--delete') || flags.includes('-d') || flags.includes('-D');
|
|
66
|
+
const hasHard = flags.includes('--hard');
|
|
67
|
+
let operation;
|
|
68
|
+
let destructiveness = 1;
|
|
69
|
+
let targets = [];
|
|
70
|
+
let branch;
|
|
71
|
+
let remote;
|
|
72
|
+
let gitOperation = true;
|
|
73
|
+
let targetsSharedBranch = false;
|
|
74
|
+
switch (subcommand) {
|
|
75
|
+
case 'push': {
|
|
76
|
+
remote = this.extractRemote(args);
|
|
77
|
+
branch = this.extractBranch(args);
|
|
78
|
+
targets = [branch, remote].filter(Boolean);
|
|
79
|
+
targetsSharedBranch = this.isProtectedBranch(branch);
|
|
80
|
+
if (hasForce || flags.includes('--force-with-lease')) {
|
|
81
|
+
operation = 'force-push';
|
|
82
|
+
destructiveness = targetsSharedBranch ? 5 : 4;
|
|
83
|
+
}
|
|
84
|
+
else if (hasDelete) {
|
|
85
|
+
// 删除远端分支。`hasDelete` 此前只在 `branch` 分支被读取,push 侧从未
|
|
86
|
+
// 使用——于是 `git push --delete origin main` 落进上面的 else,被判成
|
|
87
|
+
// 普通 push(dest=4)、`DESTRUCTIVENESS_MAP` 里的 `'push-delete': 5`
|
|
88
|
+
// 是**死条目**。删远端分支与 force push 同级:都不可逆地改动共享历史。
|
|
89
|
+
operation = 'push-delete';
|
|
90
|
+
destructiveness = targetsSharedBranch ? 5 : 4;
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
operation = 'push';
|
|
94
|
+
destructiveness = targetsSharedBranch ? 4 : 3;
|
|
95
|
+
}
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
case 'reset': {
|
|
99
|
+
if (hasHard) {
|
|
100
|
+
operation = 'reset-hard';
|
|
101
|
+
destructiveness = 5;
|
|
102
|
+
}
|
|
103
|
+
else if (flags.includes('--soft')) {
|
|
104
|
+
operation = 'reset-soft';
|
|
105
|
+
destructiveness = 2;
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
operation = 'reset-mixed';
|
|
109
|
+
destructiveness = 4;
|
|
110
|
+
}
|
|
111
|
+
targets = this.extractRefs(args);
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
case 'branch': {
|
|
115
|
+
if (hasDelete) {
|
|
116
|
+
const forceDelete = flags.includes('-D');
|
|
117
|
+
branch = this.extractBranchName(args);
|
|
118
|
+
targets = [branch].filter(Boolean);
|
|
119
|
+
targetsSharedBranch = this.isProtectedBranch(branch);
|
|
120
|
+
operation = forceDelete ? 'branch-delete-force' : 'branch-delete';
|
|
121
|
+
destructiveness = targetsSharedBranch ? 5 : (forceDelete ? 3 : 2);
|
|
122
|
+
}
|
|
123
|
+
else if (flags.includes('-m') || flags.includes('--move')) {
|
|
124
|
+
operation = 'branch-rename';
|
|
125
|
+
destructiveness = 2;
|
|
126
|
+
targets = this.extractRefs(args);
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
operation = 'branch-create';
|
|
130
|
+
destructiveness = 3;
|
|
131
|
+
branch = this.extractBranchName(args);
|
|
132
|
+
targets = [branch].filter(Boolean);
|
|
133
|
+
}
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
case 'checkout':
|
|
137
|
+
case 'switch': {
|
|
138
|
+
const isNewBranch = flags.includes('-b') || flags.includes('--create');
|
|
139
|
+
branch = this.extractBranchName(args);
|
|
140
|
+
targets = [branch].filter(Boolean);
|
|
141
|
+
operation = isNewBranch ? 'checkout-new-branch' : 'checkout';
|
|
142
|
+
destructiveness = isNewBranch ? 3 : 2;
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
case 'merge': {
|
|
146
|
+
targets = this.extractRefs(args);
|
|
147
|
+
if (flags.includes('--ff-only')) {
|
|
148
|
+
operation = 'merge-ff-only';
|
|
149
|
+
destructiveness = 3;
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
operation = 'merge';
|
|
153
|
+
destructiveness = 3;
|
|
154
|
+
}
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
case 'rebase': {
|
|
158
|
+
targets = this.extractRefs(args);
|
|
159
|
+
if (flags.includes('-i') || flags.includes('--interactive')) {
|
|
160
|
+
operation = 'rebase-interactive';
|
|
161
|
+
destructiveness = 4;
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
operation = 'rebase';
|
|
165
|
+
destructiveness = 3;
|
|
166
|
+
}
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
case 'clean': {
|
|
170
|
+
if (hasForce || flags.includes('-f')) {
|
|
171
|
+
operation = 'clean-force';
|
|
172
|
+
destructiveness = 5;
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
operation = 'clean';
|
|
176
|
+
destructiveness = 3;
|
|
177
|
+
}
|
|
178
|
+
targets = this.extractRefs(args);
|
|
179
|
+
break;
|
|
180
|
+
}
|
|
181
|
+
case 'cherry-pick': {
|
|
182
|
+
operation = 'cherry-pick';
|
|
183
|
+
destructiveness = 3;
|
|
184
|
+
targets = this.extractRefs(args);
|
|
185
|
+
break;
|
|
186
|
+
}
|
|
187
|
+
case 'revert': {
|
|
188
|
+
operation = 'revert';
|
|
189
|
+
destructiveness = 3;
|
|
190
|
+
targets = this.extractRefs(args);
|
|
191
|
+
break;
|
|
192
|
+
}
|
|
193
|
+
case 'tag': {
|
|
194
|
+
if (hasDelete) {
|
|
195
|
+
operation = 'tag-delete';
|
|
196
|
+
destructiveness = 2;
|
|
197
|
+
targets = this.extractRefs(args);
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
operation = 'tag-create';
|
|
201
|
+
destructiveness = 1;
|
|
202
|
+
targets = this.extractRefs(args);
|
|
203
|
+
}
|
|
204
|
+
break;
|
|
205
|
+
}
|
|
206
|
+
case 'stash': {
|
|
207
|
+
const stashOp = args[0]?.toLowerCase();
|
|
208
|
+
if (stashOp === 'pop' || stashOp === 'apply') {
|
|
209
|
+
operation = 'stash-pop';
|
|
210
|
+
destructiveness = 2;
|
|
211
|
+
}
|
|
212
|
+
else if (stashOp === 'drop') {
|
|
213
|
+
operation = 'stash-drop';
|
|
214
|
+
destructiveness = 2;
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
operation = 'stash-create';
|
|
218
|
+
destructiveness = 1;
|
|
219
|
+
}
|
|
220
|
+
break;
|
|
221
|
+
}
|
|
222
|
+
case 'fetch': {
|
|
223
|
+
remote = this.extractRemote(args);
|
|
224
|
+
targets = [remote].filter(Boolean);
|
|
225
|
+
operation = 'fetch';
|
|
226
|
+
destructiveness = 1;
|
|
227
|
+
break;
|
|
228
|
+
}
|
|
229
|
+
case 'pull': {
|
|
230
|
+
remote = this.extractRemote(args);
|
|
231
|
+
branch = this.extractBranch(args);
|
|
232
|
+
targets = [remote, branch].filter(Boolean);
|
|
233
|
+
operation = 'pull';
|
|
234
|
+
destructiveness = 2;
|
|
235
|
+
break;
|
|
236
|
+
}
|
|
237
|
+
case 'clone': {
|
|
238
|
+
operation = 'clone';
|
|
239
|
+
destructiveness = 1;
|
|
240
|
+
targets = this.extractRefs(args);
|
|
241
|
+
break;
|
|
242
|
+
}
|
|
243
|
+
case 'status':
|
|
244
|
+
case 'log':
|
|
245
|
+
case 'diff':
|
|
246
|
+
case 'show':
|
|
247
|
+
case 'blame':
|
|
248
|
+
case 'ls-files':
|
|
249
|
+
case 'rev-parse':
|
|
250
|
+
case 'describe': {
|
|
251
|
+
operation = subcommand;
|
|
252
|
+
destructiveness = 1;
|
|
253
|
+
break;
|
|
254
|
+
}
|
|
255
|
+
default: {
|
|
256
|
+
// Unknown git subcommand
|
|
257
|
+
operation = subcommand;
|
|
258
|
+
destructiveness = 1;
|
|
259
|
+
gitOperation = true;
|
|
260
|
+
break;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
// Detect destructive flags
|
|
264
|
+
const destructiveFlags = hasForce || hasDelete || hasHard ||
|
|
265
|
+
flags.some(f => DESTRUCTIVE_FLAGS.has(f));
|
|
266
|
+
return {
|
|
267
|
+
family: 'git',
|
|
268
|
+
subcommand,
|
|
269
|
+
operation,
|
|
270
|
+
destructiveness: destructiveness,
|
|
271
|
+
destructiveFlags,
|
|
272
|
+
targets,
|
|
273
|
+
flags,
|
|
274
|
+
requiresConfirmation: destructiveness >= 4,
|
|
275
|
+
compound: false,
|
|
276
|
+
gitOperation,
|
|
277
|
+
branch,
|
|
278
|
+
remote,
|
|
279
|
+
targetsSharedBranch,
|
|
280
|
+
rawCommand: rawCommand,
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
parseGitArgs(command) {
|
|
284
|
+
const args = [];
|
|
285
|
+
let current = '';
|
|
286
|
+
let inQuote = false;
|
|
287
|
+
let quoteChar = '';
|
|
288
|
+
let escape = false;
|
|
289
|
+
for (const char of command) {
|
|
290
|
+
if (escape) {
|
|
291
|
+
current += char;
|
|
292
|
+
escape = false;
|
|
293
|
+
continue;
|
|
294
|
+
}
|
|
295
|
+
if (char === '\\') {
|
|
296
|
+
escape = true;
|
|
297
|
+
continue;
|
|
298
|
+
}
|
|
299
|
+
if (inQuote) {
|
|
300
|
+
if (char === quoteChar) {
|
|
301
|
+
inQuote = false;
|
|
302
|
+
continue;
|
|
303
|
+
}
|
|
304
|
+
current += char;
|
|
305
|
+
continue;
|
|
306
|
+
}
|
|
307
|
+
if (char === '"' || char === "'") {
|
|
308
|
+
inQuote = true;
|
|
309
|
+
quoteChar = char;
|
|
310
|
+
continue;
|
|
311
|
+
}
|
|
312
|
+
if (/\s/.test(char)) {
|
|
313
|
+
if (current) {
|
|
314
|
+
args.push(current);
|
|
315
|
+
current = '';
|
|
316
|
+
}
|
|
317
|
+
continue;
|
|
318
|
+
}
|
|
319
|
+
current += char;
|
|
320
|
+
}
|
|
321
|
+
if (current)
|
|
322
|
+
args.push(current);
|
|
323
|
+
return args;
|
|
324
|
+
}
|
|
325
|
+
extractFlags(args) {
|
|
326
|
+
const flags = [];
|
|
327
|
+
for (const arg of args) {
|
|
328
|
+
if (arg.startsWith('-')) {
|
|
329
|
+
// Normalize long flags to lowercase, but preserve case for short flags
|
|
330
|
+
// to distinguish between -d (delete) and -D (force delete)
|
|
331
|
+
if (arg.startsWith('--')) {
|
|
332
|
+
flags.push(arg.toLowerCase());
|
|
333
|
+
}
|
|
334
|
+
else {
|
|
335
|
+
// Short flags: -f, -d, -D, etc. - preserve case
|
|
336
|
+
flags.push(arg);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
return flags;
|
|
341
|
+
}
|
|
342
|
+
extractRemote(args) {
|
|
343
|
+
// First positional arg is usually remote
|
|
344
|
+
for (const arg of args) {
|
|
345
|
+
if (!arg.startsWith('-')) {
|
|
346
|
+
if (KNOWN_REMOTES.test(arg)) {
|
|
347
|
+
return arg;
|
|
348
|
+
}
|
|
349
|
+
// Could be a URL or path
|
|
350
|
+
if (arg.includes('/') || arg.includes('.')) {
|
|
351
|
+
return arg;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
return undefined;
|
|
356
|
+
}
|
|
357
|
+
extractBranch(args) {
|
|
358
|
+
// Branch is usually the last positional arg or after remote
|
|
359
|
+
const positionalArgs = args.filter(a => !a.startsWith('-'));
|
|
360
|
+
if (positionalArgs.length > 1) {
|
|
361
|
+
// Could be "origin main" or "origin:main"
|
|
362
|
+
const last = positionalArgs[positionalArgs.length - 1];
|
|
363
|
+
// Handle refspec (e.g., HEAD:main)
|
|
364
|
+
if (last.includes(':')) {
|
|
365
|
+
return last.split(':')[1];
|
|
366
|
+
}
|
|
367
|
+
return last;
|
|
368
|
+
}
|
|
369
|
+
return positionalArgs[0];
|
|
370
|
+
}
|
|
371
|
+
extractBranchName(args) {
|
|
372
|
+
// For branch create/checkout, find the branch name
|
|
373
|
+
const positionalArgs = args.filter(a => !a.startsWith('-'));
|
|
374
|
+
// Skip -b flag value if present
|
|
375
|
+
for (let i = 0; i < args.length; i++) {
|
|
376
|
+
if (args[i] === '-b' || args[i] === '--create') {
|
|
377
|
+
return args[i + 1];
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
return positionalArgs[positionalArgs.length - 1];
|
|
381
|
+
}
|
|
382
|
+
extractRefs(args) {
|
|
383
|
+
return args.filter(a => !a.startsWith('-') && !KNOWN_REMOTES.test(a));
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* 目标是否落在保护分支上。
|
|
387
|
+
*
|
|
388
|
+
* **只剥已知的 ref 前缀,不对任意 `/` 取末段。** 早先的写法是
|
|
389
|
+
* `branch.split('/').pop()`,于是:
|
|
390
|
+
* - `refs/heads/main` → `main` ✅ 期望如此
|
|
391
|
+
* - `backup/main` → `main` ❌ **误判**(它是含斜杠的普通分支名)
|
|
392
|
+
* - `feat/release` → `release` ❌ **误判**
|
|
393
|
+
*
|
|
394
|
+
* 误判方向不是"更安全"。这条判据喂给 P0 硬拒——而 P0 是**不可配置撤销**的
|
|
395
|
+
* (见 engine.ts 顶部:"deterministic, monotonic, never negotiated")。
|
|
396
|
+
* 漏判还有关键词层与 LLM 层兜底,误判则是"合法工作流被永久挡住且无出口"。
|
|
397
|
+
*/
|
|
398
|
+
isProtectedBranch(branch) {
|
|
399
|
+
if (!branch)
|
|
400
|
+
return false;
|
|
401
|
+
const cleanBranch = branch.replace(/^refs\/(?:heads|tags|remotes\/[^/]+)\//, '');
|
|
402
|
+
return PROTECTED_BRANCHES.test(cleanBranch);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shell dangerous commands parser - rm, mv, cp, chmod, dd, diskpart, etc.
|
|
3
|
+
* P1 priority - detects destructive filesystem operations.
|
|
4
|
+
*
|
|
5
|
+
* Handles:
|
|
6
|
+
* - rm -rf / recursive deletion
|
|
7
|
+
* - mv overwriting existing files
|
|
8
|
+
* - cp -r with destructive patterns
|
|
9
|
+
* - chmod/chown with system directories
|
|
10
|
+
* - dd writing to disk
|
|
11
|
+
* - diskpart on Windows
|
|
12
|
+
* - format disk operations
|
|
13
|
+
* - PowerShell Remove-Item with dangerous patterns
|
|
14
|
+
*/
|
|
15
|
+
import type { CommandParser, CommandSemantics } from '../command-semantics.js';
|
|
16
|
+
export declare class ShellDangerousParser implements CommandParser {
|
|
17
|
+
readonly name = "shell-dangerous";
|
|
18
|
+
readonly priority = 20;
|
|
19
|
+
canParse(command: string): boolean;
|
|
20
|
+
parse(command: string): CommandSemantics | null;
|
|
21
|
+
private extractBaseName;
|
|
22
|
+
private parseRm;
|
|
23
|
+
private parseMv;
|
|
24
|
+
private parseCp;
|
|
25
|
+
private parseChmod;
|
|
26
|
+
private parseDd;
|
|
27
|
+
private parseDiskpart;
|
|
28
|
+
private parsePowerShellRemove;
|
|
29
|
+
private parseArchive;
|
|
30
|
+
private extractArgs;
|
|
31
|
+
private extractFlags;
|
|
32
|
+
}
|