@descryy/runtime-controller 0.2.1 → 0.3.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.
Files changed (61) hide show
  1. package/LICENSE +6 -0
  2. package/dist/capability-registry.d.ts +0 -15
  3. package/dist/capability-registry.d.ts.map +1 -1
  4. package/dist/capability-registry.js +9 -19
  5. package/dist/capability-registry.js.map +1 -1
  6. package/dist/collector-version.d.ts +1 -8
  7. package/dist/collector-version.d.ts.map +1 -1
  8. package/dist/collector-version.js +1 -8
  9. package/dist/collector-version.js.map +1 -1
  10. package/dist/container-sandbox.d.ts +66 -150
  11. package/dist/container-sandbox.d.ts.map +1 -1
  12. package/dist/container-sandbox.js +62 -143
  13. package/dist/container-sandbox.js.map +1 -1
  14. package/dist/controller.d.ts +49 -106
  15. package/dist/controller.d.ts.map +1 -1
  16. package/dist/controller.js +65 -123
  17. package/dist/controller.js.map +1 -1
  18. package/dist/dependency-version-check.d.ts +19 -73
  19. package/dist/dependency-version-check.d.ts.map +1 -1
  20. package/dist/dependency-version-check.js +18 -67
  21. package/dist/dependency-version-check.js.map +1 -1
  22. package/dist/env.d.ts +4 -10
  23. package/dist/env.d.ts.map +1 -1
  24. package/dist/env.js +4 -10
  25. package/dist/env.js.map +1 -1
  26. package/dist/environment-metadata.d.ts +9 -17
  27. package/dist/environment-metadata.d.ts.map +1 -1
  28. package/dist/environment-metadata.js +12 -29
  29. package/dist/environment-metadata.js.map +1 -1
  30. package/dist/environment-version-check.d.ts +22 -65
  31. package/dist/environment-version-check.d.ts.map +1 -1
  32. package/dist/environment-version-check.js +24 -66
  33. package/dist/environment-version-check.js.map +1 -1
  34. package/dist/execution-safety.d.ts +54 -112
  35. package/dist/execution-safety.d.ts.map +1 -1
  36. package/dist/execution-safety.js +48 -102
  37. package/dist/execution-safety.js.map +1 -1
  38. package/dist/index.d.ts +0 -10
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js.map +1 -1
  41. package/dist/orchestration.d.ts +24 -39
  42. package/dist/orchestration.d.ts.map +1 -1
  43. package/dist/orchestration.js +39 -75
  44. package/dist/orchestration.js.map +1 -1
  45. package/dist/process-collector.d.ts +8 -22
  46. package/dist/process-collector.d.ts.map +1 -1
  47. package/dist/process-collector.js +23 -55
  48. package/dist/process-collector.js.map +1 -1
  49. package/dist/process-manager.d.ts +45 -80
  50. package/dist/process-manager.d.ts.map +1 -1
  51. package/dist/process-manager.js +51 -101
  52. package/dist/process-manager.js.map +1 -1
  53. package/dist/readiness.d.ts +28 -70
  54. package/dist/readiness.d.ts.map +1 -1
  55. package/dist/readiness.js +73 -95
  56. package/dist/readiness.js.map +1 -1
  57. package/dist/sandbox.d.ts +60 -105
  58. package/dist/sandbox.d.ts.map +1 -1
  59. package/dist/sandbox.js +78 -121
  60. package/dist/sandbox.js.map +1 -1
  61. package/package.json +7 -2
@@ -1,111 +1,58 @@
1
1
  /**
2
- * §21's execution boundary, container backend -- the macOS/Windows half of
3
- * the sandbox-isolation lane. `sandbox.ts` closed this gap for Linux via
4
- * bubblewrap; this module closes it for macOS and Windows, but NOT by
5
- * building a second and third native OS sandbox. That path was researched
6
- * (`sandbox.ts`'s own original module doc named `sandbox-exec`/Seatbelt on
7
- * macOS and Job Objects/AppContainer on Windows as candidates) and
8
- * explicitly rejected as an architecture decision: `sandbox-exec` is
9
- * deprecated (no public API replacement), the Endpoint Security Framework
10
- * needs a special Apple entitlement this project does not have, and
11
- * hand-building Job Objects + AppContainer + WFP network enforcement on
12
- * Windows is a second and third bespoke native sandbox to build and
13
- * maintain for the same problem already solved once.
2
+ * §21's execution boundary, container backend -- the macOS/Windows half of the
3
+ * sandbox-isolation lane (`sandbox.ts` covers Linux via bubblewrap).
14
4
  *
15
- * **Mechanism: route the spawned process through a real container instead.**
16
- * This runtime's actual targets -- JVM/Spring, Node, Python backends -- are
17
- * already containerizable, so this reuses the *Linux* sandbox mechanism
18
- * bwrap already proved, by running the target process inside a `docker run`
19
- * invocation. The container's own rootfs IS the "outside allowedRoots is
20
- * unreachable" boundary; nothing inside the container needs bwrap. On
21
- * macOS, `docker run` targets Docker Desktop's Linux VM; on Windows, WSL2 /
22
- * Docker Desktop's Windows backend. Both ultimately run the same Linux
23
- * container runtime this module already drives directly.
5
+ * **Not a second native sandbox.** `sandbox-exec`/Seatbelt (macOS) and Job
6
+ * Objects/AppContainer/WFP (Windows) were researched and rejected: `sandbox-exec` is
7
+ * deprecated with no public API replacement, Endpoint Security needs an Apple
8
+ * entitlement this project doesn't have, and hand-building Windows equivalents is a
9
+ * second and third bespoke sandbox for a problem already solved once.
24
10
  *
25
- * **What was actually verified, and what was not -- stated precisely,
26
- * matching `sandbox.ts`'s own "researched and disclosed rather than
27
- * guessed" discipline:**
11
+ * **Mechanism: route the spawned process through a real container instead**, via
12
+ * `docker run` (Docker Desktop's Linux VM on macOS, WSL2/Docker Desktop on Windows).
13
+ * The container's own rootfs is the isolation boundary; no bwrap needed inside it.
28
14
  *
29
- * REAL-TESTED, on this Linux development machine, via a real installed
30
- * Docker daemon (server 29.6.1) and real `docker run` invocations -- not
31
- * mocked, not asserted from documentation: a file outside a container's
32
- * bind-mounts is genuinely unreachable (`ENOENT` from inside the running
33
- * container); a network call under `--network none` is genuinely refused
34
- * against a real host listener; both together on one spawn; the same
35
- * boundary through the full `ExecutionController.run()` path, not just this
36
- * module's own function called directly. See `container-sandbox.test.ts`
37
- * and `controller.test.ts`'s container-backend end-to-end test.
15
+ * **Verified for real** (Linux dev machine, real Docker daemon 29.6.1, not mocked):
16
+ * a file outside bind-mounts is unreachable (`ENOENT`); a network call under
17
+ * `--network none` is refused against a real listener; both together, through the
18
+ * full `ExecutionController.run()` path. See `container-sandbox.test.ts`,
19
+ * `controller.test.ts`'s container-backend e2e test.
38
20
  *
39
- * **IMPLEMENTATION-NOT-DONE, not a "gap" and not a coverage caveat: the
40
- * macOS-Docker-Desktop-VM-specific and Windows-WSL2-specific integration
41
- * paths are UNVERIFIED on real macOS/Windows hardware.** No such hardware
42
- * is available in this environment. Concretely unverified: detecting
43
- * whether Docker Desktop is actually running before attempting a spawn;
44
- * path translation across the Docker Desktop VM boundary on macOS; WSL2
45
- * path translation on Windows (a Windows host path and the path Linux
46
- * containers see are not the same string). This module's bind-mount
47
- * strategy assumes the host path and the in-container path are identical
48
- * (`-v hostPath:hostPath`, mirroring `sandbox.ts`'s own `--bind root root`
49
- * convention) -- true on Linux, true for Docker Desktop's Linux VM when the
50
- * path is already inside the VM's shared-drive mapping, but the exact
51
- * translation rules for an arbitrary Windows path are not exercised here at
52
- * all. This is "the container mechanism exists and is tested where it can
53
- * be, but full cross-platform verification needs hardware nobody here has"
54
- * -- a distinct category from a real bug or an intentionally out-of-scope
55
- * capability, and this module does not claim otherwise.
21
+ * **UNVERIFIED on real macOS/Windows hardware** (none available here): Docker
22
+ * Desktop running-detection before spawn, path translation across the Docker
23
+ * Desktop VM boundary (macOS) and WSL2 (Windows) -- this module's bind-mount assumes
24
+ * host path == in-container path (`-v hostPath:hostPath`), true on Linux and for
25
+ * Docker Desktop's Linux VM when already inside its shared-drive mapping, untested
26
+ * for an arbitrary Windows path. Mechanism exists and is tested where it can be;
27
+ * cross-platform verification needs hardware nobody here has -- not a bug, not
28
+ * claimed otherwise.
56
29
  *
57
- * **Explicit scope boundary, same treatment attach-mode already gets in
58
- * this codebase:** a target that cannot run containerized at all --deep
59
- * native OS integration, GUI-dependent processes, OS-specific native
60
- * dependencies that don't exist inside a Linux container image-- is out of
61
- * scope for this approach, on any platform. There is no fallback to a
62
- * native sandbox for such a target; it is simply not isolatable by this
63
- * mechanism, and that is disclosed rather than silently unsupported.
30
+ * **Scope boundary** (same treatment as attach-mode elsewhere): a target that can't
31
+ * run containerized at all (deep native OS integration, GUI, native deps absent
32
+ * from a Linux image) is out of scope on any platform, with no native-sandbox
33
+ * fallback -- disclosed, not silently unsupported.
64
34
  *
65
- * **Real escape testing on the container boundary is still required and
66
- * was done** -- "the container starts successfully" is not treated as
67
- * sufficient evidence here, the same bar `sandbox.ts`'s bwrap path was held
68
- * to. A mutation check on the first version of that testing (temporarily
69
- * removing `--network none`, rerunning) surfaced a genuine behavioral
70
- * difference from bwrap worth stating precisely rather than glossing over:
71
- * **Docker gives every container its own network namespace by default,
72
- * with or without `--network none`** -- unlike bwrap, which shares the
73
- * host's network unless `networkPolicy` is declared. A containerized
74
- * process can therefore never reach the HOST's own loopback either way
75
- * (that alone is not evidence `--network none` specifically did anything),
76
- * but it CAN still reach the public internet via Docker's default bridge
77
- * NAT when no `networkPolicy` is declared -- only `--network none`
78
- * additionally blocks that. `container-sandbox.test.ts`'s dedicated
79
- * mutation-sensitive test isolates exactly this variable (an external
80
- * host, not the host's own loopback) to prove the flag itself is what is
81
- * being tested, not mere containerization.
35
+ * **Measured Docker/bwrap difference** (found via a mutation check removing
36
+ * `--network none` and rerunning): Docker gives every container its own network
37
+ * namespace regardless of `--network none` -- unlike bwrap, which shares the host's
38
+ * network unless `networkPolicy` is declared. So a container can never reach the
39
+ * HOST's loopback either way, but it CAN still reach the public internet via
40
+ * Docker's default bridge NAT unless `--network none` is set. The dedicated
41
+ * mutation-sensitive test in `container-sandbox.test.ts` checks reachability to an
42
+ * external host (not loopback) to isolate exactly this.
82
43
  *
83
- * **What this module does NOT attempt to solve, disclosed rather than
84
- * silently dropped:** composition with `ResourceLimits` (`prlimit`) --
85
- * `sandbox.ts` composes bwrap with `applyResourceLimits` by wrapping
86
- * outside it; this module does not attempt the equivalent composition with
87
- * Docker's own `--memory`/`--cpus`/`--pids-limit` flags in this pass. A
88
- * `resourceLimits`-declared execution routed through the container backend
89
- * runs without OS-enforced resource limits inside the container. Selective
90
- * network allow-/deny-listing (`NetworkPolicy` shapes other than full
91
- * denial) is unimplemented here for the same reason `sandbox.ts` doesn't
92
- * implement it: it needs DNS interception and IP filtering this iteration
93
- * does not build -- `unsupportedContainerNetworkPolicyReason` reports this
94
- * the same way `sandbox.ts`'s own `unsupportedNetworkPolicyReason` does,
95
- * deliberately matching posture rather than silently claiming broader
96
- * support than the underlying mechanism has.
44
+ * **Not solved here, disclosed:** `ResourceLimits` composition -- `sandbox.ts` wraps
45
+ * bwrap with `applyResourceLimits`; this module does not wrap Docker's
46
+ * `--memory`/`--cpus`/`--pids-limit` equivalents, so a `resourceLimits`-declared
47
+ * execution on this backend runs unlimited inside the container. Selective network
48
+ * allow/deny-listing is unimplemented for the same reason as `sandbox.ts` (needs DNS
49
+ * interception + IP filtering) -- `unsupportedContainerNetworkPolicyReason` reports
50
+ * it the same way, matching posture rather than overclaiming.
97
51
  */
98
52
  import { execFileSync } from "node:child_process";
99
53
  import { randomUUID } from "node:crypto";
100
54
  import { basename } from "node:path";
101
- /**
102
- * Real capability check: is a working Docker CLI + reachable daemon
103
- * actually present, not merely "does a `docker` binary exist on PATH."
104
- * `docker version` talks to the daemon; a CLI with no running daemon behind
105
- * it (Docker Desktop not started, dockerd not running) fails this the same
106
- * way a missing binary does -- both are "cannot enforce," and the caller
107
- * does not need to tell them apart to make the right decision (refuse).
108
- */
55
+ /** Real check: working Docker CLI + reachable daemon, not just a `docker` binary on PATH. `docker version` talks to the daemon, so a CLI with no daemon running fails the same way a missing binary does -- both mean "cannot enforce." */
109
56
  export function containerRuntimeCapability(env = process.env) {
110
57
  try {
111
58
  execFileSync("docker", ["version", "--format", "{{.Server.Version}}"], { env, stdio: "ignore" });
@@ -118,26 +65,16 @@ export function containerRuntimeCapability(env = process.env) {
118
65
  }
119
66
  return { availability: "available", reason: null };
120
67
  }
121
- /**
122
- * Mirrors `sandbox.ts`'s `filesystemIsolationCapability`/
123
- * `networkIsolationCapability` split: one real mechanism underneath
124
- * (a container boundary), two named capabilities because the two policies
125
- * are declared, refused, and reasoned about independently at the call
126
- * site.
127
- */
68
+ // Mirrors sandbox.ts's filesystem/network capability split: one real mechanism
69
+ // (container boundary), two named capabilities since the policies are declared
70
+ // and reasoned about independently.
128
71
  export function containerFilesystemIsolationCapability(env = process.env) {
129
72
  return containerRuntimeCapability(env);
130
73
  }
131
74
  export function containerNetworkIsolationCapability(env = process.env) {
132
75
  return containerRuntimeCapability(env);
133
76
  }
134
- /**
135
- * Same posture as `sandbox.ts`'s `unsupportedNetworkPolicyReason`, matched
136
- * deliberately rather than reinvented: only full denial
137
- * (`{ mode: "allow", hosts: [] }`, `docker run --network none`) is
138
- * enforced. A shape bwrap already discloses as unsupported is not silently
139
- * claimed as supported here just because the underlying mechanism changed.
140
- */
77
+ /** Same posture as `sandbox.ts`'s `unsupportedNetworkPolicyReason`: only full denial (`--network none`) is enforced. A shape bwrap discloses as unsupported isn't silently claimed here just because the mechanism changed. */
141
78
  export function unsupportedContainerNetworkPolicyReason(policy) {
142
79
  if (policy.mode === "allow" && policy.hosts.length === 0)
143
80
  return null;
@@ -145,15 +82,9 @@ export function unsupportedContainerNetworkPolicyReason(policy) {
145
82
  "hosts would need a custom docker network with DNS interception and IP filtering inside it, not built in this " +
146
83
  "iteration (the same posture the bwrap backend already declares for the same shapes)");
147
84
  }
148
- /**
149
- * Minimal, official, `-slim`/`-jre` base images for this runtime's actual
150
- * fixture targets (JVM/Spring, Node, Python backends -- see
151
- * `packages/orchestrator/test/fixtures`), keyed by the interpreter's
152
- * basename so a full interpreter path (`/home/x/.nvm/versions/node/vX/bin/node`)
153
- * still resolves. Not a general-purpose image registry -- a caller with a
154
- * different runtime need passes `containerImage` explicitly instead of
155
- * extending this table with more special cases.
156
- */
85
+ // Minimal official -slim/-jre images for this runtime's fixture targets, keyed by
86
+ // interpreter basename so a full path still resolves. Not a general registry --
87
+ // other runtimes pass `containerImage` explicitly instead of extending this table.
157
88
  const KNOWN_RUNTIME_IMAGES = {
158
89
  node: "node:22-slim",
159
90
  python: "python:3.12-slim",
@@ -164,32 +95,20 @@ export function resolveContainerImage(interpreterCommand) {
164
95
  return KNOWN_RUNTIME_IMAGES[basename(interpreterCommand)] ?? null;
165
96
  }
166
97
  /**
167
- * Wraps `command`/`args` with `docker run` so a real container boundary
168
- * enforces `filesystemPolicy`/`networkPolicy`. Neither declared returns
169
- * `command`/`args` unchanged and never invokes docker at all -- the same
170
- * non-regression contract `sandbox.ts`'s `applySandbox` established for
171
- * bwrap, applied here too: a caller who never opts into a policy is
172
- * completely unaffected by this module's existence.
98
+ * Wraps `command`/`args` with `docker run` so a container boundary enforces
99
+ * `filesystemPolicy`/`networkPolicy`. Neither declared returns them unchanged and
100
+ * never invokes docker -- same non-regression contract as `sandbox.ts`'s
101
+ * `applySandbox`.
173
102
  *
174
- * **Throws rather than silently spawning unconstrained** when a policy is
175
- * requested and cannot actually be backed -- no working Docker, or a
176
- * `networkPolicy` shape this mechanism doesn't implement -- matching
177
- * `applySandbox`'s own refuse-rather-than-guess precedent exactly.
103
+ * **Throws rather than silently spawning unconstrained** when a policy can't
104
+ * actually be backed (no working Docker, unimplemented `networkPolicy` shape).
178
105
  *
179
- * **Returns a real, unique `containerName` whenever it wraps.** This was
180
- * added after a genuine finding from this module's own real escape tests,
181
- * not assumed up front: `process-manager.ts`'s existing group-kill
182
- * (`process.kill(-pid, signal)`) targets the *local* `docker` CLI process's
183
- * group -- exactly right for bwrap, which execs the sandboxed process
184
- * directly and never creates a second process group. Docker is different:
185
- * the container runs under `dockerd`, not as a child of the local `docker`
186
- * CLI, so killing the CLI's process group does not reliably stop the
187
- * container -- observed directly (a `kill()` call left a real orphaned
188
- * `node:22-slim` container running after both the CLI process and its
189
- * grace period were gone). `containerName` lets the caller
190
- * (`process-manager.ts`) issue a real, explicit `docker stop <name>`
191
- * against the container itself as the actual mechanism, not the CLI
192
- * process, for the container backend.
106
+ * **Returns a real, unique `containerName` whenever it wraps.** Found via real
107
+ * escape testing: `process-manager.ts`'s group-kill targets the local `docker` CLI
108
+ * process's group, which is right for bwrap but not Docker -- the container runs
109
+ * under `dockerd`, not as the CLI's child, so killing the CLI's group left an
110
+ * orphaned `node:22-slim` container running in testing. `containerName` lets the
111
+ * caller issue an explicit `docker stop <name>` against the container itself.
193
112
  */
194
113
  export function applyContainerSandbox(options) {
195
114
  const { filesystemPolicy, networkPolicy } = options;
@@ -1 +1 @@
1
- {"version":3,"file":"container-sandbox.js","sourceRoot":"","sources":["../src/container-sandbox.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"container-sandbox.js","sourceRoot":"","sources":["../src/container-sandbox.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAGrC,2OAA2O;AAC3O,MAAM,UAAU,0BAA0B,CAAC,MAAyB,OAAO,CAAC,GAAG;IAC7E,IAAI,CAAC;QACH,YAAY,CAAC,QAAQ,EAAE,CAAC,SAAS,EAAE,UAAU,EAAE,qBAAqB,CAAC,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;IACnG,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;YACL,YAAY,EAAE,aAAa;YAC3B,MAAM,EAAE,wIAAwI;SACjJ,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;AACrD,CAAC;AAED,+EAA+E;AAC/E,+EAA+E;AAC/E,oCAAoC;AACpC,MAAM,UAAU,sCAAsC,CAAC,MAAyB,OAAO,CAAC,GAAG;IACzF,OAAO,0BAA0B,CAAC,GAAG,CAAC,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,mCAAmC,CAAC,MAAyB,OAAO,CAAC,GAAG;IACtF,OAAO,0BAA0B,CAAC,GAAG,CAAC,CAAC;AACzC,CAAC;AAED,+NAA+N;AAC/N,MAAM,UAAU,uCAAuC,CAAC,MAAqB;IAC3E,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACtE,OAAO,CACL,sHAAsH;QACtH,+GAA+G;QAC/G,qFAAqF,CACtF,CAAC;AACJ,CAAC;AAED,kFAAkF;AAClF,gFAAgF;AAChF,mFAAmF;AACnF,MAAM,oBAAoB,GAAqC;IAC7D,IAAI,EAAE,cAAc;IACpB,MAAM,EAAE,kBAAkB;IAC1B,OAAO,EAAE,kBAAkB;IAC3B,IAAI,EAAE,wBAAwB;CAC/B,CAAC;AAEF,MAAM,UAAU,qBAAqB,CAAC,kBAA0B;IAC9D,OAAO,oBAAoB,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC,IAAI,IAAI,CAAC;AACpE,CAAC;AA0BD;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,qBAAqB,CACnC,OAAgC;IAEhC,MAAM,EAAE,gBAAgB,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC;IACpD,IAAI,gBAAgB,KAAK,SAAS,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;QAClE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC;IAC1D,CAAC;IAED,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IAEvC,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;QAChC,MAAM,WAAW,GAAG,uCAAuC,CAAC,aAAa,CAAC,CAAC;QAC3E,IAAI,WAAW,KAAK,IAAI,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,wDAAwD,WAAW,EAAE,CAAC,CAAC;QACzF,CAAC;IACH,CAAC;IAED,MAAM,UAAU,GAAG,0BAA0B,CAAC,GAAG,CAAC,CAAC;IACnD,IAAI,UAAU,CAAC,YAAY,KAAK,WAAW,EAAE,CAAC;QAC5C,MAAM,IAAI,KAAK,CAAC,2DAA2D,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;IAClG,CAAC;IAED,MAAM,KAAK,GAAG,OAAO,CAAC,cAAc,IAAI,qBAAqB,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC1F,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CACb,+EAA+E,OAAO,CAAC,kBAAkB,qCAAqC,CAC/I,CAAC;IACJ,CAAC;IAED,MAAM,aAAa,GAAG,kBAAkB,UAAU,EAAE,EAAE,CAAC;IACvD,MAAM,UAAU,GAAa,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAC;IAEtE,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;QAChC,UAAU,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;IACvC,CAAC;IAED,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;IAE1E,IAAI,gBAAgB,KAAK,SAAS,EAAE,CAAC;QACnC,KAAK,MAAM,IAAI,IAAI,gBAAgB,CAAC,YAAY,EAAE,CAAC;YACjD,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,IAAI,IAAI,EAAE,CAAC,CAAC;QAC3C,CAAC;IACH,CAAC;IAED,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,UAAU,IAAI,EAAE,CAAC,EAAE,CAAC;QACpE,IAAI,GAAG,KAAK,MAAM,IAAI,KAAK,KAAK,SAAS;YAAE,SAAS;QACpD,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,GAAG,IAAI,KAAK,EAAE,CAAC,CAAC;IAC3C,CAAC;IAED,UAAU,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEzD,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,aAAa,EAAE,CAAC;AAChE,CAAC"}
@@ -1,11 +1,8 @@
1
1
  /**
2
- * Runtime controller (plan §4, §5, §6; plan §45's "Core" bucket: runtime
3
- * controller, execution IDs, process lifecycle, readiness, timeout
4
- * handling, cleanup, configuration). Owns Execution lifecycle, spawns every
5
- * service declared in configuration, waits for each one's real readiness
6
- * (never "process exists"), and guarantees cleanup — including on partial
7
- * or total failure and on timeout. Builds no collectors and knows nothing
8
- * about any specific language or framework (plan principle 8).
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).
9
6
  */
10
7
  import { type Execution, type ProcessHandle } from "@descryy/runtime-contracts";
11
8
  import { type ReadinessCheck, type ReadinessResult } from "./readiness.ts";
@@ -23,17 +20,13 @@ export interface ServiceReadinessSpec {
23
20
  readonly timeoutMs: number;
24
21
  }
25
22
  export interface RunOptions {
26
- /** One entry required per key in `configuration.services` — RT-032 refuses rather than default a missing one to "spawn success is enough" (RT-024's own rule, applied per service). */
23
+ /** One entry required per key in `configuration.services` -- refuses rather than defaulting a missing one to "spawn success is enough" (RT-024/RT-032). */
27
24
  readonly readiness: Readonly<Record<string, ServiceReadinessSpec>>;
28
25
  /**
29
- * Optional live observer for `ProcessLifecycleEvent`. Called synchronously
30
- * at each transition, in order, for the lifetime of this execution
31
- * (including after `run()` itself has returned, for a service that exits
32
- * later). A throwing observer is not caught here — the same "must not
33
- * hang, may not silently swallow its own failure" discipline `Collector`
34
- * already imposes on every callback shape in this repo; a caller wiring a
35
- * `ProcessCollector`'s emit path in here that itself throws deserves to
36
- * see that, not have it disappear into a promise this module owns.
26
+ * Optional live observer for `ProcessLifecycleEvent`, called synchronously at each
27
+ * transition for the lifetime of this execution (including after `run()` returns).
28
+ * A throwing observer is not caught here -- same "must not hang, may not silently
29
+ * swallow its own failure" discipline `Collector` imposes on every callback here.
37
30
  */
38
31
  readonly onProcessLifecycleEvent?: (event: ProcessLifecycleEvent) => void;
39
32
  }
@@ -41,31 +34,20 @@ export interface ServiceStartResult {
41
34
  readonly serviceName: string;
42
35
  readonly stage: "spawn" | "readiness" | "not-attempted";
43
36
  readonly succeeded: boolean;
44
- /** Set when `stage === "readiness"`. RT-024/RT-031 apply to each entry independently — N of these is N liveness claims about N addresses, never a joint identity proof. */
37
+ /** Set when `stage === "readiness"`. RT-024/RT-031 apply per entry -- N of these is N liveness claims, never a joint identity proof. */
45
38
  readonly readiness: ReadinessResult | null;
46
39
  /** Set when `stage === "spawn"` and spawning itself threw. */
47
40
  readonly error: string | null;
48
41
  }
49
42
  /**
50
- * Fires at the exact moments `run()` itself observes a service's process
51
- * lifecycle — spawned, readiness settled (either way), reaped. This is a
52
- * pure notification channel: `ExecutionController` stays exactly as
53
- * ignorant of Evidence/Collector as its own module doc already claims
54
- * ("knows nothing about any specific language or framework") — nothing
55
- * here decides whether a lifecycle transition becomes Evidence, only that
56
- * a caller who wants to know *when* one happened, live, has a way to ask
57
- * that isn't "reconstruct it later from `Execution.processes`."
43
+ * Fires at the exact moments `run()` observes a service's lifecycle -- spawned,
44
+ * readiness settled either way, reaped. A pure notification channel; nothing here
45
+ * decides whether a transition becomes Evidence.
58
46
  *
59
- * That reconstruction is precisely what doesn't work for the case this
60
- * exists to make observable: `Execution.processes` and
61
- * `ServiceStartResults` are only complete once `run()` has already
62
- * returned, but a service that is spawned, then *running* (READY reached),
63
- * has not exited yet at that point — its own eventual `process-exited`
64
- * event lies in the future relative to `run()` resolving. A consumer that
65
- * only reads the final `Execution` after `run()` settles can see "started"
66
- * and "ready" (or "ready-failed") for every service, but can never see
67
- * "exited" for one still healthy when `run()` returned — only this live
68
- * channel can.
47
+ * Needed because `Execution.processes`/`ServiceStartResults` are only complete once
48
+ * `run()` returns, but a service still running when `run()` resolves hasn't exited
49
+ * yet -- its eventual `process-exited` lies in the future. Only this live channel
50
+ * can observe that exit; reading the final `Execution` later cannot.
69
51
  */
70
52
  export type ProcessLifecycleEvent = {
71
53
  readonly kind: "process-started";
@@ -83,19 +65,11 @@ export type ProcessLifecycleEvent = {
83
65
  readonly readiness: ReadinessResult;
84
66
  }
85
67
  /**
86
- * `phase` distinguishes "this service's own readiness had not yet
87
- * succeeded when it exited" (`"starting"`) from "it had already reached
88
- * READY at least once" (`"running"`) — the process-level echo of
89
- * `FAILED_START` vs `FAILED` on `ExecutionState` itself (§30). Without
90
- * it, `PROCESS_EXITED` alone cannot tell "crashed on boot" from
91
- * "finished/was stopped after running successfully," which collapses
92
- * exactly the distinction the execution lifecycle already exists to
93
- * carry. Computed from THIS service's own readiness history, not from
94
- * `Execution.state` at the moment of exit — a crash mid-readiness-poll
95
- * fires before `run()` has itself observed the failure and moved the
96
- * execution to `FAILED_START`, so reading execution state at exit time
97
- * would misreport `"starting"` as whatever the execution's not-yet-
98
- * updated state still says.
68
+ * `phase` distinguishes "readiness hadn't yet succeeded when it exited"
69
+ * (`"starting"`) from "had already reached READY" (`"running"`) -- the
70
+ * process-level echo of `FAILED_START` vs `FAILED` (§30). Computed from this
71
+ * service's own readiness history, not `Execution.state` at exit time -- a crash
72
+ * mid-readiness-poll fires before the execution's own state has caught up.
99
73
  */
100
74
  | {
101
75
  readonly kind: "process-exited";
@@ -103,82 +77,51 @@ export type ProcessLifecycleEvent = {
103
77
  readonly handle: ProcessHandle;
104
78
  readonly phase: "starting" | "running";
105
79
  };
106
- /**
107
- * `run()`'s timeout timer and a caller's `stop()`/`cancel()` can both
108
- * attempt to move a finishing execution to a terminal state at nearly the
109
- * same instant. Every transition attempted after an `await` goes through
110
- * `#tryTransition` (returns false instead of throwing) rather than the
111
- * throwing `#transition`, so whichever path loses the race degrades to a
112
- * no-op instead of an unhandled rejection from a fire-and-forget timer
113
- * callback.
114
- */
115
80
  export declare class ExecutionController {
116
81
  #private;
117
82
  private constructor();
118
83
  static create(input: CreateExecutionInput): ExecutionController;
119
84
  get execution(): Execution;
120
- /** One entry per service configured, in spawn order — including services never attempted because an earlier one failed (`stage: "not-attempted"`). Empty before `run()` returns its first result. */
85
+ /** One entry per configured service, in spawn order, including never-attempted ones (`stage: "not-attempted"`). Empty until `run()` returns its first result. */
121
86
  get serviceStartResults(): readonly ServiceStartResult[];
122
- /** Non-null only when `run()` refused before spawning anything — a bad `dependsOn` reference, a cycle, an undeclared placeholder dependency, or a service with no matching `RunOptions.readiness` entry. */
87
+ /** Non-null only when `run()` refused before spawning anything. */
123
88
  get validationError(): string | null;
124
89
  /** Combined stdout+stderr of the named service's process so far, or "" if it was never spawned. */
125
90
  readProcessOutput(serviceName: string): string;
126
91
  /**
127
- * Starts every service in `configuration.services`, in the dependency
128
- * order `validateServicesConfiguration` computes — spawned, each on its
129
- * own ephemeral port unless it opts into a fixed one, or attached to
130
- * (`service.attach`, `attachManagedProcess`) when it names an already-
131
- * running pid/log file instead of a `command`. Reaches RUNNING only if
132
- * every service starts and reaches its own readiness. On the first
133
- * failure (spawn/attach throw, or readiness never succeeding), every
134
- * already-started service is killed in reverse order (a no-op for an
135
- * attached one — see `attachManagedProcess`'s own doc) and every
136
- * not-yet-attempted service is recorded as such — a caller can always
137
- * tell "never tried" from "tried and failed" via `serviceStartResults`.
92
+ * Starts every service in dependency order, spawned (each on its own ephemeral
93
+ * port unless fixed) or attached (`service.attach`, for an already-running
94
+ * pid/log file). Reaches RUNNING only if every service starts and reaches
95
+ * readiness. On first failure, every started service is killed in reverse order
96
+ * (no-op for attached ones) and remaining services are recorded "not-attempted" --
97
+ * `serviceStartResults` always distinguishes "never tried" from "tried and failed".
138
98
  *
139
- * Configuration itself is validated first, atomically: a bad `dependsOn`
140
- * reference, a cycle, an undeclared placeholder dependency, a service
141
- * declaring neither or both of `command`/`attach`, or a missing
142
- * `RunOptions.readiness` entry refuses before anything is spawned, never
143
- * discovered mid-sequence with other services already running.
99
+ * Configuration is validated atomically first -- a bad `dependsOn`, a cycle, an
100
+ * undeclared placeholder, ambiguous `command`/`attach`, or a missing readiness
101
+ * entry refuses before anything spawns.
144
102
  *
145
- * Every **spawned** service receives `PORT` (its own resolved port,
146
- * ephemeral or fixed) in its environment unconditionally, on top of
147
- * `service.env` — a service has no other way to learn the port RT-024
148
- * chose for it. This is a real, load-bearing convention (matches
149
- * `broken-invoices`'s fixture apps), not an implementation detail: a
150
- * `ServiceConfiguration` whose command reads its listen port from
151
- * anywhere other than `PORT` will not be reachable through readiness
152
- * checks built from the same `port` this function resolves. An
153
- * **attached** service receives no env and no port allocation — it is
154
- * already running on whatever port it bound at its own launch, and
155
- * `service.port` (when the caller supplies it) is a declaration of that
156
- * fact, not a request this function can act on.
103
+ * Every **spawned** service gets `PORT` (its resolved port) unconditionally --
104
+ * load-bearing (matches the fixture apps), not incidental: a command reading its
105
+ * port from anywhere else won't be reachable via readiness checks built from the
106
+ * same `port`. An **attached** service gets no env/port allocation -- it's already
107
+ * running on whatever it bound at launch.
157
108
  */
158
109
  run(options: RunOptions): Promise<Execution>;
159
110
  stop(): Promise<Execution>;
160
111
  /**
161
- * Stop everything and record the run as `TIMED_OUT` — the same transition
162
- * `#onTimeout` makes, available to a caller that knows the budget expired
163
- * before this controller's own timer got round to saying so.
164
- *
165
- * **Why a caller needs this, and why `stop()` is wrong for the case.**
166
- * `ExecutionConfiguration.timeoutMs` is a whole-execution budget, and the
167
- * orchestrator clamps its observation window to whatever the budget has left.
168
- * That clamp made `TIMED_OUT` a race: the window ends at the deadline, the
169
- * timer fires a hair later, and whichever of `#onTimeout` and `stop()` gets
170
- * there first decides what the run *says* happened. Measured: the same case
171
- * reported `TIMED_OUT` at 1534ms and `COMPLETED` at 1515ms.
112
+ * Stop everything and record `TIMED_OUT` -- same transition `#onTimeout` makes,
113
+ * for a caller that knows the budget expired before the internal timer noticed.
172
114
  *
173
- * `execution.state` is what `descry-core`'s `observe_runtime` reads to choose
174
- * between `ok` and `timed_out`, so losing that race turns a disclosed
175
- * degradation into a silent one — a run that returns on time and says nothing
176
- * was cut short, which is worse than the overrun it replaced. A caller that
177
- * has already decided it truncated the run should not have to win a race to
178
- * report it.
115
+ * **Why not `stop()`:** the orchestrator clamps its observation window to
116
+ * whatever's left of `timeoutMs`, making `TIMED_OUT` a race between `#onTimeout`
117
+ * and `stop()` at the deadline -- measured: the same case reported `TIMED_OUT` at
118
+ * 1534ms and `COMPLETED` at 1515ms. `execution.state` is what `observe_runtime`
119
+ * reads to choose `ok` vs `timed_out`, so losing that race silently hides a real
120
+ * cutoff. A caller that already decided it truncated the run shouldn't have to
121
+ * win a race to report it.
179
122
  *
180
- * Idempotent and terminal-safe, exactly like `cancel()`: if the timer did fire
181
- * first, this returns the execution the timer already finished.
123
+ * Idempotent and terminal-safe like `cancel()`: if the timer fired first, returns
124
+ * the execution it already finished.
182
125
  */
183
126
  timeout(): Promise<Execution>;
184
127
  cancel(): Promise<Execution>;
@@ -1 +1 @@
1
- {"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../src/controller.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../src/controller.ts"],"names":[],"mappings":"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"}