@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.
@@ -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
@@ -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). The bare `kill\s+` alternative is
12
- // narrowed below so a kill of an unrelated pid is not denied as a self-kill.
13
- 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|kill\s+)/i;
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
- return SELF_KILL_RE.test(cmd)
108
- // Exclude only a command that is JUST `kill [flags] <unrelated pid>` —
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
- && !/^kill\s+(?:-\S+\s+)?\d+\s*$/i.test(cmd.trim())
112
- && !/kill\s+(?:-\S+\s+)?(\d+)\s+.*(not found|done)/i.test(cmd);
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ddtcorex/dsh-maestro-supervisor",
3
- "version": "0.7.1",
3
+ "version": "0.7.2",
4
4
  "description": "Supervisor daemon for DSH Web resilience — auto-detect crashes, rollback to LKG, report",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",