@outerlayer/cli 0.27.1 → 0.28.2
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/CHANGELOG.md +39 -0
- package/README.md +6 -0
- package/dist/{agent-setup-UW36TAQM.js → agent-setup-YVR5RO56.js} +17 -14
- package/dist/{bridge-B5VJVECY.js → bridge-WW2V7DTB.js} +3 -2
- package/dist/build-5FRC3RKM.js +13 -0
- package/dist/build-info.json +1 -1
- package/dist/{builder-6Y6ZWGNH.js → builder-4F2XNSFC.js} +7 -6
- package/dist/{check-YTXFVWK7.js → check-YEI6TCUH.js} +70 -61
- package/dist/{chunk-LPFOWUHG.js → chunk-25X2PJDI.js} +20 -13
- package/dist/{chunk-BPKO76QR.js → chunk-4XN5FRRJ.js} +4 -4
- package/dist/{chunk-EPPIISRD.js → chunk-55XLX5PA.js} +1 -1
- package/dist/{chunk-LOKSLO25.js → chunk-5B7BEQPR.js} +1 -1
- package/dist/chunk-5BHIBJDA.js +93 -0
- package/dist/{chunk-RHAGBUL5.js → chunk-5K3KB4YR.js} +1 -1
- package/dist/{chunk-ABXQBEYK.js → chunk-66T6XJAB.js} +1 -1
- package/dist/{chunk-ZFBJUOYT.js → chunk-6S4V4UIC.js} +10 -10
- package/dist/{chunk-BWH36FOC.js → chunk-7CK2TJFB.js} +20 -4
- package/dist/{chunk-QKIQ2R7F.js → chunk-ATJOFXTE.js} +3 -3
- package/dist/chunk-CDDED64E.js +13 -0
- package/dist/{chunk-QHH4OSD4.js → chunk-CTYSTE5C.js} +1 -1
- package/dist/{chunk-DJHNEGNM.js → chunk-DKWQMPSL.js} +18 -2
- package/dist/{chunk-IMOB4IOI.js → chunk-DQYMQ47E.js} +3 -2
- package/dist/{chunk-YETTWTAY.js → chunk-E7R2GIAW.js} +4 -4
- package/dist/{chunk-GFUE5TKO.js → chunk-F4FA3ZUT.js} +24 -14
- package/dist/{chunk-6TRNCUM4.js → chunk-FGF52V4V.js} +1 -1
- package/dist/{chunk-R7SGBXUD.js → chunk-GLL4TN2M.js} +226 -72
- package/dist/{chunk-MATUHHN4.js → chunk-GUXWQIEY.js} +1 -1
- package/dist/{chunk-B7DJVG25.js → chunk-HOB7Z4JQ.js} +3 -3
- package/dist/{chunk-2I3LIRZP.js → chunk-HXAEQPZR.js} +101 -10
- package/dist/{chunk-P33PZIWS.js → chunk-ITAIEJ2T.js} +7 -142
- package/dist/{chunk-RHGF73IU.js → chunk-IVX3U7KV.js} +1 -1
- package/dist/{chunk-7OUOLGUV.js → chunk-JGML2VUN.js} +3 -7
- package/dist/{chunk-6VFH52MP.js → chunk-KU7QL4XW.js} +24 -22
- package/dist/{chunk-2F762IXY.js → chunk-LNIFYSNK.js} +3 -3
- package/dist/{chunk-XBPUTQ7E.js → chunk-MHAR6S7B.js} +1 -1
- package/dist/{chunk-VS27BP3E.js → chunk-MKIC65SD.js} +52 -9
- package/dist/{chunk-64GMBWAK.js → chunk-MNHMUZGC.js} +6 -6
- package/dist/{chunk-7AQ5AM7U.js → chunk-MQHTM4YJ.js} +177 -21
- package/dist/{chunk-6KKM7VGZ.js → chunk-N7WAEEIU.js} +3 -3
- package/dist/{chunk-D7ECMB7B.js → chunk-NUHZV3A4.js} +1 -1
- package/dist/{chunk-5VMDGJGH.js → chunk-O65LES4V.js} +39 -25
- package/dist/{chunk-MHX7YX7Y.js → chunk-P2RWZCV7.js} +1 -1
- package/dist/chunk-QBQHQEUG.js +300 -0
- package/dist/{chunk-FP23SVDD.js → chunk-QJFDAKRF.js} +5 -5
- package/dist/{chunk-WUL2OP5A.js → chunk-QKXF7CLR.js} +3 -3
- package/dist/{chunk-XZ6Q6ZNR.js → chunk-SATUCMAJ.js} +3 -2
- package/dist/{chunk-Y7ZCHBYB.js → chunk-SFJXGISY.js} +3 -3
- package/dist/{chunk-2BTFKNTR.js → chunk-SJZL5F3F.js} +2 -2
- package/dist/{chunk-HWDYLXHH.js → chunk-T2QSWFSU.js} +4 -4
- package/dist/{chunk-E5IJ5533.js → chunk-TF7G2PR6.js} +3 -3
- package/dist/{chunk-O2IJTY7L.js → chunk-TVZAC2NP.js} +3 -3
- package/dist/{chunk-QE3UQAHK.js → chunk-UHU7H57K.js} +26 -7
- package/dist/{chunk-WSYXLLA5.js → chunk-USJZ2LDK.js} +6 -6
- package/dist/{chunk-EX5MQYEF.js → chunk-VC5J7QPV.js} +5 -5
- package/dist/{chunk-N4D5TMVU.js → chunk-VU7ZJPIR.js} +5 -5
- package/dist/{chunk-GLUKDQS4.js → chunk-WWQVKFN6.js} +1 -1
- package/dist/{chunk-55GNQPO6.js → chunk-X52PMPOM.js} +7 -7
- package/dist/{chunk-YB3CSYXX.js → chunk-XD4ZCMA4.js} +81 -2
- package/dist/{chunk-Y4OKEFAX.js → chunk-YL2VDSNF.js} +1 -1
- package/dist/{chunk-M3MHHIUW.js → chunk-Z3ASAXVU.js} +1 -1
- package/dist/{chunk-XS3FDWSZ.js → chunk-ZTY7HHYB.js} +1 -1
- package/dist/{claude-launcher-NQSZBTQ5.js → claude-launcher-7RGVOYCD.js} +6 -5
- package/dist/{cli-GHEOBXC7.js → cli-SCTKM2Y5.js} +151 -130
- package/dist/cli-update-notice-4DLZ3655.js +9 -0
- package/dist/{command-V7B7GTPZ.js → command-PY3C2E4B.js} +53 -37
- package/dist/{config-TWS5VZEN.js → config-5QYIKYUP.js} +3 -2
- package/dist/{connect-cmd-HGS7YPA2.js → connect-cmd-5TYAOK5M.js} +14 -11
- package/dist/{container-start-FHB2VDC4.js → container-start-7WLZMPEI.js} +37 -36
- package/dist/{control-plane-launch-DBQA3KLJ.js → control-plane-launch-FZMD4MXX.js} +13 -10
- package/dist/{dist-QPHZE47F.js → dist-JFVKLUHL.js} +1 -1
- package/dist/{docker-YT6Z3LXI.js → docker-ZTC4EIU4.js} +7 -6
- package/dist/{doctor-Y4NCNSJM.js → doctor-DQWRUAEB.js} +159 -41
- package/dist/{emit-artifact-cmd-ALDK55Y2.js → emit-artifact-cmd-SOXLBPQB.js} +19 -16
- package/dist/{emit-cmd-VAQHRWJR.js → emit-cmd-QUABLVO6.js} +6 -5
- package/dist/{emit-criteria-cmd-Q7SM6VP2.js → emit-criteria-cmd-JDO2VUG5.js} +15 -12
- package/dist/{emit-finding-cmd-2NBAPDSV.js → emit-finding-cmd-VCQPCLI2.js} +16 -13
- package/dist/{emit-result-cmd-KUSL56RI.js → emit-result-cmd-TKA3GAN7.js} +19 -16
- package/dist/{emit-step-cmd-KD4AKEAT.js → emit-step-cmd-XN44BXYU.js} +16 -13
- package/dist/{exec-client-6WVS7DRZ.js → exec-client-VKT2XNB3.js} +4 -3
- package/dist/fleet-readiness-G5X3MKP2.js +29 -0
- package/dist/{governing-source-VVUA5TKB.js → governing-source-B3M2U4BC.js} +21 -18
- package/dist/{guest-init-H5K2RW3P.js → guest-init-QW2DPX7H.js} +5 -4
- package/dist/{hook-fast-3SUJM765.js → hook-fast-EFC44SXV.js} +4 -1
- package/dist/{host-key-XNKZCWTS.js → host-key-AC6LTZDS.js} +4 -3
- package/dist/{image-tag-R34J4O3F.js → image-tag-SS7YKJHN.js} +4 -3
- package/dist/index.js +4 -4
- package/dist/init-5LHTF72R.js +56 -0
- package/dist/{init-3DAGX7UY.js → init-BTH5YPBC.js} +38 -37
- package/dist/{init-cmd-RIDBVSE4.js → init-cmd-L4VW3ZCT.js} +25 -21
- package/dist/{init-update-ECWNG47R.js → init-update-RWTQSTPE.js} +51 -35
- package/dist/{inspect-IPFA7AAT.js → inspect-L7JIBK3Y.js} +1 -1
- package/dist/{install-6OIY3KHZ.js → install-35SAMY75.js} +5 -5
- package/dist/{install-cmd-JMT67P35.js → install-cmd-GFY4QF72.js} +6 -5
- package/dist/{layout-XNFDTOET.js → layout-BBTQPS6V.js} +4 -3
- package/dist/{login-browser-EWXSGHM7.js → login-browser-WSOSQH2T.js} +2 -2
- package/dist/{logs-XHAS6LMZ.js → logs-X2IRDP5T.js} +3 -2
- package/dist/loop-QDV7T65M.js +80 -0
- package/dist/{machine-OOQ2NXC3.js → machine-PLNSGKNF.js} +32 -30
- package/dist/{machine-skills-FLIRJYP7.js → machine-skills-O7W6NMWB.js} +4 -3
- package/dist/{mcp-serve-cmd-LY5A3CE7.js → mcp-serve-cmd-IITCPAAR.js} +9 -6
- package/dist/{paths-LHSPNORF.js → paths-32DWGK35.js} +3 -2
- package/dist/pending-CSIY4Y2I.js +10 -0
- package/dist/{pidfile-DKMYYXLH.js → pidfile-CYCTH6NQ.js} +4 -3
- package/dist/{real-deps-KNNBQC75.js → real-deps-QX5YH7FG.js} +1 -1
- package/dist/{record-3LPTY3G5.js → record-N4WPZCGK.js} +4 -3
- package/dist/{relay-GFPPD6GF.js → relay-FJ5K37Z5.js} +8 -4
- package/dist/{runner-env-YRRNRKF4.js → runner-env-EIB6WFPG.js} +6 -7
- package/dist/{runner-identity-YS2BZXZV.js → runner-identity-S3V6I4I3.js} +7 -6
- package/dist/{runner-key-EFNTZWNX.js → runner-key-M4N2BY5A.js} +36 -35
- package/dist/{session-sender-SC5PSU2G.js → session-sender-UQ3VF732.js} +20 -17
- package/dist/{spec-cmd-JGYHHJ4P.js → spec-cmd-Z6MGATWC.js} +16 -13
- package/dist/{starter-pack-GPU4X6B7.js → starter-pack-5SOT5V4I.js} +4 -3
- package/dist/{status-7WM7S7JX.js → status-PWMPP4ES.js} +39 -37
- package/dist/{sync-cmd-ATXJVS7S.js → sync-cmd-N4R7ST6X.js} +19 -16
- package/dist/{watch-M7NR3DOW.js → watch-L5MSAWEO.js} +19 -16
- package/dist/{work-claim-cmd-DNUDZKJA.js → work-claim-cmd-CXALMILD.js} +21 -18
- package/dist/{work-cmd-VECTYST6.js → work-cmd-COESFSHE.js} +16 -13
- package/dist/{work-comment-cmd-F3NRWKPZ.js → work-comment-cmd-A4ZUVCSA.js} +16 -13
- package/dist/{work-logs-cmd-QF6P32FE.js → work-logs-cmd-CTF43MBE.js} +16 -13
- package/dist/{work-open-pr-cmd-XE23JA3R.js → work-open-pr-cmd-EMGYJXVD.js} +17 -14
- package/dist/{work-pr-cmd-BH56GUKN.js → work-pr-cmd-FEXMS6RH.js} +16 -13
- package/dist/{work-stop-cmd-C3F5HNUO.js → work-stop-cmd-NIHAN45R.js} +16 -13
- package/package.json +1 -1
- package/dist/build-HRLACBOZ.js +0 -12
- package/dist/chunk-STSLH5EJ.js +0 -71
- package/dist/init-SWKYV6CL.js +0 -55
- package/dist/loop-AIJZVUNA.js +0 -79
- package/dist/pending-3YZCSKON.js +0 -9
- package/dist/{chunk-6BLXUD56.js → chunk-HOU33DW5.js} +1 -1
|
@@ -1,28 +1,28 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
3
|
+
import { execCapture } from './chunk-MHAR6S7B.js';
|
|
4
|
+
import { GUEST_CID } from './chunk-WWQVKFN6.js';
|
|
5
|
+
import { keepStagedContext, describeCallFailure, controlPlaneTokenFailure, refusalCode, resolveGoverningSource, removeStagedContext, stageGovernedContext, pinnedSourceOf, commandWithShim, shimScript } from './chunk-USJZ2LDK.js';
|
|
6
|
+
import { runnerImageVersion } from './chunk-Z3ASAXVU.js';
|
|
7
|
+
import { hostAllowed } from './chunk-UXYLWVTQ.js';
|
|
8
|
+
import { readDefaultBranchHead, cloneRepository, buildRepositoryImage } from './chunk-T2QSWFSU.js';
|
|
7
9
|
import { startTimeOf, isSameProcess } from './chunk-JBJTC3UU.js';
|
|
8
10
|
import { currentCliBuild } from './chunk-OGFGZQA3.js';
|
|
9
|
-
import { createDockerHost, builderSpec, runnerLabelValue, RUNNER_LABEL, BUILD_LABEL, prepareRunArgs, containerRunArgs, HASH_ARGV, parseProgramHash, JUDGE_PROGRAM, containerExecArgs, childEnvironment, JUDGE_DIR, JUDGE_REPORT, MAX_REPORT_BYTES, spawnRun } from './chunk-
|
|
10
|
-
import { FIRECRACKER_VERSION, hostHelperPinned, firecrackerArch, MICROVM_ARCHES, RecipeError, DOCKER_FEATURE, CLAUDE_CODE_VERSION, GUEST_HELPER_SHA256, GUEST_ASSETS_BASE_URL, GUEST_KERNEL_SHA256, JAILER_BINARY_SHA256, FIRECRACKER_BINARY_SHA256, FIRECRACKER_SHA256, GUEST_ASSETS_VERSION, DEFAULT_BASE_IMAGE } from './chunk-2BTFKNTR.js';
|
|
11
|
-
import { execCapture } from './chunk-XBPUTQ7E.js';
|
|
12
|
-
import { GUEST_CID } from './chunk-GLUKDQS4.js';
|
|
13
|
-
import { WorkCommandError } from './chunk-55GNQPO6.js';
|
|
14
|
-
import { hostAllowed } from './chunk-UXYLWVTQ.js';
|
|
11
|
+
import { createDockerHost, builderSpec, runnerLabelValue, RUNNER_LABEL, BUILD_LABEL, prepareRunArgs, containerRunArgs, HASH_ARGV, parseProgramHash, JUDGE_PROGRAM, containerExecArgs, childEnvironment, JUDGE_DIR, JUDGE_REPORT, MAX_REPORT_BYTES, spawnRun } from './chunk-VC5J7QPV.js';
|
|
15
12
|
import { readDu } from './chunk-YJLHUKYS.js';
|
|
16
|
-
import {
|
|
13
|
+
import { FIRECRACKER_VERSION, hostHelperPinned, firecrackerArch, MICROVM_ARCHES, RecipeError, DOCKER_FEATURE, CLAUDE_CODE_VERSION, GUEST_HELPER_SHA256, GUEST_ASSETS_BASE_URL, GUEST_KERNEL_SHA256, JAILER_BINARY_SHA256, FIRECRACKER_BINARY_SHA256, FIRECRACKER_SHA256, GUEST_ASSETS_VERSION, DEFAULT_BASE_IMAGE } from './chunk-SJZL5F3F.js';
|
|
14
|
+
import { WorkCommandError } from './chunk-X52PMPOM.js';
|
|
15
|
+
import { setCustomScrubbers, setLocalIdentity, setRepoRoot, parseTranscript, scrubDeep, scrubText } from './chunk-UHU7H57K.js';
|
|
16
|
+
import { vmAssetsDir, RUNNER_DIR_MODE, rootfsPathFor, diskTemplatesDir, RUNNER_FILE_MODE, deliveryDir, ghConfigDir, runnerDirOfBuild, spoolDir, mirrorDir, buildDir, SHIM_DIR } from './chunk-5K3KB4YR.js';
|
|
17
|
+
import { repositoriesOf, primaryOf, RELAY_PORT, repositoryPath, CHECKOUT_DIR, lifecycleWorkdir, claudeCredential, buildEnvironment, startBuildServices, checkEnvironment, AGENT_CREDENTIAL_MISSING, checkoutPath, JOB_MOUNT } from './chunk-HXAEQPZR.js';
|
|
18
|
+
import { sharedSkillNames, skillConflictMessage } from './chunk-FGF52V4V.js';
|
|
17
19
|
import { versionAtLeast, MINIMUM_CLAUDE_VERSION } from './chunk-HCVLP7XA.js';
|
|
18
|
-
import { setCustomScrubbers, setLocalIdentity, setRepoRoot, parseTranscript, scrubDeep, scrubText } from './chunk-QE3UQAHK.js';
|
|
19
20
|
import { orderSessions, extractFacts, sessionsToTimeline } from './chunk-RKOTJQVG.js';
|
|
20
21
|
import { downconvertSession } from './chunk-QZBXLLTV.js';
|
|
21
|
-
import {
|
|
22
|
-
import { repositoriesOf, primaryOf, RELAY_PORT, repositoryPath, CHECKOUT_DIR, lifecycleWorkdir, claudeCredential, buildEnvironment, startBuildServices, checkEnvironment, AGENT_CREDENTIAL_MISSING, checkoutPath, JOB_MOUNT } from './chunk-2I3LIRZP.js';
|
|
22
|
+
import { realFdStorePort } from './chunk-XD4ZCMA4.js';
|
|
23
23
|
import { RELAY_USER, RELAY_ID, UNKNOWN_TRANSPORT_REASON, DOCKER_DESKTOP_REASON, MAX_MALFORMED_SESSIONS, MALFORMED_REASON, MAX_OPEN_STREAMS, STREAM_WINDOW, SESSION_WINDOW, targetOfPath } from './chunk-JGD5TWQ2.js';
|
|
24
|
-
import { readFileSync, mkdirSync, existsSync, mkdtempSync, rmSync, chmodSync, truncateSync, writeFileSync, readdirSync, lstatSync, copyFileSync, accessSync, constants, statSync, rmdirSync, renameSync, unlinkSync, openSync, closeSync, createWriteStream, createReadStream } from 'fs';
|
|
25
|
-
import { join, dirname, basename } from 'path';
|
|
24
|
+
import { readFileSync, mkdirSync, existsSync, mkdtempSync, rmSync, chmodSync, truncateSync, writeFileSync, readdirSync, lstatSync, copyFileSync, accessSync, constants, statSync, rmdirSync, renameSync, unlinkSync, openSync, closeSync, createWriteStream, createReadStream, writeSync } from 'fs';
|
|
25
|
+
import { join, dirname, resolve, basename } from 'path';
|
|
26
26
|
import { isIP, createConnection, connect, createServer as createServer$1 } from 'net';
|
|
27
27
|
import { spawnSync, spawn } from 'child_process';
|
|
28
28
|
import { availableParallelism, networkInterfaces } from 'os';
|
|
@@ -51,7 +51,8 @@ function prepareRunnerCgroup(setup) {
|
|
|
51
51
|
if (root === void 0) return void 0;
|
|
52
52
|
const { fs } = setup;
|
|
53
53
|
if (!fs.exists(root) || !fs.writable(join(root, "cgroup.procs"))) return void 0;
|
|
54
|
-
|
|
54
|
+
const controllers = (fs.read(join(root, "cgroup.controllers")) ?? "").split(/\s+/);
|
|
55
|
+
if (!controllers.includes("memory")) return void 0;
|
|
55
56
|
for (const name of fs.list(root)) {
|
|
56
57
|
if (!name.startsWith(BUILD_PREFIX)) continue;
|
|
57
58
|
try {
|
|
@@ -61,7 +62,7 @@ function prepareRunnerCgroup(setup) {
|
|
|
61
62
|
}
|
|
62
63
|
if (!fs.exists(join(root, LEAF))) fs.mkdir(join(root, LEAF));
|
|
63
64
|
fs.write(join(root, LEAF, "cgroup.procs"), String(setup.pid));
|
|
64
|
-
fs.write(join(root, "cgroup.subtree_control"), "+memory");
|
|
65
|
+
fs.write(join(root, "cgroup.subtree_control"), controllers.includes("io") ? "+memory +io" : "+memory");
|
|
65
66
|
return { root };
|
|
66
67
|
}
|
|
67
68
|
var BUILD_RECLAIM_HEADROOM_BYTES = 256 * 1024 ** 2;
|
|
@@ -161,7 +162,7 @@ var START_TIMEOUT_MS = 12e4;
|
|
|
161
162
|
var DEFAULT_REQUEST_TIMEOUT_MS = 3e4;
|
|
162
163
|
var MAX_REPLY_BYTES = 1024 * 1024;
|
|
163
164
|
function ask(socketPath, request, timeoutMs) {
|
|
164
|
-
return new Promise((
|
|
165
|
+
return new Promise((resolve2, reject) => {
|
|
165
166
|
const conn = createConnection(socketPath);
|
|
166
167
|
let text = "";
|
|
167
168
|
let settled = false;
|
|
@@ -187,7 +188,7 @@ function ask(socketPath, request, timeoutMs) {
|
|
|
187
188
|
return reject(new Error(`the helper at ${socketPath} sent a reply that is not JSON`));
|
|
188
189
|
}
|
|
189
190
|
if (reply.status === "refused") return reject(new HelperRefusal(String(reply.code ?? "refused"), String(reply.reason ?? "the helper refused the request")));
|
|
190
|
-
|
|
191
|
+
resolve2(reply);
|
|
191
192
|
});
|
|
192
193
|
});
|
|
193
194
|
conn.on("error", (err) => settle(() => reject(new Error(`the helper at ${socketPath} did not answer: ${err.message}`))));
|
|
@@ -374,6 +375,10 @@ function formatCpuList(cores) {
|
|
|
374
375
|
}
|
|
375
376
|
return parts.join(",");
|
|
376
377
|
}
|
|
378
|
+
function capCpus(wanted, cpuset) {
|
|
379
|
+
const cores = cpuset === void 0 ? void 0 : parseCpuList(cpuset);
|
|
380
|
+
return cores === void 0 ? wanted : Math.min(wanted, cores.length);
|
|
381
|
+
}
|
|
377
382
|
function usableCpus(deps = {}) {
|
|
378
383
|
try {
|
|
379
384
|
const status = (deps.readStatus ?? (() => readFileSync("/proc/self/status", "utf8")))();
|
|
@@ -643,9 +648,9 @@ function createContainerHost(deps = {}) {
|
|
|
643
648
|
stderr = (stderr + chunk.toString()).slice(-400);
|
|
644
649
|
});
|
|
645
650
|
child.stderr?.on("error", () => void 0);
|
|
646
|
-
const exited = new Promise((
|
|
647
|
-
child.once("error", () =>
|
|
648
|
-
child.once("close", (code) =>
|
|
651
|
+
const exited = new Promise((resolve2) => {
|
|
652
|
+
child.once("error", () => resolve2(-1));
|
|
653
|
+
child.once("close", (code) => resolve2(code ?? -1));
|
|
649
654
|
});
|
|
650
655
|
child.stdin.on("error", () => void 0);
|
|
651
656
|
return { stdin: child.stdin, stdout: child.stdout, exited, kill: () => void child.kill("SIGKILL"), stderrTail: () => stderr };
|
|
@@ -717,7 +722,7 @@ function converterArgs(dest, memoryBytes, extra, script) {
|
|
|
717
722
|
}
|
|
718
723
|
var firstLine2 = (text) => text.trim().split("\n")[0] ?? "";
|
|
719
724
|
function exportInto(container, converter) {
|
|
720
|
-
return new Promise((
|
|
725
|
+
return new Promise((resolve2, reject) => {
|
|
721
726
|
const exporter = spawn("docker", ["export", container], { stdio: ["ignore", "pipe", "pipe"], env: childEnvironment(process.env) });
|
|
722
727
|
const writer = spawn("docker", converter, { stdio: ["pipe", "ignore", "pipe"], env: childEnvironment(process.env) });
|
|
723
728
|
const errors = [];
|
|
@@ -734,7 +739,7 @@ function exportInto(container, converter) {
|
|
|
734
739
|
if (code !== 0 && failure2 === void 0) failure2 = `${name} exited ${code}`;
|
|
735
740
|
exits += 1;
|
|
736
741
|
if (exits < 2) return;
|
|
737
|
-
if (failure2 === void 0)
|
|
742
|
+
if (failure2 === void 0) resolve2();
|
|
738
743
|
else reject(new Error(`${failure2}: ${firstLine2(errors.join("\n"))}`));
|
|
739
744
|
};
|
|
740
745
|
exporter.once("exit", (code) => done("docker export", code));
|
|
@@ -819,6 +824,46 @@ async function createBuildDisk(input) {
|
|
|
819
824
|
function deleteBuildDisk(path) {
|
|
820
825
|
rmSync(path, { force: true });
|
|
821
826
|
}
|
|
827
|
+
var CONSOLE_CUT_NOTE = "[outerlayer runner: cut the console at 8 MiB; the microVM keeps running]\n";
|
|
828
|
+
function pumpConsole(fd, streams) {
|
|
829
|
+
const cap = 8 * 1024 ** 2;
|
|
830
|
+
let written = 0;
|
|
831
|
+
let lastByte = 10;
|
|
832
|
+
let cut = false;
|
|
833
|
+
const append = (data) => {
|
|
834
|
+
try {
|
|
835
|
+
writeSync(fd, data);
|
|
836
|
+
} catch {
|
|
837
|
+
}
|
|
838
|
+
};
|
|
839
|
+
const onData = (chunk) => {
|
|
840
|
+
if (cut) return;
|
|
841
|
+
const room = cap - written;
|
|
842
|
+
if (chunk.length <= room) {
|
|
843
|
+
append(chunk);
|
|
844
|
+
written += chunk.length;
|
|
845
|
+
lastByte = chunk[chunk.length - 1] ?? lastByte;
|
|
846
|
+
return;
|
|
847
|
+
}
|
|
848
|
+
const head = chunk.subarray(0, room);
|
|
849
|
+
append(head);
|
|
850
|
+
if (head.length > 0) lastByte = head[head.length - 1];
|
|
851
|
+
append(Buffer.from(`${lastByte === 10 ? "" : "\n"}${CONSOLE_CUT_NOTE}`));
|
|
852
|
+
written = cap;
|
|
853
|
+
cut = true;
|
|
854
|
+
};
|
|
855
|
+
let open = streams.length;
|
|
856
|
+
for (const stream of streams) {
|
|
857
|
+
stream.on("data", onData);
|
|
858
|
+
stream.on("error", () => void 0);
|
|
859
|
+
stream.once("close", () => {
|
|
860
|
+
open -= 1;
|
|
861
|
+
if (open === 0) closeSync(fd);
|
|
862
|
+
});
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
// src/runner/microvm/firecracker.ts
|
|
822
867
|
var clearBit = (bit) => `0b${"x".repeat(31 - bit)}0${"x".repeat(bit)}`;
|
|
823
868
|
var CPU_TEMPLATE = {
|
|
824
869
|
cpuid_modifiers: [
|
|
@@ -859,8 +904,9 @@ function machineConfig(limits2, paths) {
|
|
|
859
904
|
}
|
|
860
905
|
function firecrackerCommand(input) {
|
|
861
906
|
const args = ["--no-api", "--config-file", input.configPath];
|
|
862
|
-
|
|
863
|
-
|
|
907
|
+
const binary = resolve(input.binary);
|
|
908
|
+
if (input.cgroup === void 0) return { command: binary, args };
|
|
909
|
+
return { command: "/bin/sh", args: ["-c", 'echo $$ > "$1/cgroup.procs" && shift && exec "$@"', "sh", input.cgroup, binary, ...args] };
|
|
864
910
|
}
|
|
865
911
|
var STOP_WAIT_MS = 1e4;
|
|
866
912
|
var POLL_MS = 20;
|
|
@@ -874,6 +920,7 @@ function isZombie(pid) {
|
|
|
874
920
|
}
|
|
875
921
|
function createFirecrackerHost(options = {}) {
|
|
876
922
|
const launch = options.launch ?? firecrackerCommand;
|
|
923
|
+
const spawnChild = options.spawnChild ?? spawn;
|
|
877
924
|
const exits = /* @__PURE__ */ new Map();
|
|
878
925
|
const alive = (vm) => isSameProcess(vm.pid, vm.start) && !isZombie(vm.pid);
|
|
879
926
|
return {
|
|
@@ -881,18 +928,22 @@ function createFirecrackerHost(options = {}) {
|
|
|
881
928
|
const { command, args } = launch(input);
|
|
882
929
|
mkdirSync(dirname(input.consolePath), { recursive: true });
|
|
883
930
|
const consoleFd = openSync(input.consolePath, "a", 384);
|
|
931
|
+
let pumping = false;
|
|
884
932
|
try {
|
|
885
|
-
const child =
|
|
933
|
+
const child = spawnChild(command, args, { detached: true, stdio: ["ignore", "pipe", "pipe"], env: {} });
|
|
934
|
+
pumpConsole(consoleFd, [child.stdout, child.stderr]);
|
|
935
|
+
pumping = true;
|
|
936
|
+
for (const stream of [child.stdout, child.stderr]) stream.unref?.();
|
|
886
937
|
const failed = new Promise((_resolve, reject) => child.once("error", reject));
|
|
887
938
|
const pid = child.pid;
|
|
888
939
|
if (pid === void 0) return await failed;
|
|
889
|
-
exits.set(pid, new Promise((
|
|
940
|
+
exits.set(pid, new Promise((resolve2) => child.once("exit", () => resolve2())));
|
|
890
941
|
child.unref();
|
|
891
942
|
const start = startTimeOf(pid);
|
|
892
943
|
if (start === null) throw new Error(`${command} exited as soon as it started; its console is at ${input.consolePath}`);
|
|
893
944
|
return { pid, start };
|
|
894
945
|
} finally {
|
|
895
|
-
closeSync(consoleFd);
|
|
946
|
+
if (!pumping) closeSync(consoleFd);
|
|
896
947
|
}
|
|
897
948
|
},
|
|
898
949
|
async stop(vm) {
|
|
@@ -903,8 +954,8 @@ function createFirecrackerHost(options = {}) {
|
|
|
903
954
|
}
|
|
904
955
|
const exited = exits.get(vm.pid);
|
|
905
956
|
const deadline = Date.now() + STOP_WAIT_MS;
|
|
906
|
-
if (exited !== void 0) await Promise.race([exited, new Promise((
|
|
907
|
-
while (alive(vm) && Date.now() < deadline) await new Promise((
|
|
957
|
+
if (exited !== void 0) await Promise.race([exited, new Promise((resolve2) => setTimeout(resolve2, STOP_WAIT_MS))]);
|
|
958
|
+
while (alive(vm) && Date.now() < deadline) await new Promise((resolve2) => setTimeout(resolve2, POLL_MS));
|
|
908
959
|
exits.delete(vm.pid);
|
|
909
960
|
},
|
|
910
961
|
alive
|
|
@@ -1312,6 +1363,29 @@ async function resolveAgentUser(input) {
|
|
|
1312
1363
|
var noop = () => void 0;
|
|
1313
1364
|
var FRAME_HEADER_BYTES = 9;
|
|
1314
1365
|
var GOAWAY_FRAME = 7;
|
|
1366
|
+
function describeGoawayCode(code) {
|
|
1367
|
+
const names = [
|
|
1368
|
+
"NO_ERROR",
|
|
1369
|
+
"PROTOCOL_ERROR",
|
|
1370
|
+
"INTERNAL_ERROR",
|
|
1371
|
+
"FLOW_CONTROL_ERROR",
|
|
1372
|
+
"SETTINGS_TIMEOUT",
|
|
1373
|
+
"STREAM_CLOSED",
|
|
1374
|
+
"FRAME_SIZE_ERROR",
|
|
1375
|
+
"REFUSED_STREAM",
|
|
1376
|
+
"CANCEL",
|
|
1377
|
+
"COMPRESSION_ERROR",
|
|
1378
|
+
"CONNECT_ERROR",
|
|
1379
|
+
"ENHANCE_YOUR_CALM",
|
|
1380
|
+
"INADEQUATE_SECURITY",
|
|
1381
|
+
"HTTP_1_1_REQUIRED"
|
|
1382
|
+
];
|
|
1383
|
+
const name = names[code];
|
|
1384
|
+
return name === void 0 ? `error code ${code}` : `${name} (${code})`;
|
|
1385
|
+
}
|
|
1386
|
+
function goawayNote(label, code) {
|
|
1387
|
+
return code === void 0 ? "" : ` \xB7 ${label} ${describeGoawayCode(code)}`;
|
|
1388
|
+
}
|
|
1315
1389
|
function watchSentGoaway(onError) {
|
|
1316
1390
|
let head = Buffer.alloc(0);
|
|
1317
1391
|
let want = FRAME_HEADER_BYTES;
|
|
@@ -1334,7 +1408,10 @@ function watchSentGoaway(onError) {
|
|
|
1334
1408
|
want = FRAME_HEADER_BYTES + 8;
|
|
1335
1409
|
continue;
|
|
1336
1410
|
}
|
|
1337
|
-
if (want > FRAME_HEADER_BYTES
|
|
1411
|
+
if (want > FRAME_HEADER_BYTES) {
|
|
1412
|
+
const code = head.readUInt32BE(FRAME_HEADER_BYTES + 4);
|
|
1413
|
+
if (code !== http2.constants.NGHTTP2_NO_ERROR) onError(code);
|
|
1414
|
+
}
|
|
1338
1415
|
skip = length - (want - FRAME_HEADER_BYTES);
|
|
1339
1416
|
head = Buffer.alloc(0);
|
|
1340
1417
|
want = FRAME_HEADER_BYTES;
|
|
@@ -1346,9 +1423,11 @@ function serveSession(transport, services, opts = {}) {
|
|
|
1346
1423
|
let open = 0;
|
|
1347
1424
|
let served = 0;
|
|
1348
1425
|
let malformed = false;
|
|
1426
|
+
let goawayCode;
|
|
1349
1427
|
transport.on("error", noop);
|
|
1350
|
-
const watch = watchSentGoaway(() => {
|
|
1428
|
+
const watch = watchSentGoaway((code) => {
|
|
1351
1429
|
malformed = true;
|
|
1430
|
+
goawayCode ??= code;
|
|
1352
1431
|
setImmediate(() => session.destroy());
|
|
1353
1432
|
});
|
|
1354
1433
|
const outbound = new Transform({
|
|
@@ -1366,11 +1445,14 @@ function serveSession(transport, services, opts = {}) {
|
|
|
1366
1445
|
session.setLocalWindowSize(SESSION_WINDOW);
|
|
1367
1446
|
} catch {
|
|
1368
1447
|
}
|
|
1369
|
-
const ended = new Promise((
|
|
1448
|
+
const ended = new Promise((resolve2) => {
|
|
1370
1449
|
session.on("error", (err) => {
|
|
1371
1450
|
if (typeof err.code === "string" && err.code.startsWith("ERR_HTTP2_")) malformed = true;
|
|
1372
1451
|
});
|
|
1373
|
-
session.on("
|
|
1452
|
+
session.on("goaway", (code) => {
|
|
1453
|
+
if (code !== http2.constants.NGHTTP2_NO_ERROR) goawayCode ??= code;
|
|
1454
|
+
});
|
|
1455
|
+
session.on("close", () => resolve2({ malformed, served, goawayCode }));
|
|
1374
1456
|
});
|
|
1375
1457
|
session.on("stream", (stream, headers) => {
|
|
1376
1458
|
stream.on("error", noop);
|
|
@@ -1404,14 +1486,14 @@ var JOINED_AFTER_MS = 2e3;
|
|
|
1404
1486
|
var EXIT_WAIT_MS = 5e3;
|
|
1405
1487
|
function exitedWithin(stream, ms) {
|
|
1406
1488
|
let timer;
|
|
1407
|
-
const late = new Promise((
|
|
1408
|
-
timer = setTimeout(() =>
|
|
1489
|
+
const late = new Promise((resolve2) => {
|
|
1490
|
+
timer = setTimeout(() => resolve2(void 0), ms);
|
|
1409
1491
|
timer.unref();
|
|
1410
1492
|
});
|
|
1411
1493
|
return Promise.race([stream.exited, late]).finally(() => clearTimeout(timer));
|
|
1412
1494
|
}
|
|
1413
1495
|
function superviseRelay(input) {
|
|
1414
|
-
const sleep = input.sleep ?? ((ms) => new Promise((
|
|
1496
|
+
const sleep = input.sleep ?? ((ms) => new Promise((resolve2) => setTimeout(resolve2, ms)));
|
|
1415
1497
|
const exitWaitMs = input.exitWaitMs ?? EXIT_WAIT_MS;
|
|
1416
1498
|
let closed = false;
|
|
1417
1499
|
let fatal;
|
|
@@ -1444,14 +1526,14 @@ function superviseRelay(input) {
|
|
|
1444
1526
|
if (joined) {
|
|
1445
1527
|
backoff = FIRST_BACKOFF_MS;
|
|
1446
1528
|
failing = false;
|
|
1447
|
-
if (!closed) input.log?.(`the session with ${input.container} ended \xB7 joining again`);
|
|
1529
|
+
if (!closed) input.log?.(`the session with ${input.container} ended \xB7 joining again${goawayNote("GOAWAY", end.goawayCode)}`);
|
|
1448
1530
|
}
|
|
1449
1531
|
if (!end.malformed && end.served > 0) malformedInARow = 0;
|
|
1450
1532
|
if (end.malformed) {
|
|
1451
1533
|
malformedInARow++;
|
|
1452
1534
|
if (malformedInARow >= MAX_MALFORMED_SESSIONS) {
|
|
1453
1535
|
fatal = MALFORMED_REASON;
|
|
1454
|
-
input.log?.(`the session with ${input.container} broke HTTP/2 framing ${malformedInARow} times in a row \xB7 ending the build`);
|
|
1536
|
+
input.log?.(`the session with ${input.container} broke HTTP/2 framing ${malformedInARow} times in a row${goawayNote("last GOAWAY", end.goawayCode)} \xB7 ending the build`);
|
|
1455
1537
|
input.onFatal?.(fatal);
|
|
1456
1538
|
return;
|
|
1457
1539
|
}
|
|
@@ -1461,7 +1543,7 @@ function superviseRelay(input) {
|
|
|
1461
1543
|
input.log?.(`could not join the relay in ${input.container}${status === 0 || status === void 0 ? "" : ` (exec exited ${status})`}${reason === "" ? "" : `: ${reason}`} \xB7 trying again`);
|
|
1462
1544
|
}
|
|
1463
1545
|
if (closed) return;
|
|
1464
|
-
await Promise.race([sleep(backoff), new Promise((
|
|
1546
|
+
await Promise.race([sleep(backoff), new Promise((resolve2) => wake = resolve2)]);
|
|
1465
1547
|
backoff = Math.min(backoff * 2, LONGEST_BACKOFF_MS);
|
|
1466
1548
|
}
|
|
1467
1549
|
})();
|
|
@@ -1652,9 +1734,9 @@ async function git(args, cwd, env, input) {
|
|
|
1652
1734
|
if (size < maxOutputBytes) out.push(chunk);
|
|
1653
1735
|
size += chunk.length;
|
|
1654
1736
|
});
|
|
1655
|
-
const closed = new Promise((
|
|
1737
|
+
const closed = new Promise((resolve2, reject) => {
|
|
1656
1738
|
child.once("error", reject);
|
|
1657
|
-
child.once("close", (status) =>
|
|
1739
|
+
child.once("close", (status) => resolve2(status));
|
|
1658
1740
|
});
|
|
1659
1741
|
if (input !== void 0) {
|
|
1660
1742
|
await pipeline(input, child.stdin).catch(() => void 0);
|
|
@@ -1851,14 +1933,14 @@ async function drain(req) {
|
|
|
1851
1933
|
}
|
|
1852
1934
|
}
|
|
1853
1935
|
function readPrefix(req, gzip) {
|
|
1854
|
-
return new Promise((
|
|
1936
|
+
return new Promise((resolve2, reject) => {
|
|
1855
1937
|
const held = [];
|
|
1856
1938
|
const finish = (section) => {
|
|
1857
1939
|
req.off("data", onData);
|
|
1858
1940
|
req.off("end", onEnd);
|
|
1859
1941
|
req.off("error", reject);
|
|
1860
1942
|
req.pause();
|
|
1861
|
-
|
|
1943
|
+
resolve2({ held, section });
|
|
1862
1944
|
};
|
|
1863
1945
|
const onData = (chunk) => {
|
|
1864
1946
|
held.push(chunk);
|
|
@@ -1872,19 +1954,19 @@ function readPrefix(req, gzip) {
|
|
|
1872
1954
|
});
|
|
1873
1955
|
}
|
|
1874
1956
|
function readBody(req, limit) {
|
|
1875
|
-
return new Promise((
|
|
1957
|
+
return new Promise((resolve2, reject) => {
|
|
1876
1958
|
const chunks = [];
|
|
1877
1959
|
let size = 0;
|
|
1878
1960
|
req.on("data", (chunk) => {
|
|
1879
1961
|
size += chunk.length;
|
|
1880
1962
|
if (size > limit) {
|
|
1881
1963
|
req.pause();
|
|
1882
|
-
|
|
1964
|
+
resolve2(void 0);
|
|
1883
1965
|
return;
|
|
1884
1966
|
}
|
|
1885
1967
|
chunks.push(chunk);
|
|
1886
1968
|
});
|
|
1887
|
-
req.once("end", () =>
|
|
1969
|
+
req.once("end", () => resolve2(Buffer.concat(chunks)));
|
|
1888
1970
|
req.once("error", reject);
|
|
1889
1971
|
});
|
|
1890
1972
|
}
|
|
@@ -1898,7 +1980,7 @@ function createGitRemote(options) {
|
|
|
1898
1980
|
const { route, res } = input;
|
|
1899
1981
|
const url = new URL(`${gitUrl}/${route.owner}/${route.name}.git/${route.kind === "info-refs" ? "info/refs" : route.kind === "lfs-batch" ? "info/lfs/objects/batch" : `git-${route.kind}`}${route.search === "" ? "" : `?${route.search}`}`);
|
|
1900
1982
|
const send = url.protocol === "https:" ? request$1 : request;
|
|
1901
|
-
return new Promise((
|
|
1983
|
+
return new Promise((resolve2) => {
|
|
1902
1984
|
const upstream = send(url, { method: input.method, headers: { ...input.headers, connection: "close" } }, (answer) => {
|
|
1903
1985
|
const headers = {};
|
|
1904
1986
|
for (const [name, value] of Object.entries(answer.headers)) {
|
|
@@ -1920,18 +2002,18 @@ function createGitRemote(options) {
|
|
|
1920
2002
|
});
|
|
1921
2003
|
answer.once("end", () => {
|
|
1922
2004
|
res.end();
|
|
1923
|
-
|
|
2005
|
+
resolve2();
|
|
1924
2006
|
});
|
|
1925
2007
|
answer.once("error", () => {
|
|
1926
2008
|
res.destroy();
|
|
1927
|
-
|
|
2009
|
+
resolve2();
|
|
1928
2010
|
});
|
|
1929
2011
|
});
|
|
1930
2012
|
upstream.on("error", (err) => {
|
|
1931
2013
|
log(`could not reach GitHub for ${route.kind}: ${err.message}`);
|
|
1932
2014
|
if (res.headersSent) res.destroy();
|
|
1933
2015
|
else plain(res, 502, "the runner could not reach GitHub\n");
|
|
1934
|
-
|
|
2016
|
+
resolve2();
|
|
1935
2017
|
});
|
|
1936
2018
|
res.once("close", () => upstream.destroy());
|
|
1937
2019
|
input.feed(upstream);
|
|
@@ -2228,6 +2310,9 @@ var CONNECT_TIMEOUT_MS = 3e4;
|
|
|
2228
2310
|
var NOT_ALLOWED_RANGE = "not-allowed";
|
|
2229
2311
|
var NOT_RESOLVED = "not resolved";
|
|
2230
2312
|
var IDLE_TIMEOUT_MS = 10 * 6e4;
|
|
2313
|
+
var STALLED_RESPONSE_MS = 6e4;
|
|
2314
|
+
var MAX_BAD_GATEWAY_LINES = 10;
|
|
2315
|
+
var BAD_GATEWAY_WINDOW_MS = 1e4;
|
|
2231
2316
|
async function systemResolve(host) {
|
|
2232
2317
|
const found = await lookup(host, { all: true, verbatim: true });
|
|
2233
2318
|
return found.map((a) => ({ address: a.address }));
|
|
@@ -2235,6 +2320,13 @@ async function systemResolve(host) {
|
|
|
2235
2320
|
function systemHostAddresses() {
|
|
2236
2321
|
return Object.values(networkInterfaces()).flatMap((list) => (list ?? []).map((i) => i.address));
|
|
2237
2322
|
}
|
|
2323
|
+
function errorCode(err) {
|
|
2324
|
+
const code = err?.code;
|
|
2325
|
+
return typeof code === "string" ? code : "unknown";
|
|
2326
|
+
}
|
|
2327
|
+
function abortedError(message) {
|
|
2328
|
+
return Object.assign(new Error(message), { code: "ECONNABORTED" });
|
|
2329
|
+
}
|
|
2238
2330
|
function normalize(address) {
|
|
2239
2331
|
const zone = address.indexOf("%");
|
|
2240
2332
|
return (zone === -1 ? address : address.slice(0, zone)).toLowerCase();
|
|
@@ -2249,11 +2341,31 @@ async function startTunnel(socketPath, opts = {}) {
|
|
|
2249
2341
|
if (Buffer.byteLength(socketPath) > MAX_SOCKET_PATH_BYTES) {
|
|
2250
2342
|
throw new Error(`${socketPath} is too long for a Unix socket; keep the runner's config file nearer the root of the filesystem`);
|
|
2251
2343
|
}
|
|
2252
|
-
const
|
|
2344
|
+
const resolve2 = opts.resolve ?? systemResolve;
|
|
2253
2345
|
const openConnection = opts.connect ?? ((t) => connect({ host: t.address, port: t.port }));
|
|
2254
2346
|
const ownAddresses = opts.hostAddresses ?? systemHostAddresses;
|
|
2255
2347
|
const connectTimeoutMs = opts.connectTimeoutMs ?? CONNECT_TIMEOUT_MS;
|
|
2256
2348
|
const idleTimeoutMs = opts.idleTimeoutMs ?? IDLE_TIMEOUT_MS;
|
|
2349
|
+
const stalledResponseMs = opts.stalledResponseMs ?? STALLED_RESPONSE_MS;
|
|
2350
|
+
let windowStartedMs = 0;
|
|
2351
|
+
let linesInWindow = 0;
|
|
2352
|
+
let suppressed = 0;
|
|
2353
|
+
const logBadGateway = (what) => {
|
|
2354
|
+
if (opts.log === void 0) return;
|
|
2355
|
+
const now = Date.now();
|
|
2356
|
+
if (now - windowStartedMs >= BAD_GATEWAY_WINDOW_MS) {
|
|
2357
|
+
windowStartedMs = now;
|
|
2358
|
+
linesInWindow = 0;
|
|
2359
|
+
}
|
|
2360
|
+
if (linesInWindow >= MAX_BAD_GATEWAY_LINES) {
|
|
2361
|
+
suppressed++;
|
|
2362
|
+
return;
|
|
2363
|
+
}
|
|
2364
|
+
linesInWindow++;
|
|
2365
|
+
const more = suppressed === 0 ? "" : ` (${suppressed} more 502 lines were not written)`;
|
|
2366
|
+
suppressed = 0;
|
|
2367
|
+
opts.log(`tunnel answered 502: ${what}${more}`);
|
|
2368
|
+
};
|
|
2257
2369
|
const hosts = [];
|
|
2258
2370
|
const seen = /* @__PURE__ */ new Set();
|
|
2259
2371
|
const extraHosts = /* @__PURE__ */ new Set();
|
|
@@ -2325,7 +2437,7 @@ async function startTunnel(socketPath, opts = {}) {
|
|
|
2325
2437
|
}
|
|
2326
2438
|
persist();
|
|
2327
2439
|
};
|
|
2328
|
-
async function decide(host) {
|
|
2440
|
+
async function decide(host, port) {
|
|
2329
2441
|
if (opts.allowHosts !== void 0 && !hostAllowed(host, opts.allowHosts)) {
|
|
2330
2442
|
refused2(host, NOT_RESOLVED, NOT_ALLOWED_RANGE);
|
|
2331
2443
|
return { ok: false, status: 403, body: `refused: ${host} is not in runner.build.allowHosts
|
|
@@ -2333,13 +2445,17 @@ async function startTunnel(socketPath, opts = {}) {
|
|
|
2333
2445
|
}
|
|
2334
2446
|
let addresses;
|
|
2335
2447
|
try {
|
|
2336
|
-
addresses = await
|
|
2337
|
-
} catch {
|
|
2448
|
+
addresses = await resolve2(host);
|
|
2449
|
+
} catch (err) {
|
|
2450
|
+
logBadGateway(`could not resolve ${host}:${port}, ${errorCode(err)}`);
|
|
2338
2451
|
return { ok: false, status: 502, body: `could not resolve ${host}
|
|
2339
2452
|
` };
|
|
2340
2453
|
}
|
|
2341
|
-
if (addresses.length === 0)
|
|
2454
|
+
if (addresses.length === 0) {
|
|
2455
|
+
logBadGateway(`${host}:${port} resolved to no address`);
|
|
2456
|
+
return { ok: false, status: 502, body: `${host} has no address
|
|
2342
2457
|
` };
|
|
2458
|
+
}
|
|
2343
2459
|
const own = new Set(ownAddresses().map(normalize));
|
|
2344
2460
|
let firstRefusal;
|
|
2345
2461
|
for (const { address: address2 } of addresses) {
|
|
@@ -2381,36 +2497,70 @@ ${body}`);
|
|
|
2381
2497
|
client.end("HTTP/1.1 400 Bad Request\r\nConnection: close\r\nContent-Length: 0\r\n\r\n");
|
|
2382
2498
|
return;
|
|
2383
2499
|
}
|
|
2384
|
-
const decision = await decide(target.host);
|
|
2500
|
+
const decision = await decide(target.host, target.port);
|
|
2385
2501
|
if (!decision.ok) {
|
|
2386
2502
|
reply(client, decision.status, decision.body);
|
|
2387
2503
|
return;
|
|
2388
2504
|
}
|
|
2389
2505
|
const upstream = openConnection({ address: decision.address, port: target.port });
|
|
2390
2506
|
upstream.setTimeout(connectTimeoutMs);
|
|
2391
|
-
const failed = () => {
|
|
2507
|
+
const failed = (err) => {
|
|
2392
2508
|
upstream.destroy();
|
|
2509
|
+
logBadGateway(`could not connect to ${target.host}:${target.port}, ${err === void 0 ? "ETIMEDOUT" : errorCode(err)}`);
|
|
2393
2510
|
reply(client, 502, `could not connect to ${target.host}
|
|
2394
2511
|
`);
|
|
2395
2512
|
};
|
|
2513
|
+
const timedOut = () => failed();
|
|
2396
2514
|
upstream.once("error", failed);
|
|
2397
|
-
upstream.once("timeout",
|
|
2515
|
+
upstream.once("timeout", timedOut);
|
|
2398
2516
|
client.on("close", () => upstream.destroy());
|
|
2399
2517
|
const established = () => {
|
|
2400
2518
|
upstream.removeListener("error", failed);
|
|
2401
|
-
upstream.removeListener("timeout",
|
|
2519
|
+
upstream.removeListener("timeout", timedOut);
|
|
2402
2520
|
upstream.setTimeout(idleTimeoutMs, () => upstream.destroy());
|
|
2403
|
-
upstream.on("error", () =>
|
|
2404
|
-
upstream.on("close", () =>
|
|
2521
|
+
upstream.on("error", (err) => client.destroy(err));
|
|
2522
|
+
upstream.on("close", () => {
|
|
2523
|
+
if (!upstream.readableEnded && !client.writableEnded) client.destroy(abortedError("the tunnel closed the connection to the server before it ended"));
|
|
2524
|
+
});
|
|
2525
|
+
client.once("end", () => {
|
|
2526
|
+
upstream.destroy();
|
|
2527
|
+
client.end();
|
|
2528
|
+
});
|
|
2405
2529
|
reached(target.host);
|
|
2406
2530
|
client.write("HTTP/1.1 200 Connection Established\r\n\r\n");
|
|
2407
2531
|
upstream.write(head);
|
|
2532
|
+
releaseWhenStalled(client, upstream);
|
|
2408
2533
|
upstream.pipe(client);
|
|
2409
2534
|
client.pipe(upstream);
|
|
2410
2535
|
};
|
|
2411
2536
|
if (upstream.readyState === "open") established();
|
|
2412
2537
|
else upstream.once("connect", established);
|
|
2413
2538
|
}
|
|
2539
|
+
function releaseWhenStalled(client, upstream) {
|
|
2540
|
+
let delivered = 0;
|
|
2541
|
+
upstream.on("data", (chunk) => delivered += chunk.length);
|
|
2542
|
+
let read = delivered;
|
|
2543
|
+
let timer;
|
|
2544
|
+
const blocked = () => upstream.isPaused() || upstream.readableEnded;
|
|
2545
|
+
const check = () => {
|
|
2546
|
+
timer = void 0;
|
|
2547
|
+
if (client.writableFinished || !blocked()) return;
|
|
2548
|
+
if (delivered > read) {
|
|
2549
|
+
read = delivered;
|
|
2550
|
+
timer = setTimeout(check, stalledResponseMs);
|
|
2551
|
+
return;
|
|
2552
|
+
}
|
|
2553
|
+
client.destroy(abortedError("the build stopped reading the response"));
|
|
2554
|
+
};
|
|
2555
|
+
const watch = () => {
|
|
2556
|
+
if (timer !== void 0) return;
|
|
2557
|
+
read = delivered;
|
|
2558
|
+
timer = setTimeout(check, stalledResponseMs);
|
|
2559
|
+
};
|
|
2560
|
+
upstream.on("pause", watch);
|
|
2561
|
+
upstream.on("end", watch);
|
|
2562
|
+
client.once("close", () => clearTimeout(timer));
|
|
2563
|
+
}
|
|
2414
2564
|
async function proxyPlain(req, res) {
|
|
2415
2565
|
if (opts.gitRemote !== void 0 && (req.url ?? "").startsWith("/")) {
|
|
2416
2566
|
await opts.gitRemote(req, res);
|
|
@@ -2431,7 +2581,7 @@ ${body}`);
|
|
|
2431
2581
|
}
|
|
2432
2582
|
const host = url.hostname.replace(/^\[|\]$/g, "");
|
|
2433
2583
|
const port = url.port === "" ? 80 : Number(url.port);
|
|
2434
|
-
const decision = await decide(host);
|
|
2584
|
+
const decision = await decide(host, port);
|
|
2435
2585
|
if (!decision.ok) {
|
|
2436
2586
|
res.writeHead(decision.status, { "Content-Type": "text/plain", Connection: "close" });
|
|
2437
2587
|
res.end(decision.body);
|
|
@@ -2456,8 +2606,9 @@ ${body}`);
|
|
|
2456
2606
|
);
|
|
2457
2607
|
upstream.setTimeout(connectTimeoutMs, () => upstream.destroy());
|
|
2458
2608
|
res.on("close", () => upstream.destroy());
|
|
2459
|
-
upstream.on("error", () => {
|
|
2609
|
+
upstream.on("error", (err) => {
|
|
2460
2610
|
if (!res.headersSent) {
|
|
2611
|
+
logBadGateway(`could not reach ${host}:${port}, ${errorCode(err)}`);
|
|
2461
2612
|
res.writeHead(502, { "Content-Type": "text/plain", Connection: "close" });
|
|
2462
2613
|
res.end(`could not reach ${host}
|
|
2463
2614
|
`);
|
|
@@ -2510,6 +2661,9 @@ var RELAY_WAIT_MS = 500;
|
|
|
2510
2661
|
var BUSY_IMAGE_WAIT_MS = 5e3;
|
|
2511
2662
|
var VOLUME_REMOVE_ATTEMPTS = 4;
|
|
2512
2663
|
var WORKFLOW_PERMISSION_REASON = "workflow_permission_required";
|
|
2664
|
+
function withTunnelLog(opts, log) {
|
|
2665
|
+
return { ...opts, tunnelOptions: { log, ...opts?.tunnelOptions } };
|
|
2666
|
+
}
|
|
2513
2667
|
function createContainerRuntime(opts = {}) {
|
|
2514
2668
|
const { cli, remoteFor } = opts;
|
|
2515
2669
|
return {
|
|
@@ -2534,7 +2688,7 @@ function createContainerRuntime(opts = {}) {
|
|
|
2534
2688
|
)),
|
|
2535
2689
|
startTunnel: opts.startTunnel ?? startTunnel,
|
|
2536
2690
|
tunnelOptions: opts.tunnelOptions,
|
|
2537
|
-
sleep: opts.sleep ?? ((ms) => new Promise((
|
|
2691
|
+
sleep: opts.sleep ?? ((ms) => new Promise((resolve2) => setTimeout(resolve2, ms))),
|
|
2538
2692
|
hostEnv: opts.hostEnv ?? process.env,
|
|
2539
2693
|
platform: opts.platform ?? process.platform,
|
|
2540
2694
|
credentials: opts.credentials ?? /* @__PURE__ */ new Map(),
|
|
@@ -2835,7 +2989,7 @@ async function provisionContainer(input) {
|
|
|
2835
2989
|
} catch (err) {
|
|
2836
2990
|
return bail(`the tunnel could not start: ${describeCallFailure(err)}`);
|
|
2837
2991
|
}
|
|
2838
|
-
const limits2 = { memory: config.build?.memory ?? "8g", cpus: config.build?.cpus ?? 4, pids: config.build?.pids ?? 4096, cpuset: state.cpuset };
|
|
2992
|
+
const limits2 = { memory: config.build?.memory ?? "8g", cpus: capCpus(config.build?.cpus ?? 4, state.cpuset), pids: config.build?.pids ?? 4096, cpuset: state.cpuset };
|
|
2839
2993
|
const runnerId = runnerLabelValue(config.configPath);
|
|
2840
2994
|
const volume = await host.createVolume(name, { [BUILD_LABEL]: buildId, [RUNNER_LABEL]: runnerId });
|
|
2841
2995
|
if (volume.status !== 0) return dockerFailed("creating the build's volume", volume);
|
|
@@ -3017,8 +3171,8 @@ async function stopContainer(runtime, state) {
|
|
|
3017
3171
|
var DISK_CHECK_MS = 12e4;
|
|
3018
3172
|
async function measureDisk(runtime, state) {
|
|
3019
3173
|
let timer;
|
|
3020
|
-
const late = new Promise((
|
|
3021
|
-
timer = setTimeout(() =>
|
|
3174
|
+
const late = new Promise((resolve2) => {
|
|
3175
|
+
timer = setTimeout(() => resolve2({ failure: "du ran past 2 minutes" }), DISK_CHECK_MS);
|
|
3022
3176
|
});
|
|
3023
3177
|
try {
|
|
3024
3178
|
const run = runtime.host.exec(
|
|
@@ -3306,7 +3460,7 @@ async function startCheckContainer(input) {
|
|
|
3306
3460
|
} catch (err) {
|
|
3307
3461
|
return fail(`the tunnel could not start: ${describeCallFailure(err)}`);
|
|
3308
3462
|
}
|
|
3309
|
-
const limits2 = { memory: config.build?.memory ?? "8g", cpus: config.build?.cpus ?? 4, pids: config.build?.pids ?? 4096, cpuset };
|
|
3463
|
+
const limits2 = { memory: config.build?.memory ?? "8g", cpus: capCpus(config.build?.cpus ?? 4, cpuset), pids: config.build?.pids ?? 4096, cpuset };
|
|
3310
3464
|
const runnerId = runnerLabelValue(config.configPath);
|
|
3311
3465
|
const volume = await host.createVolume(name, { [BUILD_LABEL]: buildId, [RUNNER_LABEL]: runnerId });
|
|
3312
3466
|
if (volume.status !== 0) return dockerFailed("creating the check environment's volume", volume);
|
|
@@ -3370,4 +3524,4 @@ async function startCheckContainer(input) {
|
|
|
3370
3524
|
};
|
|
3371
3525
|
}
|
|
3372
3526
|
|
|
3373
|
-
export { ADDED_USER, AgentUserError, AssetError, DeliveryFailure, EVAL_INPUT_NAME, GH_CONFIG_YML, HelperRefusal, LEASE_SECONDS, MIN_ENGINE_MAJOR, cleanupContainer, containerCommandExec, containerJudgeEnvironment, containerSenderCommand, copyJudgeTree, copyTranscripts, copyTranscriptsFromContainer, createBuildDisk, createContainerRuntime, createLeaseChannel, deleteBuildDisk, deliverContainerHooks, ensureFirecrackerAndJailer, ensureRootfs, ensureTunnel, filesAreCopied, ghHostsYml, gitRemoteFor, helperFirecrackerNote, helperSocketPath, isLiteralAddress, keepGhConfigCurrent, leaseExpiresAtMs, leaseTimeLeftMs, lifecycleFailureReason, lifecycleSteps, machineConfig, measureDisk, obtainImage, outOfMemoryReason, parseCpuList, prepareBranch, probeHelper, provisionContainer, resolveAgentUser, runBuildSteps, senderAliveScript, senderSignalScript, setUpRunnerCgroup, shellQuote, signalInContainer, startCheckContainer, startServicesFor, stopContainer, syncInContainer, writeEvalInput };
|
|
3527
|
+
export { ADDED_USER, AgentUserError, AssetError, DeliveryFailure, EVAL_INPUT_NAME, GH_CONFIG_YML, HelperRefusal, LEASE_SECONDS, MIN_ENGINE_MAJOR, cleanupContainer, containerCommandExec, containerJudgeEnvironment, containerSenderCommand, copyJudgeTree, copyTranscripts, copyTranscriptsFromContainer, createBuildDisk, createContainerRuntime, createLeaseChannel, deleteBuildDisk, deliverContainerHooks, ensureFirecrackerAndJailer, ensureRootfs, ensureTunnel, filesAreCopied, ghHostsYml, gitRemoteFor, helperFirecrackerNote, helperSocketPath, isLiteralAddress, keepGhConfigCurrent, leaseExpiresAtMs, leaseTimeLeftMs, lifecycleFailureReason, lifecycleSteps, machineConfig, measureDisk, obtainImage, outOfMemoryReason, parseCpuList, prepareBranch, probeHelper, provisionContainer, resolveAgentUser, runBuildSteps, senderAliveScript, senderSignalScript, setUpRunnerCgroup, shellQuote, signalInContainer, startCheckContainer, startServicesFor, stopContainer, syncInContainer, withTunnelLog, writeEvalInput };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import { runnerDir, RUNNER_DIR_MODE, RUNNER_FILE_MODE } from './chunk-
|
|
3
|
+
import { runnerDir, RUNNER_DIR_MODE, RUNNER_FILE_MODE } from './chunk-5K3KB4YR.js';
|
|
4
4
|
import { readlinkSync, realpathSync, mkdirSync, unlinkSync, symlinkSync, renameSync, readFileSync, writeFileSync, rmSync, existsSync, readdirSync } from 'fs';
|
|
5
5
|
import { join, basename, sep, resolve } from 'path';
|
|
6
6
|
|