@forgezero/agent 0.1.65 → 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.
- package/README.md +745 -157
- package/dist/agent-heartbeat.js +1 -1
- package/dist/bootstrap-bundle.d.ts +1 -0
- package/dist/bootstrap-bundle.js +4 -3
- package/dist/bootstrap.d.ts +7 -1
- package/dist/bootstrap.js +264 -13
- package/dist/community-rehearsal-host.d.ts +12 -0
- package/dist/community-rehearsal-host.js +99 -36
- package/dist/definition.js +41 -4
- package/dist/deploy-compiler.js +4 -4
- package/dist/deploy-file.js +41 -4
- package/dist/deploy-plan-runner.js +4 -4
- package/dist/deploy-plan.js +4 -4
- package/dist/fz-agent.js +165 -76
- package/dist/fz.js +487 -251
- package/dist/index.d.ts +1 -1
- package/dist/metal-bootstrap.js +120 -46
- package/dist/metal-helper-socket.js +406 -65
- package/dist/metal-provision.js +402 -61
- package/dist/operator-bootstrap.d.ts +20 -4
- package/dist/operator-bootstrap.js +429 -203
- package/dist/platform-bootstrap-runtime.d.ts +33 -0
- package/dist/platform-bootstrap-runtime.js +551 -44
- package/dist/platform-fleet-verification.js +242 -18
- package/dist/platform-genesis-config.d.ts +7 -1
- package/dist/platform-genesis.d.ts +16 -17
- package/dist/platform-genesis.js +464 -0
- package/dist/provision.js +42 -5
- package/dist/software-helper.js +41 -4
- package/dist/software.d.ts +8 -2
- package/dist/software.js +41 -4
- package/dist/ssh-bootstrap.d.ts +5 -0
- package/dist/ubuntu.d.ts +15 -14
- package/dist/ubuntu.js +345 -9
- package/dist/version.d.ts +1 -1
- package/package.json +8 -4
package/dist/software.d.ts
CHANGED
|
@@ -9,16 +9,22 @@ export interface SoftwareRequirement {
|
|
|
9
9
|
export interface SoftwareCatalogEntry extends SoftwareRequirement {
|
|
10
10
|
status: CatalogStatus;
|
|
11
11
|
os: 'ubuntu';
|
|
12
|
-
osVersion: '26.04';
|
|
12
|
+
osVersion: '24.04' | '26.04';
|
|
13
13
|
architecture: 'x64';
|
|
14
14
|
/** What promotes this coordinate beyond an unreviewed candidate. */
|
|
15
15
|
evidence: 'reviewed-strategy-and-tests';
|
|
16
16
|
}
|
|
17
17
|
export interface OsCatalogEntry {
|
|
18
18
|
id: 'ubuntu';
|
|
19
|
-
version: '26.04';
|
|
19
|
+
version: '24.04' | '26.04';
|
|
20
20
|
architecture: 'x64';
|
|
21
21
|
status: CatalogStatus;
|
|
22
|
+
imageKey: 'ubuntu-noble-20260705' | 'ubuntu-resolute-20260731';
|
|
23
|
+
imageLabel: 'Ubuntu 24.04 LTS Noble' | 'Ubuntu 26.04 LTS Resolute';
|
|
24
|
+
imageVersion: '2026-07-05' | '2026-07-31';
|
|
25
|
+
imageUrl: string;
|
|
26
|
+
imageSha256: string;
|
|
27
|
+
confidentialModes: readonly [] | readonly ['sev-snp'];
|
|
22
28
|
}
|
|
23
29
|
export interface SoftwareObservation {
|
|
24
30
|
os: {
|
package/dist/software.js
CHANGED
|
@@ -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
|
-
{
|
|
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 =
|
|
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 });
|
package/dist/ssh-bootstrap.d.ts
CHANGED
|
@@ -16,6 +16,11 @@ export interface RemoteSshBootstrapClaim {
|
|
|
16
16
|
user: string;
|
|
17
17
|
hostKeySha256: string;
|
|
18
18
|
nodeHostname: string;
|
|
19
|
+
operatingSystem: {
|
|
20
|
+
id: 'ubuntu';
|
|
21
|
+
version: '24.04' | '26.04';
|
|
22
|
+
architecture: 'x64';
|
|
23
|
+
};
|
|
19
24
|
credential: {
|
|
20
25
|
source: 'runner';
|
|
21
26
|
} | {
|
package/dist/ubuntu.d.ts
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The only guest operating system ForgeZero currently supports.
|
|
3
|
-
*
|
|
4
|
-
* A dated Canonical release directory and its published SHA-256 make image
|
|
5
|
-
* acquisition reproducible. `release/current` is deliberately forbidden: it
|
|
6
|
-
* changes underneath an already reviewed metal profile.
|
|
7
|
-
*/
|
|
8
1
|
export declare const SUPPORTED_GUEST_IMAGE: Readonly<{
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
2
|
+
key: "ubuntu-noble-20260705" | "ubuntu-resolute-20260731";
|
|
3
|
+
family: "ubuntu-26.04" | "ubuntu-24.04";
|
|
4
|
+
version: "2026-07-05" | "2026-07-31";
|
|
5
|
+
label: "Ubuntu 24.04 LTS Noble" | "Ubuntu 26.04 LTS Resolute";
|
|
6
|
+
url: string;
|
|
7
|
+
sha256: string;
|
|
15
8
|
}>;
|
|
16
|
-
export declare
|
|
9
|
+
export declare const SUPPORTED_GUEST_IMAGES: readonly {
|
|
10
|
+
key: "ubuntu-noble-20260705" | "ubuntu-resolute-20260731";
|
|
11
|
+
label: "Ubuntu 24.04 LTS Noble" | "Ubuntu 26.04 LTS Resolute";
|
|
12
|
+
family: string;
|
|
13
|
+
version: "2026-07-05" | "2026-07-31";
|
|
14
|
+
confidential: boolean;
|
|
15
|
+
}[];
|
|
16
|
+
export declare function supportedGuestImage(imageKey: string): (typeof SUPPORTED_GUEST_IMAGES)[number] | undefined;
|
|
17
|
+
export declare function assertSupportedGuestImage(imageKey: string, confidential?: boolean): void;
|
package/dist/ubuntu.js
CHANGED
|
@@ -1,18 +1,354 @@
|
|
|
1
|
+
// src/software.ts
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
import {
|
|
4
|
+
accessSync,
|
|
5
|
+
chmodSync,
|
|
6
|
+
copyFileSync,
|
|
7
|
+
existsSync,
|
|
8
|
+
mkdtempSync,
|
|
9
|
+
mkdirSync,
|
|
10
|
+
readFileSync,
|
|
11
|
+
renameSync,
|
|
12
|
+
rmSync,
|
|
13
|
+
symlinkSync,
|
|
14
|
+
unlinkSync,
|
|
15
|
+
writeFileSync
|
|
16
|
+
} from "node:fs";
|
|
17
|
+
import { tmpdir } from "node:os";
|
|
18
|
+
import { join } from "node:path";
|
|
19
|
+
var PINNED_BUN_VERSION = "1.3.14";
|
|
20
|
+
var BUN_RELEASE_SHA256 = "951ee2aee855f08595aeec6225226a298d3fea83a3dcd6465c09cbccdf7e848f";
|
|
21
|
+
var ARANGO_SHA256 = "b5a9197b4343f2ed554e1ebc1ef8e6529c7c39cde0035cdc311a4747a3355066";
|
|
22
|
+
var CLOUDFLARED_SHA256 = "9d71c677db00134c1bd4144b7783486b654ad281b1ea62b4972098d19f770f17";
|
|
23
|
+
var OS_CATALOG = [
|
|
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
|
+
}
|
|
48
|
+
];
|
|
49
|
+
var SOFTWARE_CATALOG = [
|
|
50
|
+
{ id: "bun", version: "1.3.14", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
|
|
51
|
+
{ id: "docker", version: "ubuntu-26.04", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
|
|
52
|
+
{ id: "nginx", version: "ubuntu-26.04", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
|
|
53
|
+
{ id: "arangodb", version: "3.11.14", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
|
|
54
|
+
{ id: "cloudflared", version: "2026.7.3", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
|
|
55
|
+
{ id: "cloudflare-warp", version: "2026.6.822.0-min", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
|
|
56
|
+
{ id: "ufw", version: "ubuntu-26.04", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
|
|
57
|
+
{ id: "openssh-client", 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" }
|
|
64
|
+
];
|
|
65
|
+
var UBUNTU_2604_X64 = [
|
|
66
|
+
{ requirement: { id: "bun", version: "1.3.14" } },
|
|
67
|
+
{ requirement: { id: "docker", version: "ubuntu-26.04" } },
|
|
68
|
+
{ requirement: { id: "nginx", version: "ubuntu-26.04" } },
|
|
69
|
+
{ requirement: { id: "arangodb", version: "3.11.14" } },
|
|
70
|
+
{ requirement: { id: "cloudflared", version: "2026.7.3" } },
|
|
71
|
+
{ requirement: { id: "cloudflare-warp", version: "2026.6.822.0-min" } },
|
|
72
|
+
{ requirement: { id: "ufw", version: "ubuntu-26.04" } },
|
|
73
|
+
{ requirement: { id: "openssh-client", version: "ubuntu-26.04" } },
|
|
74
|
+
{ requirement: { id: "git", version: "ubuntu-26.04" } }
|
|
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;
|
|
85
|
+
var path = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
|
|
86
|
+
var DOCKER_DAEMON_PATH = "/etc/docker/daemon.json";
|
|
87
|
+
var DOCKER_DAEMON_CONFIG = `${JSON.stringify({
|
|
88
|
+
"data-root": "/var/lib/docker",
|
|
89
|
+
"storage-driver": "overlay2",
|
|
90
|
+
"live-restore": true,
|
|
91
|
+
"log-driver": "local",
|
|
92
|
+
"log-opts": { "max-size": "10m", "max-file": "3" }
|
|
93
|
+
}, null, 2)}
|
|
94
|
+
`;
|
|
95
|
+
var softwareSpawnFailure = (cause, argv) => cause.code === "ENOENT" ? { exitCode: 127, output: `executable is absent: ${argv[0]}` } : undefined;
|
|
96
|
+
var runSoftwareCommand = async (argv, env = {}) => {
|
|
97
|
+
let child;
|
|
98
|
+
try {
|
|
99
|
+
child = Bun.spawn([...argv], { stdout: "pipe", stderr: "pipe", env: { PATH: path, LANG: "C", LC_ALL: "C", ...env } });
|
|
100
|
+
} catch (cause) {
|
|
101
|
+
const failure = softwareSpawnFailure(cause, argv);
|
|
102
|
+
if (failure)
|
|
103
|
+
return failure;
|
|
104
|
+
throw cause;
|
|
105
|
+
}
|
|
106
|
+
const [stdout, stderr, exitCode] = await Promise.all([
|
|
107
|
+
new Response(child.stdout).text(),
|
|
108
|
+
new Response(child.stderr).text(),
|
|
109
|
+
child.exited
|
|
110
|
+
]);
|
|
111
|
+
return { exitCode, output: `${stdout}${stderr}` };
|
|
112
|
+
};
|
|
113
|
+
var run = runSoftwareCommand;
|
|
114
|
+
var download = async (url, destination, sha256) => {
|
|
115
|
+
const response = await fetch(url, { redirect: "follow", signal: AbortSignal.timeout(120000) });
|
|
116
|
+
if (!response.ok)
|
|
117
|
+
throw new Error(`download failed with HTTP ${response.status}`);
|
|
118
|
+
const bytes = new Uint8Array(await response.arrayBuffer());
|
|
119
|
+
if (createHash("sha256").update(bytes).digest("hex") !== sha256)
|
|
120
|
+
throw new Error("download checksum mismatch");
|
|
121
|
+
writeFileSync(destination, bytes, { mode: 384, flag: "wx" });
|
|
122
|
+
};
|
|
123
|
+
var successful = (result, pattern) => result.exitCode === 0 && (!pattern || pattern.test(result.output));
|
|
124
|
+
var aptInstall = async (name) => {
|
|
125
|
+
const environment = { DEBIAN_FRONTEND: "noninteractive" };
|
|
126
|
+
const update = await run(["/usr/bin/apt-get", "update", "-qq"], environment);
|
|
127
|
+
return update.exitCode === 0 ? run(["/usr/bin/apt-get", "install", "-y", name], environment) : update;
|
|
128
|
+
};
|
|
129
|
+
async function executeSoftwareOperation(operation) {
|
|
130
|
+
const { software, version } = operation;
|
|
131
|
+
if (![...UBUNTU_2604_X64, ...UBUNTU_2404_X64].some(({ requirement }) => requirement.id === software && requirement.version === version)) {
|
|
132
|
+
return { exitCode: 2, output: "unsupported software operation" };
|
|
133
|
+
}
|
|
134
|
+
if (operation.kind === "check") {
|
|
135
|
+
if (software === "bun")
|
|
136
|
+
return run(["/usr/local/bin/bun", "--version"]).then((r) => ({ ...r, exitCode: successful(r, /^1\.3\.14\s*$/m) ? 0 : 1 }));
|
|
137
|
+
if (software === "docker") {
|
|
138
|
+
const binary = await run(["/usr/bin/docker", "--version"]);
|
|
139
|
+
if (!successful(binary, /Docker version/))
|
|
140
|
+
return { ...binary, exitCode: 1 };
|
|
141
|
+
if (!existsSync(DOCKER_DAEMON_PATH) || readFileSync(DOCKER_DAEMON_PATH, "utf8") !== DOCKER_DAEMON_CONFIG)
|
|
142
|
+
return { exitCode: 1, output: "Docker daemon policy is absent or differs from the reviewed ForgeZero policy" };
|
|
143
|
+
const active = await run(["/usr/bin/systemctl", "is-active", "--quiet", "docker.service"]);
|
|
144
|
+
return active.exitCode === 0 ? { exitCode: 0, output: binary.output } : active;
|
|
145
|
+
}
|
|
146
|
+
if (software === "nginx") {
|
|
147
|
+
const binary = await run(["/usr/sbin/nginx", "-v"]);
|
|
148
|
+
return binary.exitCode === 0 ? run(["/usr/bin/systemctl", "is-active", "--quiet", "nginx.service"]) : binary;
|
|
149
|
+
}
|
|
150
|
+
if (software === "arangodb") {
|
|
151
|
+
const binary = await run(["/usr/sbin/arangod", "--version"]);
|
|
152
|
+
if (!successful(binary, /3\.11\.14/))
|
|
153
|
+
return { ...binary, exitCode: 1 };
|
|
154
|
+
const [active, enabled] = await Promise.all([
|
|
155
|
+
run(["/usr/bin/systemctl", "is-active", "--quiet", "arangodb3.service"]),
|
|
156
|
+
run(["/usr/bin/systemctl", "is-enabled", "--quiet", "arangodb3.service"])
|
|
157
|
+
]);
|
|
158
|
+
return active.exitCode !== 0 && enabled.exitCode !== 0 ? { exitCode: 0, output: binary.output } : { exitCode: 1, output: "vendor standalone unit remains active or enabled" };
|
|
159
|
+
}
|
|
160
|
+
if (software === "cloudflared")
|
|
161
|
+
return run(["/usr/local/bin/cloudflared", "--version"]).then((r) => ({ ...r, exitCode: successful(r, /2026\.7\.3/) ? 0 : 1 }));
|
|
162
|
+
if (software === "cloudflare-warp")
|
|
163
|
+
return run(["/usr/bin/warp-cli", "--version"]).then((result) => {
|
|
164
|
+
const match = result.output.match(/(\d{4})\.(\d+)\.(\d+)\.(\d+)/);
|
|
165
|
+
const observed = match?.slice(1).map(Number);
|
|
166
|
+
const minimum = [2026, 6, 822, 0];
|
|
167
|
+
const supported = observed && observed.some((part, index) => part > minimum[index] && observed.slice(0, index).every((prior, priorIndex) => prior === minimum[priorIndex])) || observed?.every((part, index) => part === minimum[index]);
|
|
168
|
+
return { ...result, exitCode: result.exitCode === 0 && supported ? 0 : 1 };
|
|
169
|
+
});
|
|
170
|
+
const binaries = software === "ufw" ? ["/usr/sbin/ufw"] : software === "git" ? ["/usr/bin/git"] : ["/usr/bin/ssh", "/usr/bin/scp", "/usr/bin/ssh-keyscan", "/usr/bin/ssh-keygen"];
|
|
171
|
+
try {
|
|
172
|
+
binaries.forEach((binary) => accessSync(binary));
|
|
173
|
+
return { exitCode: 0, output: "" };
|
|
174
|
+
} catch (cause) {
|
|
175
|
+
return { exitCode: 1, output: cause instanceof Error ? cause.message : String(cause) };
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
if (software === "docker" || software === "nginx" || software === "ufw" || software === "openssh-client" || software === "git") {
|
|
179
|
+
const packageName = software === "openssh-client" ? "openssh-client" : software === "docker" ? "docker.io" : software;
|
|
180
|
+
const installed = await aptInstall(packageName);
|
|
181
|
+
if (installed.exitCode !== 0 || software !== "nginx" && software !== "docker")
|
|
182
|
+
return installed;
|
|
183
|
+
if (software === "docker") {
|
|
184
|
+
mkdirSync("/etc/docker", { recursive: true, mode: 493 });
|
|
185
|
+
if (existsSync(DOCKER_DAEMON_PATH) && readFileSync(DOCKER_DAEMON_PATH, "utf8") !== DOCKER_DAEMON_CONFIG) {
|
|
186
|
+
return { exitCode: 2, output: "refusing to overwrite an existing Docker daemon configuration that differs from the reviewed ForgeZero policy" };
|
|
187
|
+
}
|
|
188
|
+
if (!existsSync(DOCKER_DAEMON_PATH))
|
|
189
|
+
writeFileSync(DOCKER_DAEMON_PATH, DOCKER_DAEMON_CONFIG, { mode: 420, flag: "wx" });
|
|
190
|
+
const enabled = await run(["/usr/bin/systemctl", "enable", "docker.service"]);
|
|
191
|
+
return enabled.exitCode === 0 ? run(["/usr/bin/systemctl", "restart", "docker.service"]) : enabled;
|
|
192
|
+
}
|
|
193
|
+
return run(["/usr/bin/systemctl", "enable", "--now", `${software}.service`]);
|
|
194
|
+
}
|
|
195
|
+
const directory = mkdtempSync(join(tmpdir(), "forgezero-software-"));
|
|
196
|
+
try {
|
|
197
|
+
if (software === "cloudflare-warp") {
|
|
198
|
+
const key = join(directory, "cloudflare-warp-key.gpg");
|
|
199
|
+
await download("https://pkg.cloudflareclient.com/pubkey.gpg", key, "0f37fc298c98e88ee3c0ee68c95b69f1dba9eb477abe3167e13982105911264d");
|
|
200
|
+
mkdirSync("/usr/share/keyrings", { recursive: true, mode: 493 });
|
|
201
|
+
const dearmored = await run([
|
|
202
|
+
"/usr/bin/gpg",
|
|
203
|
+
"--batch",
|
|
204
|
+
"--yes",
|
|
205
|
+
"--dearmor",
|
|
206
|
+
"-o",
|
|
207
|
+
"/usr/share/keyrings/cloudflare-warp-archive-keyring.gpg",
|
|
208
|
+
key
|
|
209
|
+
]);
|
|
210
|
+
if (dearmored.exitCode !== 0)
|
|
211
|
+
return dearmored;
|
|
212
|
+
mkdirSync("/etc/apt/sources.list.d", { recursive: true, mode: 493 });
|
|
213
|
+
writeFileSync("/etc/apt/sources.list.d/cloudflare-client.list", `deb [signed-by=/usr/share/keyrings/cloudflare-warp-archive-keyring.gpg] https://pkg.cloudflareclient.com/ resolute main
|
|
214
|
+
`, { mode: 420 });
|
|
215
|
+
return aptInstall("cloudflare-warp");
|
|
216
|
+
}
|
|
217
|
+
if (software === "bun") {
|
|
218
|
+
const archive = join(directory, "bun.zip");
|
|
219
|
+
await download("https://github.com/oven-sh/bun/releases/download/bun-v1.3.14/bun-linux-x64.zip", archive, BUN_RELEASE_SHA256);
|
|
220
|
+
const unpacked = join(directory, "unpacked");
|
|
221
|
+
mkdirSync(unpacked, { mode: 448 });
|
|
222
|
+
const unzipped = await run(["/usr/bin/unzip", "-q", archive, "-d", unpacked]);
|
|
223
|
+
if (unzipped.exitCode !== 0)
|
|
224
|
+
return unzipped;
|
|
225
|
+
mkdirSync("/usr/local/lib/forgezero/runtime", { recursive: true, mode: 493 });
|
|
226
|
+
copyFileSync(join(unpacked, "bun-linux-x64", "bun"), "/usr/local/lib/forgezero/runtime/bun.next");
|
|
227
|
+
chmodSync("/usr/local/lib/forgezero/runtime/bun.next", 493);
|
|
228
|
+
renameSync("/usr/local/lib/forgezero/runtime/bun.next", "/usr/local/lib/forgezero/runtime/bun");
|
|
229
|
+
try {
|
|
230
|
+
unlinkSync("/usr/local/bin/bun");
|
|
231
|
+
} catch {}
|
|
232
|
+
symlinkSync("/usr/local/lib/forgezero/runtime/bun", "/usr/local/bin/bun");
|
|
233
|
+
return { exitCode: 0, output: "" };
|
|
234
|
+
}
|
|
235
|
+
if (software === "cloudflared") {
|
|
236
|
+
const binary = join(directory, "cloudflared");
|
|
237
|
+
await download("https://github.com/cloudflare/cloudflared/releases/download/2026.7.3/cloudflared-linux-amd64", binary, CLOUDFLARED_SHA256);
|
|
238
|
+
chmodSync(binary, 493);
|
|
239
|
+
copyFileSync(binary, "/usr/local/bin/cloudflared");
|
|
240
|
+
chmodSync("/usr/local/bin/cloudflared", 493);
|
|
241
|
+
return { exitCode: 0, output: "" };
|
|
242
|
+
}
|
|
243
|
+
const deb = join(directory, "arangodb.deb");
|
|
244
|
+
await download("https://download.arangodb.com/arangodb311/DEBIAN/amd64/arangodb3_3.11.14-1_amd64.deb", deb, ARANGO_SHA256);
|
|
245
|
+
let installed = await run(["/usr/bin/dpkg", "-i", deb], { DEBIAN_FRONTEND: "noninteractive" });
|
|
246
|
+
if (installed.exitCode !== 0)
|
|
247
|
+
installed = await run(["/usr/bin/apt-get", "-y", "-f", "install"], { DEBIAN_FRONTEND: "noninteractive" });
|
|
248
|
+
if (installed.exitCode !== 0)
|
|
249
|
+
return installed;
|
|
250
|
+
await run(["/usr/bin/systemctl", "disable", "--now", "arangodb3.service"]);
|
|
251
|
+
return { exitCode: 0, output: "" };
|
|
252
|
+
} finally {
|
|
253
|
+
rmSync(directory, { recursive: true, force: true });
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
function observeSoftwareHost(osRelease = readFileSync("/etc/os-release", "utf8"), architecture = process.arch) {
|
|
257
|
+
const values = Object.fromEntries(osRelease.split(`
|
|
258
|
+
`).flatMap((line) => {
|
|
259
|
+
const separator = line.indexOf("=");
|
|
260
|
+
return separator > 0 ? [[line.slice(0, separator), line.slice(separator + 1).replace(/^['"]|['"]$/g, "")]] : [];
|
|
261
|
+
}));
|
|
262
|
+
return {
|
|
263
|
+
os: { id: (values.ID ?? "unknown").toLowerCase(), versionId: values.VERSION_ID ?? "unknown" },
|
|
264
|
+
architecture
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
function validateSoftwareRequirements(value, _options = {}) {
|
|
268
|
+
if (!Array.isArray(value) || value.length > 32)
|
|
269
|
+
throw new Error("software requirements must be an array of at most 32 entries");
|
|
270
|
+
const seen = new Set;
|
|
271
|
+
return value.map((item) => {
|
|
272
|
+
if (!item || typeof item !== "object" || Array.isArray(item))
|
|
273
|
+
throw new Error("software requirement must be an object");
|
|
274
|
+
const row = item;
|
|
275
|
+
if (Object.keys(row).some((key) => key !== "id" && key !== "version")) {
|
|
276
|
+
throw new Error("software requirement contains an unknown field");
|
|
277
|
+
}
|
|
278
|
+
if (!["bun", "docker", "nginx", "arangodb", "cloudflared", "cloudflare-warp", "ufw", "openssh-client", "git"].includes(String(row.id)) || typeof row.version !== "string" || !/^[A-Za-z0-9][A-Za-z0-9.-]{0,31}$/.test(row.version)) {
|
|
279
|
+
throw new Error("software requirement coordinate is invalid");
|
|
280
|
+
}
|
|
281
|
+
const requirement = { id: row.id, version: row.version };
|
|
282
|
+
if (seen.has(requirement.id))
|
|
283
|
+
throw new Error(`duplicate software requirement: ${requirement.id}`);
|
|
284
|
+
seen.add(requirement.id);
|
|
285
|
+
const catalog = SOFTWARE_CATALOG.find((candidate) => candidate.id === requirement.id && candidate.version === requirement.version);
|
|
286
|
+
if (!catalog || catalog.status !== "active") {
|
|
287
|
+
throw new Error(`software requirement is not active: ${requirement.id}@${requirement.version}`);
|
|
288
|
+
}
|
|
289
|
+
return requirement;
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
async function ensureSoftwareRequirements(requirementsInput, options) {
|
|
293
|
+
const requirements = validateSoftwareRequirements(requirementsInput);
|
|
294
|
+
const observation = options.observation ?? observeSoftwareHost();
|
|
295
|
+
const os = OS_CATALOG.find((candidate) => candidate.id === observation.os.id && candidate.version === observation.os.versionId && candidate.architecture === observation.architecture);
|
|
296
|
+
if (!os || os.status !== "active") {
|
|
297
|
+
throw new Error(`unsupported software strategy: ${observation.os.id} ${observation.os.versionId} ${observation.architecture}`);
|
|
298
|
+
}
|
|
299
|
+
const results = [];
|
|
300
|
+
for (const requirement of requirements) {
|
|
301
|
+
const strategy = strategiesFor(observation)?.find(({ requirement: candidate }) => candidate.id === requirement.id && candidate.version === requirement.version);
|
|
302
|
+
if (!strategy)
|
|
303
|
+
throw new Error(`unsupported software requirement: ${requirement.id}@${requirement.version}`);
|
|
304
|
+
const before = await options.exec({ kind: "check", software: requirement.id, version: requirement.version });
|
|
305
|
+
if (before.exitCode === 0) {
|
|
306
|
+
results.push({ ...requirement, changed: false });
|
|
307
|
+
continue;
|
|
308
|
+
}
|
|
309
|
+
const installed = await options.exec({ kind: "install", software: requirement.id, version: requirement.version });
|
|
310
|
+
if (installed.exitCode !== 0)
|
|
311
|
+
throw new Error(`could not install ${requirement.id}@${requirement.version}: ${installed.output.trim()}`);
|
|
312
|
+
const after = await options.exec({ kind: "check", software: requirement.id, version: requirement.version });
|
|
313
|
+
if (after.exitCode !== 0)
|
|
314
|
+
throw new Error(`${requirement.id}@${requirement.version} did not pass its post-install check`);
|
|
315
|
+
results.push({ ...requirement, changed: true });
|
|
316
|
+
}
|
|
317
|
+
return results;
|
|
318
|
+
}
|
|
319
|
+
|
|
1
320
|
// src/ubuntu.ts
|
|
321
|
+
var current = OS_CATALOG[0];
|
|
2
322
|
var SUPPORTED_GUEST_IMAGE = Object.freeze({
|
|
3
|
-
key:
|
|
4
|
-
family:
|
|
5
|
-
version:
|
|
6
|
-
label:
|
|
7
|
-
url:
|
|
8
|
-
sha256:
|
|
323
|
+
key: current.imageKey,
|
|
324
|
+
family: `${current.id}-${current.version}`,
|
|
325
|
+
version: current.imageVersion,
|
|
326
|
+
label: current.imageLabel,
|
|
327
|
+
url: current.imageUrl,
|
|
328
|
+
sha256: current.imageSha256
|
|
9
329
|
});
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
330
|
+
var SUPPORTED_GUEST_IMAGES = Object.freeze(OS_CATALOG.filter(({ status }) => status === "active").map(({ id, imageKey, imageLabel, imageVersion, version, confidentialModes }) => ({
|
|
331
|
+
key: imageKey,
|
|
332
|
+
label: imageLabel,
|
|
333
|
+
family: `${id}-${version}`,
|
|
334
|
+
version: imageVersion,
|
|
335
|
+
confidential: confidentialModes.some((mode) => mode === "sev-snp")
|
|
336
|
+
})));
|
|
337
|
+
function supportedGuestImage(imageKey) {
|
|
338
|
+
return SUPPORTED_GUEST_IMAGES.find(({ key }) => key === imageKey);
|
|
339
|
+
}
|
|
340
|
+
function assertSupportedGuestImage(imageKey, confidential = false) {
|
|
341
|
+
const selected = OS_CATALOG.find((entry) => entry.status === "active" && entry.imageKey === imageKey);
|
|
342
|
+
if (!selected) {
|
|
343
|
+
throw new Error(`unsupported guest image ${imageKey}; supported images: ${SUPPORTED_GUEST_IMAGES.map(({ key }) => key).join(", ")}`);
|
|
344
|
+
}
|
|
345
|
+
if (confidential && !selected.confidentialModes.some((mode) => mode === "sev-snp")) {
|
|
346
|
+
throw new Error(`guest image ${imageKey} is not approved for SEV-SNP`);
|
|
13
347
|
}
|
|
14
348
|
}
|
|
15
349
|
export {
|
|
350
|
+
supportedGuestImage,
|
|
16
351
|
assertSupportedGuestImage,
|
|
352
|
+
SUPPORTED_GUEST_IMAGES,
|
|
17
353
|
SUPPORTED_GUEST_IMAGE
|
|
18
354
|
};
|
package/dist/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** One package version shared by both public binaries. Pinned to package.json by tests. */
|
|
2
|
-
export declare const VERSION = "0.1.
|
|
2
|
+
export declare const VERSION = "0.1.67";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forgezero/agent",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.67",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"check": "tsc --noEmit",
|
|
@@ -11,13 +11,13 @@
|
|
|
11
11
|
"typescript": "^5.6.0",
|
|
12
12
|
"@types/bun": "latest",
|
|
13
13
|
"@types/node": "^22.0.0",
|
|
14
|
-
"@forgezero/access": "0.1.
|
|
14
|
+
"@forgezero/access": "0.1.5",
|
|
15
15
|
"@noble/curves": "^2.2.0",
|
|
16
16
|
"@noble/post-quantum": "^0.6.1"
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@forgezero/runtime": "0.1.
|
|
20
|
-
"@forgezero/vault": "0.1.
|
|
19
|
+
"@forgezero/runtime": "0.1.9",
|
|
20
|
+
"@forgezero/vault": "0.1.13",
|
|
21
21
|
"@noble/curves": "2.2.0",
|
|
22
22
|
"@noble/hashes": "2.2.0",
|
|
23
23
|
"@noble/post-quantum": "0.6.1",
|
|
@@ -153,6 +153,10 @@
|
|
|
153
153
|
"types": "./dist/metal-provision.d.ts",
|
|
154
154
|
"default": "./dist/metal-provision.js"
|
|
155
155
|
},
|
|
156
|
+
"./platform-genesis": {
|
|
157
|
+
"types": "./dist/platform-genesis.d.ts",
|
|
158
|
+
"default": "./dist/platform-genesis.js"
|
|
159
|
+
},
|
|
156
160
|
"./ubuntu": {
|
|
157
161
|
"types": "./dist/ubuntu.d.ts",
|
|
158
162
|
"default": "./dist/ubuntu.js"
|