@descryy/runtime-controller 0.2.1 → 0.3.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/LICENSE +6 -0
- package/dist/attach-fencing.d.ts +109 -0
- package/dist/attach-fencing.d.ts.map +1 -0
- package/dist/attach-fencing.js +215 -0
- package/dist/attach-fencing.js.map +1 -0
- package/dist/capability-registry.d.ts +0 -15
- package/dist/capability-registry.d.ts.map +1 -1
- package/dist/capability-registry.js +9 -19
- package/dist/capability-registry.js.map +1 -1
- package/dist/collector-version.d.ts +1 -8
- package/dist/collector-version.d.ts.map +1 -1
- package/dist/collector-version.js +1 -8
- package/dist/collector-version.js.map +1 -1
- package/dist/container-sandbox.d.ts +66 -150
- package/dist/container-sandbox.d.ts.map +1 -1
- package/dist/container-sandbox.js +62 -143
- package/dist/container-sandbox.js.map +1 -1
- package/dist/controller.d.ts +49 -106
- package/dist/controller.d.ts.map +1 -1
- package/dist/controller.js +65 -123
- package/dist/controller.js.map +1 -1
- package/dist/dependency-version-check.d.ts +19 -73
- package/dist/dependency-version-check.d.ts.map +1 -1
- package/dist/dependency-version-check.js +18 -67
- package/dist/dependency-version-check.js.map +1 -1
- package/dist/env.d.ts +4 -10
- package/dist/env.d.ts.map +1 -1
- package/dist/env.js +4 -10
- package/dist/env.js.map +1 -1
- package/dist/environment-metadata.d.ts +9 -17
- package/dist/environment-metadata.d.ts.map +1 -1
- package/dist/environment-metadata.js +12 -29
- package/dist/environment-metadata.js.map +1 -1
- package/dist/environment-version-check.d.ts +22 -65
- package/dist/environment-version-check.d.ts.map +1 -1
- package/dist/environment-version-check.js +24 -66
- package/dist/environment-version-check.js.map +1 -1
- package/dist/execution-safety.d.ts +54 -112
- package/dist/execution-safety.d.ts.map +1 -1
- package/dist/execution-safety.js +48 -102
- package/dist/execution-safety.js.map +1 -1
- package/dist/index.d.ts +2 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/orchestration.d.ts +24 -39
- package/dist/orchestration.d.ts.map +1 -1
- package/dist/orchestration.js +39 -75
- package/dist/orchestration.js.map +1 -1
- package/dist/process-collector.d.ts +8 -22
- package/dist/process-collector.d.ts.map +1 -1
- package/dist/process-collector.js +23 -55
- package/dist/process-collector.js.map +1 -1
- package/dist/process-manager.d.ts +65 -80
- package/dist/process-manager.d.ts.map +1 -1
- package/dist/process-manager.js +80 -103
- package/dist/process-manager.js.map +1 -1
- package/dist/readiness.d.ts +28 -70
- package/dist/readiness.d.ts.map +1 -1
- package/dist/readiness.js +73 -95
- package/dist/readiness.js.map +1 -1
- package/dist/sandbox.d.ts +60 -105
- package/dist/sandbox.d.ts.map +1 -1
- package/dist/sandbox.js +78 -121
- package/dist/sandbox.js.map +1 -1
- package/package.json +8 -3
|
@@ -1,35 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Process manager (
|
|
3
|
-
*
|
|
4
|
-
* exit-code capture, cleanup with a shutdown grace period, and orphan-
|
|
5
|
-
* process prevention.
|
|
2
|
+
* Process manager (§5): command execution, cwd, env, process-group tracking,
|
|
3
|
+
* stdout/stderr capture, exit-code capture, graceful shutdown, orphan prevention.
|
|
6
4
|
*
|
|
7
|
-
* Orphan prevention and group-kill use POSIX process groups
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* written — out of scope for the V1 fixture-app slice (plan §34).
|
|
5
|
+
* Orphan prevention and group-kill use POSIX process groups (`detached: true` +
|
|
6
|
+
* `process.kill(-pid, signal)`) -- not portable to Windows, out of scope for the V1
|
|
7
|
+
* fixture-app slice (§34).
|
|
11
8
|
*/
|
|
12
9
|
import type { FilesystemPolicy, NetworkPolicy, ProcessHandle, ResourceLimits, ServiceAttachConfiguration } from "@descryy/runtime-contracts";
|
|
10
|
+
import { type AttachFence } from "./attach-fencing.ts";
|
|
13
11
|
/**
|
|
14
|
-
* Binds port 0
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* socket, which `spawnProcess`'s child-process model doesn't support, and
|
|
19
|
-
* which no ordinary application would cooperate with anyway.
|
|
12
|
+
* Binds port 0, reads it, releases immediately. A real gap remains between "free
|
|
13
|
+
* when checked" and "still free when the child binds it" (RT-024's gap, one layer
|
|
14
|
+
* down) -- unavoidable without binding the real service directly to the probe
|
|
15
|
+
* socket, which the child-process model doesn't support.
|
|
20
16
|
*
|
|
21
|
-
* **Examined
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* What was done instead is to make the one symptom legible: `awaitReadiness`
|
|
28
|
-
* now names the endpoint it probed, so a collision reads as "nothing
|
|
29
|
-
* answered on this port" rather than as an unexplained application failure.
|
|
30
|
-
* In practice the window is a handful of milliseconds and readiness always
|
|
31
|
-
* runs afterwards, so a genuine collision fails loudly -- it is just no
|
|
32
|
-
* longer misattributed.
|
|
17
|
+
* **Examined and deliberately not "fixed".** Holding the probe socket longer widens
|
|
18
|
+
* the window rather than narrowing it (the child can't bind while we hold it).
|
|
19
|
+
* Instead, `awaitReadiness` names the endpoint it probed, so a collision reads as
|
|
20
|
+
* "nothing answered on this port" rather than an unexplained failure. Window is a
|
|
21
|
+
* handful of ms in practice; a genuine collision still fails loudly, just correctly
|
|
22
|
+
* attributed.
|
|
33
23
|
*/
|
|
34
24
|
export declare function allocateEphemeralPort(): Promise<number>;
|
|
35
25
|
export interface SpawnProcessOptions {
|
|
@@ -38,29 +28,24 @@ export interface SpawnProcessOptions {
|
|
|
38
28
|
readonly args?: readonly string[];
|
|
39
29
|
readonly cwd?: string;
|
|
40
30
|
readonly env?: Readonly<Record<string, string | undefined>>;
|
|
41
|
-
/** Joins the resulting ProcessHandle back to ExecutionConfiguration.services (RT-023). Omit for
|
|
31
|
+
/** Joins the resulting ProcessHandle back to ExecutionConfiguration.services (RT-023). Omit for no corresponding named service. */
|
|
42
32
|
readonly serviceName?: string;
|
|
43
|
-
/**
|
|
33
|
+
/** Real port this process is bound to, when the caller already knows it. Recorded on the handle only. */
|
|
44
34
|
readonly port?: number;
|
|
45
|
-
/** §21
|
|
35
|
+
/** §21 execution boundary (RT-070), via `applyResourceLimits`. Re-applied on every (re)spawn including `restart()`. */
|
|
46
36
|
readonly resourceLimits?: ResourceLimits;
|
|
47
|
-
/** §21
|
|
37
|
+
/** §21 execution boundary, filesystem half, via `applySandbox`. Re-applied on every (re)spawn. */
|
|
48
38
|
readonly filesystemPolicy?: FilesystemPolicy;
|
|
49
|
-
/** §21
|
|
39
|
+
/** §21 execution boundary, network half, via `applySandbox`. Re-applied on every (re)spawn. */
|
|
50
40
|
readonly networkPolicy?: NetworkPolicy;
|
|
51
41
|
/**
|
|
52
|
-
* Selects
|
|
53
|
-
*
|
|
54
|
-
* `"container"` routes through `applyContainerSandbox` (`./container-sandbox.ts`)
|
|
55
|
-
* instead. See `ExecutionConfiguration.sandboxBackend`'s own comment.
|
|
42
|
+
* Selects the mechanism enforcing `filesystemPolicy`/`networkPolicy`. Absent means
|
|
43
|
+
* `"bwrap"` (unchanged default); `"container"` routes through `applyContainerSandbox`.
|
|
56
44
|
*
|
|
57
|
-
* **Does not compose with `resourceLimits` in this pass
|
|
58
|
-
*
|
|
59
|
-
* `
|
|
60
|
-
*
|
|
61
|
-
* `--memory`/`--cpus`/`--pids-limit` equivalent is not wired up here) --
|
|
62
|
-
* disclosed in `container-sandbox.ts`'s own module doc, not silently
|
|
63
|
-
* dropped.
|
|
45
|
+
* **Does not compose with `resourceLimits` in this pass** -- the container backend
|
|
46
|
+
* skips `applyResourceLimits`'s `prlimit` wrap entirely (a minimal image isn't
|
|
47
|
+
* guaranteed to carry `prlimit`, Docker's own limit flags aren't wired up).
|
|
48
|
+
* Disclosed in `container-sandbox.ts`, not silently dropped.
|
|
64
49
|
*/
|
|
65
50
|
readonly sandboxBackend?: "bwrap" | "container";
|
|
66
51
|
}
|
|
@@ -70,36 +55,34 @@ export interface ProcessExitInfo {
|
|
|
70
55
|
}
|
|
71
56
|
export interface ManagedProcess {
|
|
72
57
|
handle(): ProcessHandle;
|
|
73
|
-
/** Combined stdout+stderr captured so far, in arrival order
|
|
58
|
+
/** Combined stdout+stderr captured so far, in arrival order -- backing store for log-pattern readiness checks. */
|
|
74
59
|
readOutput(): string;
|
|
75
60
|
waitForExit(): Promise<ProcessExitInfo>;
|
|
76
|
-
/** SIGTERM the process group, wait up to `gracePeriodMs`, then SIGKILL
|
|
61
|
+
/** SIGTERM the process group, wait up to `gracePeriodMs`, then SIGKILL. Idempotent. */
|
|
77
62
|
kill(gracePeriodMs?: number): Promise<void>;
|
|
78
63
|
/**
|
|
79
|
-
* Kills the current process (
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
* object, not a new one, so a caller holding the original reference does
|
|
84
|
-
* not need to re-fetch anything. Readiness is the caller's job, same as
|
|
85
|
-
* after the original `spawnProcess` — this resolves once the new process
|
|
86
|
-
* EXISTS, not once it is ready.
|
|
64
|
+
* Kills the current process (no-op wait if already exited) and spawns a fresh one
|
|
65
|
+
* with the same command/args/cwd/env. `handle()`/`readOutput()`/`waitForExit()`
|
|
66
|
+
* observe the new process on the same object -- no re-fetch needed. Resolves once
|
|
67
|
+
* the new process exists, not once it's ready (readiness is the caller's job).
|
|
87
68
|
*/
|
|
88
69
|
restart(gracePeriodMs?: number): Promise<void>;
|
|
70
|
+
/**
|
|
71
|
+
* The attach-time fence (RT-N3), or `null` for a process this runtime spawned
|
|
72
|
+
* itself -- fencing only exists to mark content that predates OBSERVATION, and
|
|
73
|
+
* a spawned process has no output before Descry started it. See
|
|
74
|
+
* `computeAttachFence` (`attach-fencing.ts`) for what it records and why.
|
|
75
|
+
*/
|
|
76
|
+
attachFence(): AttachFence | null;
|
|
89
77
|
}
|
|
90
78
|
export declare function spawnProcess(options: SpawnProcessOptions): ManagedProcess;
|
|
91
79
|
/**
|
|
92
|
-
* `process.kill(pid, 0)` sends no signal
|
|
93
|
-
*
|
|
94
|
-
* pid we don't own but that unambiguously exists, still alive for this
|
|
95
|
-
* purpose. Any other error is treated as "exists" rather than guessed away.
|
|
80
|
+
* `process.kill(pid, 0)` sends no signal, only asks the kernel if delivery is
|
|
81
|
+
* possible. `ESRCH` = no such pid; `EPERM` = a pid we don't own but that exists.
|
|
96
82
|
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
* would be circular. Tiny and pure, the same "duplicated because both
|
|
101
|
-
* copies are easy to notice drift" precedent `attach-to-running-jvm-process.ts`'s
|
|
102
|
-
* own `reconstructJvmSourcePath` already sets for exactly this reason.
|
|
83
|
+
* Deliberate second copy of `orchestrator/src/attach-to-running-process.ts`'s
|
|
84
|
+
* same-named function, not an import -- `orchestrator` depends on `controller`, so
|
|
85
|
+
* the reverse import would be circular. Tiny and pure enough to duplicate safely.
|
|
103
86
|
*/
|
|
104
87
|
export declare function isProcessAlive(pid: number): boolean;
|
|
105
88
|
export interface AttachProcessOptions {
|
|
@@ -109,25 +92,27 @@ export interface AttachProcessOptions {
|
|
|
109
92
|
readonly port?: number;
|
|
110
93
|
}
|
|
111
94
|
/**
|
|
112
|
-
* `ManagedProcess` for a service
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
95
|
+
* `ManagedProcess` for a service attached to rather than spawned. Reads
|
|
96
|
+
* `attach.logFilePath` fresh on every `readOutput()` -- same growing-whole-buffer
|
|
97
|
+
* contract as a spawned process's in-memory pipe buffer.
|
|
98
|
+
*
|
|
99
|
+
* **`kill()` is a deliberate no-op, not a stub.** Descry did not spawn this process,
|
|
100
|
+
* and `ATTACH_MODE_SCOPE_DISCLOSURE` is unconditional: attach mode never executes
|
|
101
|
+
* code in or applies changes to what it observes. Ending observation is the honest
|
|
102
|
+
* equivalent of "stop" -- the target keeps running. `restart()` throws for the same
|
|
103
|
+
* reason: no command exists to relaunch it with.
|
|
119
104
|
*
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
*
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
-
* for the same reason
|
|
130
|
-
*
|
|
105
|
+
* **Attach fencing (RT-N3).** `computeAttachFence` snapshots, at construction time
|
|
106
|
+
* (i.e. the moment of attach), how much of `logFilePath` already existed and
|
|
107
|
+
* whether some other process also holds it open -- see `attach-fencing.ts`. Exposed
|
|
108
|
+
* via `attachFence()` for a caller building a `ProcessOutputSource` over
|
|
109
|
+
* `readOutput()` to mark pre-existing content instead of reporting it as freshly
|
|
110
|
+
* observed. `readOutput()` itself additionally refuses (rather than silently
|
|
111
|
+
* mis-reading) if the file is ever found shorter than the largest size already
|
|
112
|
+
* seen -- the same "cannot reconstruct a rotated/truncated buffer" rule
|
|
113
|
+
* `orchestrator/src/polling-output-source.ts` enforces one layer up, duplicated
|
|
114
|
+
* here for the same reason `isProcessAlive` is: this module cannot depend on
|
|
115
|
+
* that one without a cycle, and the check is small and pure enough to repeat.
|
|
131
116
|
*/
|
|
132
117
|
export declare function attachManagedProcess(options: AttachProcessOptions): ManagedProcess;
|
|
133
118
|
//# sourceMappingURL=process-manager.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"process-manager.d.ts","sourceRoot":"","sources":["../src/process-manager.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"process-manager.d.ts","sourceRoot":"","sources":["../src/process-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,aAAa,EAAE,cAAc,EAAE,0BAA0B,EAAE,MAAM,4BAA4B,CAAC;AAI7I,OAAO,EAAsB,KAAK,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAE3E;;;;;;;;;;;;GAYG;AACH,wBAAgB,qBAAqB,IAAI,OAAO,CAAC,MAAM,CAAC,CAevD;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;IAC5D,mIAAmI;IACnI,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,yGAAyG;IACzG,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,uHAAuH;IACvH,QAAQ,CAAC,cAAc,CAAC,EAAE,cAAc,CAAC;IACzC,kGAAkG;IAClG,QAAQ,CAAC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IAC7C,+FAA+F;IAC/F,QAAQ,CAAC,aAAa,CAAC,EAAE,aAAa,CAAC;IACvC;;;;;;;;OAQG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,GAAG,WAAW,CAAC;CACjD;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;CACxC;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,IAAI,aAAa,CAAC;IACxB,kHAAkH;IAClH,UAAU,IAAI,MAAM,CAAC;IACrB,WAAW,IAAI,OAAO,CAAC,eAAe,CAAC,CAAC;IACxC,uFAAuF;IACvF,IAAI,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C;;;;;OAKG;IACH,OAAO,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C;;;;;OAKG;IACH,WAAW,IAAI,WAAW,GAAG,IAAI,CAAC;CACnC;AAID,wBAAgB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,cAAc,CAiJzE;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAOnD;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,0BAA0B,CAAC;IAC5C,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAID;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,oBAAoB,GAAG,cAAc,CAwFlF"}
|
package/dist/process-manager.js
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Process manager (
|
|
3
|
-
*
|
|
4
|
-
* exit-code capture, cleanup with a shutdown grace period, and orphan-
|
|
5
|
-
* process prevention.
|
|
2
|
+
* Process manager (§5): command execution, cwd, env, process-group tracking,
|
|
3
|
+
* stdout/stderr capture, exit-code capture, graceful shutdown, orphan prevention.
|
|
6
4
|
*
|
|
7
|
-
* Orphan prevention and group-kill use POSIX process groups
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* written — out of scope for the V1 fixture-app slice (plan §34).
|
|
5
|
+
* Orphan prevention and group-kill use POSIX process groups (`detached: true` +
|
|
6
|
+
* `process.kill(-pid, signal)`) -- not portable to Windows, out of scope for the V1
|
|
7
|
+
* fixture-app slice (§34).
|
|
11
8
|
*/
|
|
12
9
|
import { execFile, spawn } from "node:child_process";
|
|
13
10
|
import { readFileSync } from "node:fs";
|
|
@@ -16,26 +13,19 @@ import { promisify } from "node:util";
|
|
|
16
13
|
import { applyResourceLimits } from "./execution-safety.js";
|
|
17
14
|
import { applySandbox } from "./sandbox.js";
|
|
18
15
|
import { applyContainerSandbox } from "./container-sandbox.js";
|
|
16
|
+
import { computeAttachFence } from "./attach-fencing.js";
|
|
19
17
|
/**
|
|
20
|
-
* Binds port 0
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* socket, which `spawnProcess`'s child-process model doesn't support, and
|
|
25
|
-
* which no ordinary application would cooperate with anyway.
|
|
18
|
+
* Binds port 0, reads it, releases immediately. A real gap remains between "free
|
|
19
|
+
* when checked" and "still free when the child binds it" (RT-024's gap, one layer
|
|
20
|
+
* down) -- unavoidable without binding the real service directly to the probe
|
|
21
|
+
* socket, which the child-process model doesn't support.
|
|
26
22
|
*
|
|
27
|
-
* **Examined
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
* What was done instead is to make the one symptom legible: `awaitReadiness`
|
|
34
|
-
* now names the endpoint it probed, so a collision reads as "nothing
|
|
35
|
-
* answered on this port" rather than as an unexplained application failure.
|
|
36
|
-
* In practice the window is a handful of milliseconds and readiness always
|
|
37
|
-
* runs afterwards, so a genuine collision fails loudly -- it is just no
|
|
38
|
-
* longer misattributed.
|
|
23
|
+
* **Examined and deliberately not "fixed".** Holding the probe socket longer widens
|
|
24
|
+
* the window rather than narrowing it (the child can't bind while we hold it).
|
|
25
|
+
* Instead, `awaitReadiness` names the endpoint it probed, so a collision reads as
|
|
26
|
+
* "nothing answered on this port" rather than an unexplained failure. Window is a
|
|
27
|
+
* handful of ms in practice; a genuine collision still fails loudly, just correctly
|
|
28
|
+
* attributed.
|
|
39
29
|
*/
|
|
40
30
|
export function allocateEphemeralPort() {
|
|
41
31
|
return new Promise((resolve, reject) => {
|
|
@@ -63,16 +53,13 @@ export function spawnProcess(options) {
|
|
|
63
53
|
let killStarted = false;
|
|
64
54
|
let child;
|
|
65
55
|
let settled = false;
|
|
66
|
-
// Set only for the container backend (
|
|
67
|
-
//
|
|
68
|
-
// needs a real, separate stop mechanism from the bwrap path's group-kill.
|
|
56
|
+
// Set only for the container backend -- see kill() for why it needs a separate
|
|
57
|
+
// stop mechanism from bwrap's group-kill.
|
|
69
58
|
let containerName = null;
|
|
70
59
|
let resolveExit;
|
|
71
60
|
let exitPromise;
|
|
72
|
-
// Everything a (re)spawn needs to reset, in one place --
|
|
73
|
-
//
|
|
74
|
-
// sites (initial construction, restart) must not drift into resetting
|
|
75
|
-
// different subsets of this state.
|
|
61
|
+
// Everything a (re)spawn needs to reset, in one place -- construction and
|
|
62
|
+
// restart() must not drift into resetting different subsets of this state.
|
|
76
63
|
function spawnChild() {
|
|
77
64
|
startedAt = new Date().toISOString();
|
|
78
65
|
exitedAt = null;
|
|
@@ -85,9 +72,7 @@ export function spawnProcess(options) {
|
|
|
85
72
|
resolveExit = resolve;
|
|
86
73
|
});
|
|
87
74
|
// "container" skips applyResourceLimits entirely (see SpawnProcessOptions.
|
|
88
|
-
// sandboxBackend
|
|
89
|
-
// for this backend yet) -- every other case (the default, "bwrap")
|
|
90
|
-
// behaves exactly as before this field existed.
|
|
75
|
+
// sandboxBackend) -- "bwrap" (default) is unchanged.
|
|
91
76
|
const wrapped = options.sandboxBackend === "container"
|
|
92
77
|
? applyContainerSandbox({
|
|
93
78
|
interpreterCommand: options.command,
|
|
@@ -118,15 +103,10 @@ export function spawnProcess(options) {
|
|
|
118
103
|
child.stderr?.on("data", (chunk) => {
|
|
119
104
|
outputBuffer += chunk.toString("utf8");
|
|
120
105
|
});
|
|
121
|
-
//
|
|
122
|
-
//
|
|
123
|
-
//
|
|
124
|
-
//
|
|
125
|
-
// process, and with no `'exit'` guaranteed either, `exitPromise` would
|
|
126
|
-
// otherwise hang forever -- both `'exit'` and `'error'` settle the same
|
|
127
|
-
// promise exactly once, so a failed-to-spawn process reads as an
|
|
128
|
-
// ordinary never-became-ready process (no pid, no output, no readiness
|
|
129
|
-
// success) rather than crashing the caller or hanging its cleanup.
|
|
106
|
+
// A bad command (ENOENT) surfaces as an `'error'` event, not a thrown exception,
|
|
107
|
+
// and per Node's docs `'exit'` may never fire after `'error'`. Both events settle
|
|
108
|
+
// the same promise exactly once, so a failed spawn reads as an ordinary
|
|
109
|
+
// never-became-ready process rather than crashing the caller or hanging cleanup.
|
|
130
110
|
function settle(info) {
|
|
131
111
|
if (settled)
|
|
132
112
|
return;
|
|
@@ -164,22 +144,16 @@ export function spawnProcess(options) {
|
|
|
164
144
|
return;
|
|
165
145
|
}
|
|
166
146
|
if (containerName !== null) {
|
|
167
|
-
//
|
|
168
|
-
//
|
|
169
|
-
//
|
|
170
|
-
//
|
|
171
|
-
//
|
|
172
|
-
// container running in testing. `docker stop` targets the actual
|
|
173
|
-
// container by name and is the real stop mechanism for this backend;
|
|
174
|
-
// `--rm` (set by applyContainerSandbox) then removes it once stopped.
|
|
175
|
-
// Still falls through to the group-kill below afterward, as a
|
|
176
|
-
// backstop for the local CLI process itself.
|
|
147
|
+
// Found via escape testing: the local `docker` CLI process is not the
|
|
148
|
+
// container -- it runs under `dockerd`, a separate process tree.
|
|
149
|
+
// Signaling the CLI's process group left a real orphaned container running.
|
|
150
|
+
// `docker stop` (by name) is the real stop mechanism here; `--rm` then
|
|
151
|
+
// removes it. Still falls through to group-kill below as a CLI backstop.
|
|
177
152
|
try {
|
|
178
153
|
await execFileAsync("docker", ["stop", "--time", String(Math.max(1, Math.round(gracePeriodMs / 1000))), containerName]);
|
|
179
154
|
}
|
|
180
155
|
catch {
|
|
181
|
-
// Already stopped/removed
|
|
182
|
-
// first) -- not an error worth surfacing to the caller.
|
|
156
|
+
// Already stopped/removed -- not worth surfacing.
|
|
183
157
|
}
|
|
184
158
|
}
|
|
185
159
|
signalGroup(pid, "SIGTERM");
|
|
@@ -190,11 +164,9 @@ export function spawnProcess(options) {
|
|
|
190
164
|
}
|
|
191
165
|
}
|
|
192
166
|
async function restart(gracePeriodMs = DEFAULT_GRACE_PERIOD_MS) {
|
|
193
|
-
// Safe
|
|
194
|
-
//
|
|
195
|
-
//
|
|
196
|
-
// `spawnChild()` reassigns `child`/`exitPromise`/etc., so no event from
|
|
197
|
-
// the outgoing process can land on the incoming one's state.
|
|
167
|
+
// Safe regardless of the old process's state -- kill() is idempotent, and this
|
|
168
|
+
// waits for it to be fully gone before spawnChild() reassigns state, so no
|
|
169
|
+
// outgoing event can land on the incoming process.
|
|
198
170
|
await kill(gracePeriodMs);
|
|
199
171
|
spawnChild();
|
|
200
172
|
}
|
|
@@ -204,20 +176,17 @@ export function spawnProcess(options) {
|
|
|
204
176
|
waitForExit: () => exitPromise,
|
|
205
177
|
kill,
|
|
206
178
|
restart,
|
|
179
|
+
// A spawned process has no output that predates this runtime observing it.
|
|
180
|
+
attachFence: () => null,
|
|
207
181
|
};
|
|
208
182
|
}
|
|
209
183
|
/**
|
|
210
|
-
* `process.kill(pid, 0)` sends no signal
|
|
211
|
-
*
|
|
212
|
-
* pid we don't own but that unambiguously exists, still alive for this
|
|
213
|
-
* purpose. Any other error is treated as "exists" rather than guessed away.
|
|
184
|
+
* `process.kill(pid, 0)` sends no signal, only asks the kernel if delivery is
|
|
185
|
+
* possible. `ESRCH` = no such pid; `EPERM` = a pid we don't own but that exists.
|
|
214
186
|
*
|
|
215
|
-
*
|
|
216
|
-
*
|
|
217
|
-
*
|
|
218
|
-
* would be circular. Tiny and pure, the same "duplicated because both
|
|
219
|
-
* copies are easy to notice drift" precedent `attach-to-running-jvm-process.ts`'s
|
|
220
|
-
* own `reconstructJvmSourcePath` already sets for exactly this reason.
|
|
187
|
+
* Deliberate second copy of `orchestrator/src/attach-to-running-process.ts`'s
|
|
188
|
+
* same-named function, not an import -- `orchestrator` depends on `controller`, so
|
|
189
|
+
* the reverse import would be circular. Tiny and pure enough to duplicate safely.
|
|
221
190
|
*/
|
|
222
191
|
export function isProcessAlive(pid) {
|
|
223
192
|
try {
|
|
@@ -230,25 +199,27 @@ export function isProcessAlive(pid) {
|
|
|
230
199
|
}
|
|
231
200
|
const DEFAULT_ATTACH_POLL_INTERVAL_MS = 50;
|
|
232
201
|
/**
|
|
233
|
-
* `ManagedProcess` for a service
|
|
234
|
-
*
|
|
235
|
-
*
|
|
236
|
-
* growing-whole-buffer contract a spawned process's in-memory pipe buffer
|
|
237
|
-
* already has (`spawnProcess`'s own `outputBuffer`), so `createPollingProcessOutputSource`
|
|
238
|
-
* (`@descryy/runtime-orchestrator`) needs no attach-specific branch to
|
|
239
|
-
* consume either one.
|
|
202
|
+
* `ManagedProcess` for a service attached to rather than spawned. Reads
|
|
203
|
+
* `attach.logFilePath` fresh on every `readOutput()` -- same growing-whole-buffer
|
|
204
|
+
* contract as a spawned process's in-memory pipe buffer.
|
|
240
205
|
*
|
|
241
|
-
* **`kill()` is a deliberate no-op, not a stub.** Descry did not spawn this
|
|
242
|
-
*
|
|
243
|
-
*
|
|
244
|
-
*
|
|
245
|
-
*
|
|
246
|
-
*
|
|
247
|
-
*
|
|
248
|
-
*
|
|
249
|
-
*
|
|
250
|
-
*
|
|
251
|
-
*
|
|
206
|
+
* **`kill()` is a deliberate no-op, not a stub.** Descry did not spawn this process,
|
|
207
|
+
* and `ATTACH_MODE_SCOPE_DISCLOSURE` is unconditional: attach mode never executes
|
|
208
|
+
* code in or applies changes to what it observes. Ending observation is the honest
|
|
209
|
+
* equivalent of "stop" -- the target keeps running. `restart()` throws for the same
|
|
210
|
+
* reason: no command exists to relaunch it with.
|
|
211
|
+
*
|
|
212
|
+
* **Attach fencing (RT-N3).** `computeAttachFence` snapshots, at construction time
|
|
213
|
+
* (i.e. the moment of attach), how much of `logFilePath` already existed and
|
|
214
|
+
* whether some other process also holds it open -- see `attach-fencing.ts`. Exposed
|
|
215
|
+
* via `attachFence()` for a caller building a `ProcessOutputSource` over
|
|
216
|
+
* `readOutput()` to mark pre-existing content instead of reporting it as freshly
|
|
217
|
+
* observed. `readOutput()` itself additionally refuses (rather than silently
|
|
218
|
+
* mis-reading) if the file is ever found shorter than the largest size already
|
|
219
|
+
* seen -- the same "cannot reconstruct a rotated/truncated buffer" rule
|
|
220
|
+
* `orchestrator/src/polling-output-source.ts` enforces one layer up, duplicated
|
|
221
|
+
* here for the same reason `isProcessAlive` is: this module cannot depend on
|
|
222
|
+
* that one without a cycle, and the check is small and pure enough to repeat.
|
|
252
223
|
*/
|
|
253
224
|
export function attachManagedProcess(options) {
|
|
254
225
|
const { pid, logFilePath } = options.attach;
|
|
@@ -256,6 +227,8 @@ export function attachManagedProcess(options) {
|
|
|
256
227
|
throw new Error(`attachManagedProcess: pid ${String(pid)} for "${options.processId}" is not running — attach requires ` +
|
|
257
228
|
`a target that already exists.`);
|
|
258
229
|
}
|
|
230
|
+
const fence = computeAttachFence(pid, logFilePath);
|
|
231
|
+
let maxObservedByteLength = fence.attachOffsetBytes;
|
|
259
232
|
const startedAt = new Date().toISOString();
|
|
260
233
|
let exitedAt = null;
|
|
261
234
|
let exitPromise = null;
|
|
@@ -265,16 +238,12 @@ export function attachManagedProcess(options) {
|
|
|
265
238
|
}
|
|
266
239
|
return {
|
|
267
240
|
processId: options.processId,
|
|
268
|
-
// No command to report
|
|
269
|
-
// so there is nothing here that isn't a guess. Disclosed rather than
|
|
270
|
-
// fabricated.
|
|
241
|
+
// No real command to report -- disclosed rather than guessed.
|
|
271
242
|
command: `<attached: pid ${String(pid)}, ${logFilePath}>`,
|
|
272
243
|
pid,
|
|
273
244
|
startedAt,
|
|
274
245
|
exitedAt,
|
|
275
|
-
//
|
|
276
|
-
// reap — see this function's own module doc on why `kill()` never
|
|
277
|
-
// signals it, which is exactly what would let us learn either.
|
|
246
|
+
// Not observable for a process we don't spawn or reap.
|
|
278
247
|
exitCode: null,
|
|
279
248
|
signal: null,
|
|
280
249
|
serviceName: options.serviceName ?? null,
|
|
@@ -283,13 +252,23 @@ export function attachManagedProcess(options) {
|
|
|
283
252
|
};
|
|
284
253
|
}
|
|
285
254
|
function readOutput() {
|
|
255
|
+
let content;
|
|
286
256
|
try {
|
|
287
|
-
|
|
257
|
+
content = readFileSync(logFilePath, "utf8");
|
|
288
258
|
}
|
|
289
259
|
catch (error) {
|
|
290
260
|
const detail = error instanceof Error ? error.message : String(error);
|
|
291
261
|
throw new Error(`attachManagedProcess: could not read log file "${logFilePath}" for pid ${String(pid)}: ${detail}`);
|
|
292
262
|
}
|
|
263
|
+
const byteLength = Buffer.byteLength(content, "utf8");
|
|
264
|
+
if (byteLength < maxObservedByteLength) {
|
|
265
|
+
throw new Error(`attachManagedProcess: log file "${logFilePath}" for pid ${String(pid)} shrank from ${String(maxObservedByteLength)} ` +
|
|
266
|
+
`to ${String(byteLength)} bytes between reads -- this looks like log rotation or truncation, not new output. ` +
|
|
267
|
+
"The file-tail contract can't reconstruct a rotated/truncated buffer without either duplicating or dropping " +
|
|
268
|
+
`lines. Reported rather than guessed. (This run's own attach offset was ${String(fence.attachOffsetBytes)} bytes.)`);
|
|
269
|
+
}
|
|
270
|
+
maxObservedByteLength = byteLength;
|
|
271
|
+
return content;
|
|
293
272
|
}
|
|
294
273
|
function waitForExit() {
|
|
295
274
|
exitPromise ??= new Promise((resolve) => {
|
|
@@ -306,25 +285,23 @@ export function attachManagedProcess(options) {
|
|
|
306
285
|
return exitPromise;
|
|
307
286
|
}
|
|
308
287
|
function kill() {
|
|
309
|
-
// Deliberate no-op
|
|
288
|
+
// Deliberate no-op -- see module doc above.
|
|
310
289
|
return Promise.resolve();
|
|
311
290
|
}
|
|
312
291
|
function restart() {
|
|
313
292
|
return Promise.reject(new Error(`attachManagedProcess: cannot restart an attached process (pid ${String(pid)}) — Descry did not spawn ` +
|
|
314
293
|
`it and has no command to relaunch it with.`));
|
|
315
294
|
}
|
|
316
|
-
return { handle, readOutput, waitForExit, kill, restart };
|
|
295
|
+
return { handle, readOutput, waitForExit, kill, restart, attachFence: () => fence };
|
|
317
296
|
}
|
|
318
297
|
const execFileAsync = promisify(execFile);
|
|
319
298
|
function signalGroup(pid, signal) {
|
|
320
299
|
try {
|
|
321
|
-
// Negative pid targets the whole process group (
|
|
322
|
-
// leader, per `detached: true`), not just the immediate process --
|
|
323
|
-
// this is the orphan-prevention mechanism.
|
|
300
|
+
// Negative pid targets the whole process group (orphan-prevention mechanism).
|
|
324
301
|
process.kill(-pid, signal);
|
|
325
302
|
}
|
|
326
303
|
catch {
|
|
327
|
-
// Group already gone --
|
|
304
|
+
// Group already gone -- not an error.
|
|
328
305
|
}
|
|
329
306
|
}
|
|
330
307
|
function sleep(ms) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"process-manager.js","sourceRoot":"","sources":["../src/process-manager.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"process-manager.js","sourceRoot":"","sources":["../src/process-manager.ts"],"names":[],"mappings":"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"}
|