@descryy/runtime-controller 0.3.8 → 0.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/dist/attach-discovery.d.ts +94 -0
- package/dist/attach-discovery.d.ts.map +1 -0
- package/dist/attach-discovery.js +238 -0
- package/dist/attach-discovery.js.map +1 -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 +9 -0
- package/dist/capability-registry.d.ts.map +1 -0
- package/dist/capability-registry.js +32 -0
- package/dist/capability-registry.js.map +1 -0
- package/dist/collector-version.d.ts +3 -0
- package/dist/collector-version.d.ts.map +1 -0
- package/dist/collector-version.js +5 -0
- package/dist/collector-version.js.map +1 -0
- package/dist/container-sandbox.d.ts +104 -0
- package/dist/container-sandbox.d.ts.map +1 -0
- package/dist/container-sandbox.js +152 -0
- package/dist/container-sandbox.js.map +1 -0
- package/dist/controller.d.ts +152 -0
- package/dist/controller.d.ts.map +1 -0
- package/dist/controller.js +464 -0
- package/dist/controller.js.map +1 -0
- package/dist/dependency-version-check.d.ts +36 -0
- package/dist/dependency-version-check.d.ts.map +1 -0
- package/dist/dependency-version-check.js +72 -0
- package/dist/dependency-version-check.js.map +1 -0
- package/dist/env.d.ts +10 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +12 -0
- package/dist/env.js.map +1 -0
- package/dist/environment-metadata.d.ts +15 -0
- package/dist/environment-metadata.d.ts.map +1 -0
- package/dist/environment-metadata.js +63 -0
- package/dist/environment-metadata.js.map +1 -0
- package/dist/environment-version-check.d.ts +40 -0
- package/dist/environment-version-check.d.ts.map +1 -0
- package/dist/environment-version-check.js +176 -0
- package/dist/environment-version-check.js.map +1 -0
- package/dist/execution-safety.d.ts +96 -0
- package/dist/execution-safety.d.ts.map +1 -0
- package/dist/execution-safety.js +140 -0
- package/dist/execution-safety.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/orchestration.d.ts +55 -0
- package/dist/orchestration.d.ts.map +1 -0
- package/dist/orchestration.js +219 -0
- package/dist/orchestration.js.map +1 -0
- package/dist/preflight.d.ts +122 -0
- package/dist/preflight.d.ts.map +1 -0
- package/dist/preflight.js +177 -0
- package/dist/preflight.js.map +1 -0
- package/dist/process-collector.d.ts +20 -0
- package/dist/process-collector.d.ts.map +1 -0
- package/dist/process-collector.js +116 -0
- package/dist/process-collector.js.map +1 -0
- package/dist/process-identity.d.ts +46 -0
- package/dist/process-identity.d.ts.map +1 -0
- package/dist/process-identity.js +186 -0
- package/dist/process-identity.js.map +1 -0
- package/dist/process-manager.d.ts +137 -0
- package/dist/process-manager.d.ts.map +1 -0
- package/dist/process-manager.js +382 -0
- package/dist/process-manager.js.map +1 -0
- package/dist/readiness.d.ts +122 -0
- package/dist/readiness.d.ts.map +1 -0
- package/dist/readiness.js +214 -0
- package/dist/readiness.js.map +1 -0
- package/dist/sandbox.d.ts +94 -0
- package/dist/sandbox.d.ts.map +1 -0
- package/dist/sandbox.js +228 -0
- package/dist/sandbox.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime controller (§4/§5/§6/§45 "Core"). Owns Execution lifecycle, spawns every
|
|
3
|
+
* configured service, waits for each one's real readiness (never "process exists"),
|
|
4
|
+
* guarantees cleanup on partial/total failure and timeout. Knows nothing about any
|
|
5
|
+
* specific language or framework (principle 8).
|
|
6
|
+
*/
|
|
7
|
+
import { type Execution, type ProcessHandle } from "@descryy/runtime-contracts";
|
|
8
|
+
import type { AttachFence } from "./attach-fencing.ts";
|
|
9
|
+
import { type ProcessOutputReader, type ReadinessCheck, type ReadinessResult } from "./readiness.ts";
|
|
10
|
+
import type { ExecutionConfiguration } from "@descryy/runtime-contracts";
|
|
11
|
+
export interface CreateExecutionInput {
|
|
12
|
+
readonly application: string;
|
|
13
|
+
readonly repository: string;
|
|
14
|
+
readonly commit: string;
|
|
15
|
+
readonly configuration: ExecutionConfiguration;
|
|
16
|
+
}
|
|
17
|
+
export interface ServiceReadinessSpec {
|
|
18
|
+
/**
|
|
19
|
+
* `outputReader` is a real `ProcessOutputReader` bound to THIS spawned (or
|
|
20
|
+
* attached) process's own output — the only way to build a `log-pattern`
|
|
21
|
+
* check that type-checks (`readiness.ts`'s `ProcessOutputReader` brand).
|
|
22
|
+
* RT-024: this closes "log-pattern only carries the stronger this-run
|
|
23
|
+
* guarantee as caller discipline, not enforced by the type" by making the
|
|
24
|
+
* discipline the only path the type allows.
|
|
25
|
+
*/
|
|
26
|
+
readonly checks: (info: {
|
|
27
|
+
readonly port: number;
|
|
28
|
+
readonly outputReader: ProcessOutputReader;
|
|
29
|
+
}) => readonly ReadinessCheck[];
|
|
30
|
+
readonly timeoutMs: number;
|
|
31
|
+
}
|
|
32
|
+
export interface RunOptions {
|
|
33
|
+
/** One entry required per key in `configuration.services` -- refuses rather than defaulting a missing one to "spawn success is enough" (RT-024/RT-032). */
|
|
34
|
+
readonly readiness: Readonly<Record<string, ServiceReadinessSpec>>;
|
|
35
|
+
/**
|
|
36
|
+
* Optional live observer for `ProcessLifecycleEvent`, called synchronously at each
|
|
37
|
+
* transition for the lifetime of this execution (including after `run()` returns).
|
|
38
|
+
* A throwing observer is not caught here -- same "must not hang, may not silently
|
|
39
|
+
* swallow its own failure" discipline `Collector` imposes on every callback here.
|
|
40
|
+
*/
|
|
41
|
+
readonly onProcessLifecycleEvent?: (event: ProcessLifecycleEvent) => void;
|
|
42
|
+
}
|
|
43
|
+
export interface ServiceStartResult {
|
|
44
|
+
readonly serviceName: string;
|
|
45
|
+
readonly stage: "spawn" | "readiness" | "not-attempted";
|
|
46
|
+
readonly succeeded: boolean;
|
|
47
|
+
/** Set when `stage === "readiness"`. RT-024/RT-031 apply per entry -- N of these is N liveness claims, never a joint identity proof. */
|
|
48
|
+
readonly readiness: ReadinessResult | null;
|
|
49
|
+
/** Set when `stage === "spawn"` and spawning itself threw. */
|
|
50
|
+
readonly error: string | null;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Fires at the exact moments `run()` observes a service's lifecycle -- spawned,
|
|
54
|
+
* readiness settled either way, reaped. A pure notification channel; nothing here
|
|
55
|
+
* decides whether a transition becomes Evidence.
|
|
56
|
+
*
|
|
57
|
+
* Needed because `Execution.processes`/`ServiceStartResults` are only complete once
|
|
58
|
+
* `run()` returns, but a service still running when `run()` resolves hasn't exited
|
|
59
|
+
* yet -- its eventual `process-exited` lies in the future. Only this live channel
|
|
60
|
+
* can observe that exit; reading the final `Execution` later cannot.
|
|
61
|
+
*/
|
|
62
|
+
export type ProcessLifecycleEvent = {
|
|
63
|
+
readonly kind: "process-started";
|
|
64
|
+
readonly serviceName: string;
|
|
65
|
+
readonly handle: ProcessHandle;
|
|
66
|
+
} | {
|
|
67
|
+
readonly kind: "process-ready";
|
|
68
|
+
readonly serviceName: string;
|
|
69
|
+
readonly handle: ProcessHandle;
|
|
70
|
+
readonly readiness: ReadinessResult;
|
|
71
|
+
} | {
|
|
72
|
+
readonly kind: "process-ready-failed";
|
|
73
|
+
readonly serviceName: string;
|
|
74
|
+
readonly handle: ProcessHandle;
|
|
75
|
+
readonly readiness: ReadinessResult;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* `phase` distinguishes "readiness hadn't yet succeeded when it exited"
|
|
79
|
+
* (`"starting"`) from "had already reached READY" (`"running"`) -- the
|
|
80
|
+
* process-level echo of `FAILED_START` vs `FAILED` (§30). Computed from this
|
|
81
|
+
* service's own readiness history, not `Execution.state` at exit time -- a crash
|
|
82
|
+
* mid-readiness-poll fires before the execution's own state has caught up.
|
|
83
|
+
*/
|
|
84
|
+
| {
|
|
85
|
+
readonly kind: "process-exited";
|
|
86
|
+
readonly serviceName: string;
|
|
87
|
+
readonly handle: ProcessHandle;
|
|
88
|
+
readonly phase: "starting" | "running";
|
|
89
|
+
};
|
|
90
|
+
export declare class ExecutionController {
|
|
91
|
+
#private;
|
|
92
|
+
private constructor();
|
|
93
|
+
static create(input: CreateExecutionInput): ExecutionController;
|
|
94
|
+
get execution(): Execution;
|
|
95
|
+
/** One entry per configured service, in spawn order, including never-attempted ones (`stage: "not-attempted"`). Empty until `run()` returns its first result. */
|
|
96
|
+
get serviceStartResults(): readonly ServiceStartResult[];
|
|
97
|
+
/** Non-null only when `run()` refused before spawning anything. */
|
|
98
|
+
get validationError(): string | null;
|
|
99
|
+
/** Combined stdout+stderr of the named service's process so far, or "" if it was never spawned. */
|
|
100
|
+
readProcessOutput(serviceName: string): string;
|
|
101
|
+
/**
|
|
102
|
+
* RT-N3's fence for the named service's process, or `null` for a spawned
|
|
103
|
+
* service (nothing predates observation) or one this controller never
|
|
104
|
+
* started. A caller building a live `ProcessOutputSource` over
|
|
105
|
+
* `readProcessOutput` needs this to mark pre-existing content instead of
|
|
106
|
+
* reporting it as freshly observed — see `attach-fencing.ts`'s own header.
|
|
107
|
+
* Bug found here: `runInstrumentedExecution` (`@descryy/runtime-orchestrator`)
|
|
108
|
+
* built its polling source with no way to reach the fence at all, so an
|
|
109
|
+
* attached service's whole pre-existing backlog — including a crash
|
|
110
|
+
* already in the log before this run ever attached — read as this run's
|
|
111
|
+
* own evidence. This getter is the seam that fix threads through.
|
|
112
|
+
*/
|
|
113
|
+
attachFenceFor(serviceName: string): AttachFence | null;
|
|
114
|
+
/**
|
|
115
|
+
* Starts every service in dependency order, spawned (each on its own ephemeral
|
|
116
|
+
* port unless fixed) or attached (`service.attach`, for an already-running
|
|
117
|
+
* pid/log file). Reaches RUNNING only if every service starts and reaches
|
|
118
|
+
* readiness. On first failure, every started service is killed in reverse order
|
|
119
|
+
* (no-op for attached ones) and remaining services are recorded "not-attempted" --
|
|
120
|
+
* `serviceStartResults` always distinguishes "never tried" from "tried and failed".
|
|
121
|
+
*
|
|
122
|
+
* Configuration is validated atomically first -- a bad `dependsOn`, a cycle, an
|
|
123
|
+
* undeclared placeholder, ambiguous `command`/`attach`, or a missing readiness
|
|
124
|
+
* entry refuses before anything spawns.
|
|
125
|
+
*
|
|
126
|
+
* Every **spawned** service gets `PORT` (its resolved port) unconditionally --
|
|
127
|
+
* load-bearing (matches the fixture apps), not incidental: a command reading its
|
|
128
|
+
* port from anywhere else won't be reachable via readiness checks built from the
|
|
129
|
+
* same `port`. An **attached** service gets no env/port allocation -- it's already
|
|
130
|
+
* running on whatever it bound at launch.
|
|
131
|
+
*/
|
|
132
|
+
run(options: RunOptions): Promise<Execution>;
|
|
133
|
+
stop(): Promise<Execution>;
|
|
134
|
+
/**
|
|
135
|
+
* Stop everything and record `TIMED_OUT` -- same transition `#onTimeout` makes,
|
|
136
|
+
* for a caller that knows the budget expired before the internal timer noticed.
|
|
137
|
+
*
|
|
138
|
+
* **Why not `stop()`:** the orchestrator clamps its observation window to
|
|
139
|
+
* whatever's left of `timeoutMs`, making `TIMED_OUT` a race between `#onTimeout`
|
|
140
|
+
* and `stop()` at the deadline -- measured: the same case reported `TIMED_OUT` at
|
|
141
|
+
* 1534ms and `COMPLETED` at 1515ms. `execution.state` is what `observe_runtime`
|
|
142
|
+
* reads to choose `ok` vs `timed_out`, so losing that race silently hides a real
|
|
143
|
+
* cutoff. A caller that already decided it truncated the run shouldn't have to
|
|
144
|
+
* win a race to report it.
|
|
145
|
+
*
|
|
146
|
+
* Idempotent and terminal-safe like `cancel()`: if the timer fired first, returns
|
|
147
|
+
* the execution it already finished.
|
|
148
|
+
*/
|
|
149
|
+
timeout(): Promise<Execution>;
|
|
150
|
+
cancel(): Promise<Execution>;
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=controller.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../src/controller.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,464 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime controller (§4/§5/§6/§45 "Core"). Owns Execution lifecycle, spawns every
|
|
3
|
+
* configured service, waits for each one's real readiness (never "process exists"),
|
|
4
|
+
* guarantees cleanup on partial/total failure and timeout. Knows nothing about any
|
|
5
|
+
* specific language or framework (principle 8).
|
|
6
|
+
*/
|
|
7
|
+
import { randomUUID } from "node:crypto";
|
|
8
|
+
import { isTerminalExecutionState, isValidExecutionTransition, } from "@descryy/runtime-contracts";
|
|
9
|
+
import { spawnProcess, attachManagedProcess, allocateEphemeralPort } from "./process-manager.js";
|
|
10
|
+
import { awaitReadiness, createProcessOutputReader } from "./readiness.js";
|
|
11
|
+
import { withDefaultProcessEnv } from "./env.js";
|
|
12
|
+
import { validateServicesConfiguration, substitutePortPlaceholders, tokenizeCommand } from "./orchestration.js";
|
|
13
|
+
import { resourceLimitCapability, networkPolicyCapability } from "./execution-safety.js";
|
|
14
|
+
import { filesystemIsolationCapability, unsupportedNetworkPolicyReason } from "./sandbox.js";
|
|
15
|
+
import { containerFilesystemIsolationCapability, containerNetworkIsolationCapability, unsupportedContainerNetworkPolicyReason, } from "./container-sandbox.js";
|
|
16
|
+
import { captureEnvironmentMetadata } from "./environment-metadata.js";
|
|
17
|
+
/**
|
|
18
|
+
* RT-024: binds every `tcp-port`/`http` check this controller runs to the
|
|
19
|
+
* pid of the process it just spawned or attached to, unless the caller
|
|
20
|
+
* already declared one. Applied automatically so a caller does not have to
|
|
21
|
+
* opt in per check to get the stronger guarantee — see `readiness.ts`'s
|
|
22
|
+
* `identityCheckedConnection` for what happens with it.
|
|
23
|
+
*
|
|
24
|
+
* **Not applied for `sandboxBackend: "container"`.** A published Docker port
|
|
25
|
+
* is commonly fronted by a host-side `docker-proxy` process, not the pid
|
|
26
|
+
* this function would bind to — auto-injecting there would produce a false
|
|
27
|
+
* `"mismatch"` refusal against a perfectly healthy container. Disclosed as
|
|
28
|
+
* `identity: "unverified"` for that backend instead of a wrong verdict.
|
|
29
|
+
*/
|
|
30
|
+
function bindChecksToProcessIdentity(checks, pid, sandboxBackend) {
|
|
31
|
+
if (pid === null || sandboxBackend === "container")
|
|
32
|
+
return checks;
|
|
33
|
+
return checks.map((check) => {
|
|
34
|
+
if ((check.kind === "tcp-port" || check.kind === "http") && check.expectedPid === undefined) {
|
|
35
|
+
return { ...check, expectedPid: pid };
|
|
36
|
+
}
|
|
37
|
+
return check;
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
// `run()`'s timeout timer and a caller's stop()/cancel() can race to move a
|
|
41
|
+
// finishing execution to a terminal state. Every transition after an `await` uses
|
|
42
|
+
// `#tryTransition` (returns false) rather than the throwing `#transition`, so the
|
|
43
|
+
// losing path degrades to a no-op instead of an unhandled rejection.
|
|
44
|
+
export class ExecutionController {
|
|
45
|
+
#execution;
|
|
46
|
+
#processes = new Map();
|
|
47
|
+
#timeoutHandle = null;
|
|
48
|
+
#serviceStartResults = [];
|
|
49
|
+
#validationError = null;
|
|
50
|
+
constructor(execution) {
|
|
51
|
+
this.#execution = execution;
|
|
52
|
+
}
|
|
53
|
+
static create(input) {
|
|
54
|
+
const execution = {
|
|
55
|
+
executionId: randomUUID(),
|
|
56
|
+
application: input.application,
|
|
57
|
+
repository: input.repository,
|
|
58
|
+
commit: input.commit,
|
|
59
|
+
environmentMetadata: null,
|
|
60
|
+
configuration: input.configuration,
|
|
61
|
+
state: "CREATED",
|
|
62
|
+
startedAt: null,
|
|
63
|
+
endedAt: null,
|
|
64
|
+
processes: [],
|
|
65
|
+
browserSessions: [],
|
|
66
|
+
eventIds: [],
|
|
67
|
+
traceIds: [],
|
|
68
|
+
failureIds: [],
|
|
69
|
+
correlationIds: [],
|
|
70
|
+
findingIds: [],
|
|
71
|
+
};
|
|
72
|
+
return new ExecutionController(execution);
|
|
73
|
+
}
|
|
74
|
+
get execution() {
|
|
75
|
+
return this.#execution;
|
|
76
|
+
}
|
|
77
|
+
/** One entry per configured service, in spawn order, including never-attempted ones (`stage: "not-attempted"`). Empty until `run()` returns its first result. */
|
|
78
|
+
get serviceStartResults() {
|
|
79
|
+
return this.#serviceStartResults;
|
|
80
|
+
}
|
|
81
|
+
/** Non-null only when `run()` refused before spawning anything. */
|
|
82
|
+
get validationError() {
|
|
83
|
+
return this.#validationError;
|
|
84
|
+
}
|
|
85
|
+
/** Combined stdout+stderr of the named service's process so far, or "" if it was never spawned. */
|
|
86
|
+
readProcessOutput(serviceName) {
|
|
87
|
+
return this.#processes.get(serviceName)?.readOutput() ?? "";
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* RT-N3's fence for the named service's process, or `null` for a spawned
|
|
91
|
+
* service (nothing predates observation) or one this controller never
|
|
92
|
+
* started. A caller building a live `ProcessOutputSource` over
|
|
93
|
+
* `readProcessOutput` needs this to mark pre-existing content instead of
|
|
94
|
+
* reporting it as freshly observed — see `attach-fencing.ts`'s own header.
|
|
95
|
+
* Bug found here: `runInstrumentedExecution` (`@descryy/runtime-orchestrator`)
|
|
96
|
+
* built its polling source with no way to reach the fence at all, so an
|
|
97
|
+
* attached service's whole pre-existing backlog — including a crash
|
|
98
|
+
* already in the log before this run ever attached — read as this run's
|
|
99
|
+
* own evidence. This getter is the seam that fix threads through.
|
|
100
|
+
*/
|
|
101
|
+
attachFenceFor(serviceName) {
|
|
102
|
+
return this.#processes.get(serviceName)?.attachFence() ?? null;
|
|
103
|
+
}
|
|
104
|
+
#transition(to) {
|
|
105
|
+
if (!isValidExecutionTransition(this.#execution.state, to)) {
|
|
106
|
+
throw new Error(`invalid execution transition: ${this.#execution.state} -> ${to}`);
|
|
107
|
+
}
|
|
108
|
+
this.#execution = { ...this.#execution, state: to };
|
|
109
|
+
}
|
|
110
|
+
#tryTransition(to) {
|
|
111
|
+
if (!isValidExecutionTransition(this.#execution.state, to)) {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
this.#transition(to);
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
#recordProcesses() {
|
|
118
|
+
const handles = [];
|
|
119
|
+
for (const managed of this.#processes.values()) {
|
|
120
|
+
handles.push(managed.handle());
|
|
121
|
+
}
|
|
122
|
+
this.#execution = { ...this.#execution, processes: handles };
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Starts every service in dependency order, spawned (each on its own ephemeral
|
|
126
|
+
* port unless fixed) or attached (`service.attach`, for an already-running
|
|
127
|
+
* pid/log file). Reaches RUNNING only if every service starts and reaches
|
|
128
|
+
* readiness. On first failure, every started service is killed in reverse order
|
|
129
|
+
* (no-op for attached ones) and remaining services are recorded "not-attempted" --
|
|
130
|
+
* `serviceStartResults` always distinguishes "never tried" from "tried and failed".
|
|
131
|
+
*
|
|
132
|
+
* Configuration is validated atomically first -- a bad `dependsOn`, a cycle, an
|
|
133
|
+
* undeclared placeholder, ambiguous `command`/`attach`, or a missing readiness
|
|
134
|
+
* entry refuses before anything spawns.
|
|
135
|
+
*
|
|
136
|
+
* Every **spawned** service gets `PORT` (its resolved port) unconditionally --
|
|
137
|
+
* load-bearing (matches the fixture apps), not incidental: a command reading its
|
|
138
|
+
* port from anywhere else won't be reachable via readiness checks built from the
|
|
139
|
+
* same `port`. An **attached** service gets no env/port allocation -- it's already
|
|
140
|
+
* running on whatever it bound at launch.
|
|
141
|
+
*/
|
|
142
|
+
async run(options) {
|
|
143
|
+
this.#transition("STARTING");
|
|
144
|
+
this.#armTimeout();
|
|
145
|
+
const services = this.#execution.configuration.services;
|
|
146
|
+
const validation = validateServicesConfiguration(services);
|
|
147
|
+
if (!validation.valid) {
|
|
148
|
+
return this.#refuseToStart(validation.reason, Object.keys(services));
|
|
149
|
+
}
|
|
150
|
+
// §21/RT-070: refuse atomically before spawning, same discipline as
|
|
151
|
+
// tokenizeCommand -- finding out only when spawnProcess() throws would mean
|
|
152
|
+
// earlier services are already running by the time of refusal.
|
|
153
|
+
const resourceLimits = this.#execution.configuration.resourceLimits;
|
|
154
|
+
if (resourceLimits !== undefined) {
|
|
155
|
+
const capability = resourceLimitCapability();
|
|
156
|
+
if (capability.availability !== "available") {
|
|
157
|
+
return this.#refuseToStart(`resourceLimits was configured but cannot be enforced on this platform: ${capability.reason}`, Object.keys(services));
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
// Which real mechanism backs filesystemPolicy/networkPolicy -- absent means "bwrap".
|
|
161
|
+
const sandboxBackend = this.#execution.configuration.sandboxBackend ?? "bwrap";
|
|
162
|
+
// RT-193, same atomic-refusal placement. networkPolicyCapability() is real on
|
|
163
|
+
// Linux (bwrap network namespace), unavailable on macOS/Windows, and only
|
|
164
|
+
// implements full denial even where it exists -- both refused here before
|
|
165
|
+
// spawning. "container" checks the container mechanism's own functions instead.
|
|
166
|
+
const networkPolicy = this.#execution.configuration.networkPolicy;
|
|
167
|
+
if (networkPolicy !== undefined) {
|
|
168
|
+
const shapeReason = sandboxBackend === "container" ? unsupportedContainerNetworkPolicyReason(networkPolicy) : unsupportedNetworkPolicyReason(networkPolicy);
|
|
169
|
+
if (shapeReason !== null) {
|
|
170
|
+
return this.#refuseToStart(`networkPolicy was configured but cannot be enforced: ${shapeReason}`, Object.keys(services));
|
|
171
|
+
}
|
|
172
|
+
const capability = sandboxBackend === "container" ? containerNetworkIsolationCapability() : networkPolicyCapability();
|
|
173
|
+
if (capability.availability !== "available") {
|
|
174
|
+
return this.#refuseToStart(`networkPolicy was configured but cannot be enforced on this platform: ${capability.reason}`, Object.keys(services));
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
// Filesystem half, same atomic-refusal placement -- real on Linux via bwrap's
|
|
178
|
+
// mount namespace, refused where it doesn't exist. "container" checks Docker's
|
|
179
|
+
// own capability instead.
|
|
180
|
+
const filesystemPolicy = this.#execution.configuration.filesystemPolicy;
|
|
181
|
+
if (filesystemPolicy !== undefined) {
|
|
182
|
+
const capability = sandboxBackend === "container" ? containerFilesystemIsolationCapability() : filesystemIsolationCapability();
|
|
183
|
+
if (capability.availability !== "available") {
|
|
184
|
+
return this.#refuseToStart(`filesystemPolicy was configured but cannot be enforced on this platform: ${capability.reason}`, Object.keys(services));
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
for (const name of validation.order) {
|
|
188
|
+
if (options.readiness[name] === undefined) {
|
|
189
|
+
return this.#refuseToStart(`service "${name}" has no matching RunOptions.readiness entry`, validation.order);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
// RT-193: captured once spawning is committed, from the real host.
|
|
193
|
+
const environmentMetadata = await captureEnvironmentMetadata(services);
|
|
194
|
+
this.#execution = { ...this.#execution, startedAt: new Date().toISOString(), environmentMetadata };
|
|
195
|
+
const resolvedPorts = new Map();
|
|
196
|
+
for (let i = 0; i < validation.order.length; i++) {
|
|
197
|
+
const name = validation.order[i];
|
|
198
|
+
if (name === undefined)
|
|
199
|
+
continue;
|
|
200
|
+
if (isTerminalExecutionState(this.#execution.state)) {
|
|
201
|
+
// A concurrent timeout/stop/cancel already finished this execution.
|
|
202
|
+
return this.#execution;
|
|
203
|
+
}
|
|
204
|
+
const service = services[name];
|
|
205
|
+
if (service === undefined)
|
|
206
|
+
continue;
|
|
207
|
+
const readinessSpec = options.readiness[name];
|
|
208
|
+
if (readinessSpec === undefined)
|
|
209
|
+
continue;
|
|
210
|
+
let managed;
|
|
211
|
+
let port;
|
|
212
|
+
if (service.attach !== undefined) {
|
|
213
|
+
// Attach mode: the target is already running and bound to whatever it
|
|
214
|
+
// bound at launch -- nothing here can allocate a port for it, only record
|
|
215
|
+
// the one the caller already knows. `0` when unsupplied, so a readiness
|
|
216
|
+
// check needing a port fails legibly ("nothing answered") rather than
|
|
217
|
+
// this function inventing an ephemeral port unrelated to the real target.
|
|
218
|
+
// resourceLimits/filesystemPolicy/networkPolicy/sandboxBackend never pass
|
|
219
|
+
// through -- they can't apply to a process this runtime didn't spawn.
|
|
220
|
+
port = service.port ?? 0;
|
|
221
|
+
try {
|
|
222
|
+
managed = attachManagedProcess({
|
|
223
|
+
processId: randomUUID(),
|
|
224
|
+
attach: service.attach,
|
|
225
|
+
serviceName: name,
|
|
226
|
+
...(service.port === undefined ? {} : { port: service.port }),
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
catch (err) {
|
|
230
|
+
this.#serviceStartResults.push({
|
|
231
|
+
serviceName: name,
|
|
232
|
+
stage: "spawn",
|
|
233
|
+
succeeded: false,
|
|
234
|
+
readiness: null,
|
|
235
|
+
error: err instanceof Error ? err.message : String(err),
|
|
236
|
+
});
|
|
237
|
+
this.#markRemainingNotAttempted(validation.order, i + 1);
|
|
238
|
+
this.#tryTransition("FAILED_START");
|
|
239
|
+
await this.#cleanup();
|
|
240
|
+
this.#finish();
|
|
241
|
+
throw err;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
port = service.port ?? (await allocateEphemeralPort());
|
|
246
|
+
const env = withDefaultProcessEnv({
|
|
247
|
+
PORT: String(port),
|
|
248
|
+
...substitutePortPlaceholders(service.env, resolvedPorts),
|
|
249
|
+
});
|
|
250
|
+
// validateServicesConfiguration already proved this, so both branches
|
|
251
|
+
// below are unreachable in practice -- kept over a non-null assertion
|
|
252
|
+
// that would crash for real if the two ever drift apart.
|
|
253
|
+
if (service.command === undefined) {
|
|
254
|
+
return this.#refuseToStart(`service "${name}": neither "command" nor "attach" is set`, validation.order);
|
|
255
|
+
}
|
|
256
|
+
const tokenized = tokenizeCommand(service.command);
|
|
257
|
+
if (!tokenized.ok) {
|
|
258
|
+
return this.#refuseToStart(`service "${name}": ${tokenized.reason}`, validation.order);
|
|
259
|
+
}
|
|
260
|
+
const { command, args } = tokenized;
|
|
261
|
+
// Instrumentation flags (`--import <preload>`) go through NODE_OPTIONS, not
|
|
262
|
+
// spliced into the spawned command's own argv. `command` is a raw
|
|
263
|
+
// user-supplied token (`tokenizeCommand`'s output) with no proof it is
|
|
264
|
+
// literally `node` -- it may be a shebang-wrapped CLI ("next", "vite")
|
|
265
|
+
// that the kernel resolves to `node <script>` transparently, in which case
|
|
266
|
+
// anything appended to `args` lands in THAT CLI's own argv, not Node's.
|
|
267
|
+
// Frameworks fronted by a strict argv parser (cac, used by next/vite) then
|
|
268
|
+
// refuse to start. NODE_OPTIONS is consumed by Node itself before the
|
|
269
|
+
// target ever sees `process.argv`, so it works whether `command` is `node`,
|
|
270
|
+
// a shebang script, or anything else -- and appends to (never clobbers) any
|
|
271
|
+
// NODE_OPTIONS the caller already declared, in `env` or inherited from this
|
|
272
|
+
// process's own environment.
|
|
273
|
+
if (service.interpreterArgs !== undefined && service.interpreterArgs.length > 0) {
|
|
274
|
+
const existing = env.NODE_OPTIONS ?? process.env.NODE_OPTIONS;
|
|
275
|
+
const addition = service.interpreterArgs.join(" ");
|
|
276
|
+
env.NODE_OPTIONS = existing === undefined || existing === "" ? addition : `${existing} ${addition}`;
|
|
277
|
+
}
|
|
278
|
+
try {
|
|
279
|
+
managed = spawnProcess({
|
|
280
|
+
processId: randomUUID(),
|
|
281
|
+
command,
|
|
282
|
+
args,
|
|
283
|
+
cwd: service.cwd,
|
|
284
|
+
env,
|
|
285
|
+
serviceName: name,
|
|
286
|
+
port,
|
|
287
|
+
...(resourceLimits === undefined ? {} : { resourceLimits }),
|
|
288
|
+
...(filesystemPolicy === undefined ? {} : { filesystemPolicy }),
|
|
289
|
+
...(networkPolicy === undefined ? {} : { networkPolicy }),
|
|
290
|
+
...(sandboxBackend === "bwrap" ? {} : { sandboxBackend }),
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
catch (err) {
|
|
294
|
+
this.#serviceStartResults.push({
|
|
295
|
+
serviceName: name,
|
|
296
|
+
stage: "spawn",
|
|
297
|
+
succeeded: false,
|
|
298
|
+
readiness: null,
|
|
299
|
+
error: err instanceof Error ? err.message : String(err),
|
|
300
|
+
});
|
|
301
|
+
this.#markRemainingNotAttempted(validation.order, i + 1);
|
|
302
|
+
this.#tryTransition("FAILED_START");
|
|
303
|
+
await this.#cleanup();
|
|
304
|
+
this.#finish();
|
|
305
|
+
throw err;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
this.#processes.set(name, managed);
|
|
309
|
+
resolvedPorts.set(name, port);
|
|
310
|
+
this.#recordProcesses();
|
|
311
|
+
options.onProcessLifecycleEvent?.({ kind: "process-started", serviceName: name, handle: managed.handle() });
|
|
312
|
+
// Read by the exit watcher below -- true only once readiness succeeded, which
|
|
313
|
+
// lets `phase` distinguish "died before confirmed up" from "died after running".
|
|
314
|
+
let reachedReady = false;
|
|
315
|
+
// Fire-and-forget: exit can happen long after run() returns (a later crash, or
|
|
316
|
+
// #cleanup()'s reap) -- must not be awaited inline, which would block every
|
|
317
|
+
// later service in validation.order on this one's exit.
|
|
318
|
+
void managed.waitForExit().then(() => {
|
|
319
|
+
options.onProcessLifecycleEvent?.({
|
|
320
|
+
kind: "process-exited",
|
|
321
|
+
serviceName: name,
|
|
322
|
+
handle: managed.handle(),
|
|
323
|
+
phase: reachedReady ? "running" : "starting",
|
|
324
|
+
});
|
|
325
|
+
});
|
|
326
|
+
const outputReader = createProcessOutputReader(() => managed.readOutput());
|
|
327
|
+
const declaredChecks = readinessSpec.checks({ port, outputReader });
|
|
328
|
+
const identityBoundChecks = bindChecksToProcessIdentity(declaredChecks, managed.handle().pid, sandboxBackend);
|
|
329
|
+
const readinessResult = await awaitReadiness(identityBoundChecks, {
|
|
330
|
+
timeoutMs: readinessSpec.timeoutMs,
|
|
331
|
+
});
|
|
332
|
+
if (readinessResult.ready)
|
|
333
|
+
reachedReady = true;
|
|
334
|
+
this.#serviceStartResults.push({
|
|
335
|
+
serviceName: name,
|
|
336
|
+
stage: "readiness",
|
|
337
|
+
succeeded: readinessResult.ready,
|
|
338
|
+
readiness: readinessResult,
|
|
339
|
+
error: null,
|
|
340
|
+
});
|
|
341
|
+
options.onProcessLifecycleEvent?.({
|
|
342
|
+
kind: readinessResult.ready ? "process-ready" : "process-ready-failed",
|
|
343
|
+
serviceName: name,
|
|
344
|
+
handle: managed.handle(),
|
|
345
|
+
readiness: readinessResult,
|
|
346
|
+
});
|
|
347
|
+
if (isTerminalExecutionState(this.#execution.state)) {
|
|
348
|
+
return this.#execution;
|
|
349
|
+
}
|
|
350
|
+
if (!readinessResult.ready) {
|
|
351
|
+
this.#markRemainingNotAttempted(validation.order, i + 1);
|
|
352
|
+
if (this.#tryTransition("FAILED_START")) {
|
|
353
|
+
await this.#cleanup();
|
|
354
|
+
}
|
|
355
|
+
return this.#finish();
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
if (this.#tryTransition("READY")) {
|
|
359
|
+
this.#tryTransition("RUNNING");
|
|
360
|
+
}
|
|
361
|
+
return this.#execution;
|
|
362
|
+
}
|
|
363
|
+
#refuseToStart(reason, allServiceNames) {
|
|
364
|
+
this.#validationError = reason;
|
|
365
|
+
this.#serviceStartResults = allServiceNames.map((serviceName) => ({
|
|
366
|
+
serviceName,
|
|
367
|
+
stage: "not-attempted",
|
|
368
|
+
succeeded: false,
|
|
369
|
+
readiness: null,
|
|
370
|
+
error: null,
|
|
371
|
+
}));
|
|
372
|
+
this.#tryTransition("FAILED_START");
|
|
373
|
+
return this.#finish();
|
|
374
|
+
}
|
|
375
|
+
#markRemainingNotAttempted(order, fromIndex) {
|
|
376
|
+
for (let i = fromIndex; i < order.length; i++) {
|
|
377
|
+
const serviceName = order[i];
|
|
378
|
+
if (serviceName === undefined)
|
|
379
|
+
continue;
|
|
380
|
+
this.#serviceStartResults.push({
|
|
381
|
+
serviceName,
|
|
382
|
+
stage: "not-attempted",
|
|
383
|
+
succeeded: false,
|
|
384
|
+
readiness: null,
|
|
385
|
+
error: null,
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
async stop() {
|
|
390
|
+
if (isTerminalExecutionState(this.#execution.state) || this.#execution.state === "STOPPING") {
|
|
391
|
+
return this.#execution;
|
|
392
|
+
}
|
|
393
|
+
if (this.#tryTransition("STOPPING")) {
|
|
394
|
+
await this.#cleanup();
|
|
395
|
+
this.#tryTransition("COMPLETED");
|
|
396
|
+
}
|
|
397
|
+
return this.#finish();
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* Stop everything and record `TIMED_OUT` -- same transition `#onTimeout` makes,
|
|
401
|
+
* for a caller that knows the budget expired before the internal timer noticed.
|
|
402
|
+
*
|
|
403
|
+
* **Why not `stop()`:** the orchestrator clamps its observation window to
|
|
404
|
+
* whatever's left of `timeoutMs`, making `TIMED_OUT` a race between `#onTimeout`
|
|
405
|
+
* and `stop()` at the deadline -- measured: the same case reported `TIMED_OUT` at
|
|
406
|
+
* 1534ms and `COMPLETED` at 1515ms. `execution.state` is what `observe_runtime`
|
|
407
|
+
* reads to choose `ok` vs `timed_out`, so losing that race silently hides a real
|
|
408
|
+
* cutoff. A caller that already decided it truncated the run shouldn't have to
|
|
409
|
+
* win a race to report it.
|
|
410
|
+
*
|
|
411
|
+
* Idempotent and terminal-safe like `cancel()`: if the timer fired first, returns
|
|
412
|
+
* the execution it already finished.
|
|
413
|
+
*/
|
|
414
|
+
async timeout() {
|
|
415
|
+
if (isTerminalExecutionState(this.#execution.state) || this.#execution.state === "STOPPING") {
|
|
416
|
+
return this.#execution;
|
|
417
|
+
}
|
|
418
|
+
await this.#cleanup();
|
|
419
|
+
this.#tryTransition("TIMED_OUT");
|
|
420
|
+
return this.#finish();
|
|
421
|
+
}
|
|
422
|
+
async cancel() {
|
|
423
|
+
if (isTerminalExecutionState(this.#execution.state) || this.#execution.state === "STOPPING") {
|
|
424
|
+
return this.#execution;
|
|
425
|
+
}
|
|
426
|
+
await this.#cleanup();
|
|
427
|
+
this.#tryTransition("CANCELLED");
|
|
428
|
+
return this.#finish();
|
|
429
|
+
}
|
|
430
|
+
#armTimeout() {
|
|
431
|
+
this.#timeoutHandle = setTimeout(() => {
|
|
432
|
+
void this.#onTimeout();
|
|
433
|
+
}, this.#execution.configuration.timeoutMs);
|
|
434
|
+
}
|
|
435
|
+
async #onTimeout() {
|
|
436
|
+
if (isTerminalExecutionState(this.#execution.state)) {
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
await this.#cleanup();
|
|
440
|
+
this.#tryTransition("TIMED_OUT");
|
|
441
|
+
this.#finish();
|
|
442
|
+
}
|
|
443
|
+
/** Kills every spawned service in reverse start order — last up, first down. */
|
|
444
|
+
async #cleanup() {
|
|
445
|
+
if (this.#timeoutHandle !== null) {
|
|
446
|
+
clearTimeout(this.#timeoutHandle);
|
|
447
|
+
this.#timeoutHandle = null;
|
|
448
|
+
}
|
|
449
|
+
const managed = [...this.#processes.values()].reverse();
|
|
450
|
+
for (const proc of managed) {
|
|
451
|
+
await proc.kill();
|
|
452
|
+
}
|
|
453
|
+
if (managed.length > 0) {
|
|
454
|
+
this.#recordProcesses();
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
#finish() {
|
|
458
|
+
if (this.#execution.endedAt === null) {
|
|
459
|
+
this.#execution = { ...this.#execution, endedAt: new Date().toISOString() };
|
|
460
|
+
}
|
|
461
|
+
return this.#execution;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
//# sourceMappingURL=controller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"controller.js","sourceRoot":"","sources":["../src/controller.ts"],"names":[],"mappings":"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"}
|