@forgezero/agent 0.1.64 → 0.1.67

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.
@@ -21,7 +21,30 @@ var BUN_RELEASE_SHA256 = "951ee2aee855f08595aeec6225226a298d3fea83a3dcd6465c09cb
21
21
  var ARANGO_SHA256 = "b5a9197b4343f2ed554e1ebc1ef8e6529c7c39cde0035cdc311a4747a3355066";
22
22
  var CLOUDFLARED_SHA256 = "9d71c677db00134c1bd4144b7783486b654ad281b1ea62b4972098d19f770f17";
23
23
  var OS_CATALOG = [
24
- { id: "ubuntu", version: "26.04", architecture: "x64", status: "active" }
24
+ {
25
+ id: "ubuntu",
26
+ version: "26.04",
27
+ architecture: "x64",
28
+ status: "active",
29
+ imageKey: "ubuntu-resolute-20260731",
30
+ imageLabel: "Ubuntu 26.04 LTS Resolute",
31
+ imageVersion: "2026-07-31",
32
+ imageUrl: "https://cloud-images.ubuntu.com/releases/resolute/release-20260731/ubuntu-26.04-server-cloudimg-amd64.img",
33
+ imageSha256: "9dc7c5363c0146a08ba0c9aa834d82c2c6dfbb1c471ad9a2f0aba1189e21be05",
34
+ confidentialModes: ["sev-snp"]
35
+ },
36
+ {
37
+ id: "ubuntu",
38
+ version: "24.04",
39
+ architecture: "x64",
40
+ status: "active",
41
+ imageKey: "ubuntu-noble-20260705",
42
+ imageLabel: "Ubuntu 24.04 LTS Noble",
43
+ imageVersion: "2026-07-05",
44
+ imageUrl: "https://cloud-images.ubuntu.com/releases/noble/release-20260705/ubuntu-24.04-server-cloudimg-amd64.img",
45
+ imageSha256: "ffe6203da54deeb6db5d2a98a83f9ec8e55f149d3f7ba622e1abe5fa966ee3d6",
46
+ confidentialModes: []
47
+ }
25
48
  ];
26
49
  var SOFTWARE_CATALOG = [
27
50
  { id: "bun", version: "1.3.14", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
@@ -32,7 +55,12 @@ var SOFTWARE_CATALOG = [
32
55
  { id: "cloudflare-warp", version: "2026.6.822.0-min", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
33
56
  { id: "ufw", version: "ubuntu-26.04", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
34
57
  { id: "openssh-client", version: "ubuntu-26.04", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
35
- { id: "git", version: "ubuntu-26.04", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" }
58
+ { id: "git", version: "ubuntu-26.04", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
59
+ { id: "docker", version: "ubuntu-24.04", status: "active", os: "ubuntu", osVersion: "24.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
60
+ { id: "nginx", version: "ubuntu-24.04", status: "active", os: "ubuntu", osVersion: "24.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
61
+ { id: "ufw", version: "ubuntu-24.04", status: "active", os: "ubuntu", osVersion: "24.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
62
+ { id: "openssh-client", version: "ubuntu-24.04", status: "active", os: "ubuntu", osVersion: "24.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
63
+ { id: "git", version: "ubuntu-24.04", status: "active", os: "ubuntu", osVersion: "24.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" }
36
64
  ];
37
65
  var UBUNTU_2604_X64 = [
38
66
  { requirement: { id: "bun", version: "1.3.14" } },
@@ -45,6 +73,15 @@ var UBUNTU_2604_X64 = [
45
73
  { requirement: { id: "openssh-client", version: "ubuntu-26.04" } },
46
74
  { requirement: { id: "git", version: "ubuntu-26.04" } }
47
75
  ];
76
+ var UBUNTU_2404_X64 = [
77
+ { requirement: { id: "bun", version: "1.3.14" } },
78
+ { requirement: { id: "docker", version: "ubuntu-24.04" } },
79
+ { requirement: { id: "nginx", version: "ubuntu-24.04" } },
80
+ { requirement: { id: "ufw", version: "ubuntu-24.04" } },
81
+ { requirement: { id: "openssh-client", version: "ubuntu-24.04" } },
82
+ { requirement: { id: "git", version: "ubuntu-24.04" } }
83
+ ];
84
+ var strategiesFor = (observation) => observation.os.id === "ubuntu" && observation.architecture === "x64" ? observation.os.versionId === "26.04" ? UBUNTU_2604_X64 : observation.os.versionId === "24.04" ? UBUNTU_2404_X64 : undefined : undefined;
48
85
  var path = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
49
86
  var DOCKER_DAEMON_PATH = "/etc/docker/daemon.json";
50
87
  var DOCKER_DAEMON_CONFIG = `${JSON.stringify({
@@ -91,7 +128,7 @@ var aptInstall = async (name) => {
91
128
  };
92
129
  async function executeSoftwareOperation(operation) {
93
130
  const { software, version } = operation;
94
- if (!UBUNTU_2604_X64.some(({ requirement }) => requirement.id === software && requirement.version === version)) {
131
+ if (![...UBUNTU_2604_X64, ...UBUNTU_2404_X64].some(({ requirement }) => requirement.id === software && requirement.version === version)) {
95
132
  return { exitCode: 2, output: "unsupported software operation" };
96
133
  }
97
134
  if (operation.kind === "check") {
@@ -261,7 +298,7 @@ async function ensureSoftwareRequirements(requirementsInput, options) {
261
298
  }
262
299
  const results = [];
263
300
  for (const requirement of requirements) {
264
- const strategy = UBUNTU_2604_X64.find(({ requirement: candidate }) => candidate.id === requirement.id && candidate.version === requirement.version);
301
+ const strategy = strategiesFor(observation)?.find(({ requirement: candidate }) => candidate.id === requirement.id && candidate.version === requirement.version);
265
302
  if (!strategy)
266
303
  throw new Error(`unsupported software requirement: ${requirement.id}@${requirement.version}`);
267
304
  const before = await options.exec({ kind: "check", software: requirement.id, version: requirement.version });
@@ -283,19 +320,15 @@ async function ensureSoftwareRequirements(requirementsInput, options) {
283
320
  // src/community-rehearsal-host.ts
284
321
  import { createHash as createHash2 } from "node:crypto";
285
322
  import { lstatSync, mkdirSync as mkdirSync2, readFileSync as readFileSync2, rmSync as rmSync2, symlinkSync as symlinkSync2, unlinkSync as unlinkSync2, writeFileSync as writeFileSync2 } from "node:fs";
323
+ import { isIP } from "node:net";
286
324
  import { dirname } from "node:path";
287
325
  var COMMUNITY_REHEARSAL_VERSION = "3.11.14";
288
326
  var COMMUNITY_REHEARSAL_ROOT = "/opt/forgezero-rehearsals/community-cluster-api";
289
327
  var COMMUNITY_DATABASE_ROOT = "/var/lib/forgezero-rehearsal-cluster";
290
328
  var COMMUNITY_CREDENTIAL_PARENT = "/etc/forgezero-rehearsal";
291
329
  var COMMUNITY_CREDENTIAL_ROOT = "/etc/forgezero-rehearsal/creds";
292
- var NODES = new Map([
293
- ["dev-fz-n1", { address: "10.42.0.21", agency: true }],
294
- ["dev-fz-n2", { address: "10.42.0.22", agency: true }],
295
- ["dev-fz-n3", { address: "10.42.0.23", agency: true }],
296
- ["dev-fz-n4", { address: "10.42.0.24", agency: false }]
297
- ]);
298
330
  var RELEASE = /^[a-f0-9]{64}$/;
331
+ var SAFE_NAME = /^[a-z][a-z0-9-]{0,62}$/;
299
332
  async function ensureCommunityRehearsalArango(execute = executeSoftwareOperation) {
300
333
  const requirement = { software: "arangodb", version: COMMUNITY_REHEARSAL_VERSION };
301
334
  if ((await execute({ kind: "check", ...requirement })).exitCode === 0)
@@ -310,50 +343,70 @@ var exactObject = (value) => {
310
343
  throw new Error("community rehearsal request must be an object");
311
344
  return value;
312
345
  };
313
- var exactNode = (node) => {
314
- if (typeof node !== "string")
346
+ var nodeName = (node) => {
347
+ if (typeof node !== "string" || !SAFE_NAME.test(node))
315
348
  throw new Error("community rehearsal node is invalid");
316
- const expected = NODES.get(node);
317
- if (!expected)
318
- throw new Error("community rehearsal accepts only the dedicated dev-fz-n1..n4 fleet");
319
- return { name: node, ...expected };
349
+ return node;
350
+ };
351
+ var validateCommunityRehearsalTopology = (value) => {
352
+ if (!Array.isArray(value) || value.length !== 4)
353
+ throw new Error("community rehearsal requires exactly four reviewed nodes");
354
+ const rows = value.map((item, index) => {
355
+ const row = exactObject(item);
356
+ if (Object.keys(row).some((key) => !["name", "address", "agency", "starter", "readPreferred"].includes(key)) || typeof row.name !== "string" || !SAFE_NAME.test(row.name) || typeof row.address !== "string" || isIP(row.address) !== 4 || typeof row.agency !== "boolean" || typeof row.starter !== "boolean" || typeof row.readPreferred !== "boolean") {
357
+ throw new Error(`community rehearsal topology node ${index + 1} is invalid`);
358
+ }
359
+ return row;
360
+ });
361
+ if (new Set(rows.map(({ name }) => name)).size !== rows.length || new Set(rows.map(({ address }) => address)).size !== rows.length) {
362
+ throw new Error("community rehearsal node names and addresses must be unique");
363
+ }
364
+ if (rows.filter(({ agency }) => agency).length !== 3 || rows.filter(({ starter }) => starter).length !== 1 || !rows.find(({ starter }) => starter).agency || rows.filter(({ readPreferred }) => readPreferred).length !== 1 || rows.find(({ readPreferred }) => readPreferred).agency) {
365
+ throw new Error("community rehearsal requires three Agency voters, one voter starter and one non-voting read-preferred member");
366
+ }
367
+ return rows;
320
368
  };
321
369
  function parseCommunityRehearsalHostRequest(value) {
322
370
  const row = exactObject(value);
323
- const node = exactNode(row.node);
371
+ const node = nodeName(row.node);
372
+ const topology = validateCommunityRehearsalTopology(row.topology);
373
+ const expected = topology.find((entry) => entry.name === node);
374
+ if (!expected)
375
+ throw new Error("community rehearsal node is not present in the reviewed topology");
324
376
  const action = row.action;
325
377
  if (action === "prepare") {
326
- const allowed = ["action", "node", "address", "agency", "release", "archivePath", "archiveSha256", "jwt"];
327
- if (Object.keys(row).some((key) => !allowed.includes(key)) || row.address !== node.address || row.agency !== node.agency || typeof row.release !== "string" || !RELEASE.test(row.release) || row.archiveSha256 !== row.release || row.archivePath !== `/tmp/forgezero-community-${row.release}.tar.gz` || typeof row.jwt !== "string" || !/^[a-f0-9]{64}$/.test(row.jwt)) {
378
+ const allowed = ["action", "node", "address", "agency", "topology", "release", "archivePath", "archiveSha256", "jwt"];
379
+ if (Object.keys(row).some((key) => !allowed.includes(key)) || row.address !== expected.address || row.agency !== expected.agency || typeof row.release !== "string" || !RELEASE.test(row.release) || row.archiveSha256 !== row.release || row.archivePath !== `/tmp/forgezero-community-${row.release}.tar.gz` || typeof row.jwt !== "string" || !/^[a-f0-9]{64}$/.test(row.jwt)) {
328
380
  throw new Error("community rehearsal prepare request does not match the dedicated fleet contract");
329
381
  }
330
- return row;
382
+ return { ...row, topology };
331
383
  }
332
384
  if (action === "cleanup") {
333
- if (Object.keys(row).some((key) => !["action", "node"].includes(key))) {
385
+ if (Object.keys(row).some((key) => !["action", "node", "topology"].includes(key))) {
334
386
  throw new Error("community rehearsal cleanup has unknown fields");
335
387
  }
336
- return { action, node: node.name };
388
+ return { action, node, topology };
337
389
  }
338
390
  if (["database-enable", "api-enable", "database-ready", "starter-ready", "api-ready", "database-status", "api-status"].includes(String(action))) {
339
- if (Object.keys(row).some((key) => !["action", "node"].includes(key)))
391
+ if (Object.keys(row).some((key) => !["action", "node", "topology"].includes(key)))
340
392
  throw new Error("community rehearsal host action has unknown fields");
341
- return { action, node: node.name };
393
+ return { action, node, topology };
342
394
  }
343
395
  if (action === "api") {
344
- if (Object.keys(row).some((key) => !["action", "node", "operation", "key", "value"].includes(key)) || !["health", "init", "write", "read", "query", "cluster"].includes(String(row.operation)) || row.key !== undefined && (typeof row.key !== "string" || !/^[A-Za-z0-9_.:-]{1,128}$/.test(row.key)) || row.value !== undefined && (typeof row.value !== "string" || row.value.length > 4096)) {
396
+ if (Object.keys(row).some((key) => !["action", "node", "topology", "operation", "key", "value"].includes(key)) || !["health", "init", "write", "read", "query", "cluster"].includes(String(row.operation)) || row.key !== undefined && (typeof row.key !== "string" || !/^[A-Za-z0-9_.:-]{1,128}$/.test(row.key)) || row.value !== undefined && (typeof row.value !== "string" || row.value.length > 4096)) {
345
397
  throw new Error("community rehearsal API request is invalid");
346
398
  }
347
399
  if ((row.operation === "write" || row.operation === "read") && typeof row.key !== "string")
348
400
  throw new Error("community rehearsal API key is required");
349
401
  if ((row.operation === "write" || row.operation === "query") && typeof row.value !== "string")
350
402
  throw new Error("community rehearsal API value is required");
351
- return row;
403
+ return { ...row, node, topology };
352
404
  }
353
405
  throw new Error("unsupported community rehearsal host action");
354
406
  }
355
- var databaseUnit = (node) => {
356
- const join2 = node.name === "dev-fz-n1" ? "" : " --starter.join=10.42.0.21";
407
+ var databaseUnit = (node, topology) => {
408
+ const starter = topology.find((entry) => entry.starter);
409
+ const join2 = node.starter ? "" : ` --starter.join=${starter.address}`;
357
410
  const role = node.agency ? "" : " --cluster.start-agent=false --cluster.start-coordinator=true --cluster.start-dbserver=true";
358
411
  return `[Unit]
359
412
  Description=ForgeZero isolated Community ${COMMUNITY_REHEARSAL_VERSION} rehearsal cluster
@@ -388,7 +441,10 @@ LockPersonality=true
388
441
  WantedBy=multi-user.target
389
442
  `;
390
443
  };
391
- var apiUnit = (node) => `[Unit]
444
+ var apiUnit = (node, topology) => {
445
+ const urls = topology.map(({ address }) => `http://${address}:8529`).join(",");
446
+ const readPreferred = topology.filter(({ readPreferred: readPreferred2 }) => readPreferred2).map(({ address }) => `http://${address}:8529`).join(",");
447
+ return `[Unit]
392
448
  Description=ForgeZero typed Community cluster rehearsal API
393
449
  After=forgezero-rehearsal-db.service network-online.target
394
450
  Requires=forgezero-rehearsal-db.service
@@ -403,8 +459,8 @@ Environment=HOST=127.0.0.1
403
459
  Environment=PORT=8787
404
460
  Environment=NODE_NAME=${node.name}
405
461
  Environment=ARANGO_URL=http://127.0.0.1:8529
406
- Environment=ARANGO_URLS=http://10.42.0.21:8529,http://10.42.0.22:8529,http://10.42.0.23:8529,http://10.42.0.24:8529
407
- Environment=ARANGO_READ_PREFERRED_URLS=http://10.42.0.24:8529
462
+ Environment=ARANGO_URLS=${urls}
463
+ Environment=ARANGO_READ_PREFERRED_URLS=${readPreferred}
408
464
  Environment=ARANGO_READ_PREFERRED_FALLBACK=error
409
465
  ExecStart=/usr/local/bin/bun src/index.ts
410
466
  Restart=always
@@ -424,8 +480,10 @@ LockPersonality=true
424
480
  [Install]
425
481
  WantedBy=multi-user.target
426
482
  `;
483
+ };
427
484
  function planCommunityRehearsalPrepare(request) {
428
- const node = exactNode(request.node);
485
+ const topology = validateCommunityRehearsalTopology(request.topology);
486
+ const node = topology.find(({ name }) => name === request.node);
429
487
  const releaseRoot = `${COMMUNITY_REHEARSAL_ROOT}/releases/${request.release}`;
430
488
  return [
431
489
  { kind: "exec", argv: ["/usr/sbin/arangod", "--version"] },
@@ -440,13 +498,13 @@ function planCommunityRehearsalPrepare(request) {
440
498
  ` },
441
499
  { kind: "exec", argv: ["/usr/bin/chmod", "0400", `${COMMUNITY_CREDENTIAL_ROOT}/arangodb-jwt.cred.next`] },
442
500
  { kind: "exec", argv: ["/usr/bin/mv", "-f", `${COMMUNITY_CREDENTIAL_ROOT}/arangodb-jwt.cred.next`, `${COMMUNITY_CREDENTIAL_ROOT}/arangodb-jwt.cred`] },
443
- { kind: "write", path: "/etc/systemd/system/forgezero-rehearsal-db.service", content: databaseUnit(node), mode: 420 },
501
+ { kind: "write", path: "/etc/systemd/system/forgezero-rehearsal-db.service", content: databaseUnit(node, topology), mode: 420 },
444
502
  { kind: "exec", argv: ["/usr/bin/tar", "-xzf", request.archivePath, "-C", releaseRoot] },
445
503
  { kind: "exec", argv: ["/usr/bin/chown", "-R", "forgezero:forgezero", releaseRoot] },
446
504
  { kind: "exec", argv: ["/usr/sbin/runuser", "-u", "forgezero", "--", "/usr/local/bin/bun", "install", "--cwd", releaseRoot, "--frozen-lockfile", "--production"] },
447
505
  { kind: "unlink", path: `${COMMUNITY_REHEARSAL_ROOT}/current` },
448
506
  { kind: "symlink", target: releaseRoot, path: `${COMMUNITY_REHEARSAL_ROOT}/current` },
449
- { kind: "write", path: "/etc/systemd/system/forgezero-community-api.service", content: apiUnit(node), mode: 420 },
507
+ { kind: "write", path: "/etc/systemd/system/forgezero-community-api.service", content: apiUnit(node, topology), mode: 420 },
450
508
  { kind: "unlink", path: request.archivePath }
451
509
  ];
452
510
  }
@@ -524,7 +582,10 @@ var responseFor = async (request) => {
524
582
  async function runCommunityRehearsalHost(request) {
525
583
  if ((process.getuid?.() ?? -1) !== 0)
526
584
  throw new Error("community-rehearsal must run as root");
527
- const node = exactNode(request.node);
585
+ const topology = validateCommunityRehearsalTopology(request.topology);
586
+ const node = topology.find((entry) => entry.name === request.node);
587
+ if (!node)
588
+ throw new Error("community rehearsal node is not present in the reviewed topology");
528
589
  if (request.action === "cleanup") {
529
590
  await applyOperations(planCommunityRehearsalCleanup());
530
591
  return { ok: true, action: request.action, node: node.name };
@@ -561,7 +622,8 @@ async function runCommunityRehearsalHost(request) {
561
622
  return { ok: true, action: request.action, node: node.name };
562
623
  }
563
624
  if (request.action === "database-ready" || request.action === "starter-ready" || request.action === "api-ready") {
564
- const url = request.action === "database-ready" ? "http://127.0.0.1:8529/_api/version" : request.action === "starter-ready" ? "http://10.42.0.21:8528/version" : "http://127.0.0.1:8787/health";
625
+ const starter = topology.find((entry) => entry.starter);
626
+ const url = request.action === "database-ready" ? "http://127.0.0.1:8529/_api/version" : request.action === "starter-ready" ? `http://${starter.address}:8528/version` : "http://127.0.0.1:8787/health";
565
627
  const response2 = await fetch(url, { signal: AbortSignal.timeout(2000) }).catch(() => {
566
628
  return;
567
629
  });
@@ -578,6 +640,7 @@ async function runCommunityRehearsalHost(request) {
578
640
  return { ok: true, action: request.action, node: node.name, operation: request.operation, status: response.status, body };
579
641
  }
580
642
  export {
643
+ validateCommunityRehearsalTopology,
581
644
  runCommunityRehearsalHost,
582
645
  planCommunityRehearsalPrepare,
583
646
  planCommunityRehearsalCleanup,
@@ -21,7 +21,30 @@ var BUN_RELEASE_SHA256 = "951ee2aee855f08595aeec6225226a298d3fea83a3dcd6465c09cb
21
21
  var ARANGO_SHA256 = "b5a9197b4343f2ed554e1ebc1ef8e6529c7c39cde0035cdc311a4747a3355066";
22
22
  var CLOUDFLARED_SHA256 = "9d71c677db00134c1bd4144b7783486b654ad281b1ea62b4972098d19f770f17";
23
23
  var OS_CATALOG = [
24
- { id: "ubuntu", version: "26.04", architecture: "x64", status: "active" }
24
+ {
25
+ id: "ubuntu",
26
+ version: "26.04",
27
+ architecture: "x64",
28
+ status: "active",
29
+ imageKey: "ubuntu-resolute-20260731",
30
+ imageLabel: "Ubuntu 26.04 LTS Resolute",
31
+ imageVersion: "2026-07-31",
32
+ imageUrl: "https://cloud-images.ubuntu.com/releases/resolute/release-20260731/ubuntu-26.04-server-cloudimg-amd64.img",
33
+ imageSha256: "9dc7c5363c0146a08ba0c9aa834d82c2c6dfbb1c471ad9a2f0aba1189e21be05",
34
+ confidentialModes: ["sev-snp"]
35
+ },
36
+ {
37
+ id: "ubuntu",
38
+ version: "24.04",
39
+ architecture: "x64",
40
+ status: "active",
41
+ imageKey: "ubuntu-noble-20260705",
42
+ imageLabel: "Ubuntu 24.04 LTS Noble",
43
+ imageVersion: "2026-07-05",
44
+ imageUrl: "https://cloud-images.ubuntu.com/releases/noble/release-20260705/ubuntu-24.04-server-cloudimg-amd64.img",
45
+ imageSha256: "ffe6203da54deeb6db5d2a98a83f9ec8e55f149d3f7ba622e1abe5fa966ee3d6",
46
+ confidentialModes: []
47
+ }
25
48
  ];
26
49
  var SOFTWARE_CATALOG = [
27
50
  { id: "bun", version: "1.3.14", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
@@ -32,7 +55,12 @@ var SOFTWARE_CATALOG = [
32
55
  { id: "cloudflare-warp", version: "2026.6.822.0-min", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
33
56
  { id: "ufw", version: "ubuntu-26.04", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
34
57
  { id: "openssh-client", version: "ubuntu-26.04", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
35
- { id: "git", version: "ubuntu-26.04", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" }
58
+ { id: "git", version: "ubuntu-26.04", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
59
+ { id: "docker", version: "ubuntu-24.04", status: "active", os: "ubuntu", osVersion: "24.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
60
+ { id: "nginx", version: "ubuntu-24.04", status: "active", os: "ubuntu", osVersion: "24.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
61
+ { id: "ufw", version: "ubuntu-24.04", status: "active", os: "ubuntu", osVersion: "24.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
62
+ { id: "openssh-client", version: "ubuntu-24.04", status: "active", os: "ubuntu", osVersion: "24.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
63
+ { id: "git", version: "ubuntu-24.04", status: "active", os: "ubuntu", osVersion: "24.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" }
36
64
  ];
37
65
  var UBUNTU_2604_X64 = [
38
66
  { requirement: { id: "bun", version: "1.3.14" } },
@@ -45,6 +73,15 @@ var UBUNTU_2604_X64 = [
45
73
  { requirement: { id: "openssh-client", version: "ubuntu-26.04" } },
46
74
  { requirement: { id: "git", version: "ubuntu-26.04" } }
47
75
  ];
76
+ var UBUNTU_2404_X64 = [
77
+ { requirement: { id: "bun", version: "1.3.14" } },
78
+ { requirement: { id: "docker", version: "ubuntu-24.04" } },
79
+ { requirement: { id: "nginx", version: "ubuntu-24.04" } },
80
+ { requirement: { id: "ufw", version: "ubuntu-24.04" } },
81
+ { requirement: { id: "openssh-client", version: "ubuntu-24.04" } },
82
+ { requirement: { id: "git", version: "ubuntu-24.04" } }
83
+ ];
84
+ var strategiesFor = (observation) => observation.os.id === "ubuntu" && observation.architecture === "x64" ? observation.os.versionId === "26.04" ? UBUNTU_2604_X64 : observation.os.versionId === "24.04" ? UBUNTU_2404_X64 : undefined : undefined;
48
85
  var path = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
49
86
  var DOCKER_DAEMON_PATH = "/etc/docker/daemon.json";
50
87
  var DOCKER_DAEMON_CONFIG = `${JSON.stringify({
@@ -91,7 +128,7 @@ var aptInstall = async (name) => {
91
128
  };
92
129
  async function executeSoftwareOperation(operation) {
93
130
  const { software, version } = operation;
94
- if (!UBUNTU_2604_X64.some(({ requirement }) => requirement.id === software && requirement.version === version)) {
131
+ if (![...UBUNTU_2604_X64, ...UBUNTU_2404_X64].some(({ requirement }) => requirement.id === software && requirement.version === version)) {
95
132
  return { exitCode: 2, output: "unsupported software operation" };
96
133
  }
97
134
  if (operation.kind === "check") {
@@ -261,7 +298,7 @@ async function ensureSoftwareRequirements(requirementsInput, options) {
261
298
  }
262
299
  const results = [];
263
300
  for (const requirement of requirements) {
264
- const strategy = UBUNTU_2604_X64.find(({ requirement: candidate }) => candidate.id === requirement.id && candidate.version === requirement.version);
301
+ const strategy = strategiesFor(observation)?.find(({ requirement: candidate }) => candidate.id === requirement.id && candidate.version === requirement.version);
265
302
  if (!strategy)
266
303
  throw new Error(`unsupported software requirement: ${requirement.id}@${requirement.version}`);
267
304
  const before = await options.exec({ kind: "check", software: requirement.id, version: requirement.version });
@@ -92,13 +92,13 @@ function validateBuiltInProvider(requirement2, where) {
92
92
  return;
93
93
  const expected = {
94
94
  "forgezero.bun": { capability: "runtime.javascript", versions: ["1.3.14"], keys: ["installScope"] },
95
- "forgezero.docker": { capability: "runtime.container", versions: ["ubuntu-26.04"], keys: ["installScope", "storageDriver", "dataRoot", "liveRestore", "logDriver", "defaultNetwork", "rootless"] },
96
- "forgezero.nginx": { capability: "proxy.http", versions: ["ubuntu-26.04"], keys: ["installScope", "websocket", "maximumBodyMiB", "workerProcesses", "workerConnections"] },
95
+ "forgezero.docker": { capability: "runtime.container", versions: ["ubuntu-24.04", "ubuntu-26.04"], keys: ["installScope", "storageDriver", "dataRoot", "liveRestore", "logDriver", "defaultNetwork", "rootless"] },
96
+ "forgezero.nginx": { capability: "proxy.http", versions: ["ubuntu-24.04", "ubuntu-26.04"], keys: ["installScope", "websocket", "maximumBodyMiB", "workerProcesses", "workerConnections"] },
97
97
  "forgezero.arangodb": { capability: "database.arangodb", versions: ["3.11.14"], keys: ["installScope", "runtime", "dataPath", "bind"] },
98
98
  "forgezero.cloudflared": { capability: "network.public-tunnel", versions: ["2026.7.3"], keys: ["installScope", "mode"] },
99
99
  "forgezero.warp": { capability: "network.private", versions: ["2026.6.822.0-min"], keys: ["installScope", "mode"] },
100
- "forgezero.ufw": { capability: "security.firewall", versions: ["ubuntu-26.04"], keys: ["installScope", "defaultIncoming", "defaultOutgoing"] },
101
- "forgezero.openssh": { capability: "transport.ssh", versions: ["ubuntu-26.04"], keys: ["installScope", "mode"] },
100
+ "forgezero.ufw": { capability: "security.firewall", versions: ["ubuntu-24.04", "ubuntu-26.04"], keys: ["installScope", "defaultIncoming", "defaultOutgoing"] },
101
+ "forgezero.openssh": { capability: "transport.ssh", versions: ["ubuntu-24.04", "ubuntu-26.04"], keys: ["installScope", "mode"] },
102
102
  "forgezero.systemd": { capability: "service.manager", versions: ["ubuntu-26.04"], keys: ["installScope", "credentials", "serviceSandbox"] }
103
103
  };
104
104
  const contract = expected[requirement2.provider];
@@ -21,7 +21,30 @@ var BUN_RELEASE_SHA256 = "951ee2aee855f08595aeec6225226a298d3fea83a3dcd6465c09cb
21
21
  var ARANGO_SHA256 = "b5a9197b4343f2ed554e1ebc1ef8e6529c7c39cde0035cdc311a4747a3355066";
22
22
  var CLOUDFLARED_SHA256 = "9d71c677db00134c1bd4144b7783486b654ad281b1ea62b4972098d19f770f17";
23
23
  var OS_CATALOG = [
24
- { id: "ubuntu", version: "26.04", architecture: "x64", status: "active" }
24
+ {
25
+ id: "ubuntu",
26
+ version: "26.04",
27
+ architecture: "x64",
28
+ status: "active",
29
+ imageKey: "ubuntu-resolute-20260731",
30
+ imageLabel: "Ubuntu 26.04 LTS Resolute",
31
+ imageVersion: "2026-07-31",
32
+ imageUrl: "https://cloud-images.ubuntu.com/releases/resolute/release-20260731/ubuntu-26.04-server-cloudimg-amd64.img",
33
+ imageSha256: "9dc7c5363c0146a08ba0c9aa834d82c2c6dfbb1c471ad9a2f0aba1189e21be05",
34
+ confidentialModes: ["sev-snp"]
35
+ },
36
+ {
37
+ id: "ubuntu",
38
+ version: "24.04",
39
+ architecture: "x64",
40
+ status: "active",
41
+ imageKey: "ubuntu-noble-20260705",
42
+ imageLabel: "Ubuntu 24.04 LTS Noble",
43
+ imageVersion: "2026-07-05",
44
+ imageUrl: "https://cloud-images.ubuntu.com/releases/noble/release-20260705/ubuntu-24.04-server-cloudimg-amd64.img",
45
+ imageSha256: "ffe6203da54deeb6db5d2a98a83f9ec8e55f149d3f7ba622e1abe5fa966ee3d6",
46
+ confidentialModes: []
47
+ }
25
48
  ];
26
49
  var SOFTWARE_CATALOG = [
27
50
  { id: "bun", version: "1.3.14", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
@@ -32,7 +55,12 @@ var SOFTWARE_CATALOG = [
32
55
  { id: "cloudflare-warp", version: "2026.6.822.0-min", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
33
56
  { id: "ufw", version: "ubuntu-26.04", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
34
57
  { id: "openssh-client", version: "ubuntu-26.04", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
35
- { id: "git", version: "ubuntu-26.04", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" }
58
+ { id: "git", version: "ubuntu-26.04", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
59
+ { id: "docker", version: "ubuntu-24.04", status: "active", os: "ubuntu", osVersion: "24.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
60
+ { id: "nginx", version: "ubuntu-24.04", status: "active", os: "ubuntu", osVersion: "24.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
61
+ { id: "ufw", version: "ubuntu-24.04", status: "active", os: "ubuntu", osVersion: "24.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
62
+ { id: "openssh-client", version: "ubuntu-24.04", status: "active", os: "ubuntu", osVersion: "24.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
63
+ { id: "git", version: "ubuntu-24.04", status: "active", os: "ubuntu", osVersion: "24.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" }
36
64
  ];
37
65
  var UBUNTU_2604_X64 = [
38
66
  { requirement: { id: "bun", version: "1.3.14" } },
@@ -45,6 +73,15 @@ var UBUNTU_2604_X64 = [
45
73
  { requirement: { id: "openssh-client", version: "ubuntu-26.04" } },
46
74
  { requirement: { id: "git", version: "ubuntu-26.04" } }
47
75
  ];
76
+ var UBUNTU_2404_X64 = [
77
+ { requirement: { id: "bun", version: "1.3.14" } },
78
+ { requirement: { id: "docker", version: "ubuntu-24.04" } },
79
+ { requirement: { id: "nginx", version: "ubuntu-24.04" } },
80
+ { requirement: { id: "ufw", version: "ubuntu-24.04" } },
81
+ { requirement: { id: "openssh-client", version: "ubuntu-24.04" } },
82
+ { requirement: { id: "git", version: "ubuntu-24.04" } }
83
+ ];
84
+ var strategiesFor = (observation) => observation.os.id === "ubuntu" && observation.architecture === "x64" ? observation.os.versionId === "26.04" ? UBUNTU_2604_X64 : observation.os.versionId === "24.04" ? UBUNTU_2404_X64 : undefined : undefined;
48
85
  var path = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
49
86
  var DOCKER_DAEMON_PATH = "/etc/docker/daemon.json";
50
87
  var DOCKER_DAEMON_CONFIG = `${JSON.stringify({
@@ -91,7 +128,7 @@ var aptInstall = async (name) => {
91
128
  };
92
129
  async function executeSoftwareOperation(operation) {
93
130
  const { software, version } = operation;
94
- if (!UBUNTU_2604_X64.some(({ requirement }) => requirement.id === software && requirement.version === version)) {
131
+ if (![...UBUNTU_2604_X64, ...UBUNTU_2404_X64].some(({ requirement }) => requirement.id === software && requirement.version === version)) {
95
132
  return { exitCode: 2, output: "unsupported software operation" };
96
133
  }
97
134
  if (operation.kind === "check") {
@@ -261,7 +298,7 @@ async function ensureSoftwareRequirements(requirementsInput, options) {
261
298
  }
262
299
  const results = [];
263
300
  for (const requirement of requirements) {
264
- const strategy = UBUNTU_2604_X64.find(({ requirement: candidate }) => candidate.id === requirement.id && candidate.version === requirement.version);
301
+ const strategy = strategiesFor(observation)?.find(({ requirement: candidate }) => candidate.id === requirement.id && candidate.version === requirement.version);
265
302
  if (!strategy)
266
303
  throw new Error(`unsupported software requirement: ${requirement.id}@${requirement.version}`);
267
304
  const before = await options.exec({ kind: "check", software: requirement.id, version: requirement.version });
@@ -92,13 +92,13 @@ function validateBuiltInProvider(requirement2, where) {
92
92
  return;
93
93
  const expected = {
94
94
  "forgezero.bun": { capability: "runtime.javascript", versions: ["1.3.14"], keys: ["installScope"] },
95
- "forgezero.docker": { capability: "runtime.container", versions: ["ubuntu-26.04"], keys: ["installScope", "storageDriver", "dataRoot", "liveRestore", "logDriver", "defaultNetwork", "rootless"] },
96
- "forgezero.nginx": { capability: "proxy.http", versions: ["ubuntu-26.04"], keys: ["installScope", "websocket", "maximumBodyMiB", "workerProcesses", "workerConnections"] },
95
+ "forgezero.docker": { capability: "runtime.container", versions: ["ubuntu-24.04", "ubuntu-26.04"], keys: ["installScope", "storageDriver", "dataRoot", "liveRestore", "logDriver", "defaultNetwork", "rootless"] },
96
+ "forgezero.nginx": { capability: "proxy.http", versions: ["ubuntu-24.04", "ubuntu-26.04"], keys: ["installScope", "websocket", "maximumBodyMiB", "workerProcesses", "workerConnections"] },
97
97
  "forgezero.arangodb": { capability: "database.arangodb", versions: ["3.11.14"], keys: ["installScope", "runtime", "dataPath", "bind"] },
98
98
  "forgezero.cloudflared": { capability: "network.public-tunnel", versions: ["2026.7.3"], keys: ["installScope", "mode"] },
99
99
  "forgezero.warp": { capability: "network.private", versions: ["2026.6.822.0-min"], keys: ["installScope", "mode"] },
100
- "forgezero.ufw": { capability: "security.firewall", versions: ["ubuntu-26.04"], keys: ["installScope", "defaultIncoming", "defaultOutgoing"] },
101
- "forgezero.openssh": { capability: "transport.ssh", versions: ["ubuntu-26.04"], keys: ["installScope", "mode"] },
100
+ "forgezero.ufw": { capability: "security.firewall", versions: ["ubuntu-24.04", "ubuntu-26.04"], keys: ["installScope", "defaultIncoming", "defaultOutgoing"] },
101
+ "forgezero.openssh": { capability: "transport.ssh", versions: ["ubuntu-24.04", "ubuntu-26.04"], keys: ["installScope", "mode"] },
102
102
  "forgezero.systemd": { capability: "service.manager", versions: ["ubuntu-26.04"], keys: ["installScope", "credentials", "serviceSandbox"] }
103
103
  };
104
104
  const contract = expected[requirement2.provider];
@@ -92,13 +92,13 @@ function validateBuiltInProvider(requirement2, where) {
92
92
  return;
93
93
  const expected = {
94
94
  "forgezero.bun": { capability: "runtime.javascript", versions: ["1.3.14"], keys: ["installScope"] },
95
- "forgezero.docker": { capability: "runtime.container", versions: ["ubuntu-26.04"], keys: ["installScope", "storageDriver", "dataRoot", "liveRestore", "logDriver", "defaultNetwork", "rootless"] },
96
- "forgezero.nginx": { capability: "proxy.http", versions: ["ubuntu-26.04"], keys: ["installScope", "websocket", "maximumBodyMiB", "workerProcesses", "workerConnections"] },
95
+ "forgezero.docker": { capability: "runtime.container", versions: ["ubuntu-24.04", "ubuntu-26.04"], keys: ["installScope", "storageDriver", "dataRoot", "liveRestore", "logDriver", "defaultNetwork", "rootless"] },
96
+ "forgezero.nginx": { capability: "proxy.http", versions: ["ubuntu-24.04", "ubuntu-26.04"], keys: ["installScope", "websocket", "maximumBodyMiB", "workerProcesses", "workerConnections"] },
97
97
  "forgezero.arangodb": { capability: "database.arangodb", versions: ["3.11.14"], keys: ["installScope", "runtime", "dataPath", "bind"] },
98
98
  "forgezero.cloudflared": { capability: "network.public-tunnel", versions: ["2026.7.3"], keys: ["installScope", "mode"] },
99
99
  "forgezero.warp": { capability: "network.private", versions: ["2026.6.822.0-min"], keys: ["installScope", "mode"] },
100
- "forgezero.ufw": { capability: "security.firewall", versions: ["ubuntu-26.04"], keys: ["installScope", "defaultIncoming", "defaultOutgoing"] },
101
- "forgezero.openssh": { capability: "transport.ssh", versions: ["ubuntu-26.04"], keys: ["installScope", "mode"] },
100
+ "forgezero.ufw": { capability: "security.firewall", versions: ["ubuntu-24.04", "ubuntu-26.04"], keys: ["installScope", "defaultIncoming", "defaultOutgoing"] },
101
+ "forgezero.openssh": { capability: "transport.ssh", versions: ["ubuntu-24.04", "ubuntu-26.04"], keys: ["installScope", "mode"] },
102
102
  "forgezero.systemd": { capability: "service.manager", versions: ["ubuntu-26.04"], keys: ["installScope", "credentials", "serviceSandbox"] }
103
103
  };
104
104
  const contract = expected[requirement2.provider];