@forgezero/agent 0.1.135 → 0.1.136

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-agent.js CHANGED
@@ -2,8 +2,8 @@
2
2
  // @bun
3
3
 
4
4
  // src/index.ts
5
- import { randomBytes as randomBytes7 } from "crypto";
6
- import { readFileSync as readFileSync20, writeFileSync as writeFileSync18, existsSync as existsSync23, mkdirSync as mkdirSync18, chmodSync as chmodSync19, lstatSync as lstatSync10, statfsSync as statfsSync3 } from "fs";
5
+ import { randomBytes as randomBytes8 } from "crypto";
6
+ import { readFileSync as readFileSync20, writeFileSync as writeFileSync18, existsSync as existsSync23, mkdirSync as mkdirSync18, chmodSync as chmodSync20, lstatSync as lstatSync10, statfsSync as statfsSync3 } from "fs";
7
7
  import { cpus as cpus3, totalmem as totalmem3 } from "os";
8
8
  import { dirname as dirname16, join as join12 } from "path";
9
9
 
@@ -7218,11 +7218,13 @@ function compileDeployment(sourceValue) {
7218
7218
  if (provisioning.metalHostname !== undefined && !/^(?=.{1,253}$)[A-Za-z0-9](?:[A-Za-z0-9.-]*[A-Za-z0-9])?$/.test(String(provisioning.metalHostname)))
7219
7219
  fail(`deployment.spec.targets.${targetName}.provisioning.metalHostname`, "is invalid.");
7220
7220
  const provisionedResources = object(provisioning.resources, `deployment.spec.targets.${targetName}.provisioning.resources`);
7221
- exact3(provisionedResources, ["physicalCores", "vcpu", "memoryGib", "diskGib", "egressGuaranteedMbps", "egressBurstMbps", "confidential"], `deployment.spec.targets.${targetName}.provisioning.resources`);
7221
+ exact3(provisionedResources, ["physicalCores", "vcpu", "memoryGib", "diskGib", "diskEncryption", "egressGuaranteedMbps", "egressBurstMbps", "confidential"], `deployment.spec.targets.${targetName}.provisioning.resources`);
7222
7222
  integer(provisionedResources.physicalCores, `deployment.spec.targets.${targetName}.provisioning.resources.physicalCores`, 1, 1024);
7223
7223
  integer(provisionedResources.vcpu, `deployment.spec.targets.${targetName}.provisioning.resources.vcpu`, 1, 4096);
7224
7224
  integer(provisionedResources.memoryGib, `deployment.spec.targets.${targetName}.provisioning.resources.memoryGib`, 1, 4194304);
7225
7225
  integer(provisionedResources.diskGib, `deployment.spec.targets.${targetName}.provisioning.resources.diskGib`, 1, 1048576);
7226
+ if (provisionedResources.diskEncryption !== undefined && !["none", "luks2"].includes(String(provisionedResources.diskEncryption)))
7227
+ fail(`deployment.spec.targets.${targetName}.provisioning.resources.diskEncryption`, "must be none or luks2.");
7226
7228
  integer(provisionedResources.egressGuaranteedMbps, `deployment.spec.targets.${targetName}.provisioning.resources.egressGuaranteedMbps`, 0, 1e7);
7227
7229
  integer(provisionedResources.egressBurstMbps, `deployment.spec.targets.${targetName}.provisioning.resources.egressBurstMbps`, Number(provisionedResources.egressGuaranteedMbps), 1e7);
7228
7230
  if (typeof provisionedResources.confidential !== "boolean")
@@ -9681,7 +9683,7 @@ async function writeAndCloseProcessInput(input, value) {
9681
9683
  }
9682
9684
 
9683
9685
  // src/version.ts
9684
- var VERSION2 = "0.1.135";
9686
+ var VERSION2 = "0.1.136";
9685
9687
 
9686
9688
  // src/ssh-bootstrap.ts
9687
9689
  function deriveMetalAdmissionProvisioning(lscpu) {
@@ -10491,12 +10493,13 @@ function startMetalAdmissionPull(options) {
10491
10493
  }
10492
10494
 
10493
10495
  // src/metal-helper-socket.ts
10494
- import { chmodSync as chmodSync8, existsSync as existsSync8, unlinkSync as unlinkSync6 } from "fs";
10496
+ import { chmodSync as chmodSync9, existsSync as existsSync8, unlinkSync as unlinkSync6 } from "fs";
10495
10497
  import { connect as connect2, createServer as createServer3 } from "net";
10496
10498
 
10497
10499
  // src/metal-provision.ts
10498
- import { createHash as createHash7 } from "crypto";
10500
+ import { createHash as createHash7, randomBytes as randomBytes6 } from "crypto";
10499
10501
  import {
10502
+ chmodSync as chmodSync8,
10500
10503
  existsSync as existsSync7,
10501
10504
  mkdirSync as mkdirSync5,
10502
10505
  readFileSync as readFileSync6,
@@ -10560,6 +10563,10 @@ function guestUnit(spec) {
10560
10563
  `ExecStopPost=-/usr/sbin/ip link del ${spec.tap}`
10561
10564
  ].join(`
10562
10565
  `) : "";
10566
+ const encryptedDisk = spec.diskEncryption ? `LoadCredentialEncrypted=${spec.diskEncryption.credentialName}:${spec.diskEncryption.credentialPath}
10567
+ ExecStartPre=/usr/sbin/cryptsetup open --type luks2 --key-file %d/${spec.diskEncryption.credentialName} ${spec.diskEncryption.source} ${spec.diskEncryption.mapper}
10568
+ ExecStopPost=-/usr/sbin/cryptsetup close ${spec.diskEncryption.mapper}
10569
+ ` : "";
10563
10570
  return `[Unit]
10564
10571
  Description=ForgeZero guest ${spec.name}
10565
10572
  Documentation=https://www.forgezero.net
@@ -10569,7 +10576,7 @@ Wants=network-online.target
10569
10576
  [Service]
10570
10577
  Type=simple
10571
10578
  Slice=forgezero-guests.slice
10572
- ${tapSetup}
10579
+ ${encryptedDisk}${tapSetup}
10573
10580
  ExecStart=${argv2}
10574
10581
  Restart=always
10575
10582
  RestartSec=5
@@ -10860,6 +10867,8 @@ function guestBootstrapOperations(profile, attested = Boolean(profile.confidenti
10860
10867
  validateMetalProfile(profile);
10861
10868
  const agentBun = "/usr/local/lib/forgezero/bun";
10862
10869
  return [
10870
+ ["/usr/sbin/swapoff", "--all"],
10871
+ ["/usr/bin/systemctl", "mask", "--now", "swap.target"],
10863
10872
  ...attested ? [
10864
10873
  ["/usr/sbin/modprobe", "sev-guest"],
10865
10874
  ["/usr/bin/test", "-c", "/dev/sev-guest"]
@@ -10936,6 +10945,7 @@ ${access.sshPublicKeys.map((key) => ` - ${JSON.stringify(key)}`).join(`
10936
10945
  return {
10937
10946
  userData: `#cloud-config
10938
10947
  package_update: true
10948
+ swap: { size: 0 }
10939
10949
  ${users}disable_root: true
10940
10950
  # Git is part of the deployment transport, not a tenant-selected prerequisite:
10941
10951
  # every dynamically claimed repository must be cloneable on a clean image.
@@ -10968,7 +10978,8 @@ var checked2 = async (exec, argv2) => {
10968
10978
  async function provisionMetalGuest(profile, claim, exec) {
10969
10979
  validateMetalProfile(profile);
10970
10980
  assertSupportedGuestImage(claim.spec.imageKey, claim.spec.confidential);
10971
- if (!claim.computeKey || !claim.spec.reference || !SAFE_NAME.test(claim.spec.imageKey) || claim.spec.guestName !== undefined && !SAFE_NAME.test(claim.spec.guestName) || claim.spec.cpuPoolKey !== undefined && !SAFE_NAME.test(claim.spec.cpuPoolKey) || !Number.isInteger(claim.spec.physicalCores) || claim.spec.physicalCores < 1 || claim.spec.physicalCores > 256 || !Number.isInteger(claim.spec.vcpu) || claim.spec.vcpu < 1 || claim.spec.vcpu > 512 || !Number.isInteger(claim.spec.memoryGib) || claim.spec.memoryGib < 1 || claim.spec.memoryGib > 8192 || !Number.isInteger(claim.spec.diskGib) || claim.spec.diskGib < 8 || claim.spec.diskGib > 65536 || !Number.isInteger(claim.spec.egressGuaranteedMbps) || claim.spec.egressGuaranteedMbps < 0 || !Number.isInteger(claim.spec.egressBurstMbps) || claim.spec.egressBurstMbps < claim.spec.egressGuaranteedMbps)
10981
+ const diskEncryption = claim.spec.diskEncryption ?? "none";
10982
+ if (!claim.computeKey || !claim.spec.reference || !SAFE_NAME.test(claim.spec.imageKey) || claim.spec.guestName !== undefined && !SAFE_NAME.test(claim.spec.guestName) || claim.spec.cpuPoolKey !== undefined && !SAFE_NAME.test(claim.spec.cpuPoolKey) || !Number.isInteger(claim.spec.physicalCores) || claim.spec.physicalCores < 1 || claim.spec.physicalCores > 256 || !Number.isInteger(claim.spec.vcpu) || claim.spec.vcpu < 1 || claim.spec.vcpu > 512 || !Number.isInteger(claim.spec.memoryGib) || claim.spec.memoryGib < 1 || claim.spec.memoryGib > 8192 || !Number.isInteger(claim.spec.diskGib) || claim.spec.diskGib < 8 || claim.spec.diskGib > 65536 || !["none", "luks2"].includes(diskEncryption) || !Number.isInteger(claim.spec.egressGuaranteedMbps) || claim.spec.egressGuaranteedMbps < 0 || !Number.isInteger(claim.spec.egressBurstMbps) || claim.spec.egressBurstMbps < claim.spec.egressGuaranteedMbps)
10972
10983
  throw new MetalProvisionError("invalid compute claim");
10973
10984
  const image = profile.images[claim.spec.imageKey];
10974
10985
  if (!image || !isAbsolute3(image.path) || !SHA256.test(image.sha256)) {
@@ -10997,6 +11008,9 @@ async function provisionMetalGuest(profile, claim, exec) {
10997
11008
  const prior = manifests.find((row2) => row2.computeKey === claim.computeKey);
10998
11009
  if (prior && prior.reference !== claim.spec.reference)
10999
11010
  throw new MetalProvisionError("compute identity conflicts with host inventory");
11011
+ if (prior && (prior.diskEncryption ?? "none") !== diskEncryption) {
11012
+ throw new MetalProvisionError("an allocated guest disk encryption mode is immutable");
11013
+ }
11000
11014
  const address = requestedAddress(profile, claim, manifests);
11001
11015
  const cpuPool = allocateCpuPool(profile, claim, manifests);
11002
11016
  const manifest = prior ?? {
@@ -11008,6 +11022,7 @@ async function provisionMetalGuest(profile, claim, exec) {
11008
11022
  cpuPoolKey: cpuPool.key,
11009
11023
  allowedCpus: cpuPool.cpus,
11010
11024
  allowedMemoryNodes: cpuPool.memoryNodes,
11025
+ diskEncryption,
11011
11026
  phase: "allocating"
11012
11027
  };
11013
11028
  const save = () => writeFileSync6(manifestPath, `${JSON.stringify(manifest, null, 2)}
@@ -11017,8 +11032,70 @@ async function provisionMetalGuest(profile, claim, exec) {
11017
11032
  const exists = (await exec(["lvs", "--noheadings", lv])).exitCode === 0;
11018
11033
  if (!exists)
11019
11034
  await checked2(exec, ["lvcreate", "-y", "-n", name, "-L", `${claim.spec.diskGib}G`, profile.volumeGroup]);
11035
+ const encrypted = diskEncryption === "luks2";
11036
+ const mapper = `fz-${createHash7("sha256").update(claim.computeKey).digest("hex").slice(0, 20)}`;
11037
+ const mappedDisk = `/dev/mapper/${mapper}`;
11038
+ const credentialName = `guest-disk-${createHash7("sha256").update(claim.computeKey).digest("hex").slice(0, 20)}`;
11039
+ const credentialPath = `/etc/forgezero/creds/${credentialName}.cred`;
11040
+ const keyPath = `/run/forgezero/${credentialName}.key`;
11041
+ let imageTarget = lv;
11042
+ if (encrypted) {
11043
+ mkdirSync5(dirname5(credentialPath), { recursive: true, mode: 448 });
11044
+ mkdirSync5(dirname5(keyPath), { recursive: true, mode: 448 });
11045
+ if (existsSync7(keyPath))
11046
+ unlinkSync5(keyPath);
11047
+ if (!existsSync7(credentialPath)) {
11048
+ if (exists && (await exec(["cryptsetup", "isLuks", lv])).exitCode === 0) {
11049
+ throw new MetalProvisionError("encrypted guest disk exists without its sealed unlock credential");
11050
+ }
11051
+ writeFileSync6(keyPath, randomBytes6(64), { mode: 384, flag: "wx" });
11052
+ try {
11053
+ await checked2(exec, ["systemd-creds", "encrypt", `--name=${credentialName}`, keyPath, credentialPath]);
11054
+ chmodSync8(credentialPath, 384);
11055
+ } catch (cause) {
11056
+ if (existsSync7(credentialPath))
11057
+ unlinkSync5(credentialPath);
11058
+ throw cause;
11059
+ }
11060
+ } else {
11061
+ await checked2(exec, ["systemd-creds", "decrypt", `--name=${credentialName}`, credentialPath, keyPath]);
11062
+ }
11063
+ try {
11064
+ if ((await exec(["cryptsetup", "isLuks", lv])).exitCode !== 0) {
11065
+ await checked2(exec, [
11066
+ "cryptsetup",
11067
+ "luksFormat",
11068
+ "--batch-mode",
11069
+ "--type",
11070
+ "luks2",
11071
+ "--cipher",
11072
+ "aes-xts-plain64",
11073
+ "--key-size",
11074
+ "512",
11075
+ "--key-file",
11076
+ keyPath,
11077
+ lv
11078
+ ]);
11079
+ }
11080
+ if ((await exec(["cryptsetup", "status", mapper])).exitCode !== 0) {
11081
+ await checked2(exec, ["cryptsetup", "open", "--type", "luks2", "--key-file", keyPath, lv, mapper]);
11082
+ }
11083
+ imageTarget = mappedDisk;
11084
+ if (manifest.phase === "allocating") {
11085
+ await checked2(exec, ["qemu-img", "convert", "-O", "raw", image.path, imageTarget]);
11086
+ manifest.phase = "image-ready";
11087
+ save();
11088
+ }
11089
+ } finally {
11090
+ if (existsSync7(keyPath))
11091
+ unlinkSync5(keyPath);
11092
+ if ((await exec(["cryptsetup", "status", mapper])).exitCode === 0) {
11093
+ await checked2(exec, ["cryptsetup", "close", mapper]);
11094
+ }
11095
+ }
11096
+ }
11020
11097
  if (manifest.phase === "allocating") {
11021
- await checked2(exec, ["qemu-img", "convert", "-O", "raw", image.path, lv]);
11098
+ await checked2(exec, ["qemu-img", "convert", "-O", "raw", image.path, imageTarget]);
11022
11099
  manifest.phase = "image-ready";
11023
11100
  save();
11024
11101
  }
@@ -11042,7 +11119,8 @@ async function provisionMetalGuest(profile, claim, exec) {
11042
11119
  memoryGib: claim.spec.memoryGib,
11043
11120
  allowedCpus: manifest.allowedCpus,
11044
11121
  allowedMemoryNodes: manifest.allowedMemoryNodes,
11045
- disk: lv,
11122
+ disk: encrypted ? mappedDisk : lv,
11123
+ ...encrypted ? { diskEncryption: { source: lv, mapper, credentialName, credentialPath } } : {},
11046
11124
  seed,
11047
11125
  bridge: profile.bridge,
11048
11126
  mac: manifest.mac,
@@ -11100,6 +11178,7 @@ function legacyPlatformManifest(profile, claim, name) {
11100
11178
  cpuPoolKey: claim.spec.cpuPoolKey ?? "",
11101
11179
  allowedCpus: values.get("CPUSET") ?? "",
11102
11180
  allowedMemoryNodes: values.get("NUMA"),
11181
+ diskEncryption: "none",
11103
11182
  phase: "running",
11104
11183
  disk,
11105
11184
  unit: `forgezero-guest@${name}.service`
@@ -11114,6 +11193,9 @@ async function removeMetalGuest(profile, claim, exec) {
11114
11193
  const service = `forgezero-guest@${name}.service`;
11115
11194
  const unitPath = join4(profile.unitDir, service);
11116
11195
  const lv = `/dev/${profile.volumeGroup}/${name}`;
11196
+ const mapper = `fz-${createHash7("sha256").update(claim.computeKey).digest("hex").slice(0, 20)}`;
11197
+ const credentialName = `guest-disk-${createHash7("sha256").update(claim.computeKey).digest("hex").slice(0, 20)}`;
11198
+ const credentialPath = `/etc/forgezero/creds/${credentialName}.cred`;
11117
11199
  const manifest = existsSync7(manifestPath) ? JSON.parse(readFileSync6(manifestPath, "utf8")) : legacyPlatformManifest(profile, claim, name);
11118
11200
  if (!manifest) {
11119
11201
  const seedBase = join4(profile.seedDir, name);
@@ -11148,9 +11230,14 @@ async function removeMetalGuest(profile, claim, exec) {
11148
11230
  else if ((await exec(["systemctl", "is-active", service])).exitCode === 0) {
11149
11231
  throw new MetalProvisionError("guest unit is active but its owned unit file is missing");
11150
11232
  }
11233
+ const encrypted = (manifest.diskEncryption ?? "none") === "luks2";
11234
+ if (encrypted && (await exec(["cryptsetup", "status", mapper])).exitCode === 0) {
11235
+ throw new MetalProvisionError("guest disk mapping remained active after the guest stopped");
11236
+ }
11151
11237
  if ((await exec(["lvs", "--noheadings", lv])).exitCode === 0)
11152
11238
  await checked2(exec, ["lvremove", "-fy", lv]);
11153
11239
  for (const path2 of [
11240
+ ...encrypted ? [credentialPath] : [],
11154
11241
  unitPath,
11155
11242
  join4(profile.seedDir, `${name}-seed.iso`),
11156
11243
  join4(profile.seedDir, `${name}-user-data`),
@@ -11251,7 +11338,7 @@ function startMetalHelper(options) {
11251
11338
  });
11252
11339
  socket.on("error", () => socket.destroy());
11253
11340
  });
11254
- server.listen(socketPath, () => chmodSync8(socketPath, 432));
11341
+ server.listen(socketPath, () => chmodSync9(socketPath, 432));
11255
11342
  return {
11256
11343
  server,
11257
11344
  async stop() {
@@ -11291,7 +11378,7 @@ function requestMetalProvision(claim, socketPath = DEFAULT_METAL_HELPER_SOCKET)
11291
11378
  }
11292
11379
 
11293
11380
  // src/deployment-runner.ts
11294
- import { chmodSync as chmodSync9, existsSync as existsSync9, realpathSync, unlinkSync as unlinkSync7 } from "fs";
11381
+ import { chmodSync as chmodSync10, existsSync as existsSync9, realpathSync, unlinkSync as unlinkSync7 } from "fs";
11295
11382
  import { isAbsolute as isAbsolute4, resolve, sep } from "path";
11296
11383
  import { connect as connect3, createServer as createServer4 } from "net";
11297
11384
  var DEFAULT_DEPLOYMENT_RUNNER_SOCKET = "/run/forgezero-deploy/runner.sock";
@@ -11453,7 +11540,7 @@ function startDeploymentRunner(options) {
11453
11540
  const ready = new Promise((resolveReady, rejectReady) => {
11454
11541
  server.once("error", rejectReady);
11455
11542
  server.listen(socketPath, () => {
11456
- chmodSync9(socketPath, options.socketMode ?? 432);
11543
+ chmodSync10(socketPath, options.socketMode ?? 432);
11457
11544
  server.off("error", rejectReady);
11458
11545
  resolveReady();
11459
11546
  });
@@ -11805,7 +11892,7 @@ async function closeServerWithin(server, timeoutMs) {
11805
11892
  }
11806
11893
 
11807
11894
  // src/lifecycle-helper.ts
11808
- import { chmodSync as chmodSync10, existsSync as existsSync11, readFileSync as readFileSync7, unlinkSync as unlinkSync8 } from "fs";
11895
+ import { chmodSync as chmodSync11, existsSync as existsSync11, readFileSync as readFileSync7, unlinkSync as unlinkSync8 } from "fs";
11809
11896
  import { connect as connect4, createConnection, createServer as createServer5, isIP as isIP3 } from "net";
11810
11897
  var DEFAULT_LIFECYCLE_HELPER_SOCKET = "/run/forgezero-lifecycle/helper.sock";
11811
11898
  var MAX_REQUEST_BYTES4 = 16 * 1024;
@@ -11987,7 +12074,7 @@ function startLifecycleHelper(options) {
11987
12074
  });
11988
12075
  socket.on("error", () => socket.destroy());
11989
12076
  });
11990
- server.listen(socketPath, () => chmodSync10(socketPath, 432));
12077
+ server.listen(socketPath, () => chmodSync11(socketPath, 432));
11991
12078
  return {
11992
12079
  server,
11993
12080
  async stop() {
@@ -12027,7 +12114,7 @@ function requestLifecycleAction(claim, socketPath = DEFAULT_LIFECYCLE_HELPER_SOC
12027
12114
  }
12028
12115
 
12029
12116
  // src/warp-config.ts
12030
- import { chmodSync as chmodSync11, mkdirSync as mkdirSync7, renameSync as renameSync6, symlinkSync as symlinkSync3, unlinkSync as unlinkSync9, writeFileSync as writeFileSync8 } from "fs";
12117
+ import { chmodSync as chmodSync12, mkdirSync as mkdirSync7, renameSync as renameSync6, symlinkSync as symlinkSync3, unlinkSync as unlinkSync9, writeFileSync as writeFileSync8 } from "fs";
12031
12118
  var xml = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&apos;");
12032
12119
  function renderWarpMdm(options) {
12033
12120
  if (!/^[a-z0-9][a-z0-9-]{0,62}$/i.test(options.organization))
@@ -12052,7 +12139,7 @@ function materializeWarpMdm(options) {
12052
12139
  mkdirSync7(servicePath.replace(/\/[^/]+$/, ""), { recursive: true, mode: 448 });
12053
12140
  const next = `${runtimePath}.next`;
12054
12141
  writeFileSync8(next, renderWarpMdm(options), { mode: 384 });
12055
- chmodSync11(next, 384);
12142
+ chmodSync12(next, 384);
12056
12143
  renameSync6(next, runtimePath);
12057
12144
  try {
12058
12145
  unlinkSync9(servicePath);
@@ -12110,7 +12197,7 @@ async function configureMeshConnector(input) {
12110
12197
  // src/agent-update.ts
12111
12198
  import { createHash as createHash8, timingSafeEqual, randomUUID as randomUUID2 } from "crypto";
12112
12199
  import {
12113
- chmodSync as chmodSync12,
12200
+ chmodSync as chmodSync13,
12114
12201
  closeSync as closeSync2,
12115
12202
  existsSync as existsSync12,
12116
12203
  fsyncSync,
@@ -12204,8 +12291,8 @@ var checked4 = async (run2, input, label) => {
12204
12291
  return result;
12205
12292
  };
12206
12293
  async function validateReleaseDirectory(directory, release, run2) {
12207
- chmodSync12(directory, 493);
12208
- chmodSync12(join7(directory, "dist"), 493);
12294
+ chmodSync13(directory, 493);
12295
+ chmodSync13(join7(directory, "dist"), 493);
12209
12296
  const manifest = JSON.parse(readFileSync9(join7(directory, "package.json"), "utf8"));
12210
12297
  if (manifest.name !== release.package || manifest.version !== release.version) {
12211
12298
  throw new Error("agent update manifest does not match the selected release");
@@ -12218,7 +12305,7 @@ async function validateReleaseDirectory(directory, release, run2) {
12218
12305
  `)) {
12219
12306
  throw new Error("agent update artifact is not a self-contained Bun executable");
12220
12307
  }
12221
- chmodSync12(binary, 493);
12308
+ chmodSync13(binary, 493);
12222
12309
  }
12223
12310
  const version = (await checked4(run2, { command: agent, args: ["--version"] }, "agent update smoke test")).output.trim();
12224
12311
  if (version !== release.version)
@@ -12337,7 +12424,7 @@ function clearAgentCandidate(root = DEFAULT_AGENT_RELEASE_ROOT) {
12337
12424
  // src/agent-update-helper.ts
12338
12425
  import { randomUUID as randomUUID4 } from "crypto";
12339
12426
  import {
12340
- chmodSync as chmodSync14,
12427
+ chmodSync as chmodSync15,
12341
12428
  closeSync as closeSync3,
12342
12429
  existsSync as existsSync14,
12343
12430
  fsyncSync as fsyncSync2,
@@ -12354,7 +12441,7 @@ import { dirname as dirname8, join as join8, resolve as resolve3 } from "path";
12354
12441
 
12355
12442
  // src/agent-handover.ts
12356
12443
  import { randomUUID as randomUUID3 } from "crypto";
12357
- import { chmodSync as chmodSync13, existsSync as existsSync13, renameSync as renameSync8, rmSync as rmSync6, symlinkSync as symlinkSync5, unlinkSync as unlinkSync10 } from "fs";
12444
+ import { chmodSync as chmodSync14, existsSync as existsSync13, renameSync as renameSync8, rmSync as rmSync6, symlinkSync as symlinkSync5, unlinkSync as unlinkSync10 } from "fs";
12358
12445
  import { basename as basename2, dirname as dirname7 } from "path";
12359
12446
  import { connect as connect5, createServer as createServer6 } from "net";
12360
12447
  var DEFAULT_AGENT_CANDIDATE_READY_SOCKET = "/run/forgezero/candidate-ready.sock";
@@ -12375,7 +12462,7 @@ function startAgentCandidateReady(ready, socketPath = DEFAULT_AGENT_CANDIDATE_RE
12375
12462
  unlinkSync10(socketPath);
12376
12463
  const server = createServer6((socket) => socket.end(`${JSON.stringify(ready)}
12377
12464
  `));
12378
- server.listen(socketPath, () => chmodSync13(socketPath, 432));
12465
+ server.listen(socketPath, () => chmodSync14(socketPath, 432));
12379
12466
  return server;
12380
12467
  }
12381
12468
  function probeAgentCandidate(expected, socketPath = DEFAULT_AGENT_CANDIDATE_READY_SOCKET, timeoutMs = 5000) {
@@ -12928,7 +13015,7 @@ function startAgentUpdateHelper(options = {}) {
12928
13015
  });
12929
13016
  socket.on("error", () => socket.destroy());
12930
13017
  });
12931
- server.listen(socketPath, () => chmodSync14(socketPath, 432));
13018
+ server.listen(socketPath, () => chmodSync15(socketPath, 432));
12932
13019
  return server;
12933
13020
  }
12934
13021
  function requestAgentUpdate(request, socketPath = DEFAULT_AGENT_UPDATE_SOCKET, timeoutMs = 90000) {
@@ -13145,7 +13232,7 @@ function startAgentHeartbeat(options) {
13145
13232
  }
13146
13233
 
13147
13234
  // src/software-helper.ts
13148
- import { chmodSync as chmodSync15, existsSync as existsSync18, mkdirSync as mkdirSync13, unlinkSync as unlinkSync12 } from "fs";
13235
+ import { chmodSync as chmodSync16, existsSync as existsSync18, mkdirSync as mkdirSync13, unlinkSync as unlinkSync12 } from "fs";
13149
13236
  import { connect as connect7, createServer as createServer8 } from "net";
13150
13237
  import { dirname as dirname12 } from "path";
13151
13238
 
@@ -14133,7 +14220,7 @@ function startSoftwareHelper(options = {}) {
14133
14220
  });
14134
14221
  socket.on("error", () => socket.destroy());
14135
14222
  });
14136
- server.listen(socketPath, () => chmodSync15(socketPath, 432));
14223
+ server.listen(socketPath, () => chmodSync16(socketPath, 432));
14137
14224
  return server;
14138
14225
  }
14139
14226
  function requestContainer(op, request, socketPath, timeoutMs) {
@@ -15218,7 +15305,7 @@ var METAL_SYSTEMD_CREDENTIALS = {
15218
15305
 
15219
15306
  // src/platform-bootstrap-runtime.ts
15220
15307
  import {
15221
- chmodSync as chmodSync16,
15308
+ chmodSync as chmodSync17,
15222
15309
  chownSync,
15223
15310
  copyFileSync as copyFileSync2,
15224
15311
  existsSync as existsSync19,
@@ -15317,7 +15404,7 @@ var secureRelease = (path2, uid, gid) => {
15317
15404
  if (metadata.isSymbolicLink())
15318
15405
  return;
15319
15406
  chownSync(current2, uid, gid);
15320
- chmodSync16(current2, metadata.isDirectory() ? 365 : 292);
15407
+ chmodSync17(current2, metadata.isDirectory() ? 365 : 292);
15321
15408
  if (metadata.isDirectory())
15322
15409
  for (const name of readdirSync4(current2))
15323
15410
  visit(join10(current2, name));
@@ -15558,7 +15645,7 @@ import { lstatSync as lstatSync7 } from "fs";
15558
15645
 
15559
15646
  // src/bootstrap.ts
15560
15647
  import {
15561
- chmodSync as chmodSync18,
15648
+ chmodSync as chmodSync19,
15562
15649
  existsSync as existsSync22,
15563
15650
  lstatSync as lstatSync6,
15564
15651
  mkdirSync as mkdirSync16,
@@ -16559,9 +16646,9 @@ function planProvision(options) {
16559
16646
  }
16560
16647
 
16561
16648
  // src/cli/agent-install.ts
16562
- import { randomBytes as randomBytes6 } from "crypto";
16649
+ import { randomBytes as randomBytes7 } from "crypto";
16563
16650
  import {
16564
- chmodSync as chmodSync17,
16651
+ chmodSync as chmodSync18,
16565
16652
  copyFileSync as copyFileSync3,
16566
16653
  existsSync as existsSync21,
16567
16654
  lstatSync as lstatSync5,
@@ -16652,12 +16739,12 @@ var runProvisionOperation = async (operation) => {
16652
16739
  mkdirSync15(`${release}/dist`, { recursive: true, mode: 493 });
16653
16740
  mkdirSync15(dirname13(operation.binary), { recursive: true, mode: 493 });
16654
16741
  copyFileSync3(operation.source, `${release}/dist/fz-agent.js`);
16655
- chmodSync17(`${release}/dist/fz-agent.js`, 493);
16742
+ chmodSync18(`${release}/dist/fz-agent.js`, 493);
16656
16743
  const gitSshSource = `${dirname13(operation.source)}/fz-git-ssh.js`;
16657
16744
  if (!existsSync21(gitSshSource))
16658
16745
  return { stdout: "packaged fz-git-ssh.js is missing", exitCode: 1 };
16659
16746
  copyFileSync3(gitSshSource, `${release}/dist/fz-git-ssh.js`);
16660
- chmodSync17(`${release}/dist/fz-git-ssh.js`, 493);
16747
+ chmodSync18(`${release}/dist/fz-git-ssh.js`, 493);
16661
16748
  const pending = "/opt/forgezero/agent/current.next";
16662
16749
  rmSync11(pending, { force: true });
16663
16750
  symlinkSync7(`versions/${operation.version}`, pending);
@@ -16672,10 +16759,10 @@ var runProvisionOperation = async (operation) => {
16672
16759
  if (operation.kind === "ensure-seed") {
16673
16760
  if (existsSync21(operation.credential) && lstatSync5(operation.credential).size > 0)
16674
16761
  return { stdout: "", exitCode: 0 };
16675
- const seed = randomBytes6(32).toString("base64url");
16762
+ const seed = randomBytes7(32).toString("base64url");
16676
16763
  const result = await fixed(["/usr/bin/systemd-creds", "encrypt", "--name=agent-seed", "-", operation.credential], seed);
16677
16764
  if (result.exitCode === 0)
16678
- chmodSync17(operation.credential, 256);
16765
+ chmodSync18(operation.credential, 256);
16679
16766
  return result;
16680
16767
  }
16681
16768
  if (operation.kind === "ensure-git-identity") {
@@ -16691,7 +16778,7 @@ var runProvisionOperation = async (operation) => {
16691
16778
  result = await fixed(["/usr/bin/systemd-creds", "encrypt", "--name=git-deploy-key", key, operation.credential]);
16692
16779
  if (result.exitCode !== 0)
16693
16780
  return result;
16694
- chmodSync17(operation.credential, 256);
16781
+ chmodSync18(operation.credential, 256);
16695
16782
  }
16696
16783
  if (!existsSync21(operation.publicKey) || lstatSync5(operation.publicKey).size < 1) {
16697
16784
  if (!existsSync21(key)) {
@@ -16725,7 +16812,7 @@ var runProvisionOperation = async (operation) => {
16725
16812
  return { stdout: "bootstrap SSH private-key source is missing or unsafe", exitCode: 1 };
16726
16813
  }
16727
16814
  copyFileSync3(operation.source, key);
16728
- chmodSync17(key, 384);
16815
+ chmodSync18(key, 384);
16729
16816
  } else {
16730
16817
  result = await fixed(["/usr/bin/ssh-keygen", "-q", "-t", "ed25519", "-N", "", "-C", "forgezero-bootstrap-runner", "-f", key]);
16731
16818
  if (result.exitCode !== 0)
@@ -16738,14 +16825,14 @@ var runProvisionOperation = async (operation) => {
16738
16825
  result = await fixed(["/usr/bin/systemd-creds", "encrypt", "--name=bootstrap-ssh-key", key, operation.credential]);
16739
16826
  if (result.exitCode !== 0)
16740
16827
  return result;
16741
- chmodSync17(operation.credential, 256);
16828
+ chmodSync18(operation.credential, 256);
16742
16829
  }
16743
16830
  if (!existsSync21(operation.publicKey) || lstatSync5(operation.publicKey).size < 1) {
16744
16831
  if (!existsSync21(key)) {
16745
16832
  const decrypted = await fixed(["/usr/bin/systemd-creds", "decrypt", "--name=bootstrap-ssh-key", operation.credential, key]);
16746
16833
  if (decrypted.exitCode !== 0)
16747
16834
  return decrypted;
16748
- chmodSync17(key, 384);
16835
+ chmodSync18(key, 384);
16749
16836
  }
16750
16837
  const derived = await fixed(["/usr/bin/ssh-keygen", "-y", "-f", key]);
16751
16838
  const publicKey = normalizeEd25519PublicKey(derived.stdout);
@@ -16755,7 +16842,7 @@ var runProvisionOperation = async (operation) => {
16755
16842
  mkdirSync15(dirname13(operation.publicKey), { recursive: true, mode: 493 });
16756
16843
  writeFileSync15(operation.publicKey, `${publicKey} forgezero-bootstrap-runner
16757
16844
  `, { mode: 292 });
16758
- chmodSync17(operation.publicKey, 292);
16845
+ chmodSync18(operation.publicKey, 292);
16759
16846
  }
16760
16847
  if (operation.source)
16761
16848
  rmSync11(operation.source, { force: true });
@@ -16772,7 +16859,7 @@ var runProvisionOperation = async (operation) => {
16772
16859
  return { stdout: "enrolment source is missing", exitCode: 1 };
16773
16860
  const result = await fixed(["/usr/bin/systemd-creds", "encrypt", "--name=enrol-token", operation.source, operation.credential]);
16774
16861
  if (result.exitCode === 0) {
16775
- chmodSync17(operation.credential, 256);
16862
+ chmodSync18(operation.credential, 256);
16776
16863
  rmSync11(operation.source, { force: true });
16777
16864
  }
16778
16865
  return result;
@@ -17158,7 +17245,7 @@ function localBootstrapHost() {
17158
17245
  mkdirSync16(dirname14(path2), { recursive: true, mode: 493 });
17159
17246
  const temporary = `${path2}.next.${process.pid}`;
17160
17247
  writeFileSync16(temporary, content, { mode });
17161
- chmodSync18(temporary, mode);
17248
+ chmodSync19(temporary, mode);
17162
17249
  renameSync15(temporary, path2);
17163
17250
  },
17164
17251
  mkdir: (path2, mode) => mkdirSync16(path2, { recursive: true, mode }),
@@ -18034,9 +18121,9 @@ function loadOrCreateSeed(path2) {
18034
18121
  return seed2;
18035
18122
  }
18036
18123
  mkdirSync18(dirname16(path2), { recursive: true });
18037
- const seed = new Uint8Array(randomBytes7(32));
18124
+ const seed = new Uint8Array(randomBytes8(32));
18038
18125
  writeFileSync18(path2, Buffer.from(seed).toString("base64url"), { mode: 384 });
18039
- chmodSync19(path2, 384);
18126
+ chmodSync20(path2, 384);
18040
18127
  return seed;
18041
18128
  }
18042
18129
  var DEFAULT_SOCKET_PATH = DEFAULT_SOCKET;