@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.
- package/LICENSE +6 -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 +0 -10
- package/dist/index.d.ts.map +1 -1
- 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 +45 -80
- package/dist/process-manager.d.ts.map +1 -1
- package/dist/process-manager.js +51 -101
- 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 +7 -2
package/LICENSE
ADDED
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Capability registry (plan §16): assembles per-execution capabilities
|
|
3
|
-
* from the collectors actually present, so `distributedTrace: unavailable`
|
|
4
|
-
* is a first-class answer the AI planner can read rather than a silent
|
|
5
|
-
* gap. Does not know how to *produce* a `CollectorCapabilities` value —
|
|
6
|
-
* that's each collector's own `capabilities()` (Agents 2-4's concern) —
|
|
7
|
-
* only how to assemble and query what's been registered.
|
|
8
|
-
*/
|
|
9
1
|
import type { CapabilityStatus, CollectorCapabilities, EnvironmentTier, ExecutionCapabilities, FidelityLevel } from "@descryy/runtime-contracts";
|
|
10
2
|
export interface RegisteredCollectorCapabilities {
|
|
11
3
|
readonly collectorId: string;
|
|
@@ -13,12 +5,5 @@ export interface RegisteredCollectorCapabilities {
|
|
|
13
5
|
}
|
|
14
6
|
export declare function buildExecutionCapabilities(environmentTier: EnvironmentTier, fidelityLevel: FidelityLevel, collectors: readonly RegisteredCollectorCapabilities[]): ExecutionCapabilities;
|
|
15
7
|
export type CollectorCapabilityKey = keyof CollectorCapabilities;
|
|
16
|
-
/**
|
|
17
|
-
* The best (most available) status for one capability across every
|
|
18
|
-
* registered collector — "is this observable *anywhere* in this
|
|
19
|
-
* execution," not per-collector. An execution with two network collectors
|
|
20
|
-
* where one degraded and one is fully available should read as available,
|
|
21
|
-
* not degraded.
|
|
22
|
-
*/
|
|
23
8
|
export declare function bestCapabilityStatus(capabilities: ExecutionCapabilities, key: CollectorCapabilityKey): CapabilityStatus;
|
|
24
9
|
//# sourceMappingURL=capability-registry.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"capability-registry.d.ts","sourceRoot":"","sources":["../src/capability-registry.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"capability-registry.d.ts","sourceRoot":"","sources":["../src/capability-registry.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAEV,gBAAgB,EAChB,qBAAqB,EACrB,eAAe,EACf,qBAAqB,EACrB,aAAa,EACd,MAAM,4BAA4B,CAAC;AAEpC,MAAM,WAAW,+BAA+B;IAC9C,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,YAAY,EAAE,qBAAqB,CAAC;CAC9C;AAED,wBAAgB,0BAA0B,CACxC,eAAe,EAAE,eAAe,EAChC,aAAa,EAAE,aAAa,EAC5B,UAAU,EAAE,SAAS,+BAA+B,EAAE,GACrD,qBAAqB,CAEvB;AAED,MAAM,MAAM,sBAAsB,GAAG,MAAM,qBAAqB,CAAC;AAgBjE,wBAAgB,oBAAoB,CAClC,YAAY,EAAE,qBAAqB,EACnC,GAAG,EAAE,sBAAsB,GAC1B,gBAAgB,CAWlB"}
|
|
@@ -1,11 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
* gap. Does not know how to *produce* a `CollectorCapabilities` value —
|
|
6
|
-
* that's each collector's own `capabilities()` (Agents 2-4's concern) —
|
|
7
|
-
* only how to assemble and query what's been registered.
|
|
8
|
-
*/
|
|
1
|
+
// Capability registry (§16): assembles per-execution capabilities from the collectors
|
|
2
|
+
// actually present, so e.g. `distributedTrace: unavailable` is a first-class answer
|
|
3
|
+
// rather than a silent gap. Assembles and queries only — producing a
|
|
4
|
+
// `CollectorCapabilities` value is each collector's own `capabilities()`.
|
|
9
5
|
export function buildExecutionCapabilities(environmentTier, fidelityLevel, collectors) {
|
|
10
6
|
return { environmentTier, fidelityLevel, collectors };
|
|
11
7
|
}
|
|
@@ -18,18 +14,12 @@ const NO_COLLECTOR_STATUS = {
|
|
|
18
14
|
availability: "unavailable",
|
|
19
15
|
reason: "no collector registered for this execution",
|
|
20
16
|
};
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
* execution," not per-collector. An execution with two network collectors
|
|
25
|
-
* where one degraded and one is fully available should read as available,
|
|
26
|
-
* not degraded.
|
|
27
|
-
*/
|
|
17
|
+
// Best (most available) status for one capability across all registered collectors —
|
|
18
|
+
// "observable anywhere in this execution," not per-collector: two network collectors,
|
|
19
|
+
// one degraded one available, should read as available.
|
|
28
20
|
export function bestCapabilityStatus(capabilities, key) {
|
|
29
|
-
// Seeded from the first collector
|
|
30
|
-
//
|
|
31
|
-
// single collector's genuine "unavailable" tie the placeholder's rank
|
|
32
|
-
// and lose its specific reason to the generic one.
|
|
21
|
+
// Seeded from the first collector seen, not NO_COLLECTOR_STATUS — seeding from the
|
|
22
|
+
// placeholder would let a real "unavailable" tie the placeholder and lose its reason.
|
|
33
23
|
let best = null;
|
|
34
24
|
for (const collector of capabilities.collectors) {
|
|
35
25
|
const status = collector.capabilities[key];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"capability-registry.js","sourceRoot":"","sources":["../src/capability-registry.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"capability-registry.js","sourceRoot":"","sources":["../src/capability-registry.ts"],"names":[],"mappings":"AAAA,sFAAsF;AACtF,oFAAoF;AACpF,qEAAqE;AACrE,0EAA0E;AAgB1E,MAAM,UAAU,0BAA0B,CACxC,eAAgC,EAChC,aAA4B,EAC5B,UAAsD;IAEtD,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,UAAU,EAAE,CAAC;AACxD,CAAC;AAID,MAAM,iBAAiB,GAAqD;IAC1E,WAAW,EAAE,CAAC;IACd,QAAQ,EAAE,CAAC;IACX,SAAS,EAAE,CAAC;CACb,CAAC;AAEF,MAAM,mBAAmB,GAAqB;IAC5C,YAAY,EAAE,aAAa;IAC3B,MAAM,EAAE,4CAA4C;CACrD,CAAC;AAEF,qFAAqF;AACrF,sFAAsF;AACtF,wDAAwD;AACxD,MAAM,UAAU,oBAAoB,CAClC,YAAmC,EACnC,GAA2B;IAE3B,mFAAmF;IACnF,sFAAsF;IACtF,IAAI,IAAI,GAA4B,IAAI,CAAC;IACzC,KAAK,MAAM,SAAS,IAAI,YAAY,CAAC,UAAU,EAAE,CAAC;QAChD,MAAM,MAAM,GAAG,SAAS,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;QAC3C,IAAI,IAAI,KAAK,IAAI,IAAI,iBAAiB,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,iBAAiB,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC;YACnG,IAAI,GAAG,MAAM,CAAC;QAChB,CAAC;IACH,CAAC;IACD,OAAO,IAAI,IAAI,mBAAmB,CAAC;AACrC,CAAC"}
|
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `Evidence.collectorVersion`'s source for `ProcessCollector`: this
|
|
3
|
-
* package's own `package.json` "version", read from the artifact itself
|
|
4
|
-
* rather than hand-duplicated into a second string that can drift from
|
|
5
|
-
* what actually shipped. Same idea as `nodeVersion` elsewhere in this repo
|
|
6
|
-
* (`process.version`, always known, never probed) applied to a package
|
|
7
|
-
* instead of the Node runtime.
|
|
8
|
-
*/
|
|
1
|
+
/** `Evidence.collectorVersion` for `ProcessCollector`: read from package.json itself so it can't drift from what shipped. Same pattern as `nodeVersion` (`process.version`), applied to a package instead of the runtime. */
|
|
9
2
|
export declare const COLLECTOR_VERSION: string;
|
|
10
3
|
//# sourceMappingURL=collector-version.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collector-version.d.ts","sourceRoot":"","sources":["../src/collector-version.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"collector-version.d.ts","sourceRoot":"","sources":["../src/collector-version.ts"],"names":[],"mappings":"AAAA,6NAA6N;AAM7N,eAAO,MAAM,iBAAiB,EAAE,MAA6E,CAAC"}
|
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `Evidence.collectorVersion`'s source for `ProcessCollector`: this
|
|
3
|
-
* package's own `package.json` "version", read from the artifact itself
|
|
4
|
-
* rather than hand-duplicated into a second string that can drift from
|
|
5
|
-
* what actually shipped. Same idea as `nodeVersion` elsewhere in this repo
|
|
6
|
-
* (`process.version`, always known, never probed) applied to a package
|
|
7
|
-
* instead of the Node runtime.
|
|
8
|
-
*/
|
|
1
|
+
/** `Evidence.collectorVersion` for `ProcessCollector`: read from package.json itself so it can't drift from what shipped. Same pattern as `nodeVersion` (`process.version`), applied to a package instead of the runtime. */
|
|
9
2
|
import { createRequire } from "node:module";
|
|
10
3
|
const require = createRequire(import.meta.url);
|
|
11
4
|
export const COLLECTOR_VERSION = require("../package.json").version;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collector-version.js","sourceRoot":"","sources":["../src/collector-version.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"collector-version.js","sourceRoot":"","sources":["../src/collector-version.ts"],"names":[],"mappings":"AAAA,6NAA6N;AAE7N,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAE/C,MAAM,CAAC,MAAM,iBAAiB,GAAY,OAAO,CAAC,iBAAiB,CAAkC,CAAC,OAAO,CAAC"}
|
|
@@ -1,184 +1,100 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* §21's execution boundary, container backend -- the macOS/Windows half of
|
|
3
|
-
*
|
|
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
|
-
* **
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
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
|
-
* **
|
|
26
|
-
*
|
|
27
|
-
*
|
|
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
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
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
|
-
* **
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
* path
|
|
45
|
-
*
|
|
46
|
-
*
|
|
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
|
-
* **
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
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
|
-
* **
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
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
|
-
* **
|
|
84
|
-
*
|
|
85
|
-
* `
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
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 type { CapabilityStatus, FilesystemPolicy, NetworkPolicy } from "@descryy/runtime-contracts";
|
|
99
|
-
/**
|
|
100
|
-
* Real capability check: is a working Docker CLI + reachable daemon
|
|
101
|
-
* actually present, not merely "does a `docker` binary exist on PATH."
|
|
102
|
-
* `docker version` talks to the daemon; a CLI with no running daemon behind
|
|
103
|
-
* it (Docker Desktop not started, dockerd not running) fails this the same
|
|
104
|
-
* way a missing binary does -- both are "cannot enforce," and the caller
|
|
105
|
-
* does not need to tell them apart to make the right decision (refuse).
|
|
106
|
-
*/
|
|
53
|
+
/** 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." */
|
|
107
54
|
export declare function containerRuntimeCapability(env?: NodeJS.ProcessEnv): CapabilityStatus;
|
|
108
|
-
/**
|
|
109
|
-
* Mirrors `sandbox.ts`'s `filesystemIsolationCapability`/
|
|
110
|
-
* `networkIsolationCapability` split: one real mechanism underneath
|
|
111
|
-
* (a container boundary), two named capabilities because the two policies
|
|
112
|
-
* are declared, refused, and reasoned about independently at the call
|
|
113
|
-
* site.
|
|
114
|
-
*/
|
|
115
55
|
export declare function containerFilesystemIsolationCapability(env?: NodeJS.ProcessEnv): CapabilityStatus;
|
|
116
56
|
export declare function containerNetworkIsolationCapability(env?: NodeJS.ProcessEnv): CapabilityStatus;
|
|
117
|
-
/**
|
|
118
|
-
* Same posture as `sandbox.ts`'s `unsupportedNetworkPolicyReason`, matched
|
|
119
|
-
* deliberately rather than reinvented: only full denial
|
|
120
|
-
* (`{ mode: "allow", hosts: [] }`, `docker run --network none`) is
|
|
121
|
-
* enforced. A shape bwrap already discloses as unsupported is not silently
|
|
122
|
-
* claimed as supported here just because the underlying mechanism changed.
|
|
123
|
-
*/
|
|
57
|
+
/** 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. */
|
|
124
58
|
export declare function unsupportedContainerNetworkPolicyReason(policy: NetworkPolicy): string | null;
|
|
125
59
|
export declare function resolveContainerImage(interpreterCommand: string): string | null;
|
|
126
60
|
export interface ContainerSandboxOptions {
|
|
127
|
-
/**
|
|
61
|
+
/** Resolves a default base image via `resolveContainerImage` when `containerImage` is not given. */
|
|
128
62
|
readonly interpreterCommand: string;
|
|
129
|
-
/**
|
|
63
|
+
/** Command to exec inside the container -- resolved against the image's own PATH, not the host's. */
|
|
130
64
|
readonly command: string;
|
|
131
65
|
readonly args: readonly string[];
|
|
132
|
-
/**
|
|
66
|
+
/** Always bind-mounted at the identical path (`-v cwd:cwd`) -- mirrors sandbox.ts's "cwd always bound" default. */
|
|
133
67
|
readonly cwd: string;
|
|
134
68
|
readonly filesystemPolicy?: FilesystemPolicy;
|
|
135
69
|
readonly networkPolicy?: NetworkPolicy;
|
|
136
70
|
/**
|
|
137
|
-
* Env vars the
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
*
|
|
142
|
-
* interpreter happens to live), and forwarding the host's `PATH` would
|
|
143
|
-
* silently break that resolution or -- if it named a path that happens to
|
|
144
|
-
* exist for a different binary inside the image -- run the wrong thing.
|
|
145
|
-
* Every other variable is forwarded unfiltered, matching the same
|
|
146
|
-
* unfiltered-inheritance precedent `process-manager.ts` already
|
|
147
|
-
* established for the bwrap path (bwrap does not `--clearenv` either).
|
|
71
|
+
* Env vars the containerized process needs, forwarded via `-e KEY=VALUE`. `PATH` is
|
|
72
|
+
* never forwarded: the container must resolve `command` against its own image
|
|
73
|
+
* layout (`/usr/local/bin/node`, not the host's), and the host's PATH would break
|
|
74
|
+
* that or run the wrong binary. Everything else forwards unfiltered, matching
|
|
75
|
+
* bwrap's own unfiltered-inheritance precedent (no `--clearenv`).
|
|
148
76
|
*/
|
|
149
77
|
readonly processEnv?: Readonly<Record<string, string | undefined>>;
|
|
150
|
-
/** Env
|
|
78
|
+
/** Env for running the `docker` CLI itself (PATH, `DOCKER_HOST`). Defaults to `process.env`. */
|
|
151
79
|
readonly env?: NodeJS.ProcessEnv;
|
|
152
|
-
/** Explicit override
|
|
80
|
+
/** Explicit override, bypasses `resolveContainerImage`'s name-based guess. */
|
|
153
81
|
readonly containerImage?: string;
|
|
154
82
|
}
|
|
155
83
|
/**
|
|
156
|
-
* Wraps `command`/`args` with `docker run` so a
|
|
157
|
-
*
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
* bwrap, applied here too: a caller who never opts into a policy is
|
|
161
|
-
* completely unaffected by this module's existence.
|
|
84
|
+
* Wraps `command`/`args` with `docker run` so a container boundary enforces
|
|
85
|
+
* `filesystemPolicy`/`networkPolicy`. Neither declared returns them unchanged and
|
|
86
|
+
* never invokes docker -- same non-regression contract as `sandbox.ts`'s
|
|
87
|
+
* `applySandbox`.
|
|
162
88
|
*
|
|
163
|
-
* **Throws rather than silently spawning unconstrained** when a policy
|
|
164
|
-
*
|
|
165
|
-
* `networkPolicy` shape this mechanism doesn't implement -- matching
|
|
166
|
-
* `applySandbox`'s own refuse-rather-than-guess precedent exactly.
|
|
89
|
+
* **Throws rather than silently spawning unconstrained** when a policy can't
|
|
90
|
+
* actually be backed (no working Docker, unimplemented `networkPolicy` shape).
|
|
167
91
|
*
|
|
168
|
-
* **Returns a real, unique `containerName` whenever it wraps.**
|
|
169
|
-
*
|
|
170
|
-
* not
|
|
171
|
-
*
|
|
172
|
-
*
|
|
173
|
-
*
|
|
174
|
-
* the container runs under `dockerd`, not as a child of the local `docker`
|
|
175
|
-
* CLI, so killing the CLI's process group does not reliably stop the
|
|
176
|
-
* container -- observed directly (a `kill()` call left a real orphaned
|
|
177
|
-
* `node:22-slim` container running after both the CLI process and its
|
|
178
|
-
* grace period were gone). `containerName` lets the caller
|
|
179
|
-
* (`process-manager.ts`) issue a real, explicit `docker stop <name>`
|
|
180
|
-
* against the container itself as the actual mechanism, not the CLI
|
|
181
|
-
* process, for the container backend.
|
|
92
|
+
* **Returns a real, unique `containerName` whenever it wraps.** Found via real
|
|
93
|
+
* escape testing: `process-manager.ts`'s group-kill targets the local `docker` CLI
|
|
94
|
+
* process's group, which is right for bwrap but not Docker -- the container runs
|
|
95
|
+
* under `dockerd`, not as the CLI's child, so killing the CLI's group left an
|
|
96
|
+
* orphaned `node:22-slim` container running in testing. `containerName` lets the
|
|
97
|
+
* caller issue an explicit `docker stop <name>` against the container itself.
|
|
182
98
|
*/
|
|
183
99
|
export declare function applyContainerSandbox(options: ContainerSandboxOptions): {
|
|
184
100
|
readonly command: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"container-sandbox.d.ts","sourceRoot":"","sources":["../src/container-sandbox.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"container-sandbox.d.ts","sourceRoot":"","sources":["../src/container-sandbox.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AAKH,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAEpG,2OAA2O;AAC3O,wBAAgB,0BAA0B,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,gBAAgB,CAUjG;AAKD,wBAAgB,sCAAsC,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,gBAAgB,CAE7G;AAED,wBAAgB,mCAAmC,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,gBAAgB,CAE1G;AAED,+NAA+N;AAC/N,wBAAgB,uCAAuC,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,GAAG,IAAI,CAO5F;AAYD,wBAAgB,qBAAqB,CAAC,kBAAkB,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAE/E;AAED,MAAM,WAAW,uBAAuB;IACtC,oGAAoG;IACpG,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,qGAAqG;IACrG,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,mHAAmH;IACnH,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IAC7C,QAAQ,CAAC,aAAa,CAAC,EAAE,aAAa,CAAC;IACvC;;;;;;OAMG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;IACnE,gGAAgG;IAChG,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACjC,8EAA8E;IAC9E,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;CAClC;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,uBAAuB,GAC/B;IAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,CAkDjG"}
|