@ddtcorex/dsh-maestro-supervisor 0.7.1 → 0.7.2
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/lib/self-kill-guard.d.ts +7 -0
- package/lib/self-kill-guard.js +46 -7
- package/package.json +1 -1
package/lib/self-kill-guard.d.ts
CHANGED
|
@@ -4,6 +4,13 @@
|
|
|
4
4
|
* model must route restarts through the supervisor's dsh_web_restart tool, not
|
|
5
5
|
* by killing the host.
|
|
6
6
|
*/
|
|
7
|
+
/**
|
|
8
|
+
* Remove data spans (quoted strings and heredoc bodies) from a command before
|
|
9
|
+
* self-kill matching. Text inside quotes or a heredoc is content — an echo,
|
|
10
|
+
* printf, node -e script or cat <<'EOF' body can legitimately discuss kill
|
|
11
|
+
* commands without executing one.
|
|
12
|
+
*/
|
|
13
|
+
export declare function stripDataSpans(cmd: string): string;
|
|
7
14
|
/**
|
|
8
15
|
* The dsh web MainThread owns both ports (3000 = gitlab-webhook, 3080 = web).
|
|
9
16
|
* Only listeners on these ports can be dsh web; every other listening process
|
package/lib/self-kill-guard.js
CHANGED
|
@@ -8,9 +8,36 @@ import { createRequire } from 'node:module';
|
|
|
8
8
|
const require = createRequire(import.meta.url);
|
|
9
9
|
// Patterns that restart/stop/start or kill dsh web (systemctl --user units,
|
|
10
10
|
// pkill/killall over the dsh tree, killing holders of :3080, and the
|
|
11
|
-
// dsh-safe-web-update helper itself).
|
|
12
|
-
//
|
|
13
|
-
|
|
11
|
+
// dsh-safe-web-update helper itself). Matched — like dsh-maestro-guard —
|
|
12
|
+
// against the executed command surface with quoted/heredoc spans stripped, so
|
|
13
|
+
// text that merely MENTIONS these words (echo/printf/script bodies) is data,
|
|
14
|
+
// not argv.
|
|
15
|
+
const SELF_KILL_RE = /(systemctl\s+--?user\s+.*(restart|stop|start).*dsh-web|pkill\s+.*dsh|killall\s+.*dsh|ss\s+.*3080.*kill|restart-dsh-web)/i;
|
|
16
|
+
// A segment whose command position is one of these verbs is a real kill-family
|
|
17
|
+
// invocation: blanket-denied even when its target lives inside quotes
|
|
18
|
+
// (`pkill -f "dsh web"` must still be caught). `sudo`/`env VAR=` prefixes are
|
|
19
|
+
// stripped before the verb is read.
|
|
20
|
+
const DANGEROUS_KILL_VERB = /^(?:sudo\s+|env\s+\S+\s+)*(pkill|killall|kill|systemctl)\b/i;
|
|
21
|
+
/**
|
|
22
|
+
* Remove data spans (quoted strings and heredoc bodies) from a command before
|
|
23
|
+
* self-kill matching. Text inside quotes or a heredoc is content — an echo,
|
|
24
|
+
* printf, node -e script or cat <<'EOF' body can legitimately discuss kill
|
|
25
|
+
* commands without executing one.
|
|
26
|
+
*/
|
|
27
|
+
export function stripDataSpans(cmd) {
|
|
28
|
+
let out = cmd;
|
|
29
|
+
let prev = '';
|
|
30
|
+
while (out !== prev) {
|
|
31
|
+
prev = out;
|
|
32
|
+
// heredoc FIRST: the `<<'EOF'` delimiter quotes would otherwise be eaten by
|
|
33
|
+
// the generic quote-strip below and the body would survive as unquoted text
|
|
34
|
+
out = out.replace(/<<-?\s*['"]?([A-Za-z_][A-Za-z0-9_]*)['"]?[^\r\n]*\r?\n[\s\S]*?^\1\s*$/gm, ' ');
|
|
35
|
+
// quote spans respect backslash escapes (`\"` inside a double-quoted
|
|
36
|
+
// node -e body is content, not a delimiter) so nested literals stay stripped
|
|
37
|
+
out = out.replace(/"(?:[^"\\]|\\.)*"/g, ' ').replace(/'(?:[^'\\]|\\.)*'/g, ' ');
|
|
38
|
+
}
|
|
39
|
+
return out;
|
|
40
|
+
}
|
|
14
41
|
/**
|
|
15
42
|
* The dsh web MainThread owns both ports (3000 = gitlab-webhook, 3080 = web).
|
|
16
43
|
* Only listeners on these ports can be dsh web; every other listening process
|
|
@@ -99,17 +126,29 @@ export function resolveDshWebTreePids(listeners, rows, boundary = () => 'launche
|
|
|
99
126
|
* denied.
|
|
100
127
|
*/
|
|
101
128
|
export function isSelfKillCommand(cmd, livePids) {
|
|
129
|
+
// pid-targeted kill: an exact live pid is a self-kill regardless of context
|
|
102
130
|
if (/kill\s+(?:-\S+\s+)?(\d+)/i.test(cmd)) {
|
|
103
131
|
const pid = Number(cmd.match(/kill\s+(?:-\S+\s+)?(\d+)/i)?.[1]);
|
|
104
132
|
if (livePids.includes(pid))
|
|
105
133
|
return true;
|
|
106
134
|
}
|
|
107
|
-
|
|
108
|
-
|
|
135
|
+
// Targeted patterns may span segments (`ss ... | grep 3080 | xargs kill`),
|
|
136
|
+
// so test the stripped full text once, then verbs per segment.
|
|
137
|
+
const stripped = stripDataSpans(cmd);
|
|
138
|
+
if (SELF_KILL_RE.test(stripped))
|
|
139
|
+
return true;
|
|
140
|
+
for (const seg of stripped.split(/\s*(?:&&|\|\||;|\||\r?\n)+\s*/)) {
|
|
141
|
+
// Exclude ONLY a command that is JUST `kill [flags] <unrelated pid>` —
|
|
109
142
|
// anchored end-to-end so `kill 1234 && systemctl restart dsh-web` cannot
|
|
110
143
|
// whitelist the compound through its prefix.
|
|
111
|
-
|
|
112
|
-
|
|
144
|
+
if (/^kill\s+(?:-\S+\s+)?\d+\s*$/i.test(seg.trim()))
|
|
145
|
+
continue;
|
|
146
|
+
if (/kill\s+(?:-\S+\s+)?(\d+)\s+.*(not found|done)/i.test(seg))
|
|
147
|
+
continue;
|
|
148
|
+
if (DANGEROUS_KILL_VERB.test(seg))
|
|
149
|
+
return true;
|
|
150
|
+
}
|
|
151
|
+
return false;
|
|
113
152
|
}
|
|
114
153
|
/**
|
|
115
154
|
* Live pids of the dsh web OWN forest: pids owning the dsh-web ports
|
package/package.json
CHANGED