@forgezero/agent 0.1.41 → 0.1.43

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.
Files changed (64) hide show
  1. package/README.md +299 -86
  2. package/dist/agent-heartbeat.js +6 -3
  3. package/dist/agent-update-helper.js +5 -2
  4. package/dist/agent-update.js +5 -2
  5. package/dist/bootstrap.d.ts +17 -8
  6. package/dist/bootstrap.js +1509 -512
  7. package/dist/cli/agent-install.d.ts +6 -5
  8. package/dist/cli/cloudflare-bootstrap.d.ts +12 -1
  9. package/dist/cli/maintenance.d.ts +23 -0
  10. package/dist/cli/run.d.ts +3 -1
  11. package/dist/cli/session-store.d.ts +5 -0
  12. package/dist/cloudflare-bootstrap.d.ts +73 -35
  13. package/dist/cloudflare-bootstrap.js +587 -90
  14. package/dist/cloudflare-edge.d.ts +64 -12
  15. package/dist/cloudflare-edge.js +103 -8
  16. package/dist/community-rehearsal-host.d.ts +51 -0
  17. package/dist/community-rehearsal-host.js +272 -0
  18. package/dist/credential-schema.d.ts +54 -0
  19. package/dist/credential-schema.js +47 -0
  20. package/dist/definition.d.ts +31 -5
  21. package/dist/definition.js +271 -44
  22. package/dist/deploy-file.js +294 -68
  23. package/dist/deployment-runner.js +18 -5
  24. package/dist/deployment.d.ts +13 -1
  25. package/dist/fz-agent.js +3932 -582
  26. package/dist/fz-git-ssh.js +122 -0
  27. package/dist/fz.js +3636 -1263
  28. package/dist/git-ssh.d.ts +5 -0
  29. package/dist/guest-enrolment.d.ts +2 -0
  30. package/dist/guest-enrolment.js +1 -0
  31. package/dist/host-maintenance.d.ts +39 -0
  32. package/dist/host-maintenance.js +135 -0
  33. package/dist/index.d.ts +4 -2
  34. package/dist/mesh-connector.d.ts +16 -0
  35. package/dist/mesh-connector.js +46 -0
  36. package/dist/metal-bootstrap.js +150 -7
  37. package/dist/metal-helper-socket.js +61 -31
  38. package/dist/metal-provision.d.ts +2 -2
  39. package/dist/metal-provision.js +62 -32
  40. package/dist/operator-bootstrap.d.ts +90 -0
  41. package/dist/operator-bootstrap.js +5709 -0
  42. package/dist/otel-collector.d.ts +18 -0
  43. package/dist/pipeline.d.ts +3 -2
  44. package/dist/pipeline.js +1 -1
  45. package/dist/platform-bootstrap-runtime.d.ts +39 -21
  46. package/dist/platform-bootstrap-runtime.js +182 -59
  47. package/dist/platform-fleet-verification.d.ts +19 -0
  48. package/dist/platform-fleet-verification.js +3873 -0
  49. package/dist/platform-genesis-config.d.ts +7 -0
  50. package/dist/platform-genesis.d.ts +17 -0
  51. package/dist/provision.d.ts +76 -3
  52. package/dist/provision.js +1061 -229
  53. package/dist/recovery-host.d.ts +7 -0
  54. package/dist/recovery-host.js +124 -0
  55. package/dist/service-supervisor.d.ts +42 -0
  56. package/dist/software-helper.d.ts +4 -0
  57. package/dist/software-helper.js +865 -63
  58. package/dist/software.d.ts +14 -3
  59. package/dist/software.js +163 -37
  60. package/dist/ssh-bootstrap.d.ts +97 -0
  61. package/dist/supervised-app.d.ts +2 -0
  62. package/dist/version.d.ts +1 -1
  63. package/package.json +175 -164
  64. package/schema/{deploy-v2.json → deploy-v3.json} +53 -6
@@ -1,6 +1,6 @@
1
1
  export type CatalogStatus = 'testing' | 'active' | 'retired';
2
2
  export type DeploymentChannel = 'development' | 'production';
3
- export type SoftwareId = 'bun' | 'nginx' | 'arangodb' | 'cloudflared' | 'ufw' | 'openssh-client';
3
+ export type SoftwareId = 'bun' | 'nginx' | 'arangodb' | 'cloudflared' | 'cloudflare-warp' | 'ufw' | 'openssh-client';
4
4
  /** Repository input is a catalogue coordinate, never a root command. */
5
5
  export interface SoftwareRequirement {
6
6
  id: SoftwareId;
@@ -31,12 +31,23 @@ export interface SoftwareCommandResult {
31
31
  exitCode: number;
32
32
  output: string;
33
33
  }
34
- export type SoftwareExec = (command: string) => Promise<SoftwareCommandResult>;
34
+ export type SoftwareOperation = {
35
+ kind: 'check';
36
+ software: SoftwareId;
37
+ version: string;
38
+ } | {
39
+ kind: 'install';
40
+ software: SoftwareId;
41
+ version: string;
42
+ };
43
+ export type SoftwareExec = (operation: SoftwareOperation) => Promise<SoftwareCommandResult>;
35
44
  export declare const PINNED_BUN_VERSION = "1.3.14";
36
- export declare const BUN_INSTALLER_SHA256 = "bab8acfb046aac8c72407bdcce903957665d655d7acaa3e11c7c4616beae68dd";
45
+ export declare const BUN_RELEASE_SHA256 = "951ee2aee855f08595aeec6225226a298d3fea83a3dcd6465c09cbccdf7e848f";
37
46
  /** Public, command-free catalog. Root strategies remain private below. */
38
47
  export declare const OS_CATALOG: readonly OsCatalogEntry[];
39
48
  export declare const SOFTWARE_CATALOG: readonly SoftwareCatalogEntry[];
49
+ /** Closed, fixed-argv privileged strategy executor. No repository value becomes a command. */
50
+ export declare function executeSoftwareOperation(operation: SoftwareOperation): Promise<SoftwareCommandResult>;
40
51
  export declare function observeSoftwareHost(osRelease?: string, architecture?: NodeJS.Architecture): SoftwareObservation;
41
52
  export declare function validateSoftwareRequirements(value: unknown, _options?: {
42
53
  channel?: DeploymentChannel;
package/dist/software.js CHANGED
@@ -1,7 +1,22 @@
1
1
  // src/software.ts
2
- import { readFileSync } from "node:fs";
2
+ import { createHash } from "node:crypto";
3
+ import {
4
+ accessSync,
5
+ chmodSync,
6
+ copyFileSync,
7
+ mkdtempSync,
8
+ mkdirSync,
9
+ readFileSync,
10
+ renameSync,
11
+ rmSync,
12
+ symlinkSync,
13
+ unlinkSync,
14
+ writeFileSync
15
+ } from "node:fs";
16
+ import { tmpdir } from "node:os";
17
+ import { join } from "node:path";
3
18
  var PINNED_BUN_VERSION = "1.3.14";
4
- var BUN_INSTALLER_SHA256 = "bab8acfb046aac8c72407bdcce903957665d655d7acaa3e11c7c4616beae68dd";
19
+ var BUN_RELEASE_SHA256 = "951ee2aee855f08595aeec6225226a298d3fea83a3dcd6465c09cbccdf7e848f";
5
20
  var ARANGO_SHA256 = "b5a9197b4343f2ed554e1ebc1ef8e6529c7c39cde0035cdc311a4747a3355066";
6
21
  var CLOUDFLARED_SHA256 = "9d71c677db00134c1bd4144b7783486b654ad281b1ea62b4972098d19f770f17";
7
22
  var OS_CATALOG = [
@@ -12,41 +27,151 @@ var SOFTWARE_CATALOG = [
12
27
  { id: "nginx", version: "ubuntu-26.04", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
13
28
  { id: "arangodb", version: "3.11.14", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
14
29
  { id: "cloudflared", version: "2026.7.3", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
30
+ { id: "cloudflare-warp", version: "2026.6.822.0-min", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
15
31
  { id: "ufw", version: "ubuntu-26.04", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
16
32
  { id: "openssh-client", version: "ubuntu-26.04", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" }
17
33
  ];
18
34
  var UBUNTU_2604_X64 = [
19
- {
20
- requirement: { id: "bun", version: "1.3.14" },
21
- check: 'test "$(/usr/local/bin/bun --version 2>/dev/null)" = 1.3.14',
22
- install: `tmp=$(mktemp -d); trap 'rm -rf "$tmp"' EXIT; ` + `curl -fsSL https://bun.sh/install -o "$tmp/install"; ` + `echo "${BUN_INSTALLER_SHA256} $tmp/install" | sha256sum -c -; ` + `BUN_INSTALL="$tmp/bun" BUN_VERSION=1.3.14 bash "$tmp/install" >/dev/null; ` + `install -d -m 0755 /usr/local/lib/forgezero/runtime; ` + `install -m 0755 "$tmp/bun/bin/bun" /usr/local/lib/forgezero/runtime/bun.next; ` + `mv -Tf /usr/local/lib/forgezero/runtime/bun.next /usr/local/lib/forgezero/runtime/bun; ` + `ln -sfn /usr/local/lib/forgezero/runtime/bun /usr/local/bin/bun`
23
- },
24
- {
25
- requirement: { id: "nginx", version: "ubuntu-26.04" },
26
- check: "command -v nginx >/dev/null && systemctl is-active --quiet nginx",
27
- install: "DEBIAN_FRONTEND=noninteractive apt-get update -qq && apt-get install -y nginx && systemctl enable --now nginx"
28
- },
29
- {
30
- requirement: { id: "arangodb", version: "3.11.14" },
31
- check: `arangod --version 2>/dev/null | head -1 | grep -q '3.11.14' && ` + `! systemctl is-active --quiet arangodb3.service && ` + `! systemctl is-enabled --quiet arangodb3.service`,
32
- install: `tmp=$(mktemp -d); trap 'rm -rf "$tmp"' EXIT; ` + `curl -fsSL 'https://download.arangodb.com/arangodb311/DEBIAN/amd64/arangodb3_3.11.14-1_amd64.deb' -o "$tmp/arangodb.deb"; ` + `echo "${ARANGO_SHA256} $tmp/arangodb.deb" | sha256sum -c -; ` + `DEBIAN_FRONTEND=noninteractive dpkg -i "$tmp/arangodb.deb" >/dev/null 2>&1 || ` + `DEBIAN_FRONTEND=noninteractive apt-get -y -f install; ` + `systemctl disable --now arangodb3.service`
33
- },
34
- {
35
- requirement: { id: "cloudflared", version: "2026.7.3" },
36
- check: `cloudflared --version 2>/dev/null | grep -q '2026.7.3'`,
37
- install: `tmp=$(mktemp -d); trap 'rm -rf "$tmp"' EXIT; ` + `curl -fsSL 'https://github.com/cloudflare/cloudflared/releases/download/2026.7.3/cloudflared-linux-amd64' -o "$tmp/cloudflared"; ` + `echo "${CLOUDFLARED_SHA256} $tmp/cloudflared" | sha256sum -c -; ` + `install -m 0755 "$tmp/cloudflared" /usr/local/bin/cloudflared`
38
- },
39
- {
40
- requirement: { id: "ufw", version: "ubuntu-26.04" },
41
- check: "command -v ufw >/dev/null",
42
- install: "DEBIAN_FRONTEND=noninteractive apt-get update -qq && apt-get install -y ufw"
43
- },
44
- {
45
- requirement: { id: "openssh-client", version: "ubuntu-26.04" },
46
- check: "command -v ssh >/dev/null && command -v scp >/dev/null && command -v ssh-keyscan >/dev/null && command -v ssh-keygen >/dev/null",
47
- install: "DEBIAN_FRONTEND=noninteractive apt-get update -qq && apt-get install -y openssh-client"
48
- }
35
+ { requirement: { id: "bun", version: "1.3.14" } },
36
+ { requirement: { id: "nginx", version: "ubuntu-26.04" } },
37
+ { requirement: { id: "arangodb", version: "3.11.14" } },
38
+ { requirement: { id: "cloudflared", version: "2026.7.3" } },
39
+ { requirement: { id: "cloudflare-warp", version: "2026.6.822.0-min" } },
40
+ { requirement: { id: "ufw", version: "ubuntu-26.04" } },
41
+ { requirement: { id: "openssh-client", version: "ubuntu-26.04" } }
49
42
  ];
43
+ var path = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
44
+ var run = async (argv, env = {}) => {
45
+ const child = Bun.spawn([...argv], { stdout: "pipe", stderr: "pipe", env: { PATH: path, LANG: "C", LC_ALL: "C", ...env } });
46
+ const [stdout, stderr, exitCode] = await Promise.all([
47
+ new Response(child.stdout).text(),
48
+ new Response(child.stderr).text(),
49
+ child.exited
50
+ ]);
51
+ return { exitCode, output: `${stdout}${stderr}` };
52
+ };
53
+ var download = async (url, destination, sha256) => {
54
+ const response = await fetch(url, { redirect: "follow", signal: AbortSignal.timeout(120000) });
55
+ if (!response.ok)
56
+ throw new Error(`download failed with HTTP ${response.status}`);
57
+ const bytes = new Uint8Array(await response.arrayBuffer());
58
+ if (createHash("sha256").update(bytes).digest("hex") !== sha256)
59
+ throw new Error("download checksum mismatch");
60
+ writeFileSync(destination, bytes, { mode: 384, flag: "wx" });
61
+ };
62
+ var successful = (result, pattern) => result.exitCode === 0 && (!pattern || pattern.test(result.output));
63
+ var aptInstall = async (name) => {
64
+ const environment = { DEBIAN_FRONTEND: "noninteractive" };
65
+ const update = await run(["/usr/bin/apt-get", "update", "-qq"], environment);
66
+ return update.exitCode === 0 ? run(["/usr/bin/apt-get", "install", "-y", name], environment) : update;
67
+ };
68
+ async function executeSoftwareOperation(operation) {
69
+ const { software, version } = operation;
70
+ if (!UBUNTU_2604_X64.some(({ requirement }) => requirement.id === software && requirement.version === version)) {
71
+ return { exitCode: 2, output: "unsupported software operation" };
72
+ }
73
+ if (operation.kind === "check") {
74
+ if (software === "bun")
75
+ return run(["/usr/local/bin/bun", "--version"]).then((r) => ({ ...r, exitCode: successful(r, /^1\.3\.14\s*$/m) ? 0 : 1 }));
76
+ if (software === "nginx") {
77
+ const binary = await run(["/usr/sbin/nginx", "-v"]);
78
+ return binary.exitCode === 0 ? run(["/usr/bin/systemctl", "is-active", "--quiet", "nginx.service"]) : binary;
79
+ }
80
+ if (software === "arangodb") {
81
+ const binary = await run(["/usr/bin/arangod", "--version"]);
82
+ if (!successful(binary, /3\.11\.14/))
83
+ return { ...binary, exitCode: 1 };
84
+ const [active, enabled] = await Promise.all([
85
+ run(["/usr/bin/systemctl", "is-active", "--quiet", "arangodb3.service"]),
86
+ run(["/usr/bin/systemctl", "is-enabled", "--quiet", "arangodb3.service"])
87
+ ]);
88
+ return active.exitCode !== 0 && enabled.exitCode !== 0 ? { exitCode: 0, output: binary.output } : { exitCode: 1, output: "vendor standalone unit remains active or enabled" };
89
+ }
90
+ if (software === "cloudflared")
91
+ return run(["/usr/local/bin/cloudflared", "--version"]).then((r) => ({ ...r, exitCode: successful(r, /2026\.7\.3/) ? 0 : 1 }));
92
+ if (software === "cloudflare-warp")
93
+ return run(["/usr/bin/warp-cli", "--version"]).then((result) => {
94
+ const match = result.output.match(/(\d{4})\.(\d+)\.(\d+)\.(\d+)/);
95
+ const observed = match?.slice(1).map(Number);
96
+ const minimum = [2026, 6, 822, 0];
97
+ 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]);
98
+ return { ...result, exitCode: result.exitCode === 0 && supported ? 0 : 1 };
99
+ });
100
+ const binaries = software === "ufw" ? ["/usr/sbin/ufw"] : ["/usr/bin/ssh", "/usr/bin/scp", "/usr/bin/ssh-keyscan", "/usr/bin/ssh-keygen"];
101
+ try {
102
+ binaries.forEach((binary) => accessSync(binary));
103
+ return { exitCode: 0, output: "" };
104
+ } catch (cause) {
105
+ return { exitCode: 1, output: cause instanceof Error ? cause.message : String(cause) };
106
+ }
107
+ }
108
+ if (software === "nginx" || software === "ufw" || software === "openssh-client") {
109
+ const installed = await aptInstall(software === "openssh-client" ? "openssh-client" : software);
110
+ if (installed.exitCode !== 0 || software !== "nginx")
111
+ return installed;
112
+ return run(["/usr/bin/systemctl", "enable", "--now", "nginx.service"]);
113
+ }
114
+ const directory = mkdtempSync(join(tmpdir(), "forgezero-software-"));
115
+ try {
116
+ if (software === "cloudflare-warp") {
117
+ const key = join(directory, "cloudflare-warp-key.gpg");
118
+ await download("https://pkg.cloudflareclient.com/pubkey.gpg", key, "0f37fc298c98e88ee3c0ee68c95b69f1dba9eb477abe3167e13982105911264d");
119
+ mkdirSync("/usr/share/keyrings", { recursive: true, mode: 493 });
120
+ const dearmored = await run([
121
+ "/usr/bin/gpg",
122
+ "--batch",
123
+ "--yes",
124
+ "--dearmor",
125
+ "-o",
126
+ "/usr/share/keyrings/cloudflare-warp-archive-keyring.gpg",
127
+ key
128
+ ]);
129
+ if (dearmored.exitCode !== 0)
130
+ return dearmored;
131
+ mkdirSync("/etc/apt/sources.list.d", { recursive: true, mode: 493 });
132
+ 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
133
+ `, { mode: 420 });
134
+ return aptInstall("cloudflare-warp");
135
+ }
136
+ if (software === "bun") {
137
+ const archive = join(directory, "bun.zip");
138
+ await download("https://github.com/oven-sh/bun/releases/download/bun-v1.3.14/bun-linux-x64.zip", archive, BUN_RELEASE_SHA256);
139
+ const unpacked = join(directory, "unpacked");
140
+ mkdirSync(unpacked, { mode: 448 });
141
+ const unzipped = await run(["/usr/bin/unzip", "-q", archive, "-d", unpacked]);
142
+ if (unzipped.exitCode !== 0)
143
+ return unzipped;
144
+ mkdirSync("/usr/local/lib/forgezero/runtime", { recursive: true, mode: 493 });
145
+ copyFileSync(join(unpacked, "bun-linux-x64", "bun"), "/usr/local/lib/forgezero/runtime/bun.next");
146
+ chmodSync("/usr/local/lib/forgezero/runtime/bun.next", 493);
147
+ renameSync("/usr/local/lib/forgezero/runtime/bun.next", "/usr/local/lib/forgezero/runtime/bun");
148
+ try {
149
+ unlinkSync("/usr/local/bin/bun");
150
+ } catch {}
151
+ symlinkSync("/usr/local/lib/forgezero/runtime/bun", "/usr/local/bin/bun");
152
+ return { exitCode: 0, output: "" };
153
+ }
154
+ if (software === "cloudflared") {
155
+ const binary = join(directory, "cloudflared");
156
+ await download("https://github.com/cloudflare/cloudflared/releases/download/2026.7.3/cloudflared-linux-amd64", binary, CLOUDFLARED_SHA256);
157
+ chmodSync(binary, 493);
158
+ copyFileSync(binary, "/usr/local/bin/cloudflared");
159
+ chmodSync("/usr/local/bin/cloudflared", 493);
160
+ return { exitCode: 0, output: "" };
161
+ }
162
+ const deb = join(directory, "arangodb.deb");
163
+ await download("https://download.arangodb.com/arangodb311/DEBIAN/amd64/arangodb3_3.11.14-1_amd64.deb", deb, ARANGO_SHA256);
164
+ let installed = await run(["/usr/bin/dpkg", "-i", deb], { DEBIAN_FRONTEND: "noninteractive" });
165
+ if (installed.exitCode !== 0)
166
+ installed = await run(["/usr/bin/apt-get", "-y", "-f", "install"], { DEBIAN_FRONTEND: "noninteractive" });
167
+ if (installed.exitCode !== 0)
168
+ return installed;
169
+ await run(["/usr/bin/systemctl", "disable", "--now", "arangodb3.service"]);
170
+ return { exitCode: 0, output: "" };
171
+ } finally {
172
+ rmSync(directory, { recursive: true, force: true });
173
+ }
174
+ }
50
175
  function observeSoftwareHost(osRelease = readFileSync("/etc/os-release", "utf8"), architecture = process.arch) {
51
176
  const values = Object.fromEntries(osRelease.split(`
52
177
  `).flatMap((line) => {
@@ -69,7 +194,7 @@ function validateSoftwareRequirements(value, _options = {}) {
69
194
  if (Object.keys(row).some((key) => key !== "id" && key !== "version")) {
70
195
  throw new Error("software requirement contains an unknown field");
71
196
  }
72
- if (!["bun", "nginx", "arangodb", "cloudflared", "ufw", "openssh-client"].includes(String(row.id)) || typeof row.version !== "string" || !/^[A-Za-z0-9][A-Za-z0-9.-]{0,31}$/.test(row.version)) {
197
+ if (!["bun", "nginx", "arangodb", "cloudflared", "cloudflare-warp", "ufw", "openssh-client"].includes(String(row.id)) || typeof row.version !== "string" || !/^[A-Za-z0-9][A-Za-z0-9.-]{0,31}$/.test(row.version)) {
73
198
  throw new Error("software requirement coordinate is invalid");
74
199
  }
75
200
  const requirement = { id: row.id, version: row.version };
@@ -95,15 +220,15 @@ async function ensureSoftwareRequirements(requirementsInput, options) {
95
220
  const strategy = UBUNTU_2604_X64.find(({ requirement: candidate }) => candidate.id === requirement.id && candidate.version === requirement.version);
96
221
  if (!strategy)
97
222
  throw new Error(`unsupported software requirement: ${requirement.id}@${requirement.version}`);
98
- const before = await options.exec(strategy.check);
223
+ const before = await options.exec({ kind: "check", software: requirement.id, version: requirement.version });
99
224
  if (before.exitCode === 0) {
100
225
  results.push({ ...requirement, changed: false });
101
226
  continue;
102
227
  }
103
- const installed = await options.exec(strategy.install);
228
+ const installed = await options.exec({ kind: "install", software: requirement.id, version: requirement.version });
104
229
  if (installed.exitCode !== 0)
105
230
  throw new Error(`could not install ${requirement.id}@${requirement.version}: ${installed.output.trim()}`);
106
- const after = await options.exec(strategy.check);
231
+ const after = await options.exec({ kind: "check", software: requirement.id, version: requirement.version });
107
232
  if (after.exitCode !== 0)
108
233
  throw new Error(`${requirement.id}@${requirement.version} did not pass its post-install check`);
109
234
  results.push({ ...requirement, changed: true });
@@ -113,9 +238,10 @@ async function ensureSoftwareRequirements(requirementsInput, options) {
113
238
  export {
114
239
  validateSoftwareRequirements,
115
240
  observeSoftwareHost,
241
+ executeSoftwareOperation,
116
242
  ensureSoftwareRequirements,
117
243
  SOFTWARE_CATALOG,
118
244
  PINNED_BUN_VERSION,
119
245
  OS_CATALOG,
120
- BUN_INSTALLER_SHA256
246
+ BUN_RELEASE_SHA256
121
247
  };
@@ -16,9 +16,87 @@ export interface RemoteSshBootstrapClaim {
16
16
  user: string;
17
17
  hostKeySha256: string;
18
18
  nodeHostname: string;
19
+ credential: {
20
+ source: 'runner';
21
+ } | {
22
+ source: 'vault';
23
+ privateKey: string;
24
+ };
19
25
  };
20
26
  enrolmentToken: string;
21
27
  }
28
+ export interface RemoteMetalAdmissionClaim {
29
+ jobKey: string;
30
+ claimToken: string;
31
+ claimExpiresAtTs: number;
32
+ attempt: number;
33
+ tenantKey: string;
34
+ projectKey: string;
35
+ environmentKey: string;
36
+ hostname: string;
37
+ label: string;
38
+ regionKey: string;
39
+ runnerNodeKey: string;
40
+ challenge: string;
41
+ provisioning: {
42
+ volumeGroup: string;
43
+ bridge: string;
44
+ subnetPrefix: string;
45
+ addressStart: number;
46
+ addressEnd: number;
47
+ gateway: string;
48
+ nameservers: string[];
49
+ cpuPools: Array<{
50
+ key: string;
51
+ cpus: string;
52
+ physicalCores: number;
53
+ memoryNodes?: string;
54
+ }>;
55
+ housekeepingCpus: string;
56
+ housekeepingMemoryNodes?: string;
57
+ confidential?: {
58
+ cbitpos: number;
59
+ reducedPhysBits: number;
60
+ policy: string;
61
+ };
62
+ };
63
+ target: RemoteSshBootstrapClaim['target'];
64
+ }
65
+ export interface MetalAdmissionProof {
66
+ jobKey: string;
67
+ tenantKey: string;
68
+ projectKey: string;
69
+ hostname: string;
70
+ runnerNodeKey: string;
71
+ challenge: string;
72
+ target: {
73
+ host: string;
74
+ port: number;
75
+ user: string;
76
+ hostKeySha256: string;
77
+ };
78
+ publicKeys: {
79
+ ed25519: string;
80
+ mlDsa: string;
81
+ };
82
+ preflight: {
83
+ vcpu: number;
84
+ memoryGib: number;
85
+ diskGib: number;
86
+ kvm: boolean;
87
+ snpHost: boolean;
88
+ helper: boolean;
89
+ };
90
+ envelope: {
91
+ version: 1;
92
+ suite: 'ed25519+ml-dsa-65';
93
+ nodeKey: string;
94
+ timestamp: number;
95
+ nonce: string;
96
+ edSignature: string;
97
+ mlDsaSignature: string;
98
+ };
99
+ }
22
100
  export interface BootstrapCommandResult {
23
101
  exitCode: number;
24
102
  output: string;
@@ -70,3 +148,22 @@ export declare function startSshBootstrapPull(options: SshBootstrapPullOptions):
70
148
  stop(): Promise<void>;
71
149
  readonly active: boolean;
72
150
  };
151
+ export type MetalAdmissionResult = {
152
+ status: 'idle';
153
+ } | {
154
+ status: 'completed';
155
+ jobKey: string;
156
+ attempt: number;
157
+ } | {
158
+ status: 'failed';
159
+ jobKey: string;
160
+ attempt: number;
161
+ failureCode: string;
162
+ };
163
+ /** Install the fixed metal Agent profile, then ask that host—not the runner—to sign its local preflight. */
164
+ export declare function executeMetalAdmission(claim: RemoteMetalAdmissionClaim, options: Pick<SshBootstrapPullOptions, 'platformApiUrl' | 'sshKeyPath' | 'targetTelemetryEndpoint' | 'fzCliPath' | 'fzAgentPath' | 'exec' | 'resolveHost'>): Promise<MetalAdmissionProof>;
165
+ export declare function pullMetalAdmissionOnce(options: SshBootstrapPullOptions): Promise<MetalAdmissionResult>;
166
+ export declare function startMetalAdmissionPull(options: SshBootstrapPullOptions): {
167
+ stop(): Promise<void>;
168
+ readonly active: boolean;
169
+ };
@@ -0,0 +1,2 @@
1
+ /** Run one reviewed profile command as the credential-free deployment user. */
2
+ export declare function runSupervisedApp(path: string): Promise<number>;
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.41";
2
+ export declare const VERSION = "0.1.43";