@forgezero/agent 0.1.135 → 0.1.137

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.137";
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
@@ -10699,6 +10706,7 @@ var macForAddress = (address) => {
10699
10706
  }
10700
10707
  return `52:54:00:f0:${octets[2].toString(16).padStart(2, "0")}:${octets[3].toString(16).padStart(2, "0")}`;
10701
10708
  };
10709
+ var shouldCloseGuestMapper = (openedHere, active) => openedHere && active;
10702
10710
  function validateMetalProfile(profile) {
10703
10711
  if (!SAFE_NAME.test(profile.volumeGroup))
10704
10712
  throw new MetalProvisionError("invalid volume group");
@@ -10860,6 +10868,8 @@ function guestBootstrapOperations(profile, attested = Boolean(profile.confidenti
10860
10868
  validateMetalProfile(profile);
10861
10869
  const agentBun = "/usr/local/lib/forgezero/bun";
10862
10870
  return [
10871
+ ["/usr/sbin/swapoff", "--all"],
10872
+ ["/usr/bin/systemctl", "mask", "--now", "swap.target"],
10863
10873
  ...attested ? [
10864
10874
  ["/usr/sbin/modprobe", "sev-guest"],
10865
10875
  ["/usr/bin/test", "-c", "/dev/sev-guest"]
@@ -10936,6 +10946,7 @@ ${access.sshPublicKeys.map((key) => ` - ${JSON.stringify(key)}`).join(`
10936
10946
  return {
10937
10947
  userData: `#cloud-config
10938
10948
  package_update: true
10949
+ swap: { size: 0 }
10939
10950
  ${users}disable_root: true
10940
10951
  # Git is part of the deployment transport, not a tenant-selected prerequisite:
10941
10952
  # every dynamically claimed repository must be cloneable on a clean image.
@@ -10968,7 +10979,8 @@ var checked2 = async (exec, argv2) => {
10968
10979
  async function provisionMetalGuest(profile, claim, exec) {
10969
10980
  validateMetalProfile(profile);
10970
10981
  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)
10982
+ const diskEncryption = claim.spec.diskEncryption ?? "none";
10983
+ 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
10984
  throw new MetalProvisionError("invalid compute claim");
10973
10985
  const image = profile.images[claim.spec.imageKey];
10974
10986
  if (!image || !isAbsolute3(image.path) || !SHA256.test(image.sha256)) {
@@ -10997,6 +11009,9 @@ async function provisionMetalGuest(profile, claim, exec) {
10997
11009
  const prior = manifests.find((row2) => row2.computeKey === claim.computeKey);
10998
11010
  if (prior && prior.reference !== claim.spec.reference)
10999
11011
  throw new MetalProvisionError("compute identity conflicts with host inventory");
11012
+ if (prior && (prior.diskEncryption ?? "none") !== diskEncryption) {
11013
+ throw new MetalProvisionError("an allocated guest disk encryption mode is immutable");
11014
+ }
11000
11015
  const address = requestedAddress(profile, claim, manifests);
11001
11016
  const cpuPool = allocateCpuPool(profile, claim, manifests);
11002
11017
  const manifest = prior ?? {
@@ -11008,6 +11023,7 @@ async function provisionMetalGuest(profile, claim, exec) {
11008
11023
  cpuPoolKey: cpuPool.key,
11009
11024
  allowedCpus: cpuPool.cpus,
11010
11025
  allowedMemoryNodes: cpuPool.memoryNodes,
11026
+ diskEncryption,
11011
11027
  phase: "allocating"
11012
11028
  };
11013
11029
  const save = () => writeFileSync6(manifestPath, `${JSON.stringify(manifest, null, 2)}
@@ -11017,8 +11033,72 @@ async function provisionMetalGuest(profile, claim, exec) {
11017
11033
  const exists = (await exec(["lvs", "--noheadings", lv])).exitCode === 0;
11018
11034
  if (!exists)
11019
11035
  await checked2(exec, ["lvcreate", "-y", "-n", name, "-L", `${claim.spec.diskGib}G`, profile.volumeGroup]);
11036
+ const encrypted = diskEncryption === "luks2";
11037
+ const mapper = `fz-${createHash7("sha256").update(claim.computeKey).digest("hex").slice(0, 20)}`;
11038
+ const mappedDisk = `/dev/mapper/${mapper}`;
11039
+ const credentialName = `guest-disk-${createHash7("sha256").update(claim.computeKey).digest("hex").slice(0, 20)}`;
11040
+ const credentialPath = `/etc/forgezero/creds/${credentialName}.cred`;
11041
+ const keyPath = `/run/forgezero/${credentialName}.key`;
11042
+ let imageTarget = lv;
11043
+ let mapperOpenedHere = false;
11044
+ if (encrypted) {
11045
+ mkdirSync5(dirname5(credentialPath), { recursive: true, mode: 448 });
11046
+ mkdirSync5(dirname5(keyPath), { recursive: true, mode: 448 });
11047
+ if (existsSync7(keyPath))
11048
+ unlinkSync5(keyPath);
11049
+ if (!existsSync7(credentialPath)) {
11050
+ if (exists && (await exec(["cryptsetup", "isLuks", lv])).exitCode === 0) {
11051
+ throw new MetalProvisionError("encrypted guest disk exists without its sealed unlock credential");
11052
+ }
11053
+ writeFileSync6(keyPath, randomBytes6(64), { mode: 384, flag: "wx" });
11054
+ try {
11055
+ await checked2(exec, ["systemd-creds", "encrypt", `--name=${credentialName}`, keyPath, credentialPath]);
11056
+ chmodSync8(credentialPath, 384);
11057
+ } catch (cause) {
11058
+ if (existsSync7(credentialPath))
11059
+ unlinkSync5(credentialPath);
11060
+ throw cause;
11061
+ }
11062
+ } else {
11063
+ await checked2(exec, ["systemd-creds", "decrypt", `--name=${credentialName}`, credentialPath, keyPath]);
11064
+ }
11065
+ try {
11066
+ if ((await exec(["cryptsetup", "isLuks", lv])).exitCode !== 0) {
11067
+ await checked2(exec, [
11068
+ "cryptsetup",
11069
+ "luksFormat",
11070
+ "--batch-mode",
11071
+ "--type",
11072
+ "luks2",
11073
+ "--cipher",
11074
+ "aes-xts-plain64",
11075
+ "--key-size",
11076
+ "512",
11077
+ "--key-file",
11078
+ keyPath,
11079
+ lv
11080
+ ]);
11081
+ }
11082
+ if ((await exec(["cryptsetup", "status", mapper])).exitCode !== 0) {
11083
+ await checked2(exec, ["cryptsetup", "open", "--type", "luks2", "--key-file", keyPath, lv, mapper]);
11084
+ mapperOpenedHere = true;
11085
+ }
11086
+ imageTarget = mappedDisk;
11087
+ if (manifest.phase === "allocating") {
11088
+ await checked2(exec, ["qemu-img", "convert", "-O", "raw", image.path, imageTarget]);
11089
+ manifest.phase = "image-ready";
11090
+ save();
11091
+ }
11092
+ } finally {
11093
+ if (existsSync7(keyPath))
11094
+ unlinkSync5(keyPath);
11095
+ if (shouldCloseGuestMapper(mapperOpenedHere, (await exec(["cryptsetup", "status", mapper])).exitCode === 0)) {
11096
+ await checked2(exec, ["cryptsetup", "close", mapper]);
11097
+ }
11098
+ }
11099
+ }
11020
11100
  if (manifest.phase === "allocating") {
11021
- await checked2(exec, ["qemu-img", "convert", "-O", "raw", image.path, lv]);
11101
+ await checked2(exec, ["qemu-img", "convert", "-O", "raw", image.path, imageTarget]);
11022
11102
  manifest.phase = "image-ready";
11023
11103
  save();
11024
11104
  }
@@ -11042,7 +11122,8 @@ async function provisionMetalGuest(profile, claim, exec) {
11042
11122
  memoryGib: claim.spec.memoryGib,
11043
11123
  allowedCpus: manifest.allowedCpus,
11044
11124
  allowedMemoryNodes: manifest.allowedMemoryNodes,
11045
- disk: lv,
11125
+ disk: encrypted ? mappedDisk : lv,
11126
+ ...encrypted ? { diskEncryption: { source: lv, mapper, credentialName, credentialPath } } : {},
11046
11127
  seed,
11047
11128
  bridge: profile.bridge,
11048
11129
  mac: manifest.mac,
@@ -11100,6 +11181,7 @@ function legacyPlatformManifest(profile, claim, name) {
11100
11181
  cpuPoolKey: claim.spec.cpuPoolKey ?? "",
11101
11182
  allowedCpus: values.get("CPUSET") ?? "",
11102
11183
  allowedMemoryNodes: values.get("NUMA"),
11184
+ diskEncryption: "none",
11103
11185
  phase: "running",
11104
11186
  disk,
11105
11187
  unit: `forgezero-guest@${name}.service`
@@ -11114,6 +11196,9 @@ async function removeMetalGuest(profile, claim, exec) {
11114
11196
  const service = `forgezero-guest@${name}.service`;
11115
11197
  const unitPath = join4(profile.unitDir, service);
11116
11198
  const lv = `/dev/${profile.volumeGroup}/${name}`;
11199
+ const mapper = `fz-${createHash7("sha256").update(claim.computeKey).digest("hex").slice(0, 20)}`;
11200
+ const credentialName = `guest-disk-${createHash7("sha256").update(claim.computeKey).digest("hex").slice(0, 20)}`;
11201
+ const credentialPath = `/etc/forgezero/creds/${credentialName}.cred`;
11117
11202
  const manifest = existsSync7(manifestPath) ? JSON.parse(readFileSync6(manifestPath, "utf8")) : legacyPlatformManifest(profile, claim, name);
11118
11203
  if (!manifest) {
11119
11204
  const seedBase = join4(profile.seedDir, name);
@@ -11148,9 +11233,14 @@ async function removeMetalGuest(profile, claim, exec) {
11148
11233
  else if ((await exec(["systemctl", "is-active", service])).exitCode === 0) {
11149
11234
  throw new MetalProvisionError("guest unit is active but its owned unit file is missing");
11150
11235
  }
11236
+ const encrypted = (manifest.diskEncryption ?? "none") === "luks2";
11237
+ if (encrypted && (await exec(["cryptsetup", "status", mapper])).exitCode === 0) {
11238
+ throw new MetalProvisionError("guest disk mapping remained active after the guest stopped");
11239
+ }
11151
11240
  if ((await exec(["lvs", "--noheadings", lv])).exitCode === 0)
11152
11241
  await checked2(exec, ["lvremove", "-fy", lv]);
11153
11242
  for (const path2 of [
11243
+ ...encrypted ? [credentialPath] : [],
11154
11244
  unitPath,
11155
11245
  join4(profile.seedDir, `${name}-seed.iso`),
11156
11246
  join4(profile.seedDir, `${name}-user-data`),
@@ -11251,7 +11341,7 @@ function startMetalHelper(options) {
11251
11341
  });
11252
11342
  socket.on("error", () => socket.destroy());
11253
11343
  });
11254
- server.listen(socketPath, () => chmodSync8(socketPath, 432));
11344
+ server.listen(socketPath, () => chmodSync9(socketPath, 432));
11255
11345
  return {
11256
11346
  server,
11257
11347
  async stop() {
@@ -11291,7 +11381,7 @@ function requestMetalProvision(claim, socketPath = DEFAULT_METAL_HELPER_SOCKET)
11291
11381
  }
11292
11382
 
11293
11383
  // src/deployment-runner.ts
11294
- import { chmodSync as chmodSync9, existsSync as existsSync9, realpathSync, unlinkSync as unlinkSync7 } from "fs";
11384
+ import { chmodSync as chmodSync10, existsSync as existsSync9, realpathSync, unlinkSync as unlinkSync7 } from "fs";
11295
11385
  import { isAbsolute as isAbsolute4, resolve, sep } from "path";
11296
11386
  import { connect as connect3, createServer as createServer4 } from "net";
11297
11387
  var DEFAULT_DEPLOYMENT_RUNNER_SOCKET = "/run/forgezero-deploy/runner.sock";
@@ -11453,7 +11543,7 @@ function startDeploymentRunner(options) {
11453
11543
  const ready = new Promise((resolveReady, rejectReady) => {
11454
11544
  server.once("error", rejectReady);
11455
11545
  server.listen(socketPath, () => {
11456
- chmodSync9(socketPath, options.socketMode ?? 432);
11546
+ chmodSync10(socketPath, options.socketMode ?? 432);
11457
11547
  server.off("error", rejectReady);
11458
11548
  resolveReady();
11459
11549
  });
@@ -11805,7 +11895,7 @@ async function closeServerWithin(server, timeoutMs) {
11805
11895
  }
11806
11896
 
11807
11897
  // src/lifecycle-helper.ts
11808
- import { chmodSync as chmodSync10, existsSync as existsSync11, readFileSync as readFileSync7, unlinkSync as unlinkSync8 } from "fs";
11898
+ import { chmodSync as chmodSync11, existsSync as existsSync11, readFileSync as readFileSync7, unlinkSync as unlinkSync8 } from "fs";
11809
11899
  import { connect as connect4, createConnection, createServer as createServer5, isIP as isIP3 } from "net";
11810
11900
  var DEFAULT_LIFECYCLE_HELPER_SOCKET = "/run/forgezero-lifecycle/helper.sock";
11811
11901
  var MAX_REQUEST_BYTES4 = 16 * 1024;
@@ -11987,7 +12077,7 @@ function startLifecycleHelper(options) {
11987
12077
  });
11988
12078
  socket.on("error", () => socket.destroy());
11989
12079
  });
11990
- server.listen(socketPath, () => chmodSync10(socketPath, 432));
12080
+ server.listen(socketPath, () => chmodSync11(socketPath, 432));
11991
12081
  return {
11992
12082
  server,
11993
12083
  async stop() {
@@ -12027,7 +12117,7 @@ function requestLifecycleAction(claim, socketPath = DEFAULT_LIFECYCLE_HELPER_SOC
12027
12117
  }
12028
12118
 
12029
12119
  // 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";
12120
+ import { chmodSync as chmodSync12, mkdirSync as mkdirSync7, renameSync as renameSync6, symlinkSync as symlinkSync3, unlinkSync as unlinkSync9, writeFileSync as writeFileSync8 } from "fs";
12031
12121
  var xml = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&apos;");
12032
12122
  function renderWarpMdm(options) {
12033
12123
  if (!/^[a-z0-9][a-z0-9-]{0,62}$/i.test(options.organization))
@@ -12052,7 +12142,7 @@ function materializeWarpMdm(options) {
12052
12142
  mkdirSync7(servicePath.replace(/\/[^/]+$/, ""), { recursive: true, mode: 448 });
12053
12143
  const next = `${runtimePath}.next`;
12054
12144
  writeFileSync8(next, renderWarpMdm(options), { mode: 384 });
12055
- chmodSync11(next, 384);
12145
+ chmodSync12(next, 384);
12056
12146
  renameSync6(next, runtimePath);
12057
12147
  try {
12058
12148
  unlinkSync9(servicePath);
@@ -12110,7 +12200,7 @@ async function configureMeshConnector(input) {
12110
12200
  // src/agent-update.ts
12111
12201
  import { createHash as createHash8, timingSafeEqual, randomUUID as randomUUID2 } from "crypto";
12112
12202
  import {
12113
- chmodSync as chmodSync12,
12203
+ chmodSync as chmodSync13,
12114
12204
  closeSync as closeSync2,
12115
12205
  existsSync as existsSync12,
12116
12206
  fsyncSync,
@@ -12204,8 +12294,8 @@ var checked4 = async (run2, input, label) => {
12204
12294
  return result;
12205
12295
  };
12206
12296
  async function validateReleaseDirectory(directory, release, run2) {
12207
- chmodSync12(directory, 493);
12208
- chmodSync12(join7(directory, "dist"), 493);
12297
+ chmodSync13(directory, 493);
12298
+ chmodSync13(join7(directory, "dist"), 493);
12209
12299
  const manifest = JSON.parse(readFileSync9(join7(directory, "package.json"), "utf8"));
12210
12300
  if (manifest.name !== release.package || manifest.version !== release.version) {
12211
12301
  throw new Error("agent update manifest does not match the selected release");
@@ -12218,7 +12308,7 @@ async function validateReleaseDirectory(directory, release, run2) {
12218
12308
  `)) {
12219
12309
  throw new Error("agent update artifact is not a self-contained Bun executable");
12220
12310
  }
12221
- chmodSync12(binary, 493);
12311
+ chmodSync13(binary, 493);
12222
12312
  }
12223
12313
  const version = (await checked4(run2, { command: agent, args: ["--version"] }, "agent update smoke test")).output.trim();
12224
12314
  if (version !== release.version)
@@ -12337,7 +12427,7 @@ function clearAgentCandidate(root = DEFAULT_AGENT_RELEASE_ROOT) {
12337
12427
  // src/agent-update-helper.ts
12338
12428
  import { randomUUID as randomUUID4 } from "crypto";
12339
12429
  import {
12340
- chmodSync as chmodSync14,
12430
+ chmodSync as chmodSync15,
12341
12431
  closeSync as closeSync3,
12342
12432
  existsSync as existsSync14,
12343
12433
  fsyncSync as fsyncSync2,
@@ -12354,7 +12444,7 @@ import { dirname as dirname8, join as join8, resolve as resolve3 } from "path";
12354
12444
 
12355
12445
  // src/agent-handover.ts
12356
12446
  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";
12447
+ import { chmodSync as chmodSync14, existsSync as existsSync13, renameSync as renameSync8, rmSync as rmSync6, symlinkSync as symlinkSync5, unlinkSync as unlinkSync10 } from "fs";
12358
12448
  import { basename as basename2, dirname as dirname7 } from "path";
12359
12449
  import { connect as connect5, createServer as createServer6 } from "net";
12360
12450
  var DEFAULT_AGENT_CANDIDATE_READY_SOCKET = "/run/forgezero/candidate-ready.sock";
@@ -12375,7 +12465,7 @@ function startAgentCandidateReady(ready, socketPath = DEFAULT_AGENT_CANDIDATE_RE
12375
12465
  unlinkSync10(socketPath);
12376
12466
  const server = createServer6((socket) => socket.end(`${JSON.stringify(ready)}
12377
12467
  `));
12378
- server.listen(socketPath, () => chmodSync13(socketPath, 432));
12468
+ server.listen(socketPath, () => chmodSync14(socketPath, 432));
12379
12469
  return server;
12380
12470
  }
12381
12471
  function probeAgentCandidate(expected, socketPath = DEFAULT_AGENT_CANDIDATE_READY_SOCKET, timeoutMs = 5000) {
@@ -12928,7 +13018,7 @@ function startAgentUpdateHelper(options = {}) {
12928
13018
  });
12929
13019
  socket.on("error", () => socket.destroy());
12930
13020
  });
12931
- server.listen(socketPath, () => chmodSync14(socketPath, 432));
13021
+ server.listen(socketPath, () => chmodSync15(socketPath, 432));
12932
13022
  return server;
12933
13023
  }
12934
13024
  function requestAgentUpdate(request, socketPath = DEFAULT_AGENT_UPDATE_SOCKET, timeoutMs = 90000) {
@@ -13145,7 +13235,7 @@ function startAgentHeartbeat(options) {
13145
13235
  }
13146
13236
 
13147
13237
  // src/software-helper.ts
13148
- import { chmodSync as chmodSync15, existsSync as existsSync18, mkdirSync as mkdirSync13, unlinkSync as unlinkSync12 } from "fs";
13238
+ import { chmodSync as chmodSync16, existsSync as existsSync18, mkdirSync as mkdirSync13, unlinkSync as unlinkSync12 } from "fs";
13149
13239
  import { connect as connect7, createServer as createServer8 } from "net";
13150
13240
  import { dirname as dirname12 } from "path";
13151
13241
 
@@ -14133,7 +14223,7 @@ function startSoftwareHelper(options = {}) {
14133
14223
  });
14134
14224
  socket.on("error", () => socket.destroy());
14135
14225
  });
14136
- server.listen(socketPath, () => chmodSync15(socketPath, 432));
14226
+ server.listen(socketPath, () => chmodSync16(socketPath, 432));
14137
14227
  return server;
14138
14228
  }
14139
14229
  function requestContainer(op, request, socketPath, timeoutMs) {
@@ -15218,7 +15308,7 @@ var METAL_SYSTEMD_CREDENTIALS = {
15218
15308
 
15219
15309
  // src/platform-bootstrap-runtime.ts
15220
15310
  import {
15221
- chmodSync as chmodSync16,
15311
+ chmodSync as chmodSync17,
15222
15312
  chownSync,
15223
15313
  copyFileSync as copyFileSync2,
15224
15314
  existsSync as existsSync19,
@@ -15317,7 +15407,7 @@ var secureRelease = (path2, uid, gid) => {
15317
15407
  if (metadata.isSymbolicLink())
15318
15408
  return;
15319
15409
  chownSync(current2, uid, gid);
15320
- chmodSync16(current2, metadata.isDirectory() ? 365 : 292);
15410
+ chmodSync17(current2, metadata.isDirectory() ? 365 : 292);
15321
15411
  if (metadata.isDirectory())
15322
15412
  for (const name of readdirSync4(current2))
15323
15413
  visit(join10(current2, name));
@@ -15558,7 +15648,7 @@ import { lstatSync as lstatSync7 } from "fs";
15558
15648
 
15559
15649
  // src/bootstrap.ts
15560
15650
  import {
15561
- chmodSync as chmodSync18,
15651
+ chmodSync as chmodSync19,
15562
15652
  existsSync as existsSync22,
15563
15653
  lstatSync as lstatSync6,
15564
15654
  mkdirSync as mkdirSync16,
@@ -16559,9 +16649,9 @@ function planProvision(options) {
16559
16649
  }
16560
16650
 
16561
16651
  // src/cli/agent-install.ts
16562
- import { randomBytes as randomBytes6 } from "crypto";
16652
+ import { randomBytes as randomBytes7 } from "crypto";
16563
16653
  import {
16564
- chmodSync as chmodSync17,
16654
+ chmodSync as chmodSync18,
16565
16655
  copyFileSync as copyFileSync3,
16566
16656
  existsSync as existsSync21,
16567
16657
  lstatSync as lstatSync5,
@@ -16652,12 +16742,12 @@ var runProvisionOperation = async (operation) => {
16652
16742
  mkdirSync15(`${release}/dist`, { recursive: true, mode: 493 });
16653
16743
  mkdirSync15(dirname13(operation.binary), { recursive: true, mode: 493 });
16654
16744
  copyFileSync3(operation.source, `${release}/dist/fz-agent.js`);
16655
- chmodSync17(`${release}/dist/fz-agent.js`, 493);
16745
+ chmodSync18(`${release}/dist/fz-agent.js`, 493);
16656
16746
  const gitSshSource = `${dirname13(operation.source)}/fz-git-ssh.js`;
16657
16747
  if (!existsSync21(gitSshSource))
16658
16748
  return { stdout: "packaged fz-git-ssh.js is missing", exitCode: 1 };
16659
16749
  copyFileSync3(gitSshSource, `${release}/dist/fz-git-ssh.js`);
16660
- chmodSync17(`${release}/dist/fz-git-ssh.js`, 493);
16750
+ chmodSync18(`${release}/dist/fz-git-ssh.js`, 493);
16661
16751
  const pending = "/opt/forgezero/agent/current.next";
16662
16752
  rmSync11(pending, { force: true });
16663
16753
  symlinkSync7(`versions/${operation.version}`, pending);
@@ -16672,10 +16762,10 @@ var runProvisionOperation = async (operation) => {
16672
16762
  if (operation.kind === "ensure-seed") {
16673
16763
  if (existsSync21(operation.credential) && lstatSync5(operation.credential).size > 0)
16674
16764
  return { stdout: "", exitCode: 0 };
16675
- const seed = randomBytes6(32).toString("base64url");
16765
+ const seed = randomBytes7(32).toString("base64url");
16676
16766
  const result = await fixed(["/usr/bin/systemd-creds", "encrypt", "--name=agent-seed", "-", operation.credential], seed);
16677
16767
  if (result.exitCode === 0)
16678
- chmodSync17(operation.credential, 256);
16768
+ chmodSync18(operation.credential, 256);
16679
16769
  return result;
16680
16770
  }
16681
16771
  if (operation.kind === "ensure-git-identity") {
@@ -16691,7 +16781,7 @@ var runProvisionOperation = async (operation) => {
16691
16781
  result = await fixed(["/usr/bin/systemd-creds", "encrypt", "--name=git-deploy-key", key, operation.credential]);
16692
16782
  if (result.exitCode !== 0)
16693
16783
  return result;
16694
- chmodSync17(operation.credential, 256);
16784
+ chmodSync18(operation.credential, 256);
16695
16785
  }
16696
16786
  if (!existsSync21(operation.publicKey) || lstatSync5(operation.publicKey).size < 1) {
16697
16787
  if (!existsSync21(key)) {
@@ -16725,7 +16815,7 @@ var runProvisionOperation = async (operation) => {
16725
16815
  return { stdout: "bootstrap SSH private-key source is missing or unsafe", exitCode: 1 };
16726
16816
  }
16727
16817
  copyFileSync3(operation.source, key);
16728
- chmodSync17(key, 384);
16818
+ chmodSync18(key, 384);
16729
16819
  } else {
16730
16820
  result = await fixed(["/usr/bin/ssh-keygen", "-q", "-t", "ed25519", "-N", "", "-C", "forgezero-bootstrap-runner", "-f", key]);
16731
16821
  if (result.exitCode !== 0)
@@ -16738,14 +16828,14 @@ var runProvisionOperation = async (operation) => {
16738
16828
  result = await fixed(["/usr/bin/systemd-creds", "encrypt", "--name=bootstrap-ssh-key", key, operation.credential]);
16739
16829
  if (result.exitCode !== 0)
16740
16830
  return result;
16741
- chmodSync17(operation.credential, 256);
16831
+ chmodSync18(operation.credential, 256);
16742
16832
  }
16743
16833
  if (!existsSync21(operation.publicKey) || lstatSync5(operation.publicKey).size < 1) {
16744
16834
  if (!existsSync21(key)) {
16745
16835
  const decrypted = await fixed(["/usr/bin/systemd-creds", "decrypt", "--name=bootstrap-ssh-key", operation.credential, key]);
16746
16836
  if (decrypted.exitCode !== 0)
16747
16837
  return decrypted;
16748
- chmodSync17(key, 384);
16838
+ chmodSync18(key, 384);
16749
16839
  }
16750
16840
  const derived = await fixed(["/usr/bin/ssh-keygen", "-y", "-f", key]);
16751
16841
  const publicKey = normalizeEd25519PublicKey(derived.stdout);
@@ -16755,7 +16845,7 @@ var runProvisionOperation = async (operation) => {
16755
16845
  mkdirSync15(dirname13(operation.publicKey), { recursive: true, mode: 493 });
16756
16846
  writeFileSync15(operation.publicKey, `${publicKey} forgezero-bootstrap-runner
16757
16847
  `, { mode: 292 });
16758
- chmodSync17(operation.publicKey, 292);
16848
+ chmodSync18(operation.publicKey, 292);
16759
16849
  }
16760
16850
  if (operation.source)
16761
16851
  rmSync11(operation.source, { force: true });
@@ -16772,7 +16862,7 @@ var runProvisionOperation = async (operation) => {
16772
16862
  return { stdout: "enrolment source is missing", exitCode: 1 };
16773
16863
  const result = await fixed(["/usr/bin/systemd-creds", "encrypt", "--name=enrol-token", operation.source, operation.credential]);
16774
16864
  if (result.exitCode === 0) {
16775
- chmodSync17(operation.credential, 256);
16865
+ chmodSync18(operation.credential, 256);
16776
16866
  rmSync11(operation.source, { force: true });
16777
16867
  }
16778
16868
  return result;
@@ -17158,7 +17248,7 @@ function localBootstrapHost() {
17158
17248
  mkdirSync16(dirname14(path2), { recursive: true, mode: 493 });
17159
17249
  const temporary = `${path2}.next.${process.pid}`;
17160
17250
  writeFileSync16(temporary, content, { mode });
17161
- chmodSync18(temporary, mode);
17251
+ chmodSync19(temporary, mode);
17162
17252
  renameSync15(temporary, path2);
17163
17253
  },
17164
17254
  mkdir: (path2, mode) => mkdirSync16(path2, { recursive: true, mode }),
@@ -18034,9 +18124,9 @@ function loadOrCreateSeed(path2) {
18034
18124
  return seed2;
18035
18125
  }
18036
18126
  mkdirSync18(dirname16(path2), { recursive: true });
18037
- const seed = new Uint8Array(randomBytes7(32));
18127
+ const seed = new Uint8Array(randomBytes8(32));
18038
18128
  writeFileSync18(path2, Buffer.from(seed).toString("base64url"), { mode: 384 });
18039
- chmodSync19(path2, 384);
18129
+ chmodSync20(path2, 384);
18040
18130
  return seed;
18041
18131
  }
18042
18132
  var DEFAULT_SOCKET_PATH = DEFAULT_SOCKET;