@descryy/runtime-controller 0.3.9 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/attach-discovery.d.ts +120 -0
- package/dist/attach-discovery.d.ts.map +1 -0
- package/dist/attach-discovery.js +409 -0
- package/dist/attach-discovery.js.map +1 -0
- package/dist/attach-fencing.d.ts +1 -0
- package/dist/attach-fencing.d.ts.map +1 -1
- package/dist/attach-fencing.js +44 -22
- package/dist/attach-fencing.js.map +1 -1
- package/dist/attach-log-file.d.ts +21 -0
- package/dist/attach-log-file.d.ts.map +1 -0
- package/dist/attach-log-file.js +81 -0
- package/dist/attach-log-file.js.map +1 -0
- package/dist/bounded-file.d.ts +11 -0
- package/dist/bounded-file.d.ts.map +1 -0
- package/dist/bounded-file.js +41 -0
- package/dist/bounded-file.js.map +1 -0
- package/dist/bounded-output.d.ts +24 -0
- package/dist/bounded-output.d.ts.map +1 -0
- package/dist/bounded-output.js +79 -0
- package/dist/bounded-output.js.map +1 -0
- package/dist/container-sandbox.d.ts +7 -20
- package/dist/container-sandbox.d.ts.map +1 -1
- package/dist/container-sandbox.js +139 -8
- package/dist/container-sandbox.js.map +1 -1
- package/dist/controller.d.ts +24 -2
- package/dist/controller.d.ts.map +1 -1
- package/dist/controller.js +260 -84
- package/dist/controller.js.map +1 -1
- package/dist/dependency-version-check.d.ts +1 -0
- package/dist/dependency-version-check.d.ts.map +1 -1
- package/dist/dependency-version-check.js +43 -24
- package/dist/dependency-version-check.js.map +1 -1
- package/dist/environment-metadata.d.ts +13 -0
- package/dist/environment-metadata.d.ts.map +1 -1
- package/dist/environment-metadata.js +138 -24
- package/dist/environment-metadata.js.map +1 -1
- package/dist/environment-version-check.d.ts +1 -0
- package/dist/environment-version-check.d.ts.map +1 -1
- package/dist/environment-version-check.js +13 -7
- package/dist/environment-version-check.js.map +1 -1
- package/dist/execution-safety.d.ts +2 -0
- package/dist/execution-safety.d.ts.map +1 -1
- package/dist/execution-safety.js +36 -0
- package/dist/execution-safety.js.map +1 -1
- package/dist/index.d.ts +16 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -3
- package/dist/index.js.map +1 -1
- package/dist/node-options.d.ts +3 -0
- package/dist/node-options.d.ts.map +1 -0
- package/dist/node-options.js +34 -0
- package/dist/node-options.js.map +1 -0
- package/dist/orphan-reaper-process.d.ts +2 -0
- package/dist/orphan-reaper-process.d.ts.map +1 -0
- package/dist/orphan-reaper-process.js +98 -0
- package/dist/orphan-reaper-process.js.map +1 -0
- package/dist/orphan-reaper.d.ts +25 -0
- package/dist/orphan-reaper.d.ts.map +1 -0
- package/dist/orphan-reaper.js +161 -0
- package/dist/orphan-reaper.js.map +1 -0
- package/dist/process-identity.d.ts +1 -0
- package/dist/process-identity.d.ts.map +1 -1
- package/dist/process-identity.js +18 -4
- package/dist/process-identity.js.map +1 -1
- package/dist/process-manager.d.ts +12 -9
- package/dist/process-manager.d.ts.map +1 -1
- package/dist/process-manager.js +316 -125
- package/dist/process-manager.js.map +1 -1
- package/dist/readiness.d.ts +1 -0
- package/dist/readiness.d.ts.map +1 -1
- package/dist/readiness.js +77 -11
- package/dist/readiness.js.map +1 -1
- package/dist/sandbox.d.ts +21 -8
- package/dist/sandbox.d.ts.map +1 -1
- package/dist/sandbox.js +359 -49
- package/dist/sandbox.js.map +1 -1
- package/dist/spawn-environment.d.ts +16 -0
- package/dist/spawn-environment.d.ts.map +1 -0
- package/dist/spawn-environment.js +35 -0
- package/dist/spawn-environment.js.map +1 -0
- package/dist/target-pid.d.ts +6 -0
- package/dist/target-pid.d.ts.map +1 -0
- package/dist/target-pid.js +18 -0
- package/dist/target-pid.js.map +1 -0
- package/package.json +2 -2
package/dist/attach-fencing.js
CHANGED
|
@@ -36,23 +36,33 @@
|
|
|
36
36
|
* here right now."
|
|
37
37
|
*/
|
|
38
38
|
import { execFileSync } from "node:child_process";
|
|
39
|
-
import { readFileSync, readdirSync, readlinkSync, realpathSync
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
39
|
+
import { closeSync, readFileSync, readSync, readdirSync, readlinkSync, realpathSync } from "node:fs";
|
|
40
|
+
import { openAttachLogFile } from "./attach-log-file.js";
|
|
41
|
+
const LINE_COUNT_CHUNK_BYTES = 1024 * 1024;
|
|
42
|
+
const CARRIAGE_RETURN = 0x0d;
|
|
43
|
+
const LINE_FEED = 0x0a;
|
|
44
|
+
function countCompleteLinesInFile(descriptor, byteLimit) {
|
|
45
|
+
const chunk = Buffer.allocUnsafe(Math.min(LINE_COUNT_CHUNK_BYTES, Math.max(1, byteLimit)));
|
|
46
|
+
let lines = 0;
|
|
47
|
+
let position = 0;
|
|
48
|
+
let previousWasCarriageReturn = false;
|
|
49
|
+
while (position < byteLimit) {
|
|
50
|
+
const read = readSync(descriptor, chunk, 0, Math.min(chunk.length, byteLimit - position), position);
|
|
51
|
+
if (read === 0)
|
|
52
|
+
break;
|
|
53
|
+
for (let index = 0; index < read; index += 1) {
|
|
54
|
+
const byte = chunk[index];
|
|
55
|
+
if (byte === CARRIAGE_RETURN) {
|
|
56
|
+
lines += 1;
|
|
57
|
+
}
|
|
58
|
+
else if (byte === LINE_FEED && !previousWasCarriageReturn) {
|
|
59
|
+
lines += 1;
|
|
60
|
+
}
|
|
61
|
+
previousWasCarriageReturn = byte === CARRIAGE_RETURN;
|
|
62
|
+
}
|
|
63
|
+
position += read;
|
|
64
|
+
}
|
|
65
|
+
return lines;
|
|
56
66
|
}
|
|
57
67
|
let cachedClockTicksPerSecond = null;
|
|
58
68
|
/**
|
|
@@ -197,12 +207,23 @@ export function detectOtherLogWriters(logFilePath, targetPid, platform = process
|
|
|
197
207
|
export function computeAttachFence(pid, logFilePath, platform = process.platform) {
|
|
198
208
|
let attachOffsetBytes = 0;
|
|
199
209
|
let preExistingLineCount = 0;
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
210
|
+
let backlogUnavailableReason;
|
|
211
|
+
const opened = openAttachLogFile(logFilePath);
|
|
212
|
+
if (opened.ok) {
|
|
213
|
+
try {
|
|
214
|
+
attachOffsetBytes = opened.size;
|
|
215
|
+
preExistingLineCount = countCompleteLinesInFile(opened.descriptor, opened.size);
|
|
216
|
+
}
|
|
217
|
+
catch (error) {
|
|
218
|
+
preExistingLineCount = 0;
|
|
219
|
+
backlogUnavailableReason = `the existing backlog of "${logFilePath}" could not be counted: ${error instanceof Error ? error.message : String(error)}`;
|
|
220
|
+
}
|
|
221
|
+
finally {
|
|
222
|
+
closeSync(opened.descriptor);
|
|
223
|
+
}
|
|
203
224
|
}
|
|
204
|
-
|
|
205
|
-
|
|
225
|
+
else if (!opened.missing) {
|
|
226
|
+
backlogUnavailableReason = `the existing backlog of "${logFilePath}" could not be measured: ${opened.reason}`;
|
|
206
227
|
}
|
|
207
228
|
return {
|
|
208
229
|
attachOffsetBytes,
|
|
@@ -210,6 +231,7 @@ export function computeAttachFence(pid, logFilePath, platform = process.platform
|
|
|
210
231
|
processStartTime: getProcessStartTimeMs(pid, platform),
|
|
211
232
|
otherWriters: detectOtherLogWriters(logFilePath, pid, platform),
|
|
212
233
|
attachedAt: new Date().toISOString(),
|
|
234
|
+
...(backlogUnavailableReason === undefined ? {} : { backlogUnavailableReason }),
|
|
213
235
|
};
|
|
214
236
|
}
|
|
215
237
|
//# sourceMappingURL=attach-fencing.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attach-fencing.js","sourceRoot":"","sources":["../src/attach-fencing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,
|
|
1
|
+
{"version":3,"file":"attach-fencing.js","sourceRoot":"","sources":["../src/attach-fencing.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export type AttachLogPathResolution = {
|
|
2
|
+
readonly ok: true;
|
|
3
|
+
readonly path: string;
|
|
4
|
+
readonly exists: boolean;
|
|
5
|
+
} | {
|
|
6
|
+
readonly ok: false;
|
|
7
|
+
readonly reason: string;
|
|
8
|
+
};
|
|
9
|
+
export declare function resolveAttachLogPath(logFilePath: unknown): AttachLogPathResolution;
|
|
10
|
+
export type AttachLogOpenResult = {
|
|
11
|
+
readonly ok: true;
|
|
12
|
+
readonly descriptor: number;
|
|
13
|
+
readonly size: number;
|
|
14
|
+
readonly inode: number;
|
|
15
|
+
} | {
|
|
16
|
+
readonly ok: false;
|
|
17
|
+
readonly missing: boolean;
|
|
18
|
+
readonly reason: string;
|
|
19
|
+
};
|
|
20
|
+
export declare function openAttachLogFile(logFilePath: unknown): AttachLogOpenResult;
|
|
21
|
+
//# sourceMappingURL=attach-log-file.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attach-log-file.d.ts","sourceRoot":"","sources":["../src/attach-log-file.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,uBAAuB,GAC/B;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;CAAE,GACtE;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAcpD,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,OAAO,GAAG,uBAAuB,CAqClF;AAED,MAAM,MAAM,mBAAmB,GAC3B;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACjG;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE/E,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,OAAO,GAAG,mBAAmB,CAqB3E"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { closeSync, constants as fsConstants, fstatSync, openSync, realpathSync } from "node:fs";
|
|
2
|
+
import { basename, dirname, isAbsolute, join, sep } from "node:path";
|
|
3
|
+
import { CREDENTIAL_STORES } from "./sandbox.js";
|
|
4
|
+
const NON_LOG_ROOTS = ["/proc", "/sys", "/dev"];
|
|
5
|
+
function underDirectory(path, directory) {
|
|
6
|
+
return path === directory || path.startsWith(`${directory}${sep}`);
|
|
7
|
+
}
|
|
8
|
+
function credentialStoreOnPath(path) {
|
|
9
|
+
const padded = `${path}/`;
|
|
10
|
+
for (const entry of CREDENTIAL_STORES) {
|
|
11
|
+
if (padded.includes(`/${entry}/`))
|
|
12
|
+
return entry;
|
|
13
|
+
}
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
export function resolveAttachLogPath(logFilePath) {
|
|
17
|
+
if (typeof logFilePath !== "string" || logFilePath === "") {
|
|
18
|
+
return { ok: false, reason: "the log file path is empty or not a string" };
|
|
19
|
+
}
|
|
20
|
+
if (logFilePath.includes("\0"))
|
|
21
|
+
return { ok: false, reason: "the log file path contains a NUL byte" };
|
|
22
|
+
if (!isAbsolute(logFilePath))
|
|
23
|
+
return { ok: false, reason: `the log file path "${logFilePath}" is not absolute` };
|
|
24
|
+
let resolved;
|
|
25
|
+
let exists = true;
|
|
26
|
+
try {
|
|
27
|
+
resolved = realpathSync(logFilePath);
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
if (error.code !== "ENOENT") {
|
|
31
|
+
return { ok: false, reason: `the log file path "${logFilePath}" could not be resolved: ${error instanceof Error ? error.message : String(error)}` };
|
|
32
|
+
}
|
|
33
|
+
exists = false;
|
|
34
|
+
try {
|
|
35
|
+
resolved = join(realpathSync(dirname(logFilePath)), basename(logFilePath));
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
resolved = logFilePath;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
for (const root of NON_LOG_ROOTS) {
|
|
42
|
+
if (underDirectory(resolved, root)) {
|
|
43
|
+
return { ok: false, reason: `"${logFilePath}" resolves to ${resolved}, inside ${root}, which holds process and device state rather than log files` };
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
const store = credentialStoreOnPath(resolved);
|
|
47
|
+
if (store !== null) {
|
|
48
|
+
return { ok: false, reason: `"${logFilePath}" resolves to ${resolved}, inside a credential store (${store}) that must never be read as a log` };
|
|
49
|
+
}
|
|
50
|
+
const name = basename(resolved);
|
|
51
|
+
if (CREDENTIAL_STORES.includes(name)) {
|
|
52
|
+
return { ok: false, reason: `"${logFilePath}" resolves to ${resolved}, a credential file (${name}) that must never be read as a log` };
|
|
53
|
+
}
|
|
54
|
+
return { ok: true, path: resolved, exists };
|
|
55
|
+
}
|
|
56
|
+
export function openAttachLogFile(logFilePath) {
|
|
57
|
+
const resolution = resolveAttachLogPath(logFilePath);
|
|
58
|
+
if (!resolution.ok)
|
|
59
|
+
return { ok: false, missing: false, reason: resolution.reason };
|
|
60
|
+
let descriptor;
|
|
61
|
+
try {
|
|
62
|
+
descriptor = openSync(resolution.path, fsConstants.O_RDONLY | fsConstants.O_NONBLOCK);
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
const code = error.code;
|
|
66
|
+
return { ok: false, missing: code === "ENOENT", reason: error instanceof Error ? error.message : String(error) };
|
|
67
|
+
}
|
|
68
|
+
try {
|
|
69
|
+
const stats = fstatSync(descriptor);
|
|
70
|
+
if (!stats.isFile()) {
|
|
71
|
+
closeSync(descriptor);
|
|
72
|
+
return { ok: false, missing: false, reason: `"${resolution.path}" is not a regular file, so it cannot be tailed as a log` };
|
|
73
|
+
}
|
|
74
|
+
return { ok: true, descriptor, size: stats.size, inode: stats.ino };
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
closeSync(descriptor);
|
|
78
|
+
return { ok: false, missing: false, reason: error instanceof Error ? error.message : String(error) };
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=attach-log-file.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attach-log-file.js","sourceRoot":"","sources":["../src/attach-log-file.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type BoundedFileRead = {
|
|
2
|
+
readonly kind: "read";
|
|
3
|
+
readonly text: string;
|
|
4
|
+
} | {
|
|
5
|
+
readonly kind: "missing";
|
|
6
|
+
} | {
|
|
7
|
+
readonly kind: "skipped";
|
|
8
|
+
readonly reason: string;
|
|
9
|
+
};
|
|
10
|
+
export declare function readBoundedRegularFile(path: string, maxBytes: number): BoundedFileRead;
|
|
11
|
+
//# sourceMappingURL=bounded-file.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bounded-file.d.ts","sourceRoot":"","sources":["../src/bounded-file.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,eAAe,GACvB;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAChD;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;CAAE,GAC5B;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAI1D,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,eAAe,CA6BtF"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { closeSync, constants as fsConstants, fstatSync, openSync, readSync } from "node:fs";
|
|
2
|
+
const READ_CHUNK_BYTES = 64 * 1024;
|
|
3
|
+
export function readBoundedRegularFile(path, maxBytes) {
|
|
4
|
+
let descriptor;
|
|
5
|
+
try {
|
|
6
|
+
descriptor = openSync(path, fsConstants.O_RDONLY | fsConstants.O_NONBLOCK);
|
|
7
|
+
}
|
|
8
|
+
catch (error) {
|
|
9
|
+
const code = error.code;
|
|
10
|
+
if (code === "ENOENT" || code === "ENOTDIR")
|
|
11
|
+
return { kind: "missing" };
|
|
12
|
+
return { kind: "skipped", reason: `${path} could not be opened: ${error instanceof Error ? error.message : String(error)}` };
|
|
13
|
+
}
|
|
14
|
+
try {
|
|
15
|
+
const stats = fstatSync(descriptor);
|
|
16
|
+
if (!stats.isFile())
|
|
17
|
+
return { kind: "skipped", reason: `${path} is not a regular file, so it was not read` };
|
|
18
|
+
if (stats.size > maxBytes)
|
|
19
|
+
return { kind: "skipped", reason: `${path} is ${String(stats.size)} bytes, over the ${String(maxBytes)} byte limit, so it was not read` };
|
|
20
|
+
const chunks = [];
|
|
21
|
+
let total = 0;
|
|
22
|
+
for (;;) {
|
|
23
|
+
const chunk = Buffer.allocUnsafe(Math.min(READ_CHUNK_BYTES, maxBytes - total + 1));
|
|
24
|
+
const read = readSync(descriptor, chunk, 0, chunk.length, null);
|
|
25
|
+
if (read === 0)
|
|
26
|
+
break;
|
|
27
|
+
total += read;
|
|
28
|
+
if (total > maxBytes)
|
|
29
|
+
return { kind: "skipped", reason: `${path} grew past the ${String(maxBytes)} byte limit while being read, so it was not used` };
|
|
30
|
+
chunks.push(chunk.subarray(0, read));
|
|
31
|
+
}
|
|
32
|
+
return { kind: "read", text: Buffer.concat(chunks).toString("utf8") };
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
return { kind: "skipped", reason: `${path} could not be read: ${error instanceof Error ? error.message : String(error)}` };
|
|
36
|
+
}
|
|
37
|
+
finally {
|
|
38
|
+
closeSync(descriptor);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=bounded-file.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bounded-file.js","sourceRoot":"","sources":["../src/bounded-file.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,SAAS,IAAI,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAO7F,MAAM,gBAAgB,GAAG,EAAE,GAAG,IAAI,CAAC;AAEnC,MAAM,UAAU,sBAAsB,CAAC,IAAY,EAAE,QAAgB;IACnE,IAAI,UAAkB,CAAC;IACvB,IAAI,CAAC;QACH,UAAU,GAAG,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC,QAAQ,GAAG,WAAW,CAAC,UAAU,CAAC,CAAC;IAC7E,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,GAAI,KAA+B,CAAC,IAAI,CAAC;QACnD,IAAI,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,SAAS;YAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;QACxE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI,yBAAyB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC;IAC/H,CAAC;IACD,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,SAAS,CAAC,UAAU,CAAC,CAAC;QACpC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE;YAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI,4CAA4C,EAAE,CAAC;QAC7G,IAAI,KAAK,CAAC,IAAI,GAAG,QAAQ;YAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI,OAAO,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,oBAAoB,MAAM,CAAC,QAAQ,CAAC,iCAAiC,EAAE,CAAC;QACrK,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,SAAS,CAAC;YACR,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,gBAAgB,EAAE,QAAQ,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC;YACnF,MAAM,IAAI,GAAG,QAAQ,CAAC,UAAU,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;YAChE,IAAI,IAAI,KAAK,CAAC;gBAAE,MAAM;YACtB,KAAK,IAAI,IAAI,CAAC;YACd,IAAI,KAAK,GAAG,QAAQ;gBAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI,kBAAkB,MAAM,CAAC,QAAQ,CAAC,kDAAkD,EAAE,CAAC;YACtJ,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;QACvC,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;IACxE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI,uBAAuB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC;IAC7H,CAAC;YAAS,CAAC;QACT,SAAS,CAAC,UAAU,CAAC,CAAC;IACxB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export declare const OUTPUT_HEAD_BYTES: number;
|
|
2
|
+
export declare const OUTPUT_TAIL_BYTES: number;
|
|
3
|
+
export interface ProcessOutputInfo {
|
|
4
|
+
/** Every byte this process has written to stdout+stderr, whether kept or dropped. */
|
|
5
|
+
readonly totalBytesSeen: number;
|
|
6
|
+
/** True once `totalBytesSeen` exceeds what head+tail can hold -- `readOutput()` is a bounded view, not the whole thing. */
|
|
7
|
+
readonly truncated: boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface ProcessOutputRead {
|
|
10
|
+
readonly text: string;
|
|
11
|
+
readonly cursor: number;
|
|
12
|
+
readonly droppedChars: number;
|
|
13
|
+
}
|
|
14
|
+
export declare function assertCursor(cursor: number, end: number): void;
|
|
15
|
+
export declare class BoundedOutput {
|
|
16
|
+
#private;
|
|
17
|
+
appendText(text: string): void;
|
|
18
|
+
countBytes(bytes: number): void;
|
|
19
|
+
startNewEpoch(): void;
|
|
20
|
+
read(): string;
|
|
21
|
+
info(): ProcessOutputInfo;
|
|
22
|
+
readFrom(cursor: number): ProcessOutputRead;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=bounded-output.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bounded-output.d.ts","sourceRoot":"","sources":["../src/bounded-output.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,iBAAiB,QAAY,CAAC;AAC3C,eAAO,MAAM,iBAAiB,QAAc,CAAC;AAE7C,MAAM,WAAW,iBAAiB;IAChC,qFAAqF;IACrF,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,2HAA2H;IAC3H,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;CAC7B;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AAMD,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAO9D;AAED,qBAAa,aAAa;;IAOxB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAW9B,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAI/B,aAAa,IAAI,IAAI;IAYrB,IAAI,IAAI,MAAM;IAOd,IAAI,IAAI,iBAAiB;IAIzB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,iBAAiB;CAqB5C"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
export const OUTPUT_HEAD_BYTES = 64 * 1024;
|
|
2
|
+
export const OUTPUT_TAIL_BYTES = 1024 * 1024;
|
|
3
|
+
function truncationMarker(droppedChars, totalChars, totalBytes) {
|
|
4
|
+
return `\n\n...[Descry truncated ${String(droppedChars)} of ${String(totalChars)} characters (${String(totalBytes)} bytes) of output here -- head/tail kept, middle dropped]...\n\n`;
|
|
5
|
+
}
|
|
6
|
+
export function assertCursor(cursor, end) {
|
|
7
|
+
if (!Number.isSafeInteger(cursor) || cursor < 0) {
|
|
8
|
+
throw new RangeError(`output cursor must be a non-negative integer, got ${String(cursor)}`);
|
|
9
|
+
}
|
|
10
|
+
if (cursor > end) {
|
|
11
|
+
throw new RangeError(`output cursor ${String(cursor)} is past the ${String(end)} characters of output that exist`);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export class BoundedOutput {
|
|
15
|
+
#head = "";
|
|
16
|
+
#tail = "";
|
|
17
|
+
#chars = 0;
|
|
18
|
+
#bytes = 0;
|
|
19
|
+
#epochStart = 0;
|
|
20
|
+
appendText(text) {
|
|
21
|
+
if (text === "")
|
|
22
|
+
return;
|
|
23
|
+
this.#chars += text.length;
|
|
24
|
+
if (this.#head.length < OUTPUT_HEAD_BYTES) {
|
|
25
|
+
this.#head += text;
|
|
26
|
+
if (this.#head.length > OUTPUT_HEAD_BYTES)
|
|
27
|
+
this.#head = this.#head.slice(0, OUTPUT_HEAD_BYTES);
|
|
28
|
+
}
|
|
29
|
+
this.#tail += text;
|
|
30
|
+
if (this.#tail.length > OUTPUT_TAIL_BYTES)
|
|
31
|
+
this.#tail = this.#tail.slice(this.#tail.length - OUTPUT_TAIL_BYTES);
|
|
32
|
+
}
|
|
33
|
+
countBytes(bytes) {
|
|
34
|
+
this.#bytes += bytes;
|
|
35
|
+
}
|
|
36
|
+
startNewEpoch() {
|
|
37
|
+
this.#epochStart += this.#chars;
|
|
38
|
+
this.#chars = 0;
|
|
39
|
+
this.#bytes = 0;
|
|
40
|
+
this.#head = "";
|
|
41
|
+
this.#tail = "";
|
|
42
|
+
}
|
|
43
|
+
#droppedMiddleChars() {
|
|
44
|
+
return Math.max(0, this.#chars - this.#head.length - this.#tail.length);
|
|
45
|
+
}
|
|
46
|
+
read() {
|
|
47
|
+
const tailStart = this.#chars - this.#tail.length;
|
|
48
|
+
if (tailStart <= 0)
|
|
49
|
+
return this.#tail;
|
|
50
|
+
if (this.#head.length >= tailStart)
|
|
51
|
+
return this.#head.slice(0, tailStart) + this.#tail;
|
|
52
|
+
return this.#head + truncationMarker(this.#droppedMiddleChars(), this.#chars, this.#bytes) + this.#tail;
|
|
53
|
+
}
|
|
54
|
+
info() {
|
|
55
|
+
return { totalBytesSeen: this.#bytes, truncated: this.#droppedMiddleChars() > 0 };
|
|
56
|
+
}
|
|
57
|
+
readFrom(cursor) {
|
|
58
|
+
const end = this.#epochStart + this.#chars;
|
|
59
|
+
assertCursor(cursor, end);
|
|
60
|
+
let droppedChars = 0;
|
|
61
|
+
let relative = cursor - this.#epochStart;
|
|
62
|
+
if (relative < 0) {
|
|
63
|
+
droppedChars += -relative;
|
|
64
|
+
relative = 0;
|
|
65
|
+
}
|
|
66
|
+
const tailStart = this.#chars - this.#tail.length;
|
|
67
|
+
if (relative >= tailStart) {
|
|
68
|
+
return { text: this.#tail.slice(relative - tailStart), cursor: end, droppedChars };
|
|
69
|
+
}
|
|
70
|
+
if (relative < this.#head.length) {
|
|
71
|
+
if (this.#head.length >= tailStart) {
|
|
72
|
+
return { text: this.#head.slice(relative, tailStart) + this.#tail, cursor: end, droppedChars };
|
|
73
|
+
}
|
|
74
|
+
return { text: this.#head.slice(relative), cursor: this.#epochStart + this.#head.length, droppedChars };
|
|
75
|
+
}
|
|
76
|
+
return { text: this.#tail, cursor: end, droppedChars: droppedChars + (tailStart - relative) };
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=bounded-output.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bounded-output.js","sourceRoot":"","sources":["../src/bounded-output.ts"],"names":[],"mappings":"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"}
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
* interception + IP filtering) -- `unsupportedContainerNetworkPolicyReason` reports
|
|
50
50
|
* it the same way, matching posture rather than overclaiming.
|
|
51
51
|
*/
|
|
52
|
-
import type { CapabilityStatus, FilesystemPolicy, NetworkPolicy } from "@descryy/runtime-contracts";
|
|
52
|
+
import type { CapabilityStatus, FilesystemPolicy, NetworkPolicy, ResourceLimits } from "@descryy/runtime-contracts";
|
|
53
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." */
|
|
54
54
|
export declare function containerRuntimeCapability(env?: NodeJS.ProcessEnv): CapabilityStatus;
|
|
55
55
|
export declare function containerFilesystemIsolationCapability(env?: NodeJS.ProcessEnv): CapabilityStatus;
|
|
@@ -68,37 +68,24 @@ export interface ContainerSandboxOptions {
|
|
|
68
68
|
readonly filesystemPolicy?: FilesystemPolicy;
|
|
69
69
|
readonly networkPolicy?: NetworkPolicy;
|
|
70
70
|
/**
|
|
71
|
-
* Env vars the containerized process needs
|
|
71
|
+
* Env vars the containerized process needs. `PATH` is
|
|
72
72
|
* never forwarded: the container must resolve `command` against its own image
|
|
73
73
|
* layout (`/usr/local/bin/node`, not the host's), and the host's PATH would break
|
|
74
|
-
* that or run the wrong binary.
|
|
75
|
-
* bwrap's own unfiltered-inheritance precedent (no `--clearenv`).
|
|
74
|
+
* that or run the wrong binary.
|
|
76
75
|
*/
|
|
77
76
|
readonly processEnv?: Readonly<Record<string, string | undefined>>;
|
|
78
77
|
/** Env for running the `docker` CLI itself (PATH, `DOCKER_HOST`). Defaults to `process.env`. */
|
|
79
78
|
readonly env?: NodeJS.ProcessEnv;
|
|
80
79
|
/** Explicit override, bypasses `resolveContainerImage`'s name-based guess. */
|
|
81
80
|
readonly containerImage?: string;
|
|
81
|
+
readonly resourceLimits?: ResourceLimits;
|
|
82
82
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
* `filesystemPolicy`/`networkPolicy`. Neither declared returns them unchanged and
|
|
86
|
-
* never invokes docker -- same non-regression contract as `sandbox.ts`'s
|
|
87
|
-
* `applySandbox`.
|
|
88
|
-
*
|
|
89
|
-
* **Throws rather than silently spawning unconstrained** when a policy can't
|
|
90
|
-
* actually be backed (no working Docker, unimplemented `networkPolicy` shape).
|
|
91
|
-
*
|
|
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.
|
|
98
|
-
*/
|
|
83
|
+
export declare const CONTAINER_HOST_ENV_PASSTHROUGH: readonly string[];
|
|
84
|
+
export declare function containerProcessEnv(declared: Readonly<Record<string, string | undefined>> | undefined, host?: NodeJS.ProcessEnv): Record<string, string | undefined>;
|
|
99
85
|
export declare function applyContainerSandbox(options: ContainerSandboxOptions): {
|
|
100
86
|
readonly command: string;
|
|
101
87
|
readonly args: readonly string[];
|
|
102
88
|
readonly containerName?: string;
|
|
89
|
+
readonly env?: Readonly<Record<string, string>>;
|
|
103
90
|
};
|
|
104
91
|
//# sourceMappingURL=container-sandbox.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"container-sandbox.d.ts","sourceRoot":"","sources":["../src/container-sandbox.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;
|
|
1
|
+
{"version":3,"file":"container-sandbox.d.ts","sourceRoot":"","sources":["../src/container-sandbox.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AAOH,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAGpH,2OAA2O;AAC3O,wBAAgB,0BAA0B,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,gBAAgB,CAUjG;AAmCD,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;;;;;OAKG;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;IACjC,QAAQ,CAAC,cAAc,CAAC,EAAE,cAAc,CAAC;CAC1C;AA0ED,eAAO,MAAM,8BAA8B,EAAE,SAAS,MAAM,EAAqD,CAAC;AAElH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,GAAG,SAAS,EAClE,IAAI,GAAE,MAAM,CAAC,UAAwB,GACpC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAMpC;AAED,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,uBAAuB,GAC/B;IACD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACjD,CAoFA"}
|