@kitman-sh/cli 0.10.53 → 0.10.55
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/{chunk-x9dhxfts.js → chunk-148mjppg.js} +5 -5
- package/dist/{chunk-pp1p3g6e.js → chunk-4kssrezn.js} +6 -1
- package/dist/{chunk-ctasxxz5.js → chunk-5j3cxsnp.js} +10 -10
- package/dist/{chunk-7thnf14y.js → chunk-5y5axze6.js} +609 -6
- package/dist/{chunk-mbctzx7e.js → chunk-61k67vxh.js} +76 -1389
- package/dist/{chunk-arvwar2c.js → chunk-7evwar6b.js} +1 -1
- package/dist/{chunk-mej2bx5n.js → chunk-99ver3za.js} +4 -4
- package/dist/{chunk-jagzz148.js → chunk-axdmbr61.js} +26 -26
- package/dist/{chunk-p6spvbwq.js → chunk-dgb6s5vq.js} +482 -100
- package/dist/{chunk-v290mf51.js → chunk-dj7pp4w4.js} +179 -35
- package/dist/{chunk-eg8f5ncv.js → chunk-dkpqwk0q.js} +7 -7
- package/dist/{chunk-r8p3nxcp.js → chunk-eerh2t20.js} +10 -10
- package/dist/{chunk-jafetf7z.js → chunk-g53wn1q8.js} +2 -2
- package/dist/chunk-g7vk5tjp.js +1109 -0
- package/dist/{chunk-vjmz23rs.js → chunk-gwcqz1bj.js} +1 -1
- package/dist/{chunk-wh1pa2aa.js → chunk-m32wb6t0.js} +245 -108
- package/dist/{chunk-3bj7sc3v.js → chunk-mmetyep8.js} +7 -7
- package/dist/{chunk-30397r95.js → chunk-mtgkvbk4.js} +4 -4
- package/dist/{chunk-dzh9e6n2.js → chunk-q0yna8sw.js} +52 -35
- package/dist/{chunk-6vns3ej0.js → chunk-rjfxnk05.js} +5 -5
- package/dist/{chunk-g5bs3f6z.js → chunk-twp7aprz.js} +4 -6
- package/dist/{chunk-x0b92bjb.js → chunk-vtn088tq.js} +6 -6
- package/dist/{chunk-b6thzgc9.js → chunk-wczs5vrq.js} +2 -2
- package/dist/{chunk-11p4wf6n.js → chunk-xgwjcq4z.js} +3 -3
- package/dist/egress-proxy.ts +138 -21
- package/dist/half-close-relay.ts +125 -0
- package/dist/index.js +4 -4
- package/dist/tcp-forwarder.ts +29 -0
- package/package.json +1 -1
- package/dist/chunk-1mc9vgcr.js +0 -39
- package/dist/chunk-jfvq7s24.js +0 -145
- package/dist/chunk-txwt6r25.js +0 -1731
- package/dist/chunk-vyv0p5eq.js +0 -3183
- package/dist/chunk-z821b2gp.js +0 -164
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
isObject,
|
|
6
6
|
isJsonObject,
|
|
7
7
|
isString
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-7evwar6b.js";
|
|
9
9
|
import {
|
|
10
10
|
pipeArguments,
|
|
11
11
|
dual,
|
|
@@ -42,7 +42,7 @@ import {
|
|
|
42
42
|
isFailure2,
|
|
43
43
|
hasInterrupts,
|
|
44
44
|
makeUnsafe5,
|
|
45
|
-
|
|
45
|
+
make16,
|
|
46
46
|
_await,
|
|
47
47
|
fail5,
|
|
48
48
|
isDoneUnsafe,
|
|
@@ -154,7 +154,11 @@ import {
|
|
|
154
154
|
encodePrettyJsonString,
|
|
155
155
|
decodeJsonStringSync,
|
|
156
156
|
encodeUnknownJsonStringSync
|
|
157
|
-
} from "./chunk-
|
|
157
|
+
} from "./chunk-61k67vxh.js";
|
|
158
|
+
import {
|
|
159
|
+
Id,
|
|
160
|
+
secretReference
|
|
161
|
+
} from "./chunk-4kssrezn.js";
|
|
158
162
|
import {
|
|
159
163
|
currentTimeMillis,
|
|
160
164
|
SecureRandom,
|
|
@@ -217,11 +221,7 @@ import {
|
|
|
217
221
|
installCommand,
|
|
218
222
|
checkServicesFile,
|
|
219
223
|
checkServices
|
|
220
|
-
} from "./chunk-
|
|
221
|
-
import {
|
|
222
|
-
Id,
|
|
223
|
-
secretReference
|
|
224
|
-
} from "./chunk-pp1p3g6e.js";
|
|
224
|
+
} from "./chunk-m32wb6t0.js";
|
|
225
225
|
import {
|
|
226
226
|
join,
|
|
227
227
|
interrupt,
|
|
@@ -257,12 +257,13 @@ import {
|
|
|
257
257
|
writeSrtSettings2,
|
|
258
258
|
srtStepArgv2,
|
|
259
259
|
srtArgv2
|
|
260
|
-
} from "./chunk-
|
|
260
|
+
} from "./chunk-xgwjcq4z.js";
|
|
261
261
|
import {
|
|
262
262
|
writeAgentEnvironmentConfigFile2,
|
|
263
263
|
readManifestSkillPaths2,
|
|
264
264
|
tomlTableHeader2,
|
|
265
265
|
tomlKeyPath2,
|
|
266
|
+
kitmanSkillEntry,
|
|
266
267
|
SourceResolver,
|
|
267
268
|
withSourceResolutionCache2,
|
|
268
269
|
AgentEnvironmentMaterializationError2,
|
|
@@ -272,8 +273,8 @@ import {
|
|
|
272
273
|
applyAgentEnvironmentMaterialization2,
|
|
273
274
|
isPathWithin2,
|
|
274
275
|
skillIdentity2
|
|
275
|
-
} from "./chunk-
|
|
276
|
-
import"./chunk-
|
|
276
|
+
} from "./chunk-5y5axze6.js";
|
|
277
|
+
import"./chunk-twp7aprz.js";
|
|
277
278
|
import {
|
|
278
279
|
sliceBytes2,
|
|
279
280
|
maxLineBytes2,
|
|
@@ -281,31 +282,28 @@ import {
|
|
|
281
282
|
decodedOption2,
|
|
282
283
|
decoded2,
|
|
283
284
|
readOpencode2
|
|
284
|
-
} from "./chunk-
|
|
285
|
+
} from "./chunk-vtn088tq.js";
|
|
285
286
|
import {
|
|
286
287
|
writeSecretRegistry,
|
|
287
288
|
secretRefusalLog,
|
|
288
289
|
parseSecretRefusals
|
|
289
|
-
} from "./chunk-
|
|
290
|
-
import"./chunk-txwt6r25.js";
|
|
290
|
+
} from "./chunk-g53wn1q8.js";
|
|
291
291
|
import {
|
|
292
292
|
uploadRunFile,
|
|
293
293
|
programLease,
|
|
294
294
|
rpcRunFiles,
|
|
295
295
|
programHostsEnv,
|
|
296
296
|
undeclaredHostsEnv
|
|
297
|
-
} from "./chunk-
|
|
298
|
-
import"./chunk-
|
|
297
|
+
} from "./chunk-g7vk5tjp.js";
|
|
298
|
+
import"./chunk-5j3cxsnp.js";
|
|
299
299
|
import {
|
|
300
300
|
nextInt
|
|
301
|
-
} from "./chunk-
|
|
302
|
-
import"./chunk-x9dhxfts.js";
|
|
301
|
+
} from "./chunk-gwcqz1bj.js";
|
|
303
302
|
import {
|
|
304
303
|
ChildProcessSpawner,
|
|
305
|
-
|
|
306
|
-
} from "./chunk-
|
|
307
|
-
import"./chunk-
|
|
308
|
-
import"./chunk-z821b2gp.js";
|
|
304
|
+
make3
|
|
305
|
+
} from "./chunk-mmetyep8.js";
|
|
306
|
+
import"./chunk-148mjppg.js";
|
|
309
307
|
|
|
310
308
|
// packages/core/src/sync-kit.ts
|
|
311
309
|
import { createHash } from "crypto";
|
|
@@ -2432,20 +2430,20 @@ var requireKitCommands = (setup, runs) => gen(function* () {
|
|
|
2432
2430
|
});
|
|
2433
2431
|
var stepKitSetup = (agent, harness) => gen(function* () {
|
|
2434
2432
|
const kits = agent.brief.kits ?? [];
|
|
2435
|
-
if (kits.length === 0)
|
|
2436
|
-
return;
|
|
2437
|
-
const fetch = agent.setupArchive;
|
|
2438
2433
|
const unavailable = (reason) => ({
|
|
2439
2434
|
refused: failed("kit_setup_unavailable", `Kitman could not load the Run's Kit setup: ${reason}`)
|
|
2440
2435
|
});
|
|
2436
|
+
if (!isKitHarness(harness))
|
|
2437
|
+
return kits.length === 0 ? undefined : unavailable(`no Kit setup renders for the ${harness} harness`);
|
|
2438
|
+
if (kits.length === 0)
|
|
2439
|
+
return materializeKitSetup(harness, [kitmanSkillEntry], agent.brief.listedSkills ?? []);
|
|
2440
|
+
const fetch = agent.setupArchive;
|
|
2441
2441
|
if (fetch === undefined)
|
|
2442
2442
|
return unavailable("this Runner fetches no setup archives");
|
|
2443
|
-
if (!isKitHarness(harness))
|
|
2444
|
-
return unavailable(`no Kit setup renders for the ${harness} harness`);
|
|
2445
2443
|
const setups = yield* forEach(kits, (kit) => fetch(kit.setupDigest).pipe(flatMap3(decodeSetupArchive), map8((archive) => ({ name: kit.name, version: kit.version, archive })))).pipe(result);
|
|
2446
2444
|
if (isFailure(setups))
|
|
2447
2445
|
return unavailable(setups.failure.message);
|
|
2448
|
-
const setup = materializeKitSetup(harness, setups.success, agent.brief.listedSkills ?? []);
|
|
2446
|
+
const setup = materializeKitSetup(harness, [...setups.success, kitmanSkillEntry], agent.brief.listedSkills ?? []);
|
|
2449
2447
|
for (const server of setup.mcpServers) {
|
|
2450
2448
|
const missing = kitMcpSecretNames(server.transport).find((name) => agent.secrets?.[name] === undefined);
|
|
2451
2449
|
if (missing !== undefined)
|
|
@@ -5312,8 +5310,71 @@ var harnessesInSrt = (input) => gen(function* () {
|
|
|
5312
5310
|
binaries: Object.fromEntries(probed.flatMap((entry) => entry.binary === undefined ? [] : [[entry.harness, entry.binary]]))
|
|
5313
5311
|
};
|
|
5314
5312
|
});
|
|
5315
|
-
// packages/agent-runtime/src/check-
|
|
5313
|
+
// packages/agent-runtime/src/check-docker.ts
|
|
5314
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
5315
|
+
|
|
5316
|
+
// packages/agent-runtime/src/loopback-tunnel.ts
|
|
5316
5317
|
import * as net from "net";
|
|
5318
|
+
|
|
5319
|
+
class LoopbackTunnelUnavailable extends TaggedError("LoopbackTunnelUnavailable") {
|
|
5320
|
+
}
|
|
5321
|
+
var srtLoopbackTunnel = (tunnel) => [
|
|
5322
|
+
"proxy=${HTTP_PROXY:?srt set no HTTP_PROXY}",
|
|
5323
|
+
"proxy=${proxy#*://}",
|
|
5324
|
+
"proxy=${proxy%%/*}",
|
|
5325
|
+
"auth=",
|
|
5326
|
+
"case $proxy in *@*)",
|
|
5327
|
+
` auth=$(printf %s "\${proxy%@*}" | awk 'BEGIN { for (i = 1; i < 256; i++) hex[sprintf("%02X", i)] = sprintf("%c", i) }
|
|
5328
|
+
{ out = ""; while (match($0, /%[0-9A-Fa-f][0-9A-Fa-f]/)) { out = out substr($0, 1, RSTART - 1) hex[toupper(substr($0, RSTART + 1, 2))]; $0 = substr($0, RSTART + 3) } printf "%s", out $0 }')`,
|
|
5329
|
+
" proxy=${proxy##*@} ;;",
|
|
5330
|
+
"esac",
|
|
5331
|
+
"log=$(mktemp)",
|
|
5332
|
+
`${tunnel.listener ?? `socat -t 86400 TCP-LISTEN:${tunnel.listenPort},bind=127.0.0.1,fork,reuseaddr "PROXY:\${proxy%:*}:127.0.0.1:${tunnel.hostPort},proxyport=\${proxy##*:}\${auth:+,proxyauth=$auth}"`} 2>"$log" &`,
|
|
5333
|
+
"tunnel=$!",
|
|
5334
|
+
`fail() { echo "Kitman: the ${tunnel.service} tunnel did not open: $1" >&2; cat "$log" >&2; kill $tunnel 2>/dev/null; rm -f "$log"; exit 1; }`,
|
|
5335
|
+
"tries=0",
|
|
5336
|
+
"while :; do",
|
|
5337
|
+
' kill -0 $tunnel 2>/dev/null || fail "its listener stopped"',
|
|
5338
|
+
` answer=$( (${tunnel.probe}; sleep 1) | socat - TCP:127.0.0.1:${tunnel.listenPort} 2>/dev/null | ${tunnel.read})`,
|
|
5339
|
+
` case $answer in ${tunnel.answers}) break ;; esac`,
|
|
5340
|
+
" tries=$((tries + 1))",
|
|
5341
|
+
` [ $tries -lt 30 ] || fail "${tunnel.service} did not answer through it"`,
|
|
5342
|
+
" sleep 0.2",
|
|
5343
|
+
"done",
|
|
5344
|
+
'kill -0 $tunnel 2>/dev/null || fail "its listener stopped"',
|
|
5345
|
+
'sh -c "$1"',
|
|
5346
|
+
"status=$?",
|
|
5347
|
+
"kill $tunnel 2>/dev/null",
|
|
5348
|
+
'rm -f "$log"',
|
|
5349
|
+
"exit $status"
|
|
5350
|
+
].join(`
|
|
5351
|
+
`);
|
|
5352
|
+
var loopbackSocketForwarder = (hostPort, socket) => gen(function* () {
|
|
5353
|
+
const fs = yield* FileSystem;
|
|
5354
|
+
const dir = yield* flatMap3(fs.makeTempDirectoryScoped({ prefix: "kitman-lo-" }), fs.realPath).pipe(mapError2((error) => new LoopbackTunnelUnavailable({ reason: error.message })));
|
|
5355
|
+
yield* acquireRelease(callback3((resume) => {
|
|
5356
|
+
const open = new Set;
|
|
5357
|
+
const server = net.createServer({ allowHalfOpen: true }, (client) => {
|
|
5358
|
+
const upstream = net.connect({ port: hostPort, host: "127.0.0.1", allowHalfOpen: true });
|
|
5359
|
+
for (const connection of [client, upstream]) {
|
|
5360
|
+
open.add(connection);
|
|
5361
|
+
connection.on("close", () => open.delete(connection));
|
|
5362
|
+
}
|
|
5363
|
+
client.pipe(upstream);
|
|
5364
|
+
upstream.pipe(client);
|
|
5365
|
+
client.on("error", () => upstream.destroy());
|
|
5366
|
+
upstream.on("error", () => client.destroy());
|
|
5367
|
+
});
|
|
5368
|
+
server.once("error", (error) => resume(fail7(new LoopbackTunnelUnavailable({ reason: error.message }))));
|
|
5369
|
+
server.listen(`${dir}/${socket}`, () => resume(succeed6({ server, open })));
|
|
5370
|
+
}), ({ server, open }) => callback3((resume) => {
|
|
5371
|
+
server.close(() => resume(void_3));
|
|
5372
|
+
open.forEach((connection) => connection.destroy());
|
|
5373
|
+
}));
|
|
5374
|
+
return dir;
|
|
5375
|
+
});
|
|
5376
|
+
|
|
5377
|
+
// packages/agent-runtime/src/check-postgres.ts
|
|
5317
5378
|
var CheckPostgresImage = "pgvector/pgvector:0.8.7-pg16@sha256:7b822b0aac60967beb1ea5e576b8602c94c300a157d187f385ae3e0da199b90a";
|
|
5318
5379
|
var checkPostgresSandboxPort = 5432;
|
|
5319
5380
|
var checkPostgresAlias = "kitman-postgres";
|
|
@@ -5413,60 +5474,202 @@ var dockerCheckPostgres = (runnerId, replicaId) => (id) => gen(function* () {
|
|
|
5413
5474
|
return { container, hostPort, user, password };
|
|
5414
5475
|
});
|
|
5415
5476
|
var sslRequestOctal = String.raw`\000\000\000\010\004\322\026\057`;
|
|
5416
|
-
var srtPostgresTunnel = (hostPort, listenPort = checkPostgresSandboxPort) =>
|
|
5417
|
-
|
|
5418
|
-
|
|
5419
|
-
|
|
5420
|
-
|
|
5421
|
-
"
|
|
5422
|
-
|
|
5423
|
-
|
|
5424
|
-
|
|
5425
|
-
|
|
5426
|
-
|
|
5427
|
-
|
|
5428
|
-
|
|
5429
|
-
|
|
5430
|
-
|
|
5431
|
-
|
|
5432
|
-
|
|
5433
|
-
|
|
5434
|
-
|
|
5435
|
-
|
|
5436
|
-
|
|
5437
|
-
|
|
5438
|
-
|
|
5439
|
-
|
|
5440
|
-
|
|
5441
|
-
|
|
5442
|
-
|
|
5443
|
-
|
|
5444
|
-
|
|
5445
|
-
|
|
5446
|
-
|
|
5447
|
-
|
|
5448
|
-
|
|
5449
|
-
|
|
5450
|
-
|
|
5451
|
-
|
|
5452
|
-
|
|
5453
|
-
|
|
5454
|
-
|
|
5455
|
-
|
|
5456
|
-
|
|
5457
|
-
|
|
5458
|
-
|
|
5459
|
-
|
|
5460
|
-
|
|
5461
|
-
|
|
5462
|
-
|
|
5463
|
-
|
|
5464
|
-
|
|
5465
|
-
|
|
5466
|
-
|
|
5467
|
-
|
|
5468
|
-
|
|
5469
|
-
|
|
5477
|
+
var srtPostgresTunnel = (hostPort, listenPort = checkPostgresSandboxPort) => srtLoopbackTunnel({
|
|
5478
|
+
service: "Postgres",
|
|
5479
|
+
hostPort,
|
|
5480
|
+
listenPort,
|
|
5481
|
+
probe: `printf '${sslRequestOctal}'`,
|
|
5482
|
+
read: "head -c 1",
|
|
5483
|
+
answers: "N|S"
|
|
5484
|
+
});
|
|
5485
|
+
var postgresSocketForwarder = (hostPort) => loopbackSocketForwarder(hostPort, `.s.PGSQL.${checkPostgresSandboxPort}`).pipe(mapError2((error) => new CheckPostgresUnavailable({ reason: error.reason })));
|
|
5486
|
+
|
|
5487
|
+
// packages/agent-runtime/src/check-docker.ts
|
|
5488
|
+
var checkDockerPort = 2375;
|
|
5489
|
+
var checkDockerAlias = "kitman-docker";
|
|
5490
|
+
var DockerHubRegistry = "https://registry-1.docker.io";
|
|
5491
|
+
var CheckDockerLabel = "kitman.check-docker";
|
|
5492
|
+
var CheckDockerReplicaLabel = "kitman.check-docker-replica";
|
|
5493
|
+
var rootlessDataRoot = "/home/rootless/.local/share/docker";
|
|
5494
|
+
var registryDataRoot = "/var/lib/registry";
|
|
5495
|
+
var registryMirrorPort = 5000;
|
|
5496
|
+
var egressProxyPort = 3128;
|
|
5497
|
+
|
|
5498
|
+
class CheckDockerUnavailable extends TaggedError("CheckDockerUnavailable") {
|
|
5499
|
+
get message() {
|
|
5500
|
+
return `A pipeline check runs with a Docker daemon of its own, which this Runner could not start: ${this.reason}`;
|
|
5501
|
+
}
|
|
5502
|
+
}
|
|
5503
|
+
var dockerName2 = (id) => id.replaceAll(/[^a-zA-Z0-9_.-]/g, "-");
|
|
5504
|
+
var checkRegistryCacheVolume = (runnerId) => `kitman-check-registry-cache-${dockerName2(runnerId)}`;
|
|
5505
|
+
var checkDockerProxyEnvironment = (proxy, mirror) => {
|
|
5506
|
+
const direct = `localhost,127.0.0.1,${new URL(mirror).hostname}`;
|
|
5507
|
+
return {
|
|
5508
|
+
HTTP_PROXY: proxy,
|
|
5509
|
+
HTTPS_PROXY: proxy,
|
|
5510
|
+
http_proxy: proxy,
|
|
5511
|
+
https_proxy: proxy,
|
|
5512
|
+
NO_PROXY: direct,
|
|
5513
|
+
no_proxy: direct
|
|
5514
|
+
};
|
|
5515
|
+
};
|
|
5516
|
+
var checkDockerDaemonArgs = (input) => [
|
|
5517
|
+
"run",
|
|
5518
|
+
"--detach",
|
|
5519
|
+
"--name",
|
|
5520
|
+
input.name,
|
|
5521
|
+
...input.labels.flatMap(([key, value]) => ["--label", `${key}=${value}`]),
|
|
5522
|
+
"--network",
|
|
5523
|
+
input.network,
|
|
5524
|
+
"--network-alias",
|
|
5525
|
+
checkDockerAlias,
|
|
5526
|
+
"--security-opt",
|
|
5527
|
+
"seccomp=unconfined",
|
|
5528
|
+
"--security-opt",
|
|
5529
|
+
"apparmor=unconfined",
|
|
5530
|
+
"--security-opt",
|
|
5531
|
+
"systempaths=unconfined",
|
|
5532
|
+
"--device",
|
|
5533
|
+
"/dev/net/tun",
|
|
5534
|
+
"--volume",
|
|
5535
|
+
rootlessDataRoot,
|
|
5536
|
+
"--env",
|
|
5537
|
+
"DOCKER_TLS_CERTDIR=",
|
|
5538
|
+
...Object.entries(input.proxy === undefined ? {} : checkDockerProxyEnvironment(input.proxy, input.mirror)).flatMap(([key, value]) => ["--env", `${key}=${value}`]),
|
|
5539
|
+
input.image,
|
|
5540
|
+
"--registry-mirror",
|
|
5541
|
+
input.mirror,
|
|
5542
|
+
"--tls=false"
|
|
5543
|
+
];
|
|
5544
|
+
var checkRegistryMirrorArgs = (input) => [
|
|
5545
|
+
"run",
|
|
5546
|
+
"--detach",
|
|
5547
|
+
"--rm",
|
|
5548
|
+
"--name",
|
|
5549
|
+
input.name,
|
|
5550
|
+
...input.labels.flatMap(([key, value]) => ["--label", `${key}=${value}`]),
|
|
5551
|
+
"--network",
|
|
5552
|
+
input.network,
|
|
5553
|
+
"--volume",
|
|
5554
|
+
`${input.volume}:${registryDataRoot}`,
|
|
5555
|
+
"--env",
|
|
5556
|
+
`REGISTRY_PROXY_REMOTEURL=${DockerHubRegistry}`,
|
|
5557
|
+
"--env",
|
|
5558
|
+
"REGISTRY_PROXY_TTL=0",
|
|
5559
|
+
input.image
|
|
5560
|
+
];
|
|
5561
|
+
var checkDockerClientConfig = (proxy) => proxy === undefined ? {} : { proxies: { default: { httpProxy: proxy, httpsProxy: proxy, noProxy: "localhost,127.0.0.1" } } };
|
|
5562
|
+
var orphanedCheckDocker = (listing, live) => listing.split(`
|
|
5563
|
+
`).map((line) => line.trim().split(/\s+/)).flatMap(([id, replica]) => id === undefined || id === "" || live.has(replica ?? "") ? [] : [id]);
|
|
5564
|
+
var removeCheckDocker = (runnerId, liveReplicas) => gen(function* () {
|
|
5565
|
+
const filter = ["--filter", `label=${CheckDockerLabel}=${runnerId}`];
|
|
5566
|
+
const format = `{{.ID}} {{.Label "${CheckDockerReplicaLabel}"}}`;
|
|
5567
|
+
const containers = orphanedCheckDocker(yield* runCommand2("docker", ["ps", "--all", ...filter, "--format", format], { timeout: "10 seconds" }), liveReplicas);
|
|
5568
|
+
if (containers.length > 0)
|
|
5569
|
+
yield* runCommand2("docker", ["rm", "--force", "--volumes", ...containers], { timeout: "30 seconds" });
|
|
5570
|
+
const networks = orphanedCheckDocker(yield* runCommand2("docker", ["network", "ls", ...filter, "--format", format], { timeout: "10 seconds" }), liveReplicas);
|
|
5571
|
+
if (networks.length > 0)
|
|
5572
|
+
yield* runCommand2("docker", ["network", "rm", ...networks], { timeout: "30 seconds" });
|
|
5573
|
+
}).pipe(ignore);
|
|
5574
|
+
var daemonLogs = (container) => gen(function* () {
|
|
5575
|
+
const state = yield* runCommand2("docker", [
|
|
5576
|
+
"inspect",
|
|
5577
|
+
"--format",
|
|
5578
|
+
"{{.State.Status}} (exit code {{.State.ExitCode}})",
|
|
5579
|
+
container
|
|
5580
|
+
]);
|
|
5581
|
+
const logs = yield* runCommand2("sh", ["-c", 'docker logs --tail 40 "$0" 2>&1', container]);
|
|
5582
|
+
return `${state.trim()}
|
|
5583
|
+
${logs.trim().slice(-3000)}`;
|
|
5584
|
+
}).pipe(orElseSucceed(() => "nothing, since docker could not show its state or logs"));
|
|
5585
|
+
var randomHex2 = () => Array.from(crypto.getRandomValues(new Uint8Array(4)), (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
5586
|
+
var dockerCheckDaemon = (input) => ({ id, network: allowed }) => gen(function* () {
|
|
5587
|
+
const run = `${dockerName2(id)}-${randomHex2()}`;
|
|
5588
|
+
const daemon = `kitman-check-docker-${run}`;
|
|
5589
|
+
const network = `kitman-check-docker-net-${run}`;
|
|
5590
|
+
const outside = `kitman-check-docker-out-${run}`;
|
|
5591
|
+
const mirror = `kitman-check-docker-mirror-${run}`;
|
|
5592
|
+
const proxyContainer = `kitman-check-docker-egress-${run}`;
|
|
5593
|
+
const forwarder = `kitman-check-docker-api-${run}`;
|
|
5594
|
+
const runLabel = "kitman.check-docker-run";
|
|
5595
|
+
const labels = [
|
|
5596
|
+
[CheckDockerLabel, input.runnerId],
|
|
5597
|
+
[CheckDockerReplicaLabel, input.replicaId],
|
|
5598
|
+
[runLabel, run]
|
|
5599
|
+
];
|
|
5600
|
+
const labelArgs = labels.flatMap(([key, value]) => ["--label", `${key}=${value}`]);
|
|
5601
|
+
const docker = (args, timeout = "30 seconds") => runCommand2("docker", args, { timeout }).pipe(mapError2((error) => new CheckDockerUnavailable({ reason: error.message })));
|
|
5602
|
+
yield* acquireRelease(void_3, () => gen(function* () {
|
|
5603
|
+
const ids = (yield* docker(["ps", "--all", "--quiet", "--filter", `label=${runLabel}=${run}`])).split(`
|
|
5604
|
+
`).filter((line) => line.trim() !== "");
|
|
5605
|
+
if (ids.length > 0)
|
|
5606
|
+
yield* docker(["rm", "--force", "--volumes", ...ids], "2 minutes");
|
|
5607
|
+
yield* ignore(docker(["network", "rm", network]));
|
|
5608
|
+
yield* ignore(docker(["network", "rm", outside]));
|
|
5609
|
+
}).pipe(ignore));
|
|
5610
|
+
yield* docker(["network", "create", "--opt", "com.docker.network.bridge.enable_icc=false", ...labelArgs, outside]);
|
|
5611
|
+
yield* docker(["network", "create", ...allowed === "open" ? [] : ["--internal"], ...labelArgs, network]);
|
|
5612
|
+
const addressOn = (container) => gen(function* () {
|
|
5613
|
+
yield* docker(["network", "connect", network, container]);
|
|
5614
|
+
const address = (yield* docker([
|
|
5615
|
+
"inspect",
|
|
5616
|
+
"--format",
|
|
5617
|
+
`{{(index .NetworkSettings.Networks "${network}").IPAddress}}`,
|
|
5618
|
+
container
|
|
5619
|
+
])).trim();
|
|
5620
|
+
if (address === "")
|
|
5621
|
+
return yield* new CheckDockerUnavailable({ reason: `${container} has no address` });
|
|
5622
|
+
return address;
|
|
5623
|
+
});
|
|
5624
|
+
const helper = (name, args) => docker(["run", "--detach", "--rm", "--name", name, ...labelArgs, "--network", outside, ...args], "30 minutes");
|
|
5625
|
+
yield* docker(checkRegistryMirrorArgs({
|
|
5626
|
+
name: mirror,
|
|
5627
|
+
image: input.registryImage,
|
|
5628
|
+
labels,
|
|
5629
|
+
network: outside,
|
|
5630
|
+
volume: checkRegistryCacheVolume(input.runnerId)
|
|
5631
|
+
}), "30 minutes");
|
|
5632
|
+
const mirrorUrl = `http://${yield* addressOn(mirror)}:${registryMirrorPort}`;
|
|
5633
|
+
const proxy = allowed === "open" ? undefined : yield* gen(function* () {
|
|
5634
|
+
yield* helper(proxyContainer, [
|
|
5635
|
+
"--volume",
|
|
5636
|
+
`${fileURLToPath2(import.meta.resolve("./egress-proxy.ts"))}:/kitman/egress-proxy.ts:ro`,
|
|
5637
|
+
input.proxyImage ?? EgressProxyImage,
|
|
5638
|
+
"bun",
|
|
5639
|
+
"/kitman/egress-proxy.ts",
|
|
5640
|
+
allowed.hosts.join(",")
|
|
5641
|
+
]);
|
|
5642
|
+
return `http://${yield* addressOn(proxyContainer)}:${egressProxyPort}`;
|
|
5643
|
+
});
|
|
5644
|
+
yield* docker(checkDockerDaemonArgs({
|
|
5645
|
+
name: daemon,
|
|
5646
|
+
image: input.image,
|
|
5647
|
+
labels,
|
|
5648
|
+
network,
|
|
5649
|
+
mirror: mirrorUrl,
|
|
5650
|
+
...proxy === undefined ? undefined : { proxy }
|
|
5651
|
+
}), "30 minutes");
|
|
5652
|
+
yield* helper(forwarder, [
|
|
5653
|
+
"--publish",
|
|
5654
|
+
`127.0.0.1::${checkDockerPort}`,
|
|
5655
|
+
"--volume",
|
|
5656
|
+
`${fileURLToPath2(import.meta.resolve("./tcp-forwarder.ts"))}:/kitman/tcp-forwarder.ts:ro`,
|
|
5657
|
+
input.proxyImage ?? EgressProxyImage,
|
|
5658
|
+
"bun",
|
|
5659
|
+
"/kitman/tcp-forwarder.ts",
|
|
5660
|
+
String(checkDockerPort),
|
|
5661
|
+
checkDockerAlias,
|
|
5662
|
+
String(checkDockerPort)
|
|
5663
|
+
]);
|
|
5664
|
+
yield* docker(["network", "connect", network, forwarder]);
|
|
5665
|
+
const hostPort = publishedPort(yield* docker(["port", forwarder, `${checkDockerPort}/tcp`]));
|
|
5666
|
+
if (hostPort === undefined)
|
|
5667
|
+
return yield* new CheckDockerUnavailable({ reason: "docker published no port" });
|
|
5668
|
+
yield* docker(["--host", `tcp://127.0.0.1:${hostPort}`, "version", "--format", "{{.Server.Version}}"], "10 seconds").pipe(retry({ schedule: spaced("500 millis"), times: 240 }), catch_((error) => gen(function* () {
|
|
5669
|
+
const logs = yield* daemonLogs(daemon);
|
|
5670
|
+
return yield* new CheckDockerUnavailable({ reason: `${error.reason}; the daemon logged: ${logs}` });
|
|
5671
|
+
})));
|
|
5672
|
+
return { container: daemon, hostPort, ...proxy === undefined ? undefined : { proxy } };
|
|
5470
5673
|
});
|
|
5471
5674
|
// packages/agent-runtime/src/codex-hook-trust.ts
|
|
5472
5675
|
class CodexAppServerFailed extends TaggedError("CodexAppServerFailed") {
|
|
@@ -5494,7 +5697,7 @@ var codexAppServer = (binary = "codex") => (env) => gen(function* () {
|
|
|
5494
5697
|
const input = yield* unbounded2();
|
|
5495
5698
|
const pending = new Map;
|
|
5496
5699
|
let lastId = 0;
|
|
5497
|
-
const handle = yield* spawner.spawn(
|
|
5700
|
+
const handle = yield* spawner.spawn(make3(binary, ["app-server"], {
|
|
5498
5701
|
cwd: env.home,
|
|
5499
5702
|
extendEnv: true,
|
|
5500
5703
|
env: { HOME: env.home, CODEX_HOME: env.codexHome },
|
|
@@ -5517,7 +5720,7 @@ var codexAppServer = (binary = "codex") => (env) => gen(function* () {
|
|
|
5517
5720
|
return {
|
|
5518
5721
|
request: (method, params) => gen(function* () {
|
|
5519
5722
|
const id = ++lastId;
|
|
5520
|
-
const deferred = yield*
|
|
5723
|
+
const deferred = yield* make16();
|
|
5521
5724
|
pending.set(id, deferred);
|
|
5522
5725
|
yield* send({ id, method, params });
|
|
5523
5726
|
return yield* _await(deferred).pipe(mapError2((error) => new CodexAppServerFailed({ reason: `${method}: ${error.message}` })));
|
|
@@ -5657,7 +5860,7 @@ var handshake = [
|
|
|
5657
5860
|
`).join("");
|
|
5658
5861
|
var kitmanMcpPreflight = (mcp) => gen(function* () {
|
|
5659
5862
|
const spawner = yield* ChildProcessSpawner;
|
|
5660
|
-
const server = yield* spawner.spawn(
|
|
5863
|
+
const server = yield* spawner.spawn(make3(mcp.command, [...mcp.args], {
|
|
5661
5864
|
extendEnv: true,
|
|
5662
5865
|
env: mcp.env,
|
|
5663
5866
|
stdin: { stream: make11(new TextEncoder().encode(handshake)), endOnDone: false },
|
|
@@ -5733,7 +5936,7 @@ var programProcessExecutor = (input) => (work) => gen(function* () {
|
|
|
5733
5936
|
};
|
|
5734
5937
|
const exitCode = sandbox === undefined ? yield* gen(function* () {
|
|
5735
5938
|
const spawner = yield* ChildProcessSpawner;
|
|
5736
|
-
const handle = yield* spawner.spawn(
|
|
5939
|
+
const handle = yield* spawner.spawn(make3(input.bun ?? process.execPath, [file], {
|
|
5737
5940
|
stdin: make11(new TextEncoder().encode(stdin)),
|
|
5738
5941
|
stdout: "inherit",
|
|
5739
5942
|
stderr: "inherit",
|
|
@@ -5796,9 +5999,110 @@ var programProcessExecutor = (input) => (work) => gen(function* () {
|
|
|
5796
5999
|
status: "deferred",
|
|
5797
6000
|
crashed: `it did not start: ${error.message}`.slice(0, 500)
|
|
5798
6001
|
})));
|
|
6002
|
+
// packages/agent-runtime/src/half-close-relay.ts
|
|
6003
|
+
import { once } from "events";
|
|
6004
|
+
import { connect as connect2, createServer as createServer2 } from "net";
|
|
6005
|
+
var frameHeader = 4;
|
|
6006
|
+
var endOfInput = Buffer.alloc(frameHeader);
|
|
6007
|
+
var maxFrame = 1024 * 1024;
|
|
6008
|
+
var keepUp = (from, to, accepted) => {
|
|
6009
|
+
if (accepted)
|
|
6010
|
+
return;
|
|
6011
|
+
from.pause();
|
|
6012
|
+
to.once("drain", () => from.resume());
|
|
6013
|
+
};
|
|
6014
|
+
var closeTogether = (...sockets) => sockets.forEach((socket) => {
|
|
6015
|
+
socket.on("error", () => sockets.forEach((other) => other.destroy()));
|
|
6016
|
+
socket.on("close", () => sockets.forEach((other) => other.end()));
|
|
6017
|
+
});
|
|
6018
|
+
var listening = (server, port) => once(server.listen(port, "127.0.0.1"), "listening").then(() => server);
|
|
6019
|
+
var startHalfCloseDecoder = (input) => listening(createServer2({ allowHalfOpen: true }, (client) => {
|
|
6020
|
+
const upstream = connect2({ port: input.targetPort, host: "127.0.0.1", allowHalfOpen: true });
|
|
6021
|
+
let pending = Buffer.alloc(0);
|
|
6022
|
+
client.on("data", (chunk) => {
|
|
6023
|
+
pending = Buffer.concat([pending, chunk]);
|
|
6024
|
+
if (pending.length >= frameHeader && pending.readUInt32BE(0) > maxFrame)
|
|
6025
|
+
return void client.destroy();
|
|
6026
|
+
while (pending.length >= frameHeader && pending.length >= frameHeader + pending.readUInt32BE(0)) {
|
|
6027
|
+
const length = pending.readUInt32BE(0);
|
|
6028
|
+
if (length === 0)
|
|
6029
|
+
upstream.end();
|
|
6030
|
+
else
|
|
6031
|
+
keepUp(client, upstream, upstream.write(pending.subarray(frameHeader, frameHeader + length)));
|
|
6032
|
+
pending = pending.subarray(frameHeader + length);
|
|
6033
|
+
}
|
|
6034
|
+
});
|
|
6035
|
+
client.on("end", () => upstream.end());
|
|
6036
|
+
upstream.pipe(client);
|
|
6037
|
+
closeTogether(client, upstream);
|
|
6038
|
+
}), input.port);
|
|
6039
|
+
if (false)
|
|
6040
|
+
;
|
|
6041
|
+
|
|
5799
6042
|
// packages/agent-runtime/src/verification-executor.ts
|
|
6043
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
5800
6044
|
var checkTimeout = "30 minutes";
|
|
5801
6045
|
var checkFilesPerVerification = 50;
|
|
6046
|
+
var halfCloseEncoder = [process.execPath, fileURLToPath3(import.meta.resolve("./half-close-relay.ts"))];
|
|
6047
|
+
var srtDockerTunnel = (relayPort) => srtLoopbackTunnel({
|
|
6048
|
+
service: "Docker daemon",
|
|
6049
|
+
hostPort: relayPort,
|
|
6050
|
+
listenPort: checkDockerPort,
|
|
6051
|
+
listener: `${halfCloseEncoder.map(quoted).join(" ")} ${checkDockerPort} "$HTTP_PROXY" ${relayPort}`,
|
|
6052
|
+
probe: String.raw`printf 'GET /_ping HTTP/1.0\r\n\r\n'`,
|
|
6053
|
+
read: "tail -c 2",
|
|
6054
|
+
answers: "OK"
|
|
6055
|
+
});
|
|
6056
|
+
var pipelineEnvironment = (docker, dockerHost) => ({
|
|
6057
|
+
DOCKER_HOST: dockerHost,
|
|
6058
|
+
DOCKER_CONFIG: `${docker.clientDir}/docker`,
|
|
6059
|
+
GCL_HOME: `${docker.clientDir}/gitlab-ci-local-home`
|
|
6060
|
+
});
|
|
6061
|
+
var dockerRoute = (backend, docker) => {
|
|
6062
|
+
if (docker === undefined)
|
|
6063
|
+
return { env: {}, hosts: [], unixSockets: [], services: [], tunnel: undefined };
|
|
6064
|
+
if (backend === "docker")
|
|
6065
|
+
return {
|
|
6066
|
+
env: {
|
|
6067
|
+
...pipelineEnvironment(docker, `tcp://${checkDockerAlias}:${checkDockerPort}`),
|
|
6068
|
+
NO_PROXY: `localhost,127.0.0.1,${checkDockerAlias}`,
|
|
6069
|
+
no_proxy: `localhost,127.0.0.1,${checkDockerAlias}`
|
|
6070
|
+
},
|
|
6071
|
+
hosts: [],
|
|
6072
|
+
unixSockets: [],
|
|
6073
|
+
services: [{ container: docker.container, alias: checkDockerAlias }],
|
|
6074
|
+
tunnel: undefined
|
|
6075
|
+
};
|
|
6076
|
+
switch (docker.route.kind) {
|
|
6077
|
+
case "socket":
|
|
6078
|
+
return {
|
|
6079
|
+
env: pipelineEnvironment(docker, `unix://${docker.route.dir}/docker.sock`),
|
|
6080
|
+
hosts: [],
|
|
6081
|
+
unixSockets: [docker.route.dir],
|
|
6082
|
+
services: [],
|
|
6083
|
+
tunnel: undefined
|
|
6084
|
+
};
|
|
6085
|
+
case "relay":
|
|
6086
|
+
return {
|
|
6087
|
+
env: pipelineEnvironment(docker, `tcp://127.0.0.1:${checkDockerPort}`),
|
|
6088
|
+
hosts: [`127.0.0.1:${docker.route.port}`],
|
|
6089
|
+
unixSockets: [],
|
|
6090
|
+
services: [],
|
|
6091
|
+
tunnel: srtDockerTunnel(docker.route.port)
|
|
6092
|
+
};
|
|
6093
|
+
case "direct":
|
|
6094
|
+
throw new Error("A pipeline check in srt reaches its daemon through a socket or the relay, never directly.");
|
|
6095
|
+
}
|
|
6096
|
+
};
|
|
6097
|
+
var hostCheckEnvironment = (docker) => {
|
|
6098
|
+
const { POSTGRES_URL: _runnerDatabase, ...runner } = withoutPreloads2();
|
|
6099
|
+
if (docker === undefined)
|
|
6100
|
+
return runner;
|
|
6101
|
+
return {
|
|
6102
|
+
...Object.fromEntries(Object.entries(runner).filter(([name]) => !name.startsWith("DOCKER_") && !name.startsWith("GCL_") && name !== "SSH_AUTH_SOCK")),
|
|
6103
|
+
...pipelineEnvironment(docker, `tcp://127.0.0.1:${docker.hostPort}`)
|
|
6104
|
+
};
|
|
6105
|
+
};
|
|
5802
6106
|
var postgresRoute = (backend, postgres) => {
|
|
5803
6107
|
if (postgres === undefined)
|
|
5804
6108
|
return { url: undefined, hosts: [], unixSockets: [], services: [], tunnel: undefined };
|
|
@@ -5826,12 +6130,13 @@ var postgresRoute = (backend, postgres) => {
|
|
|
5826
6130
|
tunnel: srtPostgresTunnel(postgres.hostPort)
|
|
5827
6131
|
};
|
|
5828
6132
|
};
|
|
5829
|
-
var checkSandboxPolicy = (work, sandbox, checkout, cache, filesDir, postgresHosts) => ({
|
|
6133
|
+
var checkSandboxPolicy = (work, sandbox, checkout, cache, filesDir, postgresHosts, clientDir) => ({
|
|
5830
6134
|
...runnerStateSandboxPolicy(sandbox.runner, [
|
|
5831
6135
|
repositoryClone(sandbox.runner.workRoot, work.repoBinding.id),
|
|
5832
|
-
checkout
|
|
6136
|
+
checkout,
|
|
6137
|
+
...clientDir === undefined ? [] : [clientDir, ...halfCloseEncoder]
|
|
5833
6138
|
]),
|
|
5834
|
-
writablePaths: [checkout, cache, filesDir],
|
|
6139
|
+
writablePaths: [checkout, cache, filesDir, ...clientDir === undefined ? [] : [clientDir]],
|
|
5835
6140
|
network: verificationNetworkAllowlist({
|
|
5836
6141
|
apiUrl: sandbox.apiUrl,
|
|
5837
6142
|
storageOrigin: work.storageOrigin,
|
|
@@ -5841,16 +6146,15 @@ var checkSandboxPolicy = (work, sandbox, checkout, cache, filesDir, postgresHost
|
|
|
5841
6146
|
environment: srtCacheEnvironment2(cache)
|
|
5842
6147
|
});
|
|
5843
6148
|
var checkGitEnvironment = { GIT_CONFIG_GLOBAL: "/dev/null", GIT_TERMINAL_PROMPT: "0" };
|
|
5844
|
-
var checkRunner = (work, sandbox, cache, inherited) => (checkout) => ({ command, cwd, filesDir, onOutput, postgres }) => {
|
|
6149
|
+
var checkRunner = (work, sandbox, cache, inherited) => (checkout) => ({ command, cwd, filesDir, onOutput, postgres, docker }) => {
|
|
5845
6150
|
const env = { ...checkGitEnvironment, KITMAN_RUN_FILES_DIR: filesDir };
|
|
5846
6151
|
const output = onOutput === undefined ? undefined : { onOutput };
|
|
5847
6152
|
if (sandbox === undefined || sandbox.backend === undefined) {
|
|
5848
|
-
const { POSTGRES_URL: _runnerDatabase, ...runner } = withoutPreloads2();
|
|
5849
6153
|
return runShell2(command, {
|
|
5850
6154
|
cwd,
|
|
5851
6155
|
extendEnv: false,
|
|
5852
6156
|
env: {
|
|
5853
|
-
...
|
|
6157
|
+
...hostCheckEnvironment(docker),
|
|
5854
6158
|
...env,
|
|
5855
6159
|
...postgres === undefined ? undefined : { POSTGRES_URL: checkPostgresUrl(postgres, "127.0.0.1", postgres.hostPort) }
|
|
5856
6160
|
},
|
|
@@ -5859,14 +6163,18 @@ var checkRunner = (work, sandbox, cache, inherited) => (checkout) => ({ command,
|
|
|
5859
6163
|
});
|
|
5860
6164
|
}
|
|
5861
6165
|
const route = postgresRoute(sandbox.backend, postgres);
|
|
5862
|
-
const
|
|
6166
|
+
const daemon = dockerRoute(sandbox.backend, docker);
|
|
6167
|
+
const policy = checkSandboxPolicy(work, sandbox, checkout, cache, filesDir, [...route.hosts, ...daemon.hosts], docker?.clientDir);
|
|
6168
|
+
const [tunnel, ...innerTunnels] = [route.tunnel, daemon.tunnel].filter((script) => script !== undefined);
|
|
6169
|
+
const tunnelled = innerTunnels.reduceRight((inner, script) => `sh -c ${quoted(script)} sh ${quoted(inner)}`, command);
|
|
5863
6170
|
const sandboxCommand = {
|
|
5864
|
-
argv:
|
|
6171
|
+
argv: tunnel === undefined ? ["sh", "-c", command] : ["sh", "-c", tunnel, "sh", tunnelled],
|
|
5865
6172
|
cwd,
|
|
5866
6173
|
env: {
|
|
5867
6174
|
...env,
|
|
5868
6175
|
KITMAN_CHECK_SANDBOX: sandbox.backend,
|
|
5869
|
-
...route.url === undefined ? undefined : { POSTGRES_URL: route.url }
|
|
6176
|
+
...route.url === undefined ? undefined : { POSTGRES_URL: route.url },
|
|
6177
|
+
...daemon.env
|
|
5870
6178
|
},
|
|
5871
6179
|
timeout: checkTimeout,
|
|
5872
6180
|
...output
|
|
@@ -5875,7 +6183,7 @@ var checkRunner = (work, sandbox, cache, inherited) => (checkout) => ({ command,
|
|
|
5875
6183
|
backend: "srt",
|
|
5876
6184
|
policy,
|
|
5877
6185
|
command: { ...sandboxCommand, env: { ...inherited, ...sandboxCommand.env }, extendEnv: false },
|
|
5878
|
-
unixSockets: route.unixSockets,
|
|
6186
|
+
unixSockets: [...route.unixSockets, ...daemon.unixSockets],
|
|
5879
6187
|
...sandbox.srtCommand === undefined ? undefined : { srtCommand: sandbox.srtCommand }
|
|
5880
6188
|
}) : runSandboxCommand({
|
|
5881
6189
|
backend: "docker",
|
|
@@ -5885,7 +6193,7 @@ var checkRunner = (work, sandbox, cache, inherited) => (checkout) => ({ command,
|
|
|
5885
6193
|
readOnlyPaths: [repositoryClone(sandbox.runner.workRoot, work.repoBinding.id)],
|
|
5886
6194
|
policy,
|
|
5887
6195
|
command: sandboxCommand,
|
|
5888
|
-
services: route.services
|
|
6196
|
+
services: [...route.services, ...daemon.services]
|
|
5889
6197
|
});
|
|
5890
6198
|
};
|
|
5891
6199
|
var regularFiles = (dir) => gen(function* () {
|
|
@@ -5939,6 +6247,38 @@ var checkoutPostgres = (worktree, services) => gen(function* () {
|
|
|
5939
6247
|
});
|
|
5940
6248
|
return yield* services.postgres(services.id).pipe(mapError2((error) => new ServicesUnavailable({ reason: error.message })));
|
|
5941
6249
|
});
|
|
6250
|
+
var decodeListeningPort = decodeUnknownEffect2(Struct({ port: Finite }));
|
|
6251
|
+
var pipelineDaemon = (services, check) => gen(function* () {
|
|
6252
|
+
if (services.docker === undefined)
|
|
6253
|
+
return yield* new ServicesUnavailable({
|
|
6254
|
+
reason: `The pipeline check ${check} runs with a Docker daemon of its own, and this Runner cannot start one: set KITMAN_RUNNER_CHECK_DOCKER_IMAGE to a docker:*-dind-rootless image and KITMAN_RUNNER_CHECK_REGISTRY_IMAGE to a registry:3 image, each pinned by digest.`
|
|
6255
|
+
});
|
|
6256
|
+
const fs = yield* FileSystem;
|
|
6257
|
+
const started = yield* services.docker({ id: services.id, network: services.network }).pipe(mapError2((error) => new ServicesUnavailable({ reason: error.message })));
|
|
6258
|
+
const clientDir = yield* fs.makeTempDirectoryScoped({ prefix: "kitman-check-docker-" });
|
|
6259
|
+
yield* fs.makeDirectory(`${clientDir}/docker`);
|
|
6260
|
+
yield* fs.makeDirectory(`${clientDir}/gitlab-ci-local-home`);
|
|
6261
|
+
yield* fs.writeFileString(`${clientDir}/docker/config.json`, encodeUnknownJsonStringSync(checkDockerClientConfig(started.proxy)));
|
|
6262
|
+
if (services.backend !== "srt")
|
|
6263
|
+
return { ...started, clientDir, route: { kind: "direct" } };
|
|
6264
|
+
if (services.platform !== "darwin") {
|
|
6265
|
+
const relay = yield* acquireRelease(promise(() => startHalfCloseDecoder({ port: 0, targetPort: started.hostPort })), (server) => sync2(() => server.close()));
|
|
6266
|
+
const { port } = yield* decodeListeningPort(relay.address()).pipe(mapError2(() => new ServicesUnavailable({
|
|
6267
|
+
reason: `The pipeline check ${check} cannot reach its Docker daemon: its relay has no port`
|
|
6268
|
+
})));
|
|
6269
|
+
return { ...started, clientDir, route: { kind: "relay", port } };
|
|
6270
|
+
}
|
|
6271
|
+
return {
|
|
6272
|
+
...started,
|
|
6273
|
+
clientDir,
|
|
6274
|
+
route: {
|
|
6275
|
+
kind: "socket",
|
|
6276
|
+
dir: yield* loopbackSocketForwarder(started.hostPort, "docker.sock").pipe(mapError2((error) => new ServicesUnavailable({
|
|
6277
|
+
reason: `The pipeline check ${check} cannot reach its Docker daemon: ${error.reason}`
|
|
6278
|
+
})))
|
|
6279
|
+
}
|
|
6280
|
+
};
|
|
6281
|
+
});
|
|
5942
6282
|
var reachCheckPostgres = (postgres, services, worktree, run) => gen(function* () {
|
|
5943
6283
|
if (services.backend !== "srt")
|
|
5944
6284
|
return postgres;
|
|
@@ -5987,11 +6327,13 @@ var runChecks = (worktree, checks, tree, known, run, keeper, services) => gen(fu
|
|
|
5987
6327
|
const filesDir = yield* fs.makeTempDirectoryScoped({ prefix: "kitman-check-files-" });
|
|
5988
6328
|
const output = path.join(yield* fs.makeTempDirectoryScoped({ prefix: "kitman-check-output-" }), "output");
|
|
5989
6329
|
const sink = keeper === undefined ? undefined : yield* fs.open(output, { flag: "w" });
|
|
6330
|
+
const docker = check.pipeline === true ? yield* pipelineDaemon(services, check.name) : undefined;
|
|
5990
6331
|
const ran = yield* run({
|
|
5991
6332
|
command: check.command,
|
|
5992
6333
|
cwd: path.join(worktree, check.workingDirectory ?? "."),
|
|
5993
6334
|
filesDir,
|
|
5994
6335
|
...postgres === undefined ? undefined : { postgres },
|
|
6336
|
+
...docker === undefined ? undefined : { docker },
|
|
5995
6337
|
...sink === undefined ? undefined : { onOutput: (chunk) => sink.writeAll(chunk) }
|
|
5996
6338
|
});
|
|
5997
6339
|
const durationMs = (yield* currentTimeMillis) - startedAt;
|
|
@@ -6090,6 +6432,27 @@ var measureRevisions = (work, measure, checkouts, runIn) => gen(function* () {
|
|
|
6090
6432
|
}
|
|
6091
6433
|
};
|
|
6092
6434
|
});
|
|
6435
|
+
var ownRepository = (worktree, clone, targetBranch) => gen(function* () {
|
|
6436
|
+
const fs = yield* FileSystem;
|
|
6437
|
+
const path = yield* Path;
|
|
6438
|
+
const scratch = yield* fs.makeTempDirectoryScoped({
|
|
6439
|
+
directory: path.dirname(worktree),
|
|
6440
|
+
prefix: "kitman-check-git-"
|
|
6441
|
+
});
|
|
6442
|
+
const gitDir = path.join(scratch, "git");
|
|
6443
|
+
const git = (...args) => runCommand2("git", ["--git-dir", gitDir, ...args]);
|
|
6444
|
+
const revision = (yield* runCommand2("git", ["-C", worktree, "rev-parse", "HEAD"])).trim();
|
|
6445
|
+
const originUrl = (yield* runCommand2("git", ["-C", clone, "config", "--get", "remote.origin.url"])).trim();
|
|
6446
|
+
yield* runCommand2("git", ["clone", "--quiet", "--bare", "--no-hardlinks", clone, gitDir]);
|
|
6447
|
+
yield* git("fetch", "--quiet", clone, "+refs/remotes/origin/*:refs/remotes/origin/*");
|
|
6448
|
+
yield* git("config", "core.bare", "false");
|
|
6449
|
+
yield* git("remote", "set-url", "origin", originUrl);
|
|
6450
|
+
yield* git("symbolic-ref", "refs/remotes/origin/HEAD", `refs/remotes/origin/${targetBranch}`);
|
|
6451
|
+
yield* git("update-ref", "--no-deref", "HEAD", revision);
|
|
6452
|
+
yield* fs.remove(path.join(worktree, ".git"));
|
|
6453
|
+
yield* fs.rename(gitDir, path.join(worktree, ".git"));
|
|
6454
|
+
yield* runCommand2("git", ["-C", worktree, "reset", "--quiet"]);
|
|
6455
|
+
}).pipe(scoped);
|
|
6093
6456
|
var treeOf = (worktree) => map8(runCommand2("git", ["-C", worktree, "rev-parse", "HEAD^{tree}"]), (tree) => tree.trim());
|
|
6094
6457
|
var verificationExecutor = (input) => (work) => gen(function* () {
|
|
6095
6458
|
if (input.sandbox !== undefined && input.sandbox.backend === undefined)
|
|
@@ -6115,15 +6478,22 @@ var verificationExecutor = (input) => (work) => gen(function* () {
|
|
|
6115
6478
|
}, work.repoBinding);
|
|
6116
6479
|
const pipelineOnly = work.checks.every((check) => check.pipeline === true);
|
|
6117
6480
|
const baseline = pipelineOnly ? head : yield* baselineAt(work.baseline).pipe(catch_(() => baselineAt()));
|
|
6481
|
+
if (work.checks.some((check) => check.pipeline === true))
|
|
6482
|
+
yield* ownRepository(head, repositoryClone(input.rootDir, work.repoBinding.id), work.repoBinding.defaultTargetBranch);
|
|
6118
6483
|
const headTree = yield* treeOf(head);
|
|
6119
6484
|
const baselineTree = yield* treeOf(baseline);
|
|
6120
6485
|
const trees = headTree === baselineTree ? [headTree] : [headTree, baselineTree];
|
|
6121
6486
|
const known = yield* input.known(work, trees);
|
|
6487
|
+
const sandbox = input.sandbox;
|
|
6488
|
+
const checkNetwork = sandbox === undefined || sandbox.backend === undefined ? "open" : checkSandboxPolicy(work, sandbox, head, cache, cache, []).network;
|
|
6489
|
+
const daemonNetwork = checkNetwork === "open" ? "open" : { hosts: checkNetwork.hosts };
|
|
6122
6490
|
const services = (id) => ({
|
|
6123
6491
|
id,
|
|
6124
6492
|
backend: input.sandbox?.backend,
|
|
6125
6493
|
platform: (input.sandbox?.backend === "srt" ? input.sandbox.platform : undefined) ?? process.platform,
|
|
6126
|
-
postgres: input.postgres
|
|
6494
|
+
postgres: input.postgres,
|
|
6495
|
+
docker: input.docker,
|
|
6496
|
+
network: daemonNetwork
|
|
6127
6497
|
});
|
|
6128
6498
|
const headChecks = yield* runChecks(head, work.checks, headTree, known, runIn(head), keeper(""), services(work.id)).pipe(scoped);
|
|
6129
6499
|
return {
|
|
@@ -6138,7 +6508,7 @@ var verificationExecutor = (input) => (work) => gen(function* () {
|
|
|
6138
6508
|
baseline: {
|
|
6139
6509
|
revision: (yield* runCommand2("git", ["-C", baseline, "rev-parse", "HEAD"])).trim(),
|
|
6140
6510
|
tree: baselineTree,
|
|
6141
|
-
checks: yield* runChecks(baseline, work.checks, baselineTree, known, runIn(baseline), keeper("baseline-"), services(`${work.id}-baseline`)).pipe(scoped)
|
|
6511
|
+
checks: yield* runChecks(baseline, work.checks.filter((check) => check.pipeline !== true), baselineTree, known, runIn(baseline), keeper("baseline-"), services(`${work.id}-baseline`)).pipe(scoped)
|
|
6142
6512
|
}
|
|
6143
6513
|
}
|
|
6144
6514
|
}
|
|
@@ -6162,11 +6532,13 @@ export {
|
|
|
6162
6532
|
AgentRuntimePackageName,
|
|
6163
6533
|
AgentStepFailure,
|
|
6164
6534
|
BundleRefused,
|
|
6535
|
+
CheckDockerUnavailable,
|
|
6165
6536
|
CheckPostgresImage,
|
|
6166
6537
|
CheckPostgresUnavailable,
|
|
6167
6538
|
CommandFailed2 as CommandFailed,
|
|
6168
6539
|
CommandRunner2 as CommandRunner,
|
|
6169
6540
|
ContainerError,
|
|
6541
|
+
DockerHubRegistry,
|
|
6170
6542
|
EgressProxyImage,
|
|
6171
6543
|
HERDR_CORE_GENERATION2 as HERDR_CORE_GENERATION,
|
|
6172
6544
|
HERDR_CORE_INSTALL_COMMAND2 as HERDR_CORE_INSTALL_COMMAND,
|
|
@@ -6190,11 +6562,18 @@ export {
|
|
|
6190
6562
|
applyAgentEnvironmentMaterialization2 as applyAgentEnvironmentMaterialization,
|
|
6191
6563
|
applyAgentEnvironmentPlans,
|
|
6192
6564
|
assertHerdrRunnerCapability2 as assertHerdrRunnerCapability,
|
|
6565
|
+
checkDockerAlias,
|
|
6566
|
+
checkDockerClientConfig,
|
|
6567
|
+
checkDockerDaemonArgs,
|
|
6568
|
+
checkDockerPort,
|
|
6569
|
+
checkDockerProxyEnvironment,
|
|
6193
6570
|
checkPostgresAlias,
|
|
6194
6571
|
checkPostgresSandboxPort,
|
|
6195
6572
|
checkPostgresSocketUrl,
|
|
6196
6573
|
checkPostgresSweepInterval,
|
|
6197
6574
|
checkPostgresUrl,
|
|
6575
|
+
checkRegistryCacheVolume,
|
|
6576
|
+
checkRegistryMirrorArgs,
|
|
6198
6577
|
clearSettledCheckpoints,
|
|
6199
6578
|
commandHostProbe,
|
|
6200
6579
|
compiled2 as compiled,
|
|
@@ -6202,6 +6581,7 @@ export {
|
|
|
6202
6581
|
controlFailureKind,
|
|
6203
6582
|
defaultAgentRuntimeUserConfigPath,
|
|
6204
6583
|
detectHarnesses2 as detectHarnesses,
|
|
6584
|
+
dockerCheckDaemon,
|
|
6205
6585
|
dockerCheckPostgres,
|
|
6206
6586
|
dockerContainerRunner,
|
|
6207
6587
|
dockerExecArgv,
|
|
@@ -6239,6 +6619,7 @@ export {
|
|
|
6239
6619
|
liveReplicaIds,
|
|
6240
6620
|
loadAgentRuntimeConfig,
|
|
6241
6621
|
makeReplicaSignals,
|
|
6622
|
+
orphanedCheckDocker,
|
|
6242
6623
|
orphanedCheckPostgres,
|
|
6243
6624
|
pinnedSrtCommand2 as pinnedSrtCommand,
|
|
6244
6625
|
pinnedSrtStepCommand2 as pinnedSrtStepCommand,
|
|
@@ -6253,6 +6634,7 @@ export {
|
|
|
6253
6634
|
publishedPort,
|
|
6254
6635
|
readManifestSkillPaths2 as readManifestSkillPaths,
|
|
6255
6636
|
refuseAgentRequest,
|
|
6637
|
+
removeCheckDocker,
|
|
6256
6638
|
removeCheckPostgres,
|
|
6257
6639
|
removeRunnerContainers,
|
|
6258
6640
|
removeRunnerTerminals,
|