@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,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `DEC-NEXT-fault-layer-empirical-confirmation.md`'s `dependency` mechanism: declared
|
|
3
|
+
* (lockfile) vs resolved (installed) version — a structural fact, recorded not inferred.
|
|
4
|
+
*
|
|
5
|
+
* - Node-only, checked not assumed: no existing lockfile reader for any language to
|
|
6
|
+
* match. A Python/Ruby target is a real, disclosed gap — an additive second reader,
|
|
7
|
+
* not a rewrite.
|
|
8
|
+
* - Only `lockfileVersion` 2/3's flat `packages` map (keyed by `node_modules/<name>`,
|
|
9
|
+
* confirmed against `fixture-apps/broken-invoices-backend`). v1's `dependencies`
|
|
10
|
+
* shape is not read — `applicable: false`, disclosed gap.
|
|
11
|
+
* - "Resolved" is a direct read from the lockfile key's path, not Node module
|
|
12
|
+
* resolution — the key already encodes install location, including nested
|
|
13
|
+
* transitives (`node_modules/a/node_modules/b`).
|
|
14
|
+
* - Direct dependencies only (`dependencies`/`devDependencies`), not every transitive
|
|
15
|
+
* lockfile entry — matches the ruling's "cheap, always available" bar.
|
|
16
|
+
*/
|
|
17
|
+
export interface DependencyVersionMismatch {
|
|
18
|
+
readonly name: string;
|
|
19
|
+
/** The version `package-lock.json` pins this package to. */
|
|
20
|
+
readonly declaredVersion: string;
|
|
21
|
+
/** The version actually found in `node_modules/<name>/package.json` on disk. */
|
|
22
|
+
readonly resolvedVersion: string;
|
|
23
|
+
}
|
|
24
|
+
export interface DependencyVersionCheckResult {
|
|
25
|
+
/** `false` when not identifiable as a checkable Node target (no package.json/lockfile, unsupported shape, malformed JSON) — "not applicable", not a guessed clean result. `mismatches` is `[]` when `false`. */
|
|
26
|
+
readonly applicable: boolean;
|
|
27
|
+
readonly mismatches: readonly DependencyVersionMismatch[];
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Compares lockfile-declared vs installed version for every direct dependency of the
|
|
31
|
+
* Node project rooted at `cwd`. A dependency missing from the lockfile (workspace/
|
|
32
|
+
* local-link) or from `node_modules` (never installed) is skipped, not reported —
|
|
33
|
+
* different facts from a mismatch, not guessed as one.
|
|
34
|
+
*/
|
|
35
|
+
export declare function checkDependencyVersions(cwd: string): DependencyVersionCheckResult;
|
|
36
|
+
//# sourceMappingURL=dependency-version-check.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dependency-version-check.d.ts","sourceRoot":"","sources":["../src/dependency-version-check.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,4DAA4D;IAC5D,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,gFAAgF;IAChF,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;CAClC;AAED,MAAM,WAAW,4BAA4B;IAC3C,gNAAgN;IAChN,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,SAAS,yBAAyB,EAAE,CAAC;CAC3D;AAuBD;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,4BAA4B,CA4CjF"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `DEC-NEXT-fault-layer-empirical-confirmation.md`'s `dependency` mechanism: declared
|
|
3
|
+
* (lockfile) vs resolved (installed) version — a structural fact, recorded not inferred.
|
|
4
|
+
*
|
|
5
|
+
* - Node-only, checked not assumed: no existing lockfile reader for any language to
|
|
6
|
+
* match. A Python/Ruby target is a real, disclosed gap — an additive second reader,
|
|
7
|
+
* not a rewrite.
|
|
8
|
+
* - Only `lockfileVersion` 2/3's flat `packages` map (keyed by `node_modules/<name>`,
|
|
9
|
+
* confirmed against `fixture-apps/broken-invoices-backend`). v1's `dependencies`
|
|
10
|
+
* shape is not read — `applicable: false`, disclosed gap.
|
|
11
|
+
* - "Resolved" is a direct read from the lockfile key's path, not Node module
|
|
12
|
+
* resolution — the key already encodes install location, including nested
|
|
13
|
+
* transitives (`node_modules/a/node_modules/b`).
|
|
14
|
+
* - Direct dependencies only (`dependencies`/`devDependencies`), not every transitive
|
|
15
|
+
* lockfile entry — matches the ruling's "cheap, always available" bar.
|
|
16
|
+
*/
|
|
17
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
18
|
+
import { join } from "node:path";
|
|
19
|
+
function readJsonFile(path) {
|
|
20
|
+
try {
|
|
21
|
+
return JSON.parse(readFileSync(path, "utf8"));
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Compares lockfile-declared vs installed version for every direct dependency of the
|
|
29
|
+
* Node project rooted at `cwd`. A dependency missing from the lockfile (workspace/
|
|
30
|
+
* local-link) or from `node_modules` (never installed) is skipped, not reported —
|
|
31
|
+
* different facts from a mismatch, not guessed as one.
|
|
32
|
+
*/
|
|
33
|
+
export function checkDependencyVersions(cwd) {
|
|
34
|
+
const packageJsonPath = join(cwd, "package.json");
|
|
35
|
+
const lockfilePath = join(cwd, "package-lock.json");
|
|
36
|
+
if (!existsSync(packageJsonPath) || !existsSync(lockfilePath)) {
|
|
37
|
+
return { applicable: false, mismatches: [] };
|
|
38
|
+
}
|
|
39
|
+
const packageJson = readJsonFile(packageJsonPath);
|
|
40
|
+
const lockfile = readJsonFile(lockfilePath);
|
|
41
|
+
if (packageJson === null || lockfile === null) {
|
|
42
|
+
return { applicable: false, mismatches: [] };
|
|
43
|
+
}
|
|
44
|
+
const packages = lockfile.packages;
|
|
45
|
+
if (packages === undefined || typeof packages !== "object") {
|
|
46
|
+
// lockfileVersion 1, or an unrecognized shape -- see header.
|
|
47
|
+
return { applicable: false, mismatches: [] };
|
|
48
|
+
}
|
|
49
|
+
const declaredNames = new Set([
|
|
50
|
+
...Object.keys(packageJson.dependencies ?? {}),
|
|
51
|
+
...Object.keys(packageJson.devDependencies ?? {}),
|
|
52
|
+
]);
|
|
53
|
+
const mismatches = [];
|
|
54
|
+
for (const name of declaredNames) {
|
|
55
|
+
const lockEntry = packages[`node_modules/${name}`];
|
|
56
|
+
const declaredVersion = lockEntry?.version;
|
|
57
|
+
if (typeof declaredVersion !== "string")
|
|
58
|
+
continue;
|
|
59
|
+
const installedPackageJsonPath = join(cwd, "node_modules", name, "package.json");
|
|
60
|
+
if (!existsSync(installedPackageJsonPath))
|
|
61
|
+
continue;
|
|
62
|
+
const installedPackageJson = readJsonFile(installedPackageJsonPath);
|
|
63
|
+
const resolvedVersion = installedPackageJson?.version;
|
|
64
|
+
if (typeof resolvedVersion !== "string")
|
|
65
|
+
continue;
|
|
66
|
+
if (resolvedVersion !== declaredVersion) {
|
|
67
|
+
mismatches.push({ name, declaredVersion, resolvedVersion });
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return { applicable: true, mismatches };
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=dependency-version-check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dependency-version-check.js","sourceRoot":"","sources":["../src/dependency-version-check.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AA6BjC,SAAS,YAAY,CAAI,IAAY;IACnC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAM,CAAC;IACrD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CAAC,GAAW;IACjD,MAAM,eAAe,GAAG,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;IAClD,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,mBAAmB,CAAC,CAAC;IAEpD,IAAI,CAAC,UAAU,CAAC,eAAe,CAAC,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QAC9D,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;IAC/C,CAAC;IAED,MAAM,WAAW,GAAG,YAAY,CAAmB,eAAe,CAAC,CAAC;IACpE,MAAM,QAAQ,GAAG,YAAY,CAAmB,YAAY,CAAC,CAAC;IAC9D,IAAI,WAAW,KAAK,IAAI,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QAC9C,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;IAC/C,CAAC;IAED,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAC;IACnC,IAAI,QAAQ,KAAK,SAAS,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC3D,6DAA6D;QAC7D,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;IAC/C,CAAC;IAED,MAAM,aAAa,GAAG,IAAI,GAAG,CAAS;QACpC,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,YAAY,IAAI,EAAE,CAAC;QAC9C,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,eAAe,IAAI,EAAE,CAAC;KAClD,CAAC,CAAC;IAEH,MAAM,UAAU,GAAgC,EAAE,CAAC;IACnD,KAAK,MAAM,IAAI,IAAI,aAAa,EAAE,CAAC;QACjC,MAAM,SAAS,GAAG,QAAQ,CAAC,gBAAgB,IAAI,EAAE,CAAC,CAAC;QACnD,MAAM,eAAe,GAAG,SAAS,EAAE,OAAO,CAAC;QAC3C,IAAI,OAAO,eAAe,KAAK,QAAQ;YAAE,SAAS;QAElD,MAAM,wBAAwB,GAAG,IAAI,CAAC,GAAG,EAAE,cAAc,EAAE,IAAI,EAAE,cAAc,CAAC,CAAC;QACjF,IAAI,CAAC,UAAU,CAAC,wBAAwB,CAAC;YAAE,SAAS;QAEpD,MAAM,oBAAoB,GAAG,YAAY,CAAgC,wBAAwB,CAAC,CAAC;QACnG,MAAM,eAAe,GAAG,oBAAoB,EAAE,OAAO,CAAC;QACtD,IAAI,OAAO,eAAe,KAAK,QAAQ;YAAE,SAAS;QAElD,IAAI,eAAe,KAAK,eAAe,EAAE,CAAC;YACxC,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,eAAe,EAAE,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC;IAED,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;AAC1C,CAAC"}
|
package/dist/env.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default environment applied to every spawned process, on top of the caller's own.
|
|
3
|
+
*
|
|
4
|
+
* RUST_BACKTRACE=1 (§17): without it a Rust panic prints only a message, hiding the
|
|
5
|
+
* trace — a collector-absence-masquerading-as-success case, not a caller-remembers-it case.
|
|
6
|
+
*
|
|
7
|
+
* Never overrides a key the caller already set.
|
|
8
|
+
*/
|
|
9
|
+
export declare function withDefaultProcessEnv(env: Readonly<Record<string, string | undefined>>): Record<string, string | undefined>;
|
|
10
|
+
//# sourceMappingURL=env.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,GAChD,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAEpC"}
|
package/dist/env.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default environment applied to every spawned process, on top of the caller's own.
|
|
3
|
+
*
|
|
4
|
+
* RUST_BACKTRACE=1 (§17): without it a Rust panic prints only a message, hiding the
|
|
5
|
+
* trace — a collector-absence-masquerading-as-success case, not a caller-remembers-it case.
|
|
6
|
+
*
|
|
7
|
+
* Never overrides a key the caller already set.
|
|
8
|
+
*/
|
|
9
|
+
export function withDefaultProcessEnv(env) {
|
|
10
|
+
return { RUST_BACKTRACE: "1", ...env };
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=env.js.map
|
package/dist/env.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.js","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,UAAU,qBAAqB,CACnC,GAAiD;IAEjD,OAAO,EAAE,cAAc,EAAE,GAAG,EAAE,GAAG,GAAG,EAAE,CAAC;AACzC,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* §2/RT-193: `Execution.commit` alone can't reproduce a run — same commit, different
|
|
3
|
+
* Node/OS/toolchain can behave differently. Fills the gap from the real host: OS
|
|
4
|
+
* platform, this process's own `process.version`, and the version of every distinct
|
|
5
|
+
* executable `configuration.services` invokes.
|
|
6
|
+
*
|
|
7
|
+
* Toolchain probe mirrors `scripts/preflight.mjs`'s `interpreters()` (version flag,
|
|
8
|
+
* read stdout+stderr combined since some tools like `java -version` write to stderr
|
|
9
|
+
* only, keep first line) but isn't the same function: that one checks a fixed tool
|
|
10
|
+
* list against expected versions (a gate); this reports whatever `services[*].command`
|
|
11
|
+
* names, no expected version to compare against.
|
|
12
|
+
*/
|
|
13
|
+
import type { EnvironmentMetadata, ServiceConfiguration } from "@descryy/runtime-contracts";
|
|
14
|
+
export declare function captureEnvironmentMetadata(services: Readonly<Record<string, ServiceConfiguration>>): Promise<EnvironmentMetadata>;
|
|
15
|
+
//# sourceMappingURL=environment-metadata.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"environment-metadata.d.ts","sourceRoot":"","sources":["../src/environment-metadata.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,KAAK,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAM5F,wBAAsB,0BAA0B,CAC9C,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC,GACvD,OAAO,CAAC,mBAAmB,CAAC,CAmB9B"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* §2/RT-193: `Execution.commit` alone can't reproduce a run — same commit, different
|
|
3
|
+
* Node/OS/toolchain can behave differently. Fills the gap from the real host: OS
|
|
4
|
+
* platform, this process's own `process.version`, and the version of every distinct
|
|
5
|
+
* executable `configuration.services` invokes.
|
|
6
|
+
*
|
|
7
|
+
* Toolchain probe mirrors `scripts/preflight.mjs`'s `interpreters()` (version flag,
|
|
8
|
+
* read stdout+stderr combined since some tools like `java -version` write to stderr
|
|
9
|
+
* only, keep first line) but isn't the same function: that one checks a fixed tool
|
|
10
|
+
* list against expected versions (a gate); this reports whatever `services[*].command`
|
|
11
|
+
* names, no expected version to compare against.
|
|
12
|
+
*/
|
|
13
|
+
import { execFile } from "node:child_process";
|
|
14
|
+
import { platform } from "node:os";
|
|
15
|
+
import { tokenizeCommand } from "./orchestration.js";
|
|
16
|
+
/** Bounds a version probe so a hung command can't stall run() — same discipline as RT-030's readiness probes. */
|
|
17
|
+
const VERSION_PROBE_TIMEOUT_MS = 3000;
|
|
18
|
+
export async function captureEnvironmentMetadata(services) {
|
|
19
|
+
const commands = new Set();
|
|
20
|
+
for (const service of Object.values(services)) {
|
|
21
|
+
// Attach-mode services have no `command` -- nothing to probe.
|
|
22
|
+
if (service.command === undefined)
|
|
23
|
+
continue;
|
|
24
|
+
const tokenized = tokenizeCommand(service.command);
|
|
25
|
+
if (tokenized.ok)
|
|
26
|
+
commands.add(tokenized.command);
|
|
27
|
+
}
|
|
28
|
+
const toolchainVersions = {};
|
|
29
|
+
for (const command of commands) {
|
|
30
|
+
toolchainVersions[command] = await probeVersion(command);
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
platform: platform(),
|
|
34
|
+
nodeVersion: process.version,
|
|
35
|
+
toolchainVersions,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/** Tries `--version`, `-version`, `-v` in order (covers `java -version`, `mvn -v`, etc). Returns the first line of whichever exits 0, or `null` — an unprobeable command is a disclosed gap, never a thrown error. */
|
|
39
|
+
function probeVersion(command) {
|
|
40
|
+
return tryFlags(command, ["--version", "-version", "-v"]);
|
|
41
|
+
}
|
|
42
|
+
async function tryFlags(command, flags) {
|
|
43
|
+
for (const flag of flags) {
|
|
44
|
+
const output = await runVersionFlag(command, flag);
|
|
45
|
+
if (output !== null)
|
|
46
|
+
return output;
|
|
47
|
+
}
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
function runVersionFlag(command, flag) {
|
|
51
|
+
return new Promise((resolve) => {
|
|
52
|
+
execFile(command, [flag], { timeout: VERSION_PROBE_TIMEOUT_MS }, (error, stdout, stderr) => {
|
|
53
|
+
if (error !== null) {
|
|
54
|
+
resolve(null);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const combined = `${stdout}${stderr}`.trim();
|
|
58
|
+
const firstLine = combined.split("\n")[0];
|
|
59
|
+
resolve(firstLine === undefined || firstLine === "" ? null : firstLine);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=environment-metadata.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"environment-metadata.js","sourceRoot":"","sources":["../src/environment-metadata.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAErD,iHAAiH;AACjH,MAAM,wBAAwB,GAAG,IAAI,CAAC;AAEtC,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAC9C,QAAwD;IAExD,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;IACnC,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC9C,8DAA8D;QAC9D,IAAI,OAAO,CAAC,OAAO,KAAK,SAAS;YAAE,SAAS;QAC5C,MAAM,SAAS,GAAG,eAAe,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACnD,IAAI,SAAS,CAAC,EAAE;YAAE,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IACpD,CAAC;IAED,MAAM,iBAAiB,GAAkC,EAAE,CAAC;IAC5D,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,iBAAiB,CAAC,OAAO,CAAC,GAAG,MAAM,YAAY,CAAC,OAAO,CAAC,CAAC;IAC3D,CAAC;IAED,OAAO;QACL,QAAQ,EAAE,QAAQ,EAAE;QACpB,WAAW,EAAE,OAAO,CAAC,OAAO;QAC5B,iBAAiB;KAClB,CAAC;AACJ,CAAC;AAED,sNAAsN;AACtN,SAAS,YAAY,CAAC,OAAe;IACnC,OAAO,QAAQ,CAAC,OAAO,EAAE,CAAC,WAAW,EAAE,UAAU,EAAE,IAAI,CAAC,CAAC,CAAC;AAC5D,CAAC;AAED,KAAK,UAAU,QAAQ,CAAC,OAAe,EAAE,KAAwB;IAC/D,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QACnD,IAAI,MAAM,KAAK,IAAI;YAAE,OAAO,MAAM,CAAC;IACrC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,cAAc,CAAC,OAAe,EAAE,IAAY;IACnD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,QAAQ,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,EAAE,EAAE,OAAO,EAAE,wBAAwB,EAAE,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE;YACzF,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;gBACnB,OAAO,CAAC,IAAI,CAAC,CAAC;gBACd,OAAO;YACT,CAAC;YACD,MAAM,QAAQ,GAAG,GAAG,MAAM,GAAG,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC;YAC7C,MAAM,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;YAC1C,OAAO,CAAC,SAAS,KAAK,SAAS,IAAI,SAAS,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QAC1E,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `DEC-NEXT-fault-layer-empirical-confirmation.md`'s `environment` mechanism:
|
|
3
|
+
* declared/expected runner version vs observed, at execution. Same shape as
|
|
4
|
+
* `dependency-version-check.ts` -- cheap, always available, no rerun needed.
|
|
5
|
+
*
|
|
6
|
+
* - "Declared" reads `.nvmrc`/`package.json engines.node`, not a CI-workflow parser
|
|
7
|
+
* -- nothing here already parses CI YAML, and these are the load-bearing
|
|
8
|
+
* declarations `nvm`/`npm` themselves read. A future CI-file reader is a
|
|
9
|
+
* disclosed extension point: `declaredSource` is a closed union so a third source
|
|
10
|
+
* can be added without changing callers' shape.
|
|
11
|
+
* - `satisfiesDeclaredNodeVersion`'s grammar supports `^x.y.z`, `~x.y.z`,
|
|
12
|
+
* `>=`/`<=`/`>`/`<`, a bare version at any precision (x-range at that precision,
|
|
13
|
+
* matching `actions/setup-node`), and space-separated AND clauses. Does NOT
|
|
14
|
+
* support `||`, hyphen ranges, prerelease/build tags, or `x`/`*` wildcards --
|
|
15
|
+
* those parse to `null` ("cannot say"), never a guessed true/false.
|
|
16
|
+
*/
|
|
17
|
+
export declare const DECLARED_VERSION_SOURCES: readonly ["nvmrc", "package.json engines.node"];
|
|
18
|
+
export type DeclaredVersionSource = (typeof DECLARED_VERSION_SOURCES)[number];
|
|
19
|
+
export interface EnvironmentVersionCheckResult {
|
|
20
|
+
/** `false` when no declared version was found, or declared/observed didn't parse -- "not applicable," never a guessed clean result. `mismatch` is `false` when this is. */
|
|
21
|
+
readonly applicable: boolean;
|
|
22
|
+
readonly mismatch: boolean;
|
|
23
|
+
readonly declaredVersion: string | null;
|
|
24
|
+
readonly declaredSource: DeclaredVersionSource | null;
|
|
25
|
+
readonly observedVersion: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Reads the declared Node version for the project at `cwd`, compares against
|
|
29
|
+
* `observedVersion` (`process.version`/`EnvironmentMetadata.nodeVersion` -- never
|
|
30
|
+
* probed here).
|
|
31
|
+
*
|
|
32
|
+
* `.nvmrc` takes precedence over `engines.node` when both exist -- it names one
|
|
33
|
+
* exact version a developer runs locally, vs. a more often permissive compatibility
|
|
34
|
+
* range. Narrower/more specific wins, same precedence `classifyFaultLayer`
|
|
35
|
+
* (`descry-core`) applies between `dependency` and `environment`.
|
|
36
|
+
*/
|
|
37
|
+
export declare function checkEnvironmentVersion(cwd: string, observedVersion: string): EnvironmentVersionCheckResult;
|
|
38
|
+
/** Whether `observedVersion` satisfies `declaredRange` under the grammar above. `null` means the comparison couldn't be made -- distinct from `false`, a real "does not satisfy" answer. */
|
|
39
|
+
export declare function satisfiesDeclaredNodeVersion(declaredRange: string, observedVersion: string): boolean | null;
|
|
40
|
+
//# sourceMappingURL=environment-version-check.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"environment-version-check.d.ts","sourceRoot":"","sources":["../src/environment-version-check.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,eAAO,MAAM,wBAAwB,iDAAkD,CAAC;AACxF,MAAM,MAAM,qBAAqB,GAAG,CAAC,OAAO,wBAAwB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE9E,MAAM,WAAW,6BAA6B;IAC5C,2KAA2K;IAC3K,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IACxC,QAAQ,CAAC,cAAc,EAAE,qBAAqB,GAAG,IAAI,CAAC;IACtD,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;CAClC;AAMD;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,6BAA6B,CAgD3G;AAmGD,4LAA4L;AAC5L,wBAAgB,4BAA4B,CAAC,aAAa,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAU3G"}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `DEC-NEXT-fault-layer-empirical-confirmation.md`'s `environment` mechanism:
|
|
3
|
+
* declared/expected runner version vs observed, at execution. Same shape as
|
|
4
|
+
* `dependency-version-check.ts` -- cheap, always available, no rerun needed.
|
|
5
|
+
*
|
|
6
|
+
* - "Declared" reads `.nvmrc`/`package.json engines.node`, not a CI-workflow parser
|
|
7
|
+
* -- nothing here already parses CI YAML, and these are the load-bearing
|
|
8
|
+
* declarations `nvm`/`npm` themselves read. A future CI-file reader is a
|
|
9
|
+
* disclosed extension point: `declaredSource` is a closed union so a third source
|
|
10
|
+
* can be added without changing callers' shape.
|
|
11
|
+
* - `satisfiesDeclaredNodeVersion`'s grammar supports `^x.y.z`, `~x.y.z`,
|
|
12
|
+
* `>=`/`<=`/`>`/`<`, a bare version at any precision (x-range at that precision,
|
|
13
|
+
* matching `actions/setup-node`), and space-separated AND clauses. Does NOT
|
|
14
|
+
* support `||`, hyphen ranges, prerelease/build tags, or `x`/`*` wildcards --
|
|
15
|
+
* those parse to `null` ("cannot say"), never a guessed true/false.
|
|
16
|
+
*/
|
|
17
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
18
|
+
import { join } from "node:path";
|
|
19
|
+
export const DECLARED_VERSION_SOURCES = ["nvmrc", "package.json engines.node"];
|
|
20
|
+
/**
|
|
21
|
+
* Reads the declared Node version for the project at `cwd`, compares against
|
|
22
|
+
* `observedVersion` (`process.version`/`EnvironmentMetadata.nodeVersion` -- never
|
|
23
|
+
* probed here).
|
|
24
|
+
*
|
|
25
|
+
* `.nvmrc` takes precedence over `engines.node` when both exist -- it names one
|
|
26
|
+
* exact version a developer runs locally, vs. a more often permissive compatibility
|
|
27
|
+
* range. Narrower/more specific wins, same precedence `classifyFaultLayer`
|
|
28
|
+
* (`descry-core`) applies between `dependency` and `environment`.
|
|
29
|
+
*/
|
|
30
|
+
export function checkEnvironmentVersion(cwd, observedVersion) {
|
|
31
|
+
const notApplicable = {
|
|
32
|
+
applicable: false,
|
|
33
|
+
mismatch: false,
|
|
34
|
+
declaredVersion: null,
|
|
35
|
+
declaredSource: null,
|
|
36
|
+
observedVersion,
|
|
37
|
+
};
|
|
38
|
+
const nvmrcPath = join(cwd, ".nvmrc");
|
|
39
|
+
let declaredVersion = null;
|
|
40
|
+
let declaredSource = null;
|
|
41
|
+
if (existsSync(nvmrcPath)) {
|
|
42
|
+
const raw = readFileSync(nvmrcPath, "utf8").trim();
|
|
43
|
+
if (raw.length > 0) {
|
|
44
|
+
declaredVersion = raw;
|
|
45
|
+
declaredSource = "nvmrc";
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
const packageJsonPath = join(cwd, "package.json");
|
|
50
|
+
if (existsSync(packageJsonPath)) {
|
|
51
|
+
let parsed;
|
|
52
|
+
try {
|
|
53
|
+
parsed = JSON.parse(readFileSync(packageJsonPath, "utf8"));
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
parsed = null;
|
|
57
|
+
}
|
|
58
|
+
const node = parsed?.engines?.node;
|
|
59
|
+
if (typeof node === "string" && node.trim().length > 0) {
|
|
60
|
+
declaredVersion = node;
|
|
61
|
+
declaredSource = "package.json engines.node";
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (declaredVersion === null || declaredSource === null) {
|
|
66
|
+
return notApplicable;
|
|
67
|
+
}
|
|
68
|
+
const satisfies = satisfiesDeclaredNodeVersion(declaredVersion, observedVersion);
|
|
69
|
+
if (satisfies === null) {
|
|
70
|
+
// Grammar not covered (or observed string unparseable) -- "not applicable",
|
|
71
|
+
// not a comparison that was actually made.
|
|
72
|
+
return { applicable: false, mismatch: false, declaredVersion, declaredSource, observedVersion };
|
|
73
|
+
}
|
|
74
|
+
return { applicable: true, mismatch: !satisfies, declaredVersion, declaredSource, observedVersion };
|
|
75
|
+
}
|
|
76
|
+
const VERSION_PATTERN = /^v?(\d+)(?:\.(\d+))?(?:\.(\d+))?/;
|
|
77
|
+
function parseVersion(raw) {
|
|
78
|
+
const match = VERSION_PATTERN.exec(raw.trim());
|
|
79
|
+
if (match === null)
|
|
80
|
+
return null;
|
|
81
|
+
const major = Number(match[1]);
|
|
82
|
+
if (!Number.isFinite(major))
|
|
83
|
+
return null;
|
|
84
|
+
return {
|
|
85
|
+
major,
|
|
86
|
+
minor: match[2] !== undefined ? Number(match[2]) : 0,
|
|
87
|
+
minorSpecified: match[2] !== undefined,
|
|
88
|
+
patch: match[3] !== undefined ? Number(match[3]) : 0,
|
|
89
|
+
patchSpecified: match[3] !== undefined,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
/** Positive when `a` > `b`, negative when `a` < `b`, zero when equal -- major.minor.patch only. */
|
|
93
|
+
function compareVersions(a, b) {
|
|
94
|
+
if (a.major !== b.major)
|
|
95
|
+
return a.major - b.major;
|
|
96
|
+
if (a.minor !== b.minor)
|
|
97
|
+
return a.minor - b.minor;
|
|
98
|
+
return a.patch - b.patch;
|
|
99
|
+
}
|
|
100
|
+
const CARET_PATTERN = /^\^(\d+)(?:\.(\d+))?(?:\.(\d+))?$/;
|
|
101
|
+
const TILDE_PATTERN = /^~(\d+)(?:\.(\d+))?(?:\.(\d+))?$/;
|
|
102
|
+
const COMPARATOR_PATTERN = /^(>=|<=|>|<|=)?(\d+)(?:\.(\d+))?(?:\.(\d+))?$/;
|
|
103
|
+
/** `null` means the clause's grammar isn't covered -- propagated up, never coerced to a guessed true/false. */
|
|
104
|
+
function satisfiesClause(clause, observed) {
|
|
105
|
+
const trimmed = clause.trim();
|
|
106
|
+
if (trimmed.length === 0)
|
|
107
|
+
return null;
|
|
108
|
+
const caret = CARET_PATTERN.exec(trimmed);
|
|
109
|
+
if (caret !== null) {
|
|
110
|
+
const base = {
|
|
111
|
+
major: Number(caret[1]),
|
|
112
|
+
minor: caret[2] !== undefined ? Number(caret[2]) : 0,
|
|
113
|
+
minorSpecified: true,
|
|
114
|
+
patch: caret[3] !== undefined ? Number(caret[3]) : 0,
|
|
115
|
+
patchSpecified: true,
|
|
116
|
+
};
|
|
117
|
+
return compareVersions(observed, base) >= 0 && observed.major === base.major;
|
|
118
|
+
}
|
|
119
|
+
const tilde = TILDE_PATTERN.exec(trimmed);
|
|
120
|
+
if (tilde !== null) {
|
|
121
|
+
const base = {
|
|
122
|
+
major: Number(tilde[1]),
|
|
123
|
+
minor: tilde[2] !== undefined ? Number(tilde[2]) : 0,
|
|
124
|
+
minorSpecified: true,
|
|
125
|
+
patch: tilde[3] !== undefined ? Number(tilde[3]) : 0,
|
|
126
|
+
patchSpecified: true,
|
|
127
|
+
};
|
|
128
|
+
return compareVersions(observed, base) >= 0 && observed.major === base.major && observed.minor === base.minor;
|
|
129
|
+
}
|
|
130
|
+
const comparator = COMPARATOR_PATTERN.exec(trimmed);
|
|
131
|
+
if (comparator === null)
|
|
132
|
+
return null;
|
|
133
|
+
const op = comparator[1];
|
|
134
|
+
const base = {
|
|
135
|
+
major: Number(comparator[2]),
|
|
136
|
+
minor: comparator[3] !== undefined ? Number(comparator[3]) : 0,
|
|
137
|
+
minorSpecified: comparator[3] !== undefined,
|
|
138
|
+
patch: comparator[4] !== undefined ? Number(comparator[4]) : 0,
|
|
139
|
+
patchSpecified: comparator[4] !== undefined,
|
|
140
|
+
};
|
|
141
|
+
const cmp = compareVersions(observed, base);
|
|
142
|
+
switch (op) {
|
|
143
|
+
case ">=":
|
|
144
|
+
return cmp >= 0;
|
|
145
|
+
case "<=":
|
|
146
|
+
return cmp <= 0;
|
|
147
|
+
case ">":
|
|
148
|
+
return cmp > 0;
|
|
149
|
+
case "<":
|
|
150
|
+
return cmp < 0;
|
|
151
|
+
case "=":
|
|
152
|
+
case undefined:
|
|
153
|
+
// Bare version: an x-range at whatever precision was actually given.
|
|
154
|
+
if (!base.minorSpecified)
|
|
155
|
+
return observed.major === base.major;
|
|
156
|
+
if (!base.patchSpecified)
|
|
157
|
+
return observed.major === base.major && observed.minor === base.minor;
|
|
158
|
+
return cmp === 0;
|
|
159
|
+
default:
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/** Whether `observedVersion` satisfies `declaredRange` under the grammar above. `null` means the comparison couldn't be made -- distinct from `false`, a real "does not satisfy" answer. */
|
|
164
|
+
export function satisfiesDeclaredNodeVersion(declaredRange, observedVersion) {
|
|
165
|
+
const observed = parseVersion(observedVersion);
|
|
166
|
+
if (observed === null)
|
|
167
|
+
return null;
|
|
168
|
+
const clauses = declaredRange.split(/\s+/).filter((clause) => clause.length > 0);
|
|
169
|
+
if (clauses.length === 0)
|
|
170
|
+
return null;
|
|
171
|
+
const results = clauses.map((clause) => satisfiesClause(clause, observed));
|
|
172
|
+
if (results.some((result) => result === null))
|
|
173
|
+
return null;
|
|
174
|
+
return results.every((result) => result === true);
|
|
175
|
+
}
|
|
176
|
+
//# sourceMappingURL=environment-version-check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"environment-version-check.js","sourceRoot":"","sources":["../src/environment-version-check.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* §21/RT-070's execution boundary: resource limits and privilege reporting for a
|
|
3
|
+
* runtime declared trusted-local -- every spawned process runs with the invoking
|
|
4
|
+
* user's own OS privileges, no filesystem/network restriction. Names the boundary
|
|
5
|
+
* rather than leaving it absent (§38); real isolation (containers/namespaces) is a
|
|
6
|
+
* separate decision this module does not invent (§29).
|
|
7
|
+
*
|
|
8
|
+
* Enforces for real, via the OS: CPU time, virtual memory, process count, through
|
|
9
|
+
* `prlimit` -- an exec wrapper, never a shell (a shell would undo RT-036's
|
|
10
|
+
* `tokenizeCommand` refusal of shell metacharacters). `prlimit` is util-linux, absent
|
|
11
|
+
* on macOS, so it's reported as a capability, never assumed.
|
|
12
|
+
*/
|
|
13
|
+
import type { CapabilityStatus, ResourceLimits } from "@descryy/runtime-contracts";
|
|
14
|
+
/** Whether `prlimit` is reachable on PATH. `env` is a parameter (default `process.env`) so the "unavailable" branch is testable without mutating the real environment. */
|
|
15
|
+
export declare function resourceLimitCapability(env?: NodeJS.ProcessEnv): CapabilityStatus;
|
|
16
|
+
/**
|
|
17
|
+
* RT-193 originally made this always `unavailable`. Now delegates to
|
|
18
|
+
* `networkIsolationCapability()` (`./sandbox.ts`), real on Linux via a bwrap network
|
|
19
|
+
* namespace -- kept as the stable name every caller already imports (the seam
|
|
20
|
+
* RT-193 anticipated). Still unconditionally `unavailable` on macOS/Windows.
|
|
21
|
+
*/
|
|
22
|
+
export declare function networkPolicyCapability(env?: NodeJS.ProcessEnv): CapabilityStatus;
|
|
23
|
+
/**
|
|
24
|
+
* Wraps `command`/`args` so the OS enforces `limits`, via `prlimit`. `undefined` or
|
|
25
|
+
* empty `limits` returns them unchanged -- opt-in only.
|
|
26
|
+
*
|
|
27
|
+
* **Throws rather than silently spawning unconstrained** when a limit was requested
|
|
28
|
+
* and `prlimit` is unavailable (refuse-not-guess, per RT-036) -- the alternative is a
|
|
29
|
+
* caller asking for a memory cap and silently getting an unbounded process, the
|
|
30
|
+
* "sandbox that doesn't sandbox" shape §38 bans.
|
|
31
|
+
*/
|
|
32
|
+
export declare function applyResourceLimits(command: string, args: readonly string[], limits: ResourceLimits | undefined, env?: NodeJS.ProcessEnv): {
|
|
33
|
+
readonly command: string;
|
|
34
|
+
readonly args: readonly string[];
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* DEC-272: the sandbox boundary (RT-070) must be stated to the user directly, not
|
|
38
|
+
* left as a silent doc gap. Fixed, not derived from `runningAsRoot` -- the boundary
|
|
39
|
+
* is the same regardless of privilege level found.
|
|
40
|
+
*
|
|
41
|
+
* **Scope: this is the unconditional-unisolated text, not a universal one.** Accurate
|
|
42
|
+
* for every execution before `sandbox.ts` existed; no longer true once spawn-mode got
|
|
43
|
+
* real bwrap-backed isolation (`applySandbox`) -- using this unconditionally for an
|
|
44
|
+
* isolated process would understate its boundary, which is not the safe direction to
|
|
45
|
+
* be wrong in. `sandboxBoundaryDisclosureFor()` below is the mode-aware replacement;
|
|
46
|
+
* this constant remains its no-policy-applied return value and attach-mode's own
|
|
47
|
+
* disclosure (attach-mode never has anything more accurate to say).
|
|
48
|
+
*/
|
|
49
|
+
export declare const SANDBOX_BOUNDARY_DISCLOSURE: string;
|
|
50
|
+
/**
|
|
51
|
+
* Whether a real policy was actually enforced, not merely requested. `applySandbox`
|
|
52
|
+
* already throws rather than proceed unconstrained when a declared policy can't be
|
|
53
|
+
* enforced, so by the time a process is observed running, "declared" and "applied"
|
|
54
|
+
* are the same fact -- this type makes the caller state it explicitly.
|
|
55
|
+
*/
|
|
56
|
+
export interface AppliedIsolationPolicies {
|
|
57
|
+
readonly filesystemPolicyApplied: boolean;
|
|
58
|
+
readonly networkPolicyApplied: boolean;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Mode-aware replacement for reading `SANDBOX_BOUNDARY_DISCLOSURE` unconditionally.
|
|
62
|
+
* Defaults to no-policy-applied, so a no-arg call matches the old constant exactly.
|
|
63
|
+
*
|
|
64
|
+
* **Only ever true for spawn-mode.** Attach-mode has no path to produce
|
|
65
|
+
* `filesystemPolicyApplied`/`networkPolicyApplied: true` for a process it didn't
|
|
66
|
+
* spawn (structural, see `sandbox.ts`) -- attach-mode callers should never pass
|
|
67
|
+
* anything but the default.
|
|
68
|
+
*/
|
|
69
|
+
export declare function sandboxBoundaryDisclosureFor(policies?: AppliedIsolationPolicies): string;
|
|
70
|
+
/**
|
|
71
|
+
* Attach mode's contractual scope guarantee -- distinct from the sandbox-boundary
|
|
72
|
+
* disclosure above: this is what an attach-mode `Collector` is permitted to *do*, not
|
|
73
|
+
* what OS boundary wraps it. Mirrors `Collector` in `@descryy/runtime-contracts`.
|
|
74
|
+
* Stated once so every attach-mode caller surfaces the identical sentence.
|
|
75
|
+
*/
|
|
76
|
+
export declare const ATTACH_MODE_SCOPE_DISCLOSURE: string;
|
|
77
|
+
export interface PrivilegeReport {
|
|
78
|
+
/** Null when the platform has no uid concept (`process.getuid` undefined on Windows) -- distinct from `false`, a real answer. */
|
|
79
|
+
readonly runningAsRoot: boolean | null;
|
|
80
|
+
/** DEC-272: plain-language sandbox boundary statement, carried on this result rather than a new return path. Always populated, independent of `runningAsRoot`. */
|
|
81
|
+
readonly disclosure: string;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Reports, never enforces. §21's policy for trusted-local (RT-070) is not "refuse to
|
|
85
|
+
* run as root" -- CI containers commonly do, and a hard refusal would turn a
|
|
86
|
+
* documented boundary into an undocumented outage. The privilege level just becomes
|
|
87
|
+
* observable instead of invisible.
|
|
88
|
+
*
|
|
89
|
+
* A required parameter, not defaulted: `undefined` is the real value a no-uid-concept
|
|
90
|
+
* platform produces, and a default can't distinguish "explicitly undefined" from
|
|
91
|
+
* "omitted." `currentPrivilegeReport()` below is the convenience wrapper; this makes
|
|
92
|
+
* both branches testable without actually running as root or on Windows.
|
|
93
|
+
*/
|
|
94
|
+
export declare function privilegeReportFor(getuid: (() => number) | undefined): PrivilegeReport;
|
|
95
|
+
export declare function currentPrivilegeReport(): PrivilegeReport;
|
|
96
|
+
//# sourceMappingURL=execution-safety.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execution-safety.d.ts","sourceRoot":"","sources":["../src/execution-safety.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAGnF,0KAA0K;AAC1K,wBAAgB,uBAAuB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,gBAAgB,CAU9F;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,gBAAgB,CAE9F;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,MAAM,EAAE,cAAc,GAAG,SAAS,EAClC,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC;IAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAchE;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,2BAA2B,QAGT,CAAC;AAEhC;;;;;GAKG;AACH,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,uBAAuB,EAAE,OAAO,CAAC;IAC1C,QAAQ,CAAC,oBAAoB,EAAE,OAAO,CAAC;CACxC;AAID;;;;;;;;GAQG;AACH,wBAAgB,4BAA4B,CAAC,QAAQ,GAAE,wBAA8C,GAAG,MAAM,CAwB7G;AAED;;;;;GAKG;AACH,eAAO,MAAM,4BAA4B,QAKoC,CAAC;AAE9E,MAAM,WAAW,eAAe;IAC9B,iIAAiI;IACjI,QAAQ,CAAC,aAAa,EAAE,OAAO,GAAG,IAAI,CAAC;IACvC,kKAAkK;IAClK,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,CAAC,MAAM,MAAM,CAAC,GAAG,SAAS,GAAG,eAAe,CAGtF;AAED,wBAAgB,sBAAsB,IAAI,eAAe,CAExD"}
|