@forgezero/agent 0.1.88 → 0.1.89

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/fz.js CHANGED
@@ -4810,9 +4810,8 @@ async function spawnWith(command, env, report = () => {}, options = {}) {
4810
4810
  }
4811
4811
 
4812
4812
  // src/cli/index.ts
4813
- import { chmodSync as chmodSync7, existsSync as existsSync12, lstatSync as lstatSync10, mkdirSync as mkdirSync13, readFileSync as readFileSync16, writeFileSync as writeFileSync13 } from "fs";
4813
+ import { existsSync as existsSync13, lstatSync as lstatSync10, mkdirSync as mkdirSync13, readFileSync as readFileSync16, writeFileSync as writeFileSync13 } from "fs";
4814
4814
  import { basename as basename3, dirname as dirname14, isAbsolute as isAbsolute7, join as join13, resolve as resolve12 } from "path";
4815
- import { randomBytes as randomBytes10 } from "crypto";
4816
4815
 
4817
4816
  // src/process-input.ts
4818
4817
  async function writeAndCloseProcessInput(input, value) {
@@ -4822,8 +4821,7 @@ async function writeAndCloseProcessInput(input, value) {
4822
4821
 
4823
4822
  // src/cli/index.ts
4824
4823
  init_dist();
4825
- import { fileURLToPath as fileURLToPath4 } from "url";
4826
- import { hostname } from "os";
4824
+ import { homedir as homedir2, hostname } from "os";
4827
4825
 
4828
4826
  // src/agent-update.ts
4829
4827
  var DEFAULT_AGENT_RELEASE_ROOT = "/opt/forgezero/agent";
@@ -4842,7 +4840,7 @@ var UPDATE_RETRY_BASE_MS = 5 * 60000;
4842
4840
  var UPDATE_RETRY_MAX_MS = 24 * 60 * 60000;
4843
4841
 
4844
4842
  // src/version.ts
4845
- var VERSION2 = "0.1.88";
4843
+ var VERSION2 = "0.1.89";
4846
4844
 
4847
4845
  // src/software.ts
4848
4846
  var PINNED_BUN_VERSION = "1.3.14";
@@ -4944,9 +4942,12 @@ function validateCapacityCalibrationOptions(options) {
4944
4942
  const requestsPerWorker = options.requestsPerWorker ?? 8;
4945
4943
  const maxP95Ms = options.maxP95Ms ?? 250;
4946
4944
  const maxErrorRate = options.maxErrorRate ?? 0.01;
4947
- const headroomRatio = options.headroomRatio ?? 0.8;
4945
+ const safetyRatio = options.safetyRatio ?? 0.8;
4948
4946
  const requestTimeoutMs = options.requestTimeoutMs ?? 5000;
4949
- if (!Number.isSafeInteger(maxConcurrency) || maxConcurrency < 1 || maxConcurrency > 4096 || !Number.isSafeInteger(requestsPerWorker) || requestsPerWorker < 2 || requestsPerWorker > 100 || !Number.isFinite(maxP95Ms) || maxP95Ms < 1 || !Number.isFinite(maxErrorRate) || maxErrorRate < 0 || maxErrorRate > 0.2 || !Number.isFinite(headroomRatio) || headroomRatio < 0.25 || headroomRatio > 0.95 || !Number.isSafeInteger(requestTimeoutMs) || requestTimeoutMs < 100 || requestTimeoutMs > 30000) {
4947
+ const minimumStageDurationMs = options.minimumStageDurationMs ?? 5000;
4948
+ const maxCpuUtilizationPercent = options.maxCpuUtilizationPercent ?? 90;
4949
+ const maxMemoryUtilizationPercent = options.maxMemoryUtilizationPercent ?? 90;
4950
+ if (!Number.isSafeInteger(maxConcurrency) || maxConcurrency < 1 || maxConcurrency > 4096 || !Number.isSafeInteger(requestsPerWorker) || requestsPerWorker < 2 || requestsPerWorker > 100 || !Number.isFinite(maxP95Ms) || maxP95Ms < 1 || !Number.isFinite(maxErrorRate) || maxErrorRate < 0 || maxErrorRate > 0.2 || !Number.isFinite(safetyRatio) || safetyRatio < 0.25 || safetyRatio > 0.95 || !Number.isSafeInteger(requestTimeoutMs) || requestTimeoutMs < 100 || requestTimeoutMs > 30000 || !Number.isSafeInteger(minimumStageDurationMs) || minimumStageDurationMs < 100 || minimumStageDurationMs > 60000 || !Number.isFinite(maxCpuUtilizationPercent) || maxCpuUtilizationPercent < 25 || maxCpuUtilizationPercent > 100 || !Number.isFinite(maxMemoryUtilizationPercent) || maxMemoryUtilizationPercent < 25 || maxMemoryUtilizationPercent > 100) {
4950
4951
  throw new Error("Capacity calibration bounds are invalid.");
4951
4952
  }
4952
4953
  return {
@@ -4955,8 +4956,11 @@ function validateCapacityCalibrationOptions(options) {
4955
4956
  requestsPerWorker,
4956
4957
  maxP95Ms,
4957
4958
  maxErrorRate,
4958
- headroomRatio,
4959
- requestTimeoutMs
4959
+ safetyRatio,
4960
+ requestTimeoutMs,
4961
+ minimumStageDurationMs,
4962
+ maxCpuUtilizationPercent,
4963
+ maxMemoryUtilizationPercent
4960
4964
  };
4961
4965
  }
4962
4966
 
@@ -5031,8 +5035,11 @@ function capacityCalibration(value, where) {
5031
5035
  "requestsPerWorker",
5032
5036
  "maxP95Ms",
5033
5037
  "maxErrorRate",
5034
- "headroomRatio",
5035
- "requestTimeoutMs"
5038
+ "safetyRatio",
5039
+ "requestTimeoutMs",
5040
+ "minimumStageDurationMs",
5041
+ "maxCpuUtilizationPercent",
5042
+ "maxMemoryUtilizationPercent"
5036
5043
  ], where);
5037
5044
  const endpoint = text(calibration.endpoint, `${where}.endpoint`);
5038
5045
  try {
@@ -5056,8 +5063,11 @@ function capacityCalibration(value, where) {
5056
5063
  "requestsPerWorker",
5057
5064
  "maxP95Ms",
5058
5065
  "maxErrorRate",
5059
- "headroomRatio",
5060
- "requestTimeoutMs"
5066
+ "safetyRatio",
5067
+ "requestTimeoutMs",
5068
+ "minimumStageDurationMs",
5069
+ "maxCpuUtilizationPercent",
5070
+ "maxMemoryUtilizationPercent"
5061
5071
  ].flatMap((name) => {
5062
5072
  const found = optionalNumber(name);
5063
5073
  return found === undefined ? [] : [[name, found]];
@@ -5479,6 +5489,7 @@ function agentEgressUnit(options) {
5479
5489
  }
5480
5490
  const deploymentEnabled = Boolean(options.repository || bootstrapBundleEnabled || options.pullDeployments);
5481
5491
  const runnerLoopbackPorts = normalizeEgressTcpPorts(options.runnerLoopbackPorts ?? []);
5492
+ const agentLoopbackPorts = normalizeEgressTcpPorts(options.agentLoopbackPorts ?? []);
5482
5493
  const runnerPublicTcpPorts = normalizeEgressTcpPorts(options.runnerPublicTcpPorts ?? DEFAULT_RUNNER_PUBLIC_TCP_PORTS);
5483
5494
  if (deploymentEnabled && runnerPublicTcpPorts.length < 1) {
5484
5495
  throw new Error("deployed project runner needs at least one vetted public TCP port");
@@ -5486,8 +5497,10 @@ function agentEgressUnit(options) {
5486
5497
  if (deploymentEnabled)
5487
5498
  systemdAgentEgressDirectives(runnerLoopbackPorts);
5488
5499
  const users = [user, ...deploymentEnabled ? [DEPLOYMENT_RUNNER_USER] : []];
5489
- const runnerGrant = deploymentEnabled ? ` --loopback-user=${DEPLOYMENT_RUNNER_USER}` + runnerLoopbackPorts.map((port) => ` --loopback-tcp-port=${port}`).join("") + runnerPublicTcpPorts.map((port) => ` --public-tcp-port=${port}`).join("") : "";
5490
- const policyProof = `ExecStartPost=${bin} egress-policy-check ${users.map((name) => `--user=${name}`).join(" ")}${runnerGrant}`;
5500
+ const portGrantEnabled = deploymentEnabled || agentLoopbackPorts.length > 0;
5501
+ const restrictedUser = deploymentEnabled ? DEPLOYMENT_RUNNER_USER : user;
5502
+ const portGrant = portGrantEnabled ? ` --loopback-user=${restrictedUser}` + (deploymentEnabled ? runnerLoopbackPorts.map((port) => ` --loopback-tcp-port=${port}`).join("") : "") + agentLoopbackPorts.map((port) => ` --shared-loopback-tcp-port=${port}`).join("") + (deploymentEnabled ? runnerPublicTcpPorts.map((port) => ` --public-tcp-port=${port}`).join("") : "") : "";
5503
+ const policyProof = `ExecStartPost=${bin} egress-policy-check ${users.map((name) => `--user=${name}`).join(" ")}${portGrant}`;
5491
5504
  return `[Unit]
5492
5505
  Description=ForgeZero Agent host egress policy
5493
5506
  Documentation=https://www.forgezero.net/docs/agent
@@ -5500,7 +5513,7 @@ Type=notify
5500
5513
  NotifyAccess=all
5501
5514
  User=root
5502
5515
  Group=root
5503
- ExecStart=${bin} egress-policy ${users.map((name) => `--user=${name}`).join(" ")}${runnerGrant}
5516
+ ExecStart=${bin} egress-policy ${users.map((name) => `--user=${name}`).join(" ")}${portGrant}
5504
5517
  ${policyProof}
5505
5518
  Restart=on-failure
5506
5519
  RestartSec=2
@@ -5784,7 +5797,7 @@ function agentEnrolmentUnit(options) {
5784
5797
  Requires=forgezero-agent-egress.service
5785
5798
  BindsTo=forgezero-agent-egress.service
5786
5799
  ` : "";
5787
- const egressDirectives = options.enforceEgress ? systemdAgentEgressDirectives() : "";
5800
+ const egressDirectives = options.enforceEgress ? systemdAgentEgressDirectives(options.agentLoopbackPorts ?? []) : "";
5788
5801
  return `[Unit]
5789
5802
  Description=Bind this machine to its ForgeZero compute
5790
5803
  After=network-online.target
@@ -5821,7 +5834,7 @@ WantedBy=multi-user.target
5821
5834
  function deploymentRunnerUnit(options) {
5822
5835
  const bin = options.binPath ?? "fz-agent";
5823
5836
  const root = options.deployRoot ?? "/opt/forgezero";
5824
- const agentUser = options.user ?? "forgezero-agent";
5837
+ const agentUser = options.user ?? "forgezero";
5825
5838
  const egressDependency = options.enforceEgress ? `After=forgezero-agent-egress.service
5826
5839
  Requires=forgezero-agent-egress.service
5827
5840
  BindsTo=forgezero-agent-egress.service
@@ -5862,7 +5875,7 @@ RestrictRealtime=true
5862
5875
  MemoryDenyWriteExecute=true
5863
5876
  LockPersonality=true
5864
5877
  ${egressDirectives}
5865
- ReadWritePaths=${root}/releases ${root}/runner-home
5878
+ ReadWritePaths=${root}/releases ${root}/runner-home ${root}/slots /etc/nginx/conf.d /var/log/nginx
5866
5879
 
5867
5880
  [Install]
5868
5881
  WantedBy=multi-user.target
@@ -5997,7 +6010,7 @@ function agentUnit(options) {
5997
6010
  const supplementaryGroups = [
5998
6011
  AGENT_UPDATE_GROUP,
5999
6012
  deploymentEnabled ? DEPLOYMENT_GROUP : null,
6000
- deploymentEnabled ? SOFTWARE_HELPER_GROUP : null,
6013
+ SOFTWARE_HELPER_GROUP,
6001
6014
  lifecycleEnabled ? LIFECYCLE_GROUP : null
6002
6015
  ].filter((value) => value !== null);
6003
6016
  const deploymentGroup = supplementaryGroups.length > 0 ? `SupplementaryGroups=${supplementaryGroups.join(" ")}` : "";
@@ -6006,7 +6019,7 @@ function agentUnit(options) {
6006
6019
  "forgezero-agent-update-helper.service",
6007
6020
  options.enforceEgress ? "forgezero-agent-egress.service" : null,
6008
6021
  deploymentEnabled ? "forgezero-deploy-runner.service" : null,
6009
- deploymentEnabled ? "forgezero-software-helper.service" : null,
6022
+ "forgezero-software-helper.service",
6010
6023
  lifecycleEnabled ? "forgezero-lifecycle-helper.service" : null,
6011
6024
  warpEnabled ? "warp-svc.service" : null,
6012
6025
  enrolmentEnabled ? "forgezero-agent-enrol.service" : null
@@ -6015,7 +6028,7 @@ function agentUnit(options) {
6015
6028
  "forgezero-agent-update-helper.service",
6016
6029
  options.enforceEgress ? "forgezero-agent-egress.service" : null,
6017
6030
  deploymentEnabled ? "forgezero-deploy-runner.service" : null,
6018
- deploymentEnabled ? "forgezero-software-helper.service" : null,
6031
+ "forgezero-software-helper.service",
6019
6032
  lifecycleEnabled ? "forgezero-lifecycle-helper.service" : null,
6020
6033
  warpEnabled ? "warp-svc.service" : null,
6021
6034
  enrolmentEnabled ? "forgezero-agent-enrol.service" : null
@@ -6030,9 +6043,9 @@ function agentUnit(options) {
6030
6043
  const snpDevice = options.mode === "attested" ? `DevicePolicy=closed
6031
6044
  DeviceAllow=/dev/sev-guest rw` : "";
6032
6045
  const snpPrepare = options.mode === "attested" ? `ExecStartPre=+/bin/chgrp ${VAULT_GROUP} /dev/sev-guest
6033
- ExecStartPre=+/bin/chmod 0640 /dev/sev-guest
6046
+ ExecStartPre=+/bin/chmod 0660 /dev/sev-guest
6034
6047
  ` : "";
6035
- const egressDirectives = options.enforceEgress ? systemdAgentEgressDirectives() : "";
6048
+ const egressDirectives = options.enforceEgress ? systemdAgentEgressDirectives(options.agentLoopbackPorts ?? []) : "";
6036
6049
  return `[Unit]
6037
6050
  Description=ForgeZero node agent (${options.mode})
6038
6051
  Documentation=https://www.forgezero.net/docs/agent
@@ -6163,6 +6176,7 @@ function planProvision(options) {
6163
6176
  const deployRoot = options.deployRoot ?? "/opt/forgezero";
6164
6177
  const deploymentEnabled = Boolean(options.repository || options.pullDeployments);
6165
6178
  const runnerLoopbackPorts = normalizeEgressTcpPorts(options.runnerLoopbackPorts ?? []);
6179
+ const agentLoopbackPorts = normalizeEgressTcpPorts(options.agentLoopbackPorts ?? []);
6166
6180
  const runnerPublicTcpPorts = normalizeEgressTcpPorts(options.runnerPublicTcpPorts ?? DEFAULT_RUNNER_PUBLIC_TCP_PORTS);
6167
6181
  const lifecycleEnabled = Boolean(options.pullMigrations && options.lifecycleProfilePath);
6168
6182
  if (Boolean(options.pullMigrations) !== Boolean(options.lifecycleProfilePath)) {
@@ -6211,8 +6225,9 @@ function planProvision(options) {
6211
6225
  const enabledUnits = [
6212
6226
  "forgezero-agent.socket",
6213
6227
  "forgezero-agent-update-helper.service",
6228
+ "forgezero-software-helper.service",
6214
6229
  ...options.enforceEgress ? ["forgezero-agent-egress.service"] : [],
6215
- ...deploymentEnabled ? ["forgezero-deploy-runner.service", "forgezero-software-helper.service"] : [],
6230
+ ...deploymentEnabled ? ["forgezero-deploy-runner.service"] : [],
6216
6231
  ...lifecycleEnabled ? ["forgezero-lifecycle-helper.service"] : [],
6217
6232
  ...warpEnabled ? ["forgezero-warp-config.service", "warp-svc.service"] : [],
6218
6233
  ...enrolmentEnabled ? ["forgezero-agent-enrol.service"] : [],
@@ -6220,8 +6235,9 @@ function planProvision(options) {
6220
6235
  ];
6221
6236
  const restartedUnits = [
6222
6237
  "forgezero-agent-update-helper.service",
6238
+ "forgezero-software-helper.service",
6223
6239
  ...options.enforceEgress ? ["forgezero-agent-egress.service"] : [],
6224
- ...deploymentEnabled ? ["forgezero-deploy-runner.service", "forgezero-software-helper.service"] : [],
6240
+ ...deploymentEnabled ? ["forgezero-deploy-runner.service"] : [],
6225
6241
  ...lifecycleEnabled ? ["forgezero-lifecycle-helper.service"] : [],
6226
6242
  ...warpEnabled ? ["forgezero-warp-config.service", "warp-svc.service"] : [],
6227
6243
  ...enrolmentEnabled ? ["forgezero-agent-enrol.service"] : []
@@ -6245,9 +6261,9 @@ function planProvision(options) {
6245
6261
  ...options.enforceEgress ? [
6246
6262
  { path: AGENT_EGRESS_UNIT_PATH, unit: agentEgressUnit(options) }
6247
6263
  ] : [],
6264
+ { path: SOFTWARE_HELPER_UNIT_PATH, unit: softwareHelperUnit(options) },
6248
6265
  ...deploymentEnabled ? [
6249
- { path: DEPLOYMENT_RUNNER_UNIT_PATH, unit: deploymentRunnerUnit(options) },
6250
- { path: SOFTWARE_HELPER_UNIT_PATH, unit: softwareHelperUnit(options) }
6266
+ { path: DEPLOYMENT_RUNNER_UNIT_PATH, unit: deploymentRunnerUnit(options) }
6251
6267
  ] : [],
6252
6268
  ...enrolmentEnabled ? [
6253
6269
  { path: ENROLMENT_UNIT_PATH, unit: agentEnrolmentUnit(options) }
@@ -6280,24 +6296,29 @@ function planProvision(options) {
6280
6296
  step("Agent update helper access group", { kind: "commands", commands: [{ argv: ["/usr/sbin/groupadd", "--system", AGENT_UPDATE_GROUP], acceptedExitCodes: [0, 9] }] }),
6281
6297
  ...sourceBinPath && binPath ? [step("root-owned agent runtime", { kind: "install-runtime", source: sourceBinPath, binary: binPath, version: VERSION2 })] : [],
6282
6298
  ...warpEnabled ? [step("Cloudflare One client for Ubuntu 26.04", { kind: "install-warp" })] : [],
6283
- ...deploymentEnabled ? [step("deployment isolation group", { kind: "commands", commands: [
6284
- { argv: ["/usr/sbin/groupadd", "--system", DEPLOYMENT_GROUP], acceptedExitCodes: [0, 9] },
6299
+ step("software strategy helper group", { kind: "commands", commands: [
6285
6300
  { argv: ["/usr/sbin/groupadd", "--system", SOFTWARE_HELPER_GROUP], acceptedExitCodes: [0, 9] }
6301
+ ] }),
6302
+ ...deploymentEnabled ? [step("deployment isolation group", { kind: "commands", commands: [
6303
+ { argv: ["/usr/sbin/groupadd", "--system", DEPLOYMENT_GROUP], acceptedExitCodes: [0, 9] }
6286
6304
  ] })] : [],
6287
6305
  ...lifecycleEnabled ? [step("lifecycle helper access group", { kind: "commands", commands: [{ argv: ["/usr/sbin/groupadd", "--system", LIFECYCLE_GROUP], acceptedExitCodes: [0, 9] }] })] : [],
6288
6306
  step("service account", { kind: "commands", commands: [{ argv: ["/usr/sbin/useradd", "--system", "--no-create-home", "--shell", "/usr/sbin/nologin", user], acceptedExitCodes: [0, 9] }] }),
6289
6307
  step("bind service account to vault group", { kind: "commands", commands: [{ argv: ["/usr/sbin/usermod", "-g", VAULT_GROUP, user] }] }),
6290
6308
  step("grant verified Agent update access", { kind: "commands", commands: [{ argv: ["/usr/sbin/usermod", "-a", "-G", AGENT_UPDATE_GROUP, user] }] }),
6309
+ step("grant software helper socket access", { kind: "commands", commands: [
6310
+ { argv: ["/usr/sbin/usermod", "-a", "-G", SOFTWARE_HELPER_GROUP, user] }
6311
+ ] }),
6291
6312
  ...lifecycleEnabled ? [step("grant lifecycle helper socket access", { kind: "commands", commands: [{ argv: ["/usr/sbin/usermod", "-a", "-G", LIFECYCLE_GROUP, user] }] })] : [],
6292
6313
  ...deploymentEnabled ? [step("credential-free deployment account", { kind: "commands", commands: [
6293
6314
  { argv: ["/usr/sbin/useradd", "--system", "--no-create-home", "--shell", "/usr/sbin/nologin", "--gid", DEPLOYMENT_GROUP, DEPLOYMENT_RUNNER_USER], acceptedExitCodes: [0, 9] },
6294
6315
  { argv: ["/usr/sbin/useradd", "--system", "--no-create-home", "--shell", "/usr/sbin/nologin", "--gid", VAULT_GROUP, APPLICATION_RUNTIME_USER], acceptedExitCodes: [0, 9] },
6295
6316
  { argv: ["/usr/sbin/usermod", "-a", "-G", DEPLOYMENT_GROUP, APPLICATION_RUNTIME_USER] },
6296
- { argv: ["/usr/sbin/usermod", "-a", "-G", `${DEPLOYMENT_GROUP},${SOFTWARE_HELPER_GROUP}`, user] }
6317
+ { argv: ["/usr/sbin/usermod", "-a", "-G", DEPLOYMENT_GROUP, user] }
6297
6318
  ] })] : [],
6298
6319
  step("credential and state directories", { kind: "directories", directories: [
6299
6320
  { path: credentialDir, mode: 448, owner: "root", group: "root" },
6300
- { path: "/var/lib/forgezero", mode: 488, owner: "root", group: "root" }
6321
+ { path: "/var/lib/forgezero", mode: 488, owner: "root", group: VAULT_GROUP }
6301
6322
  ] }),
6302
6323
  step("encrypted node identity", { kind: "ensure-seed", credential: seedCredentialPath }),
6303
6324
  ...options.generateGitIdentity && gitCredentialPath && gitPublicKeyPath ? [
@@ -6348,19 +6369,26 @@ function planProvision(options) {
6348
6369
  { argv: ["/usr/bin/systemctl", "enable", ...enabledUnits] },
6349
6370
  { argv: ["/usr/bin/systemctl", "reset-failed", "forgezero-agent.service"], acceptedExitCodes: [0, 1] },
6350
6371
  ...restartedUnits.length ? [{ argv: ["/usr/bin/systemctl", "restart", ...restartedUnits] }] : [],
6372
+ { argv: ["/usr/bin/systemctl", "stop", "forgezero-agent-proxy.service"], acceptedExitCodes: [0, 1, 5] },
6351
6373
  { argv: ["/usr/bin/systemctl", "restart", "forgezero-agent.socket"] },
6352
6374
  { argv: ["/usr/bin/systemctl", "reset-failed", "forgezero-agent.service"], acceptedExitCodes: [0, 1] },
6353
6375
  { argv: ["/usr/bin/systemctl", "restart", "forgezero-agent.service"] }
6354
6376
  ] }),
6355
6377
  ...enrolmentEnabled ? [step("prove the compute binding is durable", { kind: "verify-file", path: enrolStatePath })] : [],
6356
- ...options.enforceEgress ? [step("prove the Agent egress policy is active", { kind: "verify-egress", runnerPublicTcpPorts, runnerLoopbackPorts })] : [],
6378
+ ...options.enforceEgress ? [step("prove the Agent egress policy is active", {
6379
+ kind: "verify-egress",
6380
+ deploymentEnabled,
6381
+ runnerPublicTcpPorts,
6382
+ runnerLoopbackPorts,
6383
+ agentLoopbackPorts
6384
+ })] : [],
6357
6385
  step("prove it is running", { kind: "commands", commands: [{ argv: ["/usr/bin/systemctl", "is-active", "forgezero-agent.service"] }] }),
6358
6386
  step("prove the public Vault socket exists", { kind: "wait-socket", path: options.socketPath, attempts: 100, intervalMs: 100 }),
6359
6387
  step("prove the Agent Vault backend exists", { kind: "wait-socket", path: agentBackendSocketPath(options.socketPath), attempts: 100, intervalMs: 100 }),
6360
6388
  step("prove the Agent update helper exists", { kind: "wait-socket", path: DEFAULT_AGENT_UPDATE_SOCKET, attempts: 100, intervalMs: 100 }),
6389
+ step("prove the software strategy helper socket exists", { kind: "wait-socket", path: DEFAULT_SOFTWARE_HELPER_SOCKET, attempts: 100, intervalMs: 100 }),
6361
6390
  ...deploymentEnabled ? [
6362
- step("prove the deployment runner socket exists", { kind: "wait-socket", path: DEPLOYMENT_RUNNER_SOCKET, attempts: 100, intervalMs: 100 }),
6363
- step("prove the software strategy helper socket exists", { kind: "wait-socket", path: DEFAULT_SOFTWARE_HELPER_SOCKET, attempts: 100, intervalMs: 100 })
6391
+ step("prove the deployment runner socket exists", { kind: "wait-socket", path: DEPLOYMENT_RUNNER_SOCKET, attempts: 100, intervalMs: 100 })
6364
6392
  ] : [],
6365
6393
  ...lifecycleEnabled ? [step("prove the lifecycle helper socket exists", { kind: "wait-socket", path: lifecycleHelperSocketPath, attempts: 100, intervalMs: 100 })] : [],
6366
6394
  ...warpEnabled ? [step("prove Cloudflare WARP is connected", { kind: "verify-warp" })] : [],
@@ -6385,6 +6413,25 @@ import {
6385
6413
  writeFileSync as writeFileSync3
6386
6414
  } from "fs";
6387
6415
  import { dirname as dirname3 } from "path";
6416
+ function normalizeEd25519PublicKey(output) {
6417
+ const line = output.trim();
6418
+ if (!/^ssh-ed25519 [A-Za-z0-9+/]+={0,3}(?: [^\r\n]{1,256})?$/.test(line))
6419
+ return;
6420
+ const [algorithm, encoded] = line.split(" ", 3);
6421
+ if (algorithm !== "ssh-ed25519" || !encoded)
6422
+ return;
6423
+ let blob;
6424
+ try {
6425
+ blob = Buffer.from(encoded, "base64");
6426
+ } catch {
6427
+ return;
6428
+ }
6429
+ if (blob.length !== 51 || blob.readUInt32BE(0) !== 11 || blob.subarray(4, 15).toString("ascii") !== "ssh-ed25519" || blob.readUInt32BE(15) !== 32)
6430
+ return;
6431
+ if (blob.toString("base64") !== encoded)
6432
+ return;
6433
+ return `${algorithm} ${encoded}`;
6434
+ }
6388
6435
  function parseAssignments(value) {
6389
6436
  if (!value?.trim())
6390
6437
  return;
@@ -6557,7 +6604,7 @@ var runProvisionOperation = async (operation) => {
6557
6604
  return result;
6558
6605
  }
6559
6606
  result = await fixed(["/usr/bin/ssh-keygen", "-y", "-f", key]);
6560
- if (result.exitCode !== 0 || !/^ssh-ed25519 [A-Za-z0-9+/]+={0,3}\s*$/.test(result.stdout)) {
6607
+ if (result.exitCode !== 0 || !normalizeEd25519PublicKey(result.stdout)) {
6561
6608
  return { stdout: "bootstrap SSH private key is not a valid Ed25519 OpenSSH key", exitCode: 1 };
6562
6609
  }
6563
6610
  result = await fixed(["/usr/bin/systemd-creds", "encrypt", "--name=bootstrap-ssh-key", key, operation.credential]);
@@ -6573,11 +6620,12 @@ var runProvisionOperation = async (operation) => {
6573
6620
  chmodSync(key, 384);
6574
6621
  }
6575
6622
  const derived = await fixed(["/usr/bin/ssh-keygen", "-y", "-f", key]);
6576
- if (derived.exitCode !== 0 || !/^ssh-ed25519 [A-Za-z0-9+/]+={0,3}\s*$/.test(derived.stdout)) {
6623
+ const publicKey = normalizeEd25519PublicKey(derived.stdout);
6624
+ if (derived.exitCode !== 0 || !publicKey) {
6577
6625
  return { stdout: "bootstrap SSH public key derivation failed", exitCode: 1 };
6578
6626
  }
6579
6627
  mkdirSync3(dirname3(operation.publicKey), { recursive: true, mode: 493 });
6580
- writeFileSync3(operation.publicKey, `${derived.stdout.trim()} forgezero-bootstrap-runner
6628
+ writeFileSync3(operation.publicKey, `${publicKey} forgezero-bootstrap-runner
6581
6629
  `, { mode: 292 });
6582
6630
  chmodSync(operation.publicKey, 292);
6583
6631
  }
@@ -6620,8 +6668,9 @@ var runProvisionOperation = async (operation) => {
6620
6668
  const policy = await fixed(["/usr/sbin/nft", "--numeric", "list", "table", "inet", "forgezero_agent_egress"]);
6621
6669
  const required = [
6622
6670
  "forgezero-agent-egress-v1",
6623
- `public-tcp=${operation.runnerPublicTcpPorts.join(",")}`,
6624
- ...operation.runnerLoopbackPorts.length ? [`:${operation.runnerLoopbackPorts.join(",")}`] : []
6671
+ ...operation.agentLoopbackPorts.length ? [`shared-loopback=${operation.agentLoopbackPorts.join(",")}`] : [],
6672
+ ...operation.deploymentEnabled && operation.runnerPublicTcpPorts.length ? [`public-tcp=${operation.runnerPublicTcpPorts.join(",")}`] : [],
6673
+ ...operation.deploymentEnabled && operation.runnerLoopbackPorts.length ? [`:${operation.runnerLoopbackPorts.join(",")}`] : []
6625
6674
  ];
6626
6675
  return policy.exitCode === 0 && required.every((part) => policy.stdout.includes(part)) ? { stdout: policy.stdout, exitCode: 0 } : { stdout: policy.stdout, exitCode: 1 };
6627
6676
  }
@@ -6697,7 +6746,9 @@ async function applyPlan(plan, run) {
6697
6746
  const result = await run(step2.operation);
6698
6747
  transcript.push({ label: step2.label, command: step2.command, exitCode: result.exitCode });
6699
6748
  if (result.exitCode !== 0 && !step2.optional) {
6700
- throw new Error(`${step2.label} failed (exit ${result.exitCode}): ${step2.command}`);
6749
+ const safeDetail = step2.operation.kind === "ensure-bootstrap-ssh-identity" ? result.stdout.trim().slice(0, 1000) : "";
6750
+ throw new Error(`${step2.label} failed (exit ${result.exitCode}): ${step2.command}${safeDetail ? `
6751
+ ${safeDetail}` : ""}`);
6701
6752
  }
6702
6753
  }
6703
6754
  return transcript;
@@ -12509,12 +12560,26 @@ map $limit_conn_status $forgezero_retry_after { default ''; REJECTED 1; REJECTED
12509
12560
  server {
12510
12561
  listen 127.0.0.1:${input.publicPort};
12511
12562
  server_name _;
12563
+ server_tokens off;
12564
+ more_clear_headers Server X-Powered-By;
12512
12565
  limit_conn forgezero_admission ${concurrencyLimit};
12513
12566
  limit_conn_status 503;
12514
12567
  add_header Retry-After $forgezero_retry_after always;
12515
- location ^~ /api/ { proxy_pass http://forgezero; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Forwarded-Proto https; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $forgezero_connection; proxy_read_timeout 3600s; }
12516
- location ^~ /v1/ { proxy_pass http://forgezero; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Forwarded-Proto https; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $forgezero_connection; proxy_read_timeout 3600s; }
12517
- location / { return 404; }
12568
+ error_page 400 403 404 405 408 413 414 429 500 502 503 504 = @transport_failure;
12569
+ location @transport_failure { internal; return 444; }
12570
+ location / {
12571
+ proxy_pass http://forgezero;
12572
+ proxy_http_version 1.1;
12573
+ proxy_intercept_errors off;
12574
+ proxy_hide_header Server;
12575
+ proxy_hide_header X-Powered-By;
12576
+ proxy_set_header Host $host;
12577
+ proxy_set_header X-Forwarded-Proto https;
12578
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
12579
+ proxy_set_header Upgrade $http_upgrade;
12580
+ proxy_set_header Connection $forgezero_connection;
12581
+ proxy_read_timeout 3600s;
12582
+ }
12518
12583
  }
12519
12584
  `
12520
12585
  };
@@ -14362,7 +14427,7 @@ Type=oneshot
14362
14427
  User=arangodb
14363
14428
  Group=arangodb
14364
14429
  LoadCredentialEncrypted=arangodb-jwt:${JWT_CREDENTIAL}
14365
- ExecStart=/usr/bin/arangosh --server.endpoint tcp://${unitEscape(address)}:8529 --server.jwt-secret-keyfile %d/arangodb-jwt --javascript.execute-string 'const c=require("@arangodb").db._connection;let last;for(let i=0;i<90;i++){try{const v=c.GET("/_api/version?details=true");const s=c.GET("/_admin/status");const m=c.GET("/_admin/server/mode");if(!v.error&&v.version==="3.11.14"&&v.details&&v.details.license==="community"&&!s.error&&s.serverInfo&&s.serverInfo.role==="COORDINATOR"&&!m.error&&m.mode==="default")quit(0);last={v,s,m};}catch(e){last=String(e);}require("internal").wait(2);}throw new Error("writable Community Coordinator verification failed: "+JSON.stringify(last));'
14430
+ ExecStart=/usr/bin/arangosh --server.endpoint tcp://${unitEscape(address)}:8529 --server.jwt-secret-keyfile %d/arangodb-jwt --javascript.execute-string 'const c=require("@arangodb").db._connection;let last;let ok=false;for(let i=0;i<90;i++){try{const v=c.GET("/_api/version?details=true");const s=c.GET("/_admin/status");const m=c.GET("/_admin/server/mode");if(!v.error&&v.version==="3.11.14"&&v.details&&v.details.license==="community"&&!s.error&&s.serverInfo&&s.serverInfo.role==="COORDINATOR"&&!m.error&&m.mode==="default"){ok=true;break;}last={v,s,m};}catch(e){last=String(e);}require("internal").wait(2);}if(!ok)throw new Error("writable Community Coordinator verification failed: "+JSON.stringify(last));'
14366
14431
  RemainAfterExit=yes
14367
14432
  TimeoutStartSec=200
14368
14433
  NoNewPrivileges=true
@@ -14488,11 +14553,11 @@ async function seal(host, name, destination2, value) {
14488
14553
  async function verifyBootstrapBundleOnHost(host, config, verifyGit = false) {
14489
14554
  const manifestMetadata = host.inspect?.(config.bootstrapBundle.manifestFile);
14490
14555
  const bundleMetadata = host.inspect?.(config.bootstrapBundle.bundleFile);
14491
- if (manifestMetadata && (!manifestMetadata.regular || manifestMetadata.symbolic || manifestMetadata.uid !== 0 || manifestMetadata.links !== 1 || (manifestMetadata.mode & 63) !== 0 || manifestMetadata.size > 16 * 1024)) {
14492
- throw new Error("bootstrap bundle manifest must be a root-owned owner-only regular file");
14556
+ if (manifestMetadata && (!manifestMetadata.regular || manifestMetadata.symbolic || manifestMetadata.uid !== 0 || manifestMetadata.links !== 1 || (manifestMetadata.mode & 18) !== 0 || manifestMetadata.size > 16 * 1024)) {
14557
+ throw new Error("bootstrap bundle manifest must be a root-owned non-writable regular file");
14493
14558
  }
14494
- if (bundleMetadata && (!bundleMetadata.regular || bundleMetadata.symbolic || bundleMetadata.uid !== 0 || bundleMetadata.links !== 1 || (bundleMetadata.mode & 63) !== 0 || bundleMetadata.size < 1 || bundleMetadata.size > 512 * 1024 * 1024)) {
14495
- throw new Error("bootstrap bundle must be a root-owned owner-only regular file within 512 MiB");
14559
+ if (bundleMetadata && (!bundleMetadata.regular || bundleMetadata.symbolic || bundleMetadata.uid !== 0 || bundleMetadata.links !== 1 || (bundleMetadata.mode & 18) !== 0 || bundleMetadata.size < 1 || bundleMetadata.size > 512 * 1024 * 1024)) {
14560
+ throw new Error("bootstrap bundle must be a root-owned non-writable regular file within 512 MiB");
14496
14561
  }
14497
14562
  if (!host.exists(config.bootstrapBundle.bundleFile) || !host.exists(config.bootstrapBundle.manifestFile)) {
14498
14563
  throw new Error("attended bootstrap bundle and manifest are required for release generation one");
@@ -14511,11 +14576,25 @@ async function verifyBootstrapBundleOnHost(host, config, verifyGit = false) {
14511
14576
  if (digest !== manifest.sha256)
14512
14577
  throw new Error("bootstrap bundle digest does not match its manifest");
14513
14578
  if (verifyGit) {
14514
- await checked3(host, ["/usr/bin/git", "bundle", "verify", config.bootstrapBundle.bundleFile], "bootstrap Git bundle verification");
14579
+ const verificationRepository = "/run/forgezero-bootstrap-bundle-verify";
14580
+ await checked3(host, ["/usr/bin/rm", "-rf", "--", verificationRepository], "stale bootstrap bundle verifier cleanup");
14581
+ await checked3(host, ["/usr/bin/git", "init", "--bare", "--quiet", verificationRepository], "bootstrap bundle verifier repository");
14582
+ try {
14583
+ await checked3(host, [
14584
+ "/usr/bin/git",
14585
+ "-C",
14586
+ verificationRepository,
14587
+ "bundle",
14588
+ "verify",
14589
+ config.bootstrapBundle.bundleFile
14590
+ ], "bootstrap Git bundle verification");
14591
+ } finally {
14592
+ await checked3(host, ["/usr/bin/rm", "-rf", "--", verificationRepository], "bootstrap bundle verifier cleanup");
14593
+ }
14515
14594
  }
14516
14595
  return manifest;
14517
14596
  }
14518
- function bootstrapIdentity(config) {
14597
+ function bootstrapIdentity(config, includeDeploymentEvidence = false) {
14519
14598
  if (config.kind === "enrolled-compute")
14520
14599
  return {
14521
14600
  kind: config.kind,
@@ -14534,7 +14613,13 @@ function bootstrapIdentity(config) {
14534
14613
  bootstrapRunner: config.bootstrapRunner ? { targetTelemetryEndpoint: config.bootstrapRunner.targetTelemetryEndpoint } : null
14535
14614
  };
14536
14615
  const environment = config.runtime.environment;
14537
- const { cloudflare: _cloudflare, realtime: _realtime, ...stableEnvironment } = environment;
14616
+ const { cloudflare: _cloudflare, realtime: _realtime, initialInventory, ...stableEnvironmentRest } = environment;
14617
+ const stableEnvironment = {
14618
+ ...stableEnvironmentRest,
14619
+ ...initialInventory ? {
14620
+ initialInventory: { ...initialInventory, deployment: includeDeploymentEvidence ? initialInventory.deployment : undefined }
14621
+ } : {}
14622
+ };
14538
14623
  return {
14539
14624
  kind: config.kind,
14540
14625
  environment: config.environment,
@@ -14575,6 +14660,26 @@ function bootstrapIdentity(config) {
14575
14660
  function bootstrapIdentityDigest(config) {
14576
14661
  return createHash4("sha256").update(JSON.stringify(bootstrapIdentity(config))).digest("hex");
14577
14662
  }
14663
+ var legacyBootstrapIdentityDigest = (config) => createHash4("sha256").update(JSON.stringify(bootstrapIdentity(config, true))).digest("hex");
14664
+ function interruptedPlatformReleaseIdentityDigests(config, releaseEvidence, bootstrapManifest) {
14665
+ if (!config.runtime.environment.initialInventory)
14666
+ return [];
14667
+ const previous = structuredClone(config);
14668
+ previous.runtime.environment.initialInventory.deployment = {
14669
+ source: "bootstrap-bundle",
14670
+ branch: releaseEvidence.branch,
14671
+ revision: releaseEvidence.revision,
14672
+ bundleSha256: releaseEvidence.sha256
14673
+ };
14674
+ const expectedCurrentEpoch = bootstrapManifest ? `${config.environment}-${bootstrapManifest.revision.slice(0, 16)}` : undefined;
14675
+ if (expectedCurrentEpoch && config.runtime.environment.seedSyncEpoch === expectedCurrentEpoch) {
14676
+ previous.runtime.environment.seedSyncEpoch = `${config.environment}-${releaseEvidence.revision.slice(0, 16)}`;
14677
+ }
14678
+ return [bootstrapIdentityDigest(previous), legacyBootstrapIdentityDigest(previous)];
14679
+ }
14680
+ function storedPlatformCoordinatesMatch(state, config) {
14681
+ return state.kind === "platform" && state.profile === config.profile && state.nodeHostname === config.nodeHostname && state.apiUrl === config.apiUrl && state.environment === config.environment && state.databaseRole === config.database.role && state.databaseAgency === config.database.agency && state.databaseReadPreferred === config.database.readPreferred && state.databaseServerMode === config.database.serverMode && (state.databaseAddress ?? null) === (config.database.address ?? null) && JSON.stringify(state.databaseCoordinators ?? []) === JSON.stringify(config.database.coordinators) && state.collectorUnit === config.runtime.environment.otlpCollectorUnit && state.publicApiPort === config.runtime.environment.publicApiPort && state.healthPath === config.runtime.healthPath;
14682
+ }
14578
14683
  function parseStoredState(raw) {
14579
14684
  let value;
14580
14685
  try {
@@ -14605,11 +14710,21 @@ function parseStoredIntent(raw) {
14605
14710
  }
14606
14711
  return intent;
14607
14712
  }
14608
- function bindBootstrapIntent(host, config) {
14713
+ function bindBootstrapIntent(host, config, previousReleaseDigests = []) {
14609
14714
  const identityDigest = bootstrapIdentityDigest(config);
14610
14715
  if (host.exists(INTENT_PATH)) {
14611
14716
  const intent = parseStoredIntent(host.read(INTENT_PATH));
14612
14717
  if (intent.kind !== config.kind || intent.identityDigest !== identityDigest) {
14718
+ if (previousReleaseDigests.includes(intent.identityDigest) && intent.kind === "platform" && config.kind === "platform") {
14719
+ host.write(INTENT_PATH, `${JSON.stringify({
14720
+ format: 1,
14721
+ kind: config.kind,
14722
+ identityDigest,
14723
+ createdAt: new Date().toISOString()
14724
+ }, null, 2)}
14725
+ `, 384);
14726
+ return identityDigest;
14727
+ }
14613
14728
  throw new Error("bootstrap resume coordinates do not match the interrupted host intent");
14614
14729
  }
14615
14730
  } else if (!host.exists(STATE_PATH)) {
@@ -14777,7 +14892,42 @@ async function applyBootstrap(input, host = localBootstrapHost(), secrets, depen
14777
14892
  let installed;
14778
14893
  if (host.exists(STATE_PATH))
14779
14894
  installed = parseStoredState(host.read(STATE_PATH));
14780
- const bootstrapManifest = config.kind === "platform" && !host.exists(BOOTSTRAP_RELEASE_EVIDENCE) ? await verifyBootstrapBundleOnHost(host, config) : undefined;
14895
+ let bootstrapManifest;
14896
+ let releaseEvidence;
14897
+ if (config.kind === "platform") {
14898
+ const staged = host.exists(config.bootstrapBundle.bundleFile) || host.exists(config.bootstrapBundle.manifestFile);
14899
+ if (staged && !(host.exists(config.bootstrapBundle.bundleFile) && host.exists(config.bootstrapBundle.manifestFile))) {
14900
+ throw new Error("bootstrap bundle and manifest must be staged together");
14901
+ }
14902
+ const reviewed = staged ? await verifyBootstrapBundleOnHost(host, config) : undefined;
14903
+ if (!host.exists(BOOTSTRAP_RELEASE_EVIDENCE)) {
14904
+ if (!reviewed)
14905
+ throw new Error("attended bootstrap bundle and manifest are required for release generation one");
14906
+ bootstrapManifest = reviewed;
14907
+ } else if (reviewed) {
14908
+ let evidence;
14909
+ try {
14910
+ evidence = JSON.parse(host.read(BOOTSTRAP_RELEASE_EVIDENCE));
14911
+ } catch {
14912
+ throw new Error("bootstrap release evidence is malformed");
14913
+ }
14914
+ if (typeof evidence.revision !== "string" || !/^[a-f0-9]{40}$/.test(evidence.revision) || typeof evidence.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(evidence.sha256) || typeof evidence.branch !== "string")
14915
+ throw new Error("bootstrap release evidence is malformed");
14916
+ releaseEvidence = { revision: evidence.revision, sha256: evidence.sha256, branch: evidence.branch };
14917
+ if (evidence.revision !== reviewed.revision || evidence.sha256 !== reviewed.sha256 || evidence.branch !== reviewed.branch)
14918
+ bootstrapManifest = reviewed;
14919
+ } else if (host.exists(BOOTSTRAP_RELEASE_EVIDENCE)) {
14920
+ let evidence;
14921
+ try {
14922
+ evidence = JSON.parse(host.read(BOOTSTRAP_RELEASE_EVIDENCE));
14923
+ } catch {
14924
+ throw new Error("bootstrap release evidence is malformed");
14925
+ }
14926
+ if (typeof evidence.revision !== "string" || !/^[a-f0-9]{40}$/.test(evidence.revision) || typeof evidence.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(evidence.sha256) || typeof evidence.branch !== "string")
14927
+ throw new Error("bootstrap release evidence is malformed");
14928
+ releaseEvidence = { revision: evidence.revision, sha256: evidence.sha256, branch: evidence.branch };
14929
+ }
14930
+ }
14781
14931
  let cloudflare;
14782
14932
  if (config.cloudflareHandoff) {
14783
14933
  if (host.exists(config.cloudflareHandoff.handoffFile)) {
@@ -14827,10 +14977,14 @@ async function applyBootstrap(input, host = localBootstrapHost(), secrets, depen
14827
14977
  throw new Error("platform realtime coordinates require a realtime-enabled Cloudflare handoff");
14828
14978
  }
14829
14979
  }
14980
+ let allowInterruptedReleaseRebind = false;
14830
14981
  if (installed) {
14831
- if (installed.kind !== config.kind || installed.identityDigest !== bootstrapIdentityDigest(config)) {
14982
+ const exactIdentity = installed.kind === config.kind && installed.identityDigest === bootstrapIdentityDigest(config);
14983
+ const boundedReleaseResume = config.kind === "platform" && !host.exists("/var/lib/forgezero/enrolment.json") && host.exists(BOOTSTRAP_RELEASE_EVIDENCE) && storedPlatformCoordinatesMatch(installed, config);
14984
+ if (!exactIdentity && !boundedReleaseResume) {
14832
14985
  throw new Error("bootstrap repair coordinates do not match the installed host identity");
14833
14986
  }
14987
+ allowInterruptedReleaseRebind = !exactIdentity && boundedReleaseResume;
14834
14988
  }
14835
14989
  const platformPrivate = config.kind === "platform" ? (() => {
14836
14990
  if (!secrets)
@@ -14850,10 +15004,14 @@ async function applyBootstrap(input, host = localBootstrapHost(), secrets, depen
14850
15004
  if (config.kind === "enrolled-compute" && config.bootstrapRunner?.sshPrivateKeyFile && !host.exists(BOOTSTRAP_SSH_CREDENTIAL)) {
14851
15005
  privateFile(host, config.bootstrapRunner.sshPrivateKeyFile, "bootstrap runner SSH private key");
14852
15006
  }
14853
- bindBootstrapIntent(host, config);
15007
+ let previousReleaseDigests = [];
15008
+ if (!installed && config.kind === "platform" && releaseEvidence && !host.exists("/var/lib/forgezero/enrolment.json")) {
15009
+ previousReleaseDigests = [...interruptedPlatformReleaseIdentityDigests(config, releaseEvidence, bootstrapManifest)];
15010
+ }
15011
+ bindBootstrapIntent(host, config, allowInterruptedReleaseRebind && installed?.identityDigest ? [installed.identityDigest] : previousReleaseDigests);
14854
15012
  const plan = planBootstrap(config, host.exists(STATE_PATH));
14855
15013
  await checked3(host, ["hostnamectl", "set-hostname", "--static", config.nodeHostname], "compute hostname");
14856
- const alreadyEnrolled = host.exists("/var/lib/forgezero/enrolment.json");
15014
+ let alreadyEnrolled = host.exists("/var/lib/forgezero/enrolment.json");
14857
15015
  host.mkdir(CREDS, 448);
14858
15016
  host.mkdir("/var/lib/forgezero", 448);
14859
15017
  if (!alreadyEnrolled && !host.exists(ENROL_CREDENTIAL)) {
@@ -14882,14 +15040,29 @@ async function applyBootstrap(input, host = localBootstrapHost(), secrets, depen
14882
15040
  if (connectorCapabilities?.meshConnectorToken && !host.exists(WARP_CONNECTOR_CREDENTIAL)) {
14883
15041
  await seal(host, "CF_WARP_CONNECTOR_TOKEN", WARP_CONNECTOR_CREDENTIAL, connectorCapabilities.meshConnectorToken);
14884
15042
  }
15043
+ let installedAgentPlan;
14885
15044
  if (alreadyEnrolled) {
14886
- await host.installAgent(config, "bound");
15045
+ installedAgentPlan = await host.installAgent(config, "bound");
14887
15046
  } else if (config.kind === "platform") {
14888
15047
  if (bootstrapManifest)
14889
- await host.installAgent(config, "bootstrap");
15048
+ installedAgentPlan = await host.installAgent(config, "bootstrap");
15049
+ else if (host.exists(BOOTSTRAP_RELEASE_EVIDENCE)) {
15050
+ await checked3(host, [
15051
+ "curl",
15052
+ "--fail",
15053
+ "--silent",
15054
+ "--show-error",
15055
+ "--max-time",
15056
+ "10",
15057
+ `http://127.0.0.1:${config.runtime.environment.publicApiPort}${config.runtime.healthPath}`
15058
+ ], "persisted release-one API health");
15059
+ await host.installAgent(config, "enrol");
15060
+ installedAgentPlan = await host.installAgent(config, "bound");
15061
+ alreadyEnrolled = true;
15062
+ }
14890
15063
  } else {
14891
15064
  await host.installAgent(config, "enrol");
14892
- await host.installAgent(config, "bound");
15065
+ installedAgentPlan = await host.installAgent(config, "bound");
14893
15066
  }
14894
15067
  if (config.kind === "platform" && config.firewall.enabled) {
14895
15068
  await host.ensureSoftware(plan.software.filter(({ id: id2 }) => id2 === "ufw"));
@@ -14969,6 +15142,7 @@ async function applyBootstrap(input, host = localBootstrapHost(), secrets, depen
14969
15142
  await checked3(host, ["useradd", "--system", "--no-create-home", "--shell", "/usr/sbin/nologin", runtime.serviceUser], "API service account").catch(async () => {
14970
15143
  await checked3(host, ["id", runtime.serviceUser], "existing API service account");
14971
15144
  });
15145
+ await checked3(host, ["usermod", "-a", "-G", DEPLOYMENT_GROUP, runtime.serviceUser], "API deployment group");
14972
15146
  host.mkdir(runtime.environment.sharedDirectory, 488);
14973
15147
  host.mkdir(runtime.slotsDirectory, 493);
14974
15148
  host.write(envPath, renderPlatformSharedEnvironment(runtime.environment), 416);
@@ -14987,7 +15161,7 @@ async function applyBootstrap(input, host = localBootstrapHost(), secrets, depen
14987
15161
  host.write("/etc/sudoers.d/forgezero-runner", activation.sudoers, 288);
14988
15162
  await checked3(host, ["visudo", "-cf", "/etc/sudoers.d/forgezero-runner"], "activation sudo policy");
14989
15163
  const telemetry = planLocalOtlpProof(runtime.environment.otlpEndpoint, runtime.environment.otlpCollectorUnit);
14990
- await checked3(host, telemetry.unitCheck.argv, "OTLP collector supervision");
15164
+ await checked3(host, [telemetry.unitCheck.command, ...telemetry.unitCheck.argv], "OTLP collector supervision");
14991
15165
  const otlpStatus = (await checked3(host, [telemetry.receiverCheck.command, ...telemetry.receiverCheck.argv], "OTLP receiver")).trim();
14992
15166
  if (!/^2\d\d$/.test(otlpStatus))
14993
15167
  throw new Error(`OTLP receiver returned HTTP ${otlpStatus || "unknown"}`);
@@ -15020,10 +15194,12 @@ async function applyBootstrap(input, host = localBootstrapHost(), secrets, depen
15020
15194
  `, 384);
15021
15195
  }
15022
15196
  if (bootstrapManifest) {
15197
+ if (!installedAgentPlan?.user)
15198
+ throw new Error("initial Agent deployment requires the converged Agent user");
15023
15199
  await checked3(host, [
15024
15200
  "runuser",
15025
15201
  "-u",
15026
- "forgezero-agent",
15202
+ installedAgentPlan.user,
15027
15203
  "--",
15028
15204
  "/usr/local/bin/fz-agent",
15029
15205
  "deploy",
@@ -15050,7 +15226,7 @@ async function applyBootstrap(input, host = localBootstrapHost(), secrets, depen
15050
15226
  "--show-error",
15051
15227
  "--max-time",
15052
15228
  "10",
15053
- `http://127.0.0.1:3000${runtime.healthPath}`
15229
+ `http://127.0.0.1:${runtime.environment.publicApiPort}${runtime.healthPath}`
15054
15230
  ], "release-one API health");
15055
15231
  await host.installAgent(config, "enrol");
15056
15232
  await host.installAgent(config, "bound");
@@ -15291,6 +15467,8 @@ function planBootstrapAgentInstall(config, phase, context) {
15291
15467
  bootstrapTargetTelemetryEndpoint: bound && bootstrapRunner ? platformBootstrapRunner(config) ? config.telemetryEndpoint : config.kind === "enrolled-compute" ? config.bootstrapRunner?.targetTelemetryEndpoint : undefined : undefined,
15292
15468
  lifecycleProfilePath: bound && config.kind === "platform" ? LIFECYCLE_PROFILE : undefined,
15293
15469
  enforceEgress: true,
15470
+ runnerLoopbackPorts: config.kind === "platform" ? [config.runtime.environment.publicApiPort, config.runtime.bluePort, config.runtime.greenPort] : [],
15471
+ agentLoopbackPorts: config.kind === "platform" ? [config.runtime.environment.publicApiPort] : [],
15294
15472
  nodeHostname: config.nodeHostname,
15295
15473
  telemetryEndpoint: config.telemetryEndpoint,
15296
15474
  binPath: "/usr/local/lib/forgezero/agent/fz-agent",
@@ -15300,7 +15478,7 @@ function planBootstrapAgentInstall(config, phase, context) {
15300
15478
  enrolStatePath: "/var/lib/forgezero/enrolment.json"
15301
15479
  } : bound ? { enrolStatePath: "/var/lib/forgezero/enrolment.json" } : {},
15302
15480
  ...authenticated ? {
15303
- apiUrl: config.apiUrl,
15481
+ apiUrl: config.kind === "platform" ? `http://127.0.0.1:${config.runtime.environment.publicApiPort}` : config.apiUrl,
15304
15482
  project: config.kind === "enrolled-compute" ? config.realm : "platform",
15305
15483
  environment: config.kind === "enrolled-compute" ? undefined : config.environment,
15306
15484
  nodeLabel: config.kind === "enrolled-compute" ? config.nodeHostname : config.computeReference
@@ -15309,6 +15487,7 @@ function planBootstrapAgentInstall(config, phase, context) {
15309
15487
  return planInstall(options);
15310
15488
  }
15311
15489
  function localBootstrapHost() {
15490
+ let softwareClientUser;
15312
15491
  const execute = async (argv2, options = {}) => {
15313
15492
  const child = Bun.spawn([...argv2], { stdin: options.stdin === undefined ? "ignore" : "pipe", stdout: "pipe", stderr: "pipe" });
15314
15493
  if (options.stdin !== undefined && child.stdin && typeof child.stdin !== "number") {
@@ -15341,10 +15520,12 @@ function localBootstrapHost() {
15341
15520
  exec: execute,
15342
15521
  sleep: (milliseconds) => Bun.sleep(milliseconds),
15343
15522
  async ensureSoftware(requirements) {
15523
+ if (!softwareClientUser)
15524
+ throw new Error("Agent must be converged before software requirements are applied");
15344
15525
  const result = await execute([
15345
15526
  "runuser",
15346
15527
  "-u",
15347
- "forgezero-agent",
15528
+ softwareClientUser,
15348
15529
  "--",
15349
15530
  "/usr/local/bin/fz-agent",
15350
15531
  "software-ensure",
@@ -15358,7 +15539,7 @@ function localBootstrapHost() {
15358
15539
  const capabilities = await readCapabilities(localRunner);
15359
15540
  const hasBinding = existsSync9("/var/lib/forgezero/enrolment.json");
15360
15541
  const hasEnrolCredential = existsSync9(ENROL_CREDENTIAL);
15361
- const initialBundle = config.kind === "platform" && !existsSync9(BOOTSTRAP_RELEASE_EVIDENCE) ? {
15542
+ const initialBundle = config.kind === "platform" && phase === "bootstrap" && existsSync9(config.bootstrapBundle.bundleFile) && existsSync9(config.bootstrapBundle.manifestFile) ? {
15362
15543
  path: config.bootstrapBundle.bundleFile,
15363
15544
  manifestPath: config.bootstrapBundle.manifestFile,
15364
15545
  manifest: parseBootstrapBundleManifest(JSON.parse(readFileSync9(config.bootstrapBundle.manifestFile, "utf8")))
@@ -15389,6 +15570,7 @@ function localBootstrapHost() {
15389
15570
  writeFileSync9(unit.path, unit.unit, { mode: 420 });
15390
15571
  }
15391
15572
  await applyPlan(plan, localRunner);
15573
+ softwareClientUser = plan.user;
15392
15574
  return plan;
15393
15575
  }
15394
15576
  };
@@ -15658,7 +15840,7 @@ async function runCloudflareBootstrapFinalizeCommand(configPath, dependencies =
15658
15840
 
15659
15841
  // src/operator-bootstrap.ts
15660
15842
  import { createHash as createHash6, randomBytes as randomBytes9 } from "crypto";
15661
- import { chmodSync as chmodSync6, lstatSync as lstatSync7, mkdirSync as mkdirSync12, mkdtempSync as mkdtempSync2, readFileSync as readFileSync12, rmSync as rmSync7, writeFileSync as writeFileSync12 } from "fs";
15843
+ import { chmodSync as chmodSync6, existsSync as existsSync11, lstatSync as lstatSync7, mkdirSync as mkdirSync12, mkdtempSync as mkdtempSync2, readFileSync as readFileSync12, rmSync as rmSync7, writeFileSync as writeFileSync12 } from "fs";
15662
15844
  import { isIP as isIP6 } from "net";
15663
15845
  import { tmpdir as tmpdir2 } from "os";
15664
15846
  import { basename as basename2, dirname as dirname13, isAbsolute as isAbsolute5, join as join11, resolve as resolve9 } from "path";
@@ -16630,6 +16812,21 @@ async function metalBootstrapStatus(exec = defaultExec2) {
16630
16812
  }
16631
16813
 
16632
16814
  // src/operator-bootstrap.ts
16815
+ function operatorPackagedBinary(name) {
16816
+ const candidates = [
16817
+ fileURLToPath3(new URL(`./${name}`, import.meta.url)),
16818
+ fileURLToPath3(new URL(`../dist/${name}`, import.meta.url))
16819
+ ];
16820
+ const found = candidates.find(existsSync11);
16821
+ if (!found)
16822
+ throw new Error(`packaged ${name} is missing; checked ${candidates.join(" and ")}`);
16823
+ return found;
16824
+ }
16825
+ var operatorPackagedFzCliPath = () => operatorPackagedBinary("fz.js");
16826
+ var operatorPackagedAgentPath = () => operatorPackagedBinary("fz-agent.js");
16827
+ var operatorPackagedGitSshPath = () => operatorPackagedBinary("fz-git-ssh.js");
16828
+ var PLATFORM_CLUSTER_CREDENTIAL_NAME = "forgezero-platform-cluster-bootstrap-code";
16829
+ var PLATFORM_CLUSTER_CREDENTIAL_PATH = `/etc/forgezero/creds/${PLATFORM_CLUSTER_CREDENTIAL_NAME}.cred`;
16633
16830
  var REQUEST_LIMIT = 64 * 1024;
16634
16831
  var SECRET_LIMIT = 256 * 1024;
16635
16832
  var REMOTE_STAGE = "/run/forgezero-operator-bootstrap";
@@ -17072,9 +17269,11 @@ function operatorPlatformFleetCoordinates(fleet) {
17072
17269
  function planOperatorPlatformFleetBootstrap(fleet, mode) {
17073
17270
  const { requests, configs, environment } = validatedPlatformFleet(fleet);
17074
17271
  const secretInputs = mode === "apply" ? attendedSecretNames(configs[0]) : [];
17075
- for (const config of configs.slice(1)) {
17076
- if (JSON.stringify(attendedSecretNames(config)) !== JSON.stringify(secretInputs)) {
17077
- throw new Error("operator fleet configs do not share one attended secret schema");
17272
+ if (mode === "apply") {
17273
+ for (const config of configs.slice(1)) {
17274
+ if (JSON.stringify(attendedSecretNames(config)) !== JSON.stringify(secretInputs)) {
17275
+ throw new Error("operator fleet configs do not share one attended secret schema");
17276
+ }
17078
17277
  }
17079
17278
  }
17080
17279
  return {
@@ -17112,9 +17311,33 @@ var defaultExec3 = async (argv2, options = {}) => {
17112
17311
  ]);
17113
17312
  return {
17114
17313
  exitCode,
17115
- output: options.secret ? options.safeStdout && exitCode === 0 ? stdout.slice(0, 65536) : "" : `${stdout}${stderr}`.slice(0, 65536)
17314
+ output: options.secret ? exitCode === 0 ? options.safeStdout ? stdout.slice(0, 65536) : "" : redactOperatorSecretDiagnostic(stderr, options.stdin) : `${stdout}${stderr}`.slice(0, 65536)
17116
17315
  };
17117
17316
  };
17317
+ function redactOperatorSecretDiagnostic(stderr, stdin) {
17318
+ if (!stdin)
17319
+ return "";
17320
+ let parsed;
17321
+ try {
17322
+ parsed = JSON.parse(stdin);
17323
+ } catch {
17324
+ return "";
17325
+ }
17326
+ const values = [];
17327
+ const visit = (value) => {
17328
+ if (typeof value === "string" && value)
17329
+ values.push(value);
17330
+ else if (Array.isArray(value))
17331
+ value.forEach(visit);
17332
+ else if (value && typeof value === "object")
17333
+ Object.values(value).forEach(visit);
17334
+ };
17335
+ visit(parsed);
17336
+ let safe = stderr.slice(0, 16384);
17337
+ for (const value of values.sort((left, right) => right.length - left.length))
17338
+ safe = safe.replaceAll(value, "[REDACTED]");
17339
+ return safe.slice(0, 8192);
17340
+ }
17118
17341
  var checked5 = async (exec, argv2, label, options) => {
17119
17342
  const result = await exec(argv2, options);
17120
17343
  if (result.exitCode !== 0)
@@ -17157,7 +17380,7 @@ var sshOptions = (request, knownHosts, scp = false) => [
17157
17380
  "-o",
17158
17381
  "ClearAllForwardings=yes",
17159
17382
  "-o",
17160
- "ConnectTimeout=10",
17383
+ "ConnectTimeout=30",
17161
17384
  "-o",
17162
17385
  request.target.jump ? `ProxyJump=${destination2(request.target.jump)}:${request.target.jump.port}` : "ProxyJump=none",
17163
17386
  scp ? "-P" : "-p",
@@ -17192,6 +17415,93 @@ var remoteRegularFileExists = async (exec, request, knownHosts, path) => {
17192
17415
  return false;
17193
17416
  throw new Error(`remote initialized-state probe failed${result.output ? `: ${result.output.trim()}` : ""}`);
17194
17417
  };
17418
+ async function operatorMetalClusterBootstrapCode(requestInput, options = {}) {
17419
+ const request = validateMetalRequestValue(requestInput);
17420
+ publicIdentity(request.target.identityPublicKeyFile);
17421
+ socketPath(request.target.agentSocket);
17422
+ const exec = options.exec ?? defaultExec3;
17423
+ const directory = mkdtempSync2(join11(tmpdir2(), "forgezero-operator-metal-credential-"));
17424
+ try {
17425
+ const knownHosts = writeKnownHosts(request, directory);
17426
+ const probe = await exec([
17427
+ "ssh",
17428
+ ...sshOptions(request, knownHosts),
17429
+ destination2(request.target),
17430
+ "--",
17431
+ "/usr/bin/sudo",
17432
+ "-n",
17433
+ "/usr/bin/test",
17434
+ "-f",
17435
+ PLATFORM_CLUSTER_CREDENTIAL_PATH
17436
+ ]);
17437
+ if (probe.exitCode !== 0 && probe.exitCode !== 1) {
17438
+ throw new Error("Metal cluster credential probe failed");
17439
+ }
17440
+ if (probe.exitCode === 1) {
17441
+ const value2 = randomBytes9(32).toString("hex");
17442
+ await remote(exec, request, knownHosts, [
17443
+ "/usr/bin/sudo",
17444
+ "-n",
17445
+ "/usr/bin/install",
17446
+ "-d",
17447
+ "-o",
17448
+ "root",
17449
+ "-g",
17450
+ "root",
17451
+ "-m",
17452
+ "0700",
17453
+ dirname13(PLATFORM_CLUSTER_CREDENTIAL_PATH)
17454
+ ], "Metal credential directory");
17455
+ await remote(exec, request, knownHosts, [
17456
+ "/usr/bin/sudo",
17457
+ "-n",
17458
+ "/usr/bin/systemd-creds",
17459
+ "encrypt",
17460
+ `--name=${PLATFORM_CLUSTER_CREDENTIAL_NAME}`,
17461
+ "-",
17462
+ PLATFORM_CLUSTER_CREDENTIAL_PATH
17463
+ ], "seal Metal cluster credential", true, `${value2}
17464
+ `);
17465
+ await remote(exec, request, knownHosts, [
17466
+ "/usr/bin/sudo",
17467
+ "-n",
17468
+ "/usr/bin/chown",
17469
+ "root:root",
17470
+ PLATFORM_CLUSTER_CREDENTIAL_PATH
17471
+ ], "own Metal cluster credential");
17472
+ await remote(exec, request, knownHosts, [
17473
+ "/usr/bin/sudo",
17474
+ "-n",
17475
+ "/usr/bin/chmod",
17476
+ "0600",
17477
+ PLATFORM_CLUSTER_CREDENTIAL_PATH
17478
+ ], "protect Metal cluster credential");
17479
+ }
17480
+ const metadata = await remote(exec, request, knownHosts, [
17481
+ "/usr/bin/sudo",
17482
+ "-n",
17483
+ "/usr/bin/stat",
17484
+ "--format=%u:%g:%a:%h",
17485
+ PLATFORM_CLUSTER_CREDENTIAL_PATH
17486
+ ], "verify Metal cluster credential");
17487
+ if (metadata !== "0:0:600:1")
17488
+ throw new Error("Metal cluster credential is not one root-owned 0600 file");
17489
+ const value = await remote(exec, request, knownHosts, [
17490
+ "/usr/bin/sudo",
17491
+ "-n",
17492
+ "/usr/bin/systemd-creds",
17493
+ "decrypt",
17494
+ `--name=${PLATFORM_CLUSTER_CREDENTIAL_NAME}`,
17495
+ PLATFORM_CLUSTER_CREDENTIAL_PATH,
17496
+ "-"
17497
+ ], "open Metal cluster credential", true, undefined, true);
17498
+ if (!/^[a-f0-9]{64}$/i.test(value))
17499
+ throw new Error("Metal cluster credential is invalid");
17500
+ return value;
17501
+ } finally {
17502
+ rmSync7(directory, { recursive: true, force: true });
17503
+ }
17504
+ }
17195
17505
  var copy = async (exec, request, knownHosts, local, remotePath, secret = false) => {
17196
17506
  safeRemoteArg(remotePath);
17197
17507
  await checked5(exec, [
@@ -17308,9 +17618,9 @@ async function verifiedBunArchive(directory, fetcher) {
17308
17618
  }
17309
17619
  async function installPackagedAgent(request, knownHosts, exec, directory, remoteTemp, options) {
17310
17620
  const artifacts = [
17311
- [options.fzCliPath ?? fileURLToPath3(new URL("./fz.js", import.meta.url)), "fz.js"],
17312
- [options.fzAgentPath ?? fileURLToPath3(new URL("./fz-agent.js", import.meta.url)), "fz-agent.js"],
17313
- [options.fzGitSshPath ?? fileURLToPath3(new URL("./fz-git-ssh.js", import.meta.url)), "fz-git-ssh.js"]
17621
+ [options.fzCliPath ?? operatorPackagedFzCliPath(), "fz.js"],
17622
+ [options.fzAgentPath ?? operatorPackagedAgentPath(), "fz-agent.js"],
17623
+ [options.fzGitSshPath ?? operatorPackagedGitSshPath(), "fz-git-ssh.js"]
17314
17624
  ];
17315
17625
  for (const [artifact] of artifacts) {
17316
17626
  if (!readFileSync12(artifact).length)
@@ -17347,6 +17657,7 @@ async function installPackagedAgent(request, knownHosts, exec, directory, remote
17347
17657
  for (const [, name] of artifacts)
17348
17658
  await remote(exec, request, knownHosts, ["/usr/bin/sudo", "-n", "/usr/bin/install", "-m", "0755", `${remoteTemp}/${name}`, `/usr/local/lib/forgezero/agent/${name}`], "remote Agent install");
17349
17659
  await remote(exec, request, knownHosts, ["/usr/bin/sudo", "-n", "/usr/bin/ln", "-sfn", "/usr/local/lib/forgezero/agent/fz.js", "/usr/local/bin/fz"], "remote fz link");
17660
+ await remote(exec, request, knownHosts, ["/usr/bin/sudo", "-n", "/usr/bin/ln", "-sfn", "/usr/local/lib/forgezero/agent/fz-agent", "/usr/local/bin/fz-agent"], "remote fz-agent link");
17350
17661
  }
17351
17662
  async function applyOperatorPlatformBootstrap(request, mode, options = {}) {
17352
17663
  const plan = planOperatorPlatformBootstrap(request, mode);
@@ -17373,8 +17684,10 @@ async function applyOperatorPlatformBootstrap(request, mode, options = {}) {
17373
17684
  await copy(exec, request, knownHosts, join11(directory, name), `${remoteTemp}/${name}`, true);
17374
17685
  for (const bundle of staged.bundleFiles)
17375
17686
  await copy(exec, request, knownHosts, bundle.source, `${remoteTemp}/${bundle.name}`, true);
17376
- for (const name of ["platform-config.json", ...staged.files, ...staged.bundleFiles.map(({ name: name2 }) => name2)])
17687
+ for (const name of ["platform-config.json", ...staged.files])
17377
17688
  await remote(exec, request, knownHosts, ["/usr/bin/sudo", "-n", "/usr/bin/install", "-m", "0600", `${remoteTemp}/${name}`, `${REMOTE_STAGE}/${name}`], "remote bootstrap handoff", true);
17689
+ for (const { name } of staged.bundleFiles)
17690
+ await remote(exec, request, knownHosts, ["/usr/bin/sudo", "-n", "/usr/bin/install", "-m", "0644", `${remoteTemp}/${name}`, `${REMOTE_STAGE}/${name}`], "remote bootstrap bundle", true);
17378
17691
  const command = ["/usr/bin/sudo", "-n", "/usr/local/bin/fz", "bootstrap", "platform", "credentials-stdin"];
17379
17692
  command.push("--bootstrap-config", `${REMOTE_STAGE}/platform-config.json`, "--apply");
17380
17693
  const output = await remote(exec, request, knownHosts, command, "remote typed bootstrap", mode === "apply", secrets ? `${JSON.stringify(secrets)}
@@ -17596,7 +17909,7 @@ var PROFILES = {
17596
17909
  appOrigin: "https://dev.forgezero.net",
17597
17910
  apiOrigin: "https://dev-api.forgezero.net",
17598
17911
  zoneName: "forgezero.net",
17599
- kvNamespaceTitle: "forgezero-dev-nodes",
17912
+ kvNamespaceTitle: "forgezero dev nodes",
17600
17913
  workerScriptName: "forgezero-api-edge-development",
17601
17914
  region: { key: "in-south", label: "India South", country: "IN" },
17602
17915
  agentOtlpEndpoint: "https://otel.forgezero.net",
@@ -17608,7 +17921,7 @@ var PROFILES = {
17608
17921
  appOrigin: "https://www.forgezero.net",
17609
17922
  apiOrigin: "https://api.forgezero.net",
17610
17923
  zoneName: "forgezero.net",
17611
- kvNamespaceTitle: "forgezero-nodes",
17924
+ kvNamespaceTitle: "forgezero nodes",
17612
17925
  workerScriptName: "forgezero-api-edge-production",
17613
17926
  region: { key: "in-south", label: "India South", country: "IN" },
17614
17927
  agentOtlpEndpoint: "https://otel.forgezero.net",
@@ -17707,7 +18020,7 @@ function forgeZeroLaunchTemplate(profile, guests, bundle, owner) {
17707
18020
  // src/host-maintenance.ts
17708
18021
  import { lstatSync as lstatSync8, readFileSync as readFileSync13 } from "fs";
17709
18022
  var ROOT = "/opt/forgezero";
17710
- var SLOT_FILE = `${ROOT}/.forge-slot`;
18023
+ var SLOT_FILE = `${ROOT}/slots/.active`;
17711
18024
  var SHARED_ENV = `${ROOT}/shared/.env`;
17712
18025
  var JWT = "/etc/forgezero/creds/arangodb-jwt.cred";
17713
18026
  var FZ = "/usr/local/bin/fz";
@@ -17836,7 +18149,7 @@ async function applyHostMaintenance(request, runtime = localRuntime()) {
17836
18149
  }
17837
18150
 
17838
18151
  // src/cli/maintenance.ts
17839
- import { existsSync as existsSync11, lstatSync as lstatSync9, readFileSync as readFileSync14, realpathSync as realpathSync5 } from "fs";
18152
+ import { existsSync as existsSync12, lstatSync as lstatSync9, readFileSync as readFileSync14, realpathSync as realpathSync5 } from "fs";
17840
18153
  import { isAbsolute as isAbsolute6, join as join12, relative as relative2, resolve as resolve10 } from "path";
17841
18154
  var API_OPERATION_ENTRYPOINTS = {
17842
18155
  "dev-reset": ["src", "server", "maintenance", "dev-reset.ts"],
@@ -17907,7 +18220,7 @@ function unsupportedRepositoryCliOption(argv2) {
17907
18220
  }
17908
18221
  function manifestName(root) {
17909
18222
  const manifestPath = join12(root, "package.json");
17910
- if (!existsSync11(manifestPath)) {
18223
+ if (!existsSync12(manifestPath)) {
17911
18224
  throw new Error(`No package.json exists at repository root ${root}.`);
17912
18225
  }
17913
18226
  let parsed;
@@ -17923,7 +18236,7 @@ function manifestName(root) {
17923
18236
  }
17924
18237
  function checkedEntrypoint(root, parts) {
17925
18238
  const candidate = join12(root, ...parts);
17926
- if (!existsSync11(candidate) || !lstatSync9(candidate).isFile()) {
18239
+ if (!existsSync12(candidate) || !lstatSync9(candidate).isFile()) {
17927
18240
  throw new Error(`The reviewed operation entrypoint is missing: ${candidate}`);
17928
18241
  }
17929
18242
  if (lstatSync9(candidate).isSymbolicLink()) {
@@ -18046,7 +18359,7 @@ function planAppBuild(input) {
18046
18359
 
18047
18360
  // src/cli/index.ts
18048
18361
  var DEFAULT_MODE = (THRESHOLD_MODES.find((mode) => mode.threshold === 1 && mode.total === 1) ?? THRESHOLD_MODES[0]).id;
18049
- var PACKAGED_AGENT_BIN2 = fileURLToPath4(new URL("./fz-agent.js", import.meta.url));
18362
+ var PACKAGED_AGENT_BIN2 = operatorPackagedAgentPath();
18050
18363
  function parseOptions(argv2) {
18051
18364
  const options = {
18052
18365
  api: process.env.FZ_API ?? "http://localhost:8787",
@@ -18792,7 +19105,7 @@ async function cmdAgent(options, args) {
18792
19105
  out.ok(`Wrote ${auxiliary.path}`);
18793
19106
  }
18794
19107
  if (options.enrol) {
18795
- if (!existsSync12(enrolStatePath) && !existsSync12(enrolTokenCredentialPath)) {
19108
+ if (!existsSync13(enrolStatePath) && !existsSync13(enrolTokenCredentialPath)) {
18796
19109
  const token = await bootstrapSecret("ForgeZero one-time enrolment token");
18797
19110
  if (!/^fze_[A-Za-z0-9_-]{40,100}$/.test(token))
18798
19111
  throw new Error("A valid fze_ enrolment token was not provided.");
@@ -18811,7 +19124,7 @@ async function cmdAgent(options, args) {
18811
19124
  for (const step3 of transcript)
18812
19125
  out.ok(step3.label);
18813
19126
  out.ok("Agent service and socket verified");
18814
- if (gitIdentity.gitPublicKeyPath && existsSync12(gitIdentity.gitPublicKeyPath)) {
19127
+ if (gitIdentity.gitPublicKeyPath && existsSync13(gitIdentity.gitPublicKeyPath)) {
18815
19128
  out.line();
18816
19129
  out.line(" Compatibility SSH deploy public key:");
18817
19130
  out.line();
@@ -18855,7 +19168,6 @@ async function bootstrapSecret(question) {
18855
19168
  throw new Error(`${question} was not provided`);
18856
19169
  return value;
18857
19170
  }
18858
- var PLATFORM_CLUSTER_CREDENTIAL = "forgezero-platform-cluster-bootstrap-code";
18859
19171
  function readPlatformLaunchEnvironment(path) {
18860
19172
  const absolute2 = resolve12(path);
18861
19173
  const stat2 = lstatSync10(absolute2);
@@ -18915,37 +19227,6 @@ function readPlatformLaunchEnvironment(path) {
18915
19227
  cloudflareApiToken: requiredValue("CF_API_TOKEN")
18916
19228
  };
18917
19229
  }
18918
- async function platformLaunchClusterBootstrapCode(outputDirectory) {
18919
- const path = join13(dirname14(outputDirectory), `${PLATFORM_CLUSTER_CREDENTIAL}.cred`);
18920
- if (existsSync12(path)) {
18921
- const stat2 = lstatSync10(path);
18922
- if (!stat2.isFile() || stat2.isSymbolicLink() || stat2.nlink !== 1 || typeof process.getuid === "function" && stat2.uid !== process.getuid() || (stat2.mode & 63) !== 0) {
18923
- throw new Error(`platform cluster credential must be one owner-only regular file: ${path}`);
18924
- }
18925
- const child2 = Bun.spawn(["systemd-creds", "decrypt", `--name=${PLATFORM_CLUSTER_CREDENTIAL}`, path, "-"], { stdin: "ignore", stdout: "pipe", stderr: "pipe" });
18926
- const [stdout, stderr2, exitCode2] = await Promise.all([
18927
- new Response(child2.stdout).text(),
18928
- new Response(child2.stderr).text(),
18929
- child2.exited
18930
- ]);
18931
- if (exitCode2 !== 0)
18932
- throw new Error(`cannot open the retained platform cluster credential: ${stderr2.trim()}`);
18933
- const value2 = stdout.trim();
18934
- if (!/^[a-f0-9]{64}$/i.test(value2))
18935
- throw new Error("retained platform cluster credential is invalid");
18936
- return value2;
18937
- }
18938
- mkdirSync13(dirname14(path), { recursive: true, mode: 448 });
18939
- const value = randomBytes10(32).toString("hex");
18940
- const child = Bun.spawn(["systemd-creds", "encrypt", `--name=${PLATFORM_CLUSTER_CREDENTIAL}`, "-", path], { stdin: "pipe", stdout: "pipe", stderr: "pipe" });
18941
- await writeAndCloseProcessInput(child.stdin, `${value}
18942
- `);
18943
- const [stderr, exitCode] = await Promise.all([new Response(child.stderr).text(), child.exited]);
18944
- if (exitCode !== 0)
18945
- throw new Error(`cannot retain the platform cluster credential: ${stderr.trim()}`);
18946
- chmodSync7(path, 384);
18947
- return value;
18948
- }
18949
19230
  async function promptPlatformBootstrapSecrets(config, generatedClusterBootstrapCode) {
18950
19231
  return validatePlatformBootstrapSecrets(config, {
18951
19232
  clusterBootstrapCode: generatedClusterBootstrapCode ?? await bootstrapSecret("Shared 64-hex cluster bootstrap code"),
@@ -19082,7 +19363,7 @@ async function interactiveCloudflareBootstrap() {
19082
19363
  function genesisOutputDirectory(path) {
19083
19364
  if (!isAbsolute7(path) || resolve12(path) !== path)
19084
19365
  throw new Error("--output must be a canonical absolute directory");
19085
- if (!existsSync12(path))
19366
+ if (!existsSync13(path))
19086
19367
  mkdirSync13(path, { recursive: true, mode: 448 });
19087
19368
  const metadata = lstatSync10(path);
19088
19369
  const uid = process.getuid?.();
@@ -19260,14 +19541,14 @@ async function prepareForgeZeroPlatformLaunch(environment, outputDirectory, proj
19260
19541
  [metalRequestFile, "reviewed Metal request"],
19261
19542
  [guestHostKeysFile, "pinned genesis guest host-key evidence"]
19262
19543
  ]) {
19263
- if (!existsSync12(path))
19544
+ if (!existsSync13(path))
19264
19545
  throw new Error(`${label} is missing at ${path}`);
19265
19546
  }
19266
19547
  const root = resolve12(projectRoot);
19267
19548
  const nestedApi = join13(root, "api");
19268
- const repositoryRoot = existsSync12(join13(nestedApi, "package.json")) ? nestedApi : root;
19549
+ const repositoryRoot = existsSync13(join13(nestedApi, "package.json")) ? nestedApi : root;
19269
19550
  const bundlePath = join13(base, "api.bundle");
19270
- const bundle = existsSync12(bundlePath) || existsSync12(`${bundlePath}.json`) ? await readBootstrapBundle(bundlePath) : await buildBootstrapBundle({ repositoryRoot, outputPath: bundlePath, branch: profile.branch });
19551
+ const bundle = existsSync13(bundlePath) || existsSync13(`${bundlePath}.json`) ? await readBootstrapBundle(bundlePath) : await buildBootstrapBundle({ repositoryRoot, outputPath: bundlePath, branch: profile.branch });
19271
19552
  if (bundle.manifest.branch !== profile.branch) {
19272
19553
  throw new Error(`existing bootstrap bundle is for ${bundle.manifest.branch}, expected ${profile.branch}`);
19273
19554
  }
@@ -19476,14 +19757,17 @@ async function cmdBootstrap(options, args) {
19476
19757
  if (environment === "production" && options.bootstrapSecretsEnvFile) {
19477
19758
  throw new Error("production platform launch requires interactive hidden secret prompts");
19478
19759
  }
19479
- const outputDirectory = options.outputPath ?? `/secure/forgezero/${environment}/genesis`;
19760
+ const outputDirectory = options.outputPath ?? join13(homedir2(), ".forgezero-secure", environment, "genesis");
19480
19761
  const environmentInput = options.bootstrapSecretsEnvFile ? readPlatformLaunchEnvironment(options.bootstrapSecretsEnvFile) : undefined;
19481
- const generated = await prepareForgeZeroPlatformLaunch(environment, outputDirectory, options.projectRoot, environmentInput?.owner);
19482
- const fleet = readOperatorPlatformBootstrapFleetRequest(generated.fleetRequest);
19762
+ const existingFleetPath = join13(outputDirectory, "platform-fleet-remote.json");
19763
+ const fleet = existsSync13(existingFleetPath) ? readOperatorPlatformBootstrapFleetRequest(existingFleetPath) : readOperatorPlatformBootstrapFleetRequest((await prepareForgeZeroPlatformLaunch(environment, outputDirectory, options.projectRoot, environmentInput?.owner)).fleetRequest);
19764
+ if (planOperatorPlatformFleetBootstrap(fleet, "apply").environment !== environment) {
19765
+ throw new Error("existing platform fleet does not match the selected launch profile");
19766
+ }
19483
19767
  if (options.apply && !environmentInput && bootstrapAnswer("Type APPLY to run the reviewed Cloudflare and three-compute plan") !== "APPLY") {
19484
19768
  throw new Error("attended platform bootstrap was not confirmed");
19485
19769
  }
19486
- return await runAttendedPlatformFleet(fleet, options.apply, options.apply ? await platformLaunchClusterBootstrapCode(outputDirectory) : undefined, environmentInput);
19770
+ return await runAttendedPlatformFleet(fleet, options.apply, options.apply ? await operatorMetalClusterBootstrapCode(readOperatorMetalBootstrapRequest(join13(dirname14(outputDirectory), "metal", "metal-remote.json"), { validateMetalConfig: false })) : undefined, environmentInput);
19487
19771
  }
19488
19772
  if (operation === "platform" && args[1] === "fleet") {
19489
19773
  const mode = args[2];
@@ -19606,8 +19890,8 @@ async function cmdBootstrap(options, args) {
19606
19890
  if (credentialStdin && args[2] !== undefined)
19607
19891
  throw new Error("platform credential stdin accepts no additional positional arguments");
19608
19892
  const installedBootstrapKind = () => resolveInstalledBootstrapKind({
19609
- metal: existsSync12(METAL_BOOTSTRAP_STATE_PATH),
19610
- compute: existsSync12(BOOTSTRAP_STATE_PATH)
19893
+ metal: existsSync13(METAL_BOOTSTRAP_STATE_PATH),
19894
+ compute: existsSync13(BOOTSTRAP_STATE_PATH)
19611
19895
  });
19612
19896
  if (operation === "status") {
19613
19897
  if (installedBootstrapKind() === "metal") {
@@ -19978,7 +20262,7 @@ function projectFromCheckout(options) {
19978
20262
  try {
19979
20263
  return loadConfig({
19980
20264
  cwd: options.projectRoot,
19981
- readFile: (path) => existsSync12(path) ? readFileSync16(path, "utf8") : undefined
20265
+ readFile: (path) => existsSync13(path) ? readFileSync16(path, "utf8") : undefined
19982
20266
  }).config.project;
19983
20267
  } catch (cause) {
19984
20268
  throw new Error(`No --project was given and the checkout has no usable .fz/config.json: ${cause instanceof Error ? cause.message : String(cause)}`);
@@ -20100,7 +20384,7 @@ async function cmdDeploy(options, args) {
20100
20384
  return problems.length === 0 ? 0 : 1;
20101
20385
  }
20102
20386
  if (operation === "check" || operation === "sync") {
20103
- if (existsSync12(resolve12(options.projectRoot, DEPLOY_SOURCE_FILE))) {
20387
+ if (existsSync13(resolve12(options.projectRoot, DEPLOY_SOURCE_FILE))) {
20104
20388
  const expected = await compileDeploymentProject(options.projectRoot, { write: false });
20105
20389
  const actual = inspectCompiledDeployment(options.projectRoot);
20106
20390
  const current2 = canonicalJson(expected.plan) === canonicalJson(actual.plan);