@forgezero/agent 0.1.28 → 0.1.29

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.
@@ -429,7 +429,7 @@ async function postSignedNode(options, path, body) {
429
429
  }
430
430
 
431
431
  // src/version.ts
432
- var VERSION2 = "0.1.28";
432
+ var VERSION2 = "0.1.29";
433
433
 
434
434
  // src/agent-heartbeat.ts
435
435
  var unquote = (value) => value.replace(/^['"]|['"]$/g, "");
package/dist/fz-agent.js CHANGED
@@ -6377,11 +6377,10 @@ ${attestationSetup}if [[ ! -x /usr/local/bin/bun ]]; then
6377
6377
  install -m 0755 ${agentBun}/bin/bun /usr/local/bin/bun
6378
6378
  rm -f /run/fz-bun-install
6379
6379
  fi
6380
- if [[ ! -x /usr/local/bin/fz-agent ]] || [[ "$(/usr/local/bin/fz-agent --version 2>/dev/null || true)" != "${profile.agentVersion}" ]]; then
6380
+ if [[ ! -x /usr/local/lib/forgezero/agent/fz-agent ]] || [[ "$(/usr/local/lib/forgezero/agent/fz-agent --version 2>/dev/null || true)" != "${profile.agentVersion}" ]]; then
6381
6381
  env BUN_INSTALL=${agentBun} /usr/local/bin/bun add -g --no-cache --force @forgezero/agent@${profile.agentVersion}
6382
- ln -sfn ${agentBun}/bin/fz-agent /usr/local/bin/fz-agent
6383
6382
  fi
6384
- env FZ_API=${profile.apiUrl} FZ_AGENT_BIN=/usr/local/bin/fz-agent FZ_AGENT_USER=forgezero-agent FZ_SOCKET_PATH=/run/forgezero/vault.sock FZ_SEED_CREDENTIAL_PATH=/etc/forgezero/creds/agent-seed.cred FZ_GIT_CREDENTIAL_PATH=/etc/forgezero/creds/git-deploy-key.cred FZ_GIT_PUBLIC_KEY_PATH=/etc/forgezero/git/deploy.pub FZ_DEPLOY_ROOT=/opt/forgezero FZ_DEPLOY_PULL=${hasEnrolment ? "true" : "false"} FZ_NODE_LABEL=${nodeLabel} ${agentBun}/bin/fz agent install --apply${hasEnrolment ? " --enrol" : ""}
6383
+ env FZ_API=${profile.apiUrl} FZ_AGENT_BIN=/usr/local/lib/forgezero/agent/fz-agent FZ_AGENT_USER=forgezero-agent FZ_SOCKET_PATH=/run/forgezero/vault.sock FZ_SEED_CREDENTIAL_PATH=/etc/forgezero/creds/agent-seed.cred FZ_GIT_CREDENTIAL_PATH=/etc/forgezero/creds/git-deploy-key.cred FZ_GIT_PUBLIC_KEY_PATH=/etc/forgezero/git/deploy.pub FZ_DEPLOY_ROOT=/opt/forgezero FZ_DEPLOY_PULL=${hasEnrolment ? "true" : "false"} FZ_NODE_LABEL=${nodeLabel} ${agentBun}/bin/fz agent install --apply${hasEnrolment ? " --enrol" : ""}
6385
6384
  `;
6386
6385
  }
6387
6386
  function cloudInit(profile, claim, manifest) {
@@ -7876,7 +7875,7 @@ function requestAgentUpdate(request, socketPath = DEFAULT_AGENT_UPDATE_SOCKET, t
7876
7875
  import { readFileSync as readFileSync7 } from "fs";
7877
7876
 
7878
7877
  // src/version.ts
7879
- var VERSION2 = "0.1.28";
7878
+ var VERSION2 = "0.1.29";
7880
7879
 
7881
7880
  // src/agent-heartbeat.ts
7882
7881
  var unquote = (value) => value.replace(/^['"]|['"]$/g, "");
@@ -8487,7 +8486,6 @@ if (import.meta.main) {
8487
8486
  const attestationSource = existsSync13("/dev/sev-guest") ? createSnpAttestationSource() : undefined;
8488
8487
  const running = runAgent({
8489
8488
  socketPath: process.env.FZ_SOCKET_PATH ?? DEFAULT_SOCKET_PATH,
8490
- listenFd: systemdListenFd(),
8491
8489
  seedCredential: process.env.FZ_SEED_CREDENTIAL,
8492
8490
  seedPath: process.env.FZ_SEED_PATH ?? DEFAULT_SEED_PATH,
8493
8491
  nodeKey: process.env.FZ_NODE_KEY,
package/dist/fz.js CHANGED
@@ -4886,7 +4886,7 @@ var AGENT_UPDATE_HELPER_UNIT_PATH = "/etc/systemd/system/forgezero-agent-update-
4886
4886
  var MAX_REQUEST_BYTES = 8 * 1024;
4887
4887
 
4888
4888
  // src/version.ts
4889
- var VERSION2 = "0.1.28";
4889
+ var VERSION2 = "0.1.29";
4890
4890
 
4891
4891
  // src/software.ts
4892
4892
  var BUN_INSTALLER_SHA256 = "bab8acfb046aac8c72407bdcce903957665d655d7acaa3e11c7c4616beae68dd";
@@ -4973,6 +4973,7 @@ var VAULT_GROUP = "forgezero-vault";
4973
4973
  var LIFECYCLE_GROUP = "forgezero-lifecycle";
4974
4974
  var DEPLOYMENT_RUNNER_UNIT_PATH = "/etc/systemd/system/forgezero-deploy-runner.service";
4975
4975
  var AGENT_SOCKET_UNIT_PATH = "/etc/systemd/system/forgezero-agent.socket";
4976
+ var AGENT_SOCKET_PROXY_UNIT_PATH = "/etc/systemd/system/forgezero-agent-proxy.service";
4976
4977
  var DEPLOYMENT_RUNNER_SOCKET = "/run/forgezero-deploy/runner.sock";
4977
4978
  var ENROLMENT_UNIT_PATH = "/etc/systemd/system/forgezero-agent-enrol.service";
4978
4979
  var LIFECYCLE_HELPER_UNIT_PATH = "/etc/systemd/system/forgezero-lifecycle-helper.service";
@@ -5062,17 +5063,55 @@ SocketGroup=${VAULT_GROUP}
5062
5063
  SocketMode=0660
5063
5064
  DirectoryMode=0750
5064
5065
  RemoveOnStop=true
5065
- Service=forgezero-agent.service
5066
+ Service=forgezero-agent-proxy.service
5066
5067
 
5067
5068
  [Install]
5068
5069
  WantedBy=sockets.target
5069
5070
  `;
5070
5071
  }
5072
+ function agentSocketProxyUnit(options) {
5073
+ const backend = agentBackendSocketPath(options.socketPath);
5074
+ const user = options.user ?? "forgezero";
5075
+ return `[Unit]
5076
+ Description=ForgeZero application Vault socket proxy
5077
+ Documentation=https://www.forgezero.net/docs/agent
5078
+ Requires=forgezero-agent.service
5079
+ After=forgezero-agent.service
5080
+
5081
+ [Service]
5082
+ User=${user}
5083
+ Group=${VAULT_GROUP}
5084
+ ExecStart=/usr/lib/systemd/systemd-socket-proxyd ${backend}
5085
+ NoNewPrivileges=true
5086
+ PrivateTmp=true
5087
+ ProtectSystem=strict
5088
+ ProtectHome=true
5089
+ ProtectKernelTunables=true
5090
+ ProtectKernelModules=true
5091
+ ProtectControlGroups=true
5092
+ RestrictSUIDSGID=true
5093
+ RestrictRealtime=true
5094
+ MemoryDenyWriteExecute=true
5095
+ LockPersonality=true
5096
+ RestrictAddressFamilies=AF_UNIX
5097
+ `;
5098
+ }
5099
+ function agentBackendSocketPath(publicSocketPath) {
5100
+ const socket = systemdPath(publicSocketPath, "agent socket");
5101
+ const backend = `${socket}.backend`;
5102
+ if (Buffer.byteLength(backend) > 100)
5103
+ throw new Error("agent socket path is too long for a Unix socket");
5104
+ return backend;
5105
+ }
5071
5106
  var systemdPath = (value, label) => {
5072
5107
  if (!value || !/^\/[A-Za-z0-9._@/-]+$/.test(value))
5073
5108
  throw new Error(`invalid ${label} path`);
5074
5109
  return value;
5075
5110
  };
5111
+ var awaitSocketCommand = (path) => {
5112
+ const socket = systemdPath(path, "readiness socket");
5113
+ return `for attempt in $(seq 1 100); do test -S ${socket} && exit 0; sleep 0.1; done; exit 1`;
5114
+ };
5076
5115
  var validNodeHostname = (value) => !value || value.length <= 253 && value === value.toLowerCase() && value.split(".").length >= 3 && value.split(".").every((label) => /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/.test(label));
5077
5116
  function warpConfigUnit(options) {
5078
5117
  if (!options.warpOrganization || !/^[a-z0-9][a-z0-9-]{0,62}$/i.test(options.warpOrganization)) {
@@ -5311,7 +5350,7 @@ function agentUnit(options) {
5311
5350
  }
5312
5351
  }
5313
5352
  const environment = [
5314
- `FZ_SOCKET_PATH=${options.socketPath}`,
5353
+ `FZ_SOCKET_PATH=${agentBackendSocketPath(options.socketPath)}`,
5315
5354
  `FZ_CONTROL_SOCKET=${controlSocketPath}`,
5316
5355
  `FZ_SEED_CREDENTIAL=agent-seed`,
5317
5356
  `FZ_AGENT_MODE=${options.mode}`,
@@ -5391,7 +5430,6 @@ Type=simple
5391
5430
  User=${user}
5392
5431
  Group=${VAULT_GROUP}
5393
5432
  ${deploymentGroup}
5394
- Sockets=forgezero-agent.socket
5395
5433
  LoadCredentialEncrypted=agent-seed:${seedCredentialPath}
5396
5434
  ${gitCredential}${projectCredentials}${projectCredentials ? `
5397
5435
  ` : ""}${snpPrepare}ExecStart=${bin}
@@ -5479,6 +5517,7 @@ function planProvision(options) {
5479
5517
  unit: agentUnit({ ...options, mode, lifecycleProfilePath, lifecycleHelperSocketPath }),
5480
5518
  auxiliaryUnits: [
5481
5519
  { path: AGENT_SOCKET_UNIT_PATH, unit: agentSocketUnit(options) },
5520
+ { path: AGENT_SOCKET_PROXY_UNIT_PATH, unit: agentSocketProxyUnit(options) },
5482
5521
  { path: AGENT_UPDATE_HELPER_UNIT_PATH, unit: agentUpdateHelperUnit(options) },
5483
5522
  ...deploymentEnabled ? [
5484
5523
  { path: DEPLOYMENT_RUNNER_UNIT_PATH, unit: deploymentRunnerUnit(options) },
@@ -5554,6 +5593,10 @@ function planProvision(options) {
5554
5593
  label: "credential directory",
5555
5594
  command: `install -d -o root -g root -m 0700 ${credentialDir}`
5556
5595
  },
5596
+ {
5597
+ label: "Agent state directory",
5598
+ command: "install -d -o root -g root -m 0750 /var/lib/forgezero"
5599
+ },
5557
5600
  {
5558
5601
  label: "encrypted node identity",
5559
5602
  command: `test -s ${seedCredentialPath} || { ` + `openssl rand -base64 32 | tr '+/' '-_' | tr -d '=\\n' | ` + `systemd-creds encrypt --name=agent-seed - ${seedCredentialPath}; ` + `chmod 0400 ${seedCredentialPath}; }`
@@ -5588,8 +5631,8 @@ function planProvision(options) {
5588
5631
  command: "systemctl disable --now forgezero-deploy-runner.socket 2>/dev/null || true; rm -f /etc/systemd/system/forgezero-deploy-runner.socket; systemctl daemon-reload"
5589
5632
  }] : [],
5590
5633
  {
5591
- label: "enable and start",
5592
- command: `systemctl enable --now ${[
5634
+ label: "enable and converge services",
5635
+ command: `systemctl enable ${[
5593
5636
  "forgezero-agent.socket",
5594
5637
  "forgezero-agent-update-helper.service",
5595
5638
  ...deploymentEnabled ? ["forgezero-deploy-runner.service", "forgezero-software-helper.service"] : [],
@@ -5597,25 +5640,32 @@ function planProvision(options) {
5597
5640
  ...warpEnabled ? ["forgezero-warp-config.service", "warp-svc.service"] : [],
5598
5641
  ...enrolmentEnabled ? ["forgezero-agent-enrol.service"] : [],
5599
5642
  "forgezero-agent.service"
5600
- ].join(" ")}`
5643
+ ].join(" ")}; systemctl reset-failed forgezero-agent.service || true; systemctl restart ${[
5644
+ "forgezero-agent-update-helper.service",
5645
+ ...deploymentEnabled ? ["forgezero-deploy-runner.service", "forgezero-software-helper.service"] : [],
5646
+ ...lifecycleEnabled ? ["forgezero-lifecycle-helper.service"] : [],
5647
+ ...warpEnabled ? ["forgezero-warp-config.service", "warp-svc.service"] : [],
5648
+ ...enrolmentEnabled ? ["forgezero-agent-enrol.service"] : []
5649
+ ].join(" ")}; systemctl restart forgezero-agent.socket; systemctl reset-failed forgezero-agent.service || true; systemctl restart forgezero-agent.service`
5601
5650
  },
5602
5651
  ...enrolmentEnabled ? [{
5603
5652
  label: "prove the compute binding is durable",
5604
5653
  command: `test -s ${enrolStatePath}`
5605
5654
  }] : [],
5606
5655
  { label: "prove it is running", command: "systemctl is-active forgezero-agent.service" },
5607
- { label: "prove the vault socket exists", command: `test -S ${options.socketPath}` },
5608
- { label: "prove the Agent update helper exists", command: `test -S ${DEFAULT_AGENT_UPDATE_SOCKET}` },
5656
+ { label: "prove the public Vault socket exists", command: awaitSocketCommand(options.socketPath) },
5657
+ { label: "prove the Agent Vault backend exists", command: awaitSocketCommand(agentBackendSocketPath(options.socketPath)) },
5658
+ { label: "prove the Agent update helper exists", command: awaitSocketCommand(DEFAULT_AGENT_UPDATE_SOCKET) },
5609
5659
  ...deploymentEnabled ? [{
5610
5660
  label: "prove the deployment runner socket exists",
5611
- command: `test -S ${DEPLOYMENT_RUNNER_SOCKET}`
5661
+ command: awaitSocketCommand(DEPLOYMENT_RUNNER_SOCKET)
5612
5662
  }, {
5613
5663
  label: "prove the software strategy helper socket exists",
5614
- command: `test -S ${DEFAULT_SOFTWARE_HELPER_SOCKET}`
5664
+ command: awaitSocketCommand(DEFAULT_SOFTWARE_HELPER_SOCKET)
5615
5665
  }] : [],
5616
5666
  ...lifecycleEnabled ? [{
5617
5667
  label: "prove the lifecycle helper socket exists",
5618
- command: `test -S ${lifecycleHelperSocketPath}`
5668
+ command: awaitSocketCommand(lifecycleHelperSocketPath)
5619
5669
  }] : [],
5620
5670
  ...warpEnabled ? [{
5621
5671
  label: "prove Cloudflare WARP is connected",
@@ -5623,7 +5673,7 @@ function planProvision(options) {
5623
5673
  }] : [],
5624
5674
  ...options.repository ? [{
5625
5675
  label: "prove the deployment control socket exists",
5626
- command: `test -S ${options.controlSocketPath ?? "/run/forgezero/control.sock"}`
5676
+ command: awaitSocketCommand(options.controlSocketPath ?? "/run/forgezero/control.sock")
5627
5677
  }] : []
5628
5678
  ]
5629
5679
  };
@@ -352,11 +352,10 @@ ${attestationSetup}if [[ ! -x /usr/local/bin/bun ]]; then
352
352
  install -m 0755 ${agentBun}/bin/bun /usr/local/bin/bun
353
353
  rm -f /run/fz-bun-install
354
354
  fi
355
- if [[ ! -x /usr/local/bin/fz-agent ]] || [[ "$(/usr/local/bin/fz-agent --version 2>/dev/null || true)" != "${profile.agentVersion}" ]]; then
355
+ if [[ ! -x /usr/local/lib/forgezero/agent/fz-agent ]] || [[ "$(/usr/local/lib/forgezero/agent/fz-agent --version 2>/dev/null || true)" != "${profile.agentVersion}" ]]; then
356
356
  env BUN_INSTALL=${agentBun} /usr/local/bin/bun add -g --no-cache --force @forgezero/agent@${profile.agentVersion}
357
- ln -sfn ${agentBun}/bin/fz-agent /usr/local/bin/fz-agent
358
357
  fi
359
- env FZ_API=${profile.apiUrl} FZ_AGENT_BIN=/usr/local/bin/fz-agent FZ_AGENT_USER=forgezero-agent FZ_SOCKET_PATH=/run/forgezero/vault.sock FZ_SEED_CREDENTIAL_PATH=/etc/forgezero/creds/agent-seed.cred FZ_GIT_CREDENTIAL_PATH=/etc/forgezero/creds/git-deploy-key.cred FZ_GIT_PUBLIC_KEY_PATH=/etc/forgezero/git/deploy.pub FZ_DEPLOY_ROOT=/opt/forgezero FZ_DEPLOY_PULL=${hasEnrolment ? "true" : "false"} FZ_NODE_LABEL=${nodeLabel} ${agentBun}/bin/fz agent install --apply${hasEnrolment ? " --enrol" : ""}
358
+ env FZ_API=${profile.apiUrl} FZ_AGENT_BIN=/usr/local/lib/forgezero/agent/fz-agent FZ_AGENT_USER=forgezero-agent FZ_SOCKET_PATH=/run/forgezero/vault.sock FZ_SEED_CREDENTIAL_PATH=/etc/forgezero/creds/agent-seed.cred FZ_GIT_CREDENTIAL_PATH=/etc/forgezero/creds/git-deploy-key.cred FZ_GIT_PUBLIC_KEY_PATH=/etc/forgezero/git/deploy.pub FZ_DEPLOY_ROOT=/opt/forgezero FZ_DEPLOY_PULL=${hasEnrolment ? "true" : "false"} FZ_NODE_LABEL=${nodeLabel} ${agentBun}/bin/fz agent install --apply${hasEnrolment ? " --enrol" : ""}
360
359
  `;
361
360
  }
362
361
  function cloudInit(profile, claim, manifest) {
@@ -352,11 +352,10 @@ ${attestationSetup}if [[ ! -x /usr/local/bin/bun ]]; then
352
352
  install -m 0755 ${agentBun}/bin/bun /usr/local/bin/bun
353
353
  rm -f /run/fz-bun-install
354
354
  fi
355
- if [[ ! -x /usr/local/bin/fz-agent ]] || [[ "$(/usr/local/bin/fz-agent --version 2>/dev/null || true)" != "${profile.agentVersion}" ]]; then
355
+ if [[ ! -x /usr/local/lib/forgezero/agent/fz-agent ]] || [[ "$(/usr/local/lib/forgezero/agent/fz-agent --version 2>/dev/null || true)" != "${profile.agentVersion}" ]]; then
356
356
  env BUN_INSTALL=${agentBun} /usr/local/bin/bun add -g --no-cache --force @forgezero/agent@${profile.agentVersion}
357
- ln -sfn ${agentBun}/bin/fz-agent /usr/local/bin/fz-agent
358
357
  fi
359
- env FZ_API=${profile.apiUrl} FZ_AGENT_BIN=/usr/local/bin/fz-agent FZ_AGENT_USER=forgezero-agent FZ_SOCKET_PATH=/run/forgezero/vault.sock FZ_SEED_CREDENTIAL_PATH=/etc/forgezero/creds/agent-seed.cred FZ_GIT_CREDENTIAL_PATH=/etc/forgezero/creds/git-deploy-key.cred FZ_GIT_PUBLIC_KEY_PATH=/etc/forgezero/git/deploy.pub FZ_DEPLOY_ROOT=/opt/forgezero FZ_DEPLOY_PULL=${hasEnrolment ? "true" : "false"} FZ_NODE_LABEL=${nodeLabel} ${agentBun}/bin/fz agent install --apply${hasEnrolment ? " --enrol" : ""}
358
+ env FZ_API=${profile.apiUrl} FZ_AGENT_BIN=/usr/local/lib/forgezero/agent/fz-agent FZ_AGENT_USER=forgezero-agent FZ_SOCKET_PATH=/run/forgezero/vault.sock FZ_SEED_CREDENTIAL_PATH=/etc/forgezero/creds/agent-seed.cred FZ_GIT_CREDENTIAL_PATH=/etc/forgezero/creds/git-deploy-key.cred FZ_GIT_PUBLIC_KEY_PATH=/etc/forgezero/git/deploy.pub FZ_DEPLOY_ROOT=/opt/forgezero FZ_DEPLOY_PULL=${hasEnrolment ? "true" : "false"} FZ_NODE_LABEL=${nodeLabel} ${agentBun}/bin/fz agent install --apply${hasEnrolment ? " --enrol" : ""}
360
359
  `;
361
360
  }
362
361
  function cloudInit(profile, claim, manifest) {
@@ -128,6 +128,7 @@ export declare const VAULT_GROUP = "forgezero-vault";
128
128
  export declare const LIFECYCLE_GROUP = "forgezero-lifecycle";
129
129
  export declare const DEPLOYMENT_RUNNER_UNIT_PATH = "/etc/systemd/system/forgezero-deploy-runner.service";
130
130
  export declare const AGENT_SOCKET_UNIT_PATH = "/etc/systemd/system/forgezero-agent.socket";
131
+ export declare const AGENT_SOCKET_PROXY_UNIT_PATH = "/etc/systemd/system/forgezero-agent-proxy.service";
131
132
  export declare const DEPLOYMENT_RUNNER_SOCKET = "/run/forgezero-deploy/runner.sock";
132
133
  export declare const ENROLMENT_UNIT_PATH = "/etc/systemd/system/forgezero-agent-enrol.service";
133
134
  export declare const LIFECYCLE_HELPER_UNIT_PATH = "/etc/systemd/system/forgezero-lifecycle-helper.service";
@@ -146,6 +147,13 @@ export declare function agentUpdateHelperUnit(options: Pick<UnitOptions, 'binPat
146
147
  * terminal, and it works identically on platform and tenant computes.
147
148
  */
148
149
  export declare function agentSocketUnit(options: Pick<UnitOptions, 'socketPath'>): string;
150
+ /**
151
+ * Bun does not support inheriting systemd's listening file descriptor. Keep
152
+ * PID 1 as the owner of the stable application socket and let systemd's small,
153
+ * credential-free proxy bridge it to the Agent-owned backend Unix socket.
154
+ */
155
+ export declare function agentSocketProxyUnit(options: Pick<UnitOptions, 'socketPath' | 'user'>): string;
156
+ export declare function agentBackendSocketPath(publicSocketPath: string): string;
149
157
  export declare function warpConfigUnit(options: Pick<UnitOptions, 'binPath' | 'warpOrganization' | 'warpClientIdCredentialPath' | 'warpClientSecretCredentialPath'>): string;
150
158
  export declare function warpServiceDropIn(): string;
151
159
  export declare function lifecycleHelperUnit(options: Pick<UnitOptions, 'binPath' | 'lifecycleProfilePath' | 'lifecycleHelperSocketPath'>): string;
package/dist/provision.js CHANGED
@@ -554,7 +554,7 @@ function requestSoftware(requirements, socketPath = DEFAULT_SOFTWARE_HELPER_SOCK
554
554
  }
555
555
 
556
556
  // src/version.ts
557
- var VERSION2 = "0.1.28";
557
+ var VERSION2 = "0.1.29";
558
558
 
559
559
  // src/provision.ts
560
560
  function atLeast(version, floor) {
@@ -603,6 +603,7 @@ var VAULT_GROUP = "forgezero-vault";
603
603
  var LIFECYCLE_GROUP = "forgezero-lifecycle";
604
604
  var DEPLOYMENT_RUNNER_UNIT_PATH = "/etc/systemd/system/forgezero-deploy-runner.service";
605
605
  var AGENT_SOCKET_UNIT_PATH = "/etc/systemd/system/forgezero-agent.socket";
606
+ var AGENT_SOCKET_PROXY_UNIT_PATH = "/etc/systemd/system/forgezero-agent-proxy.service";
606
607
  var DEPLOYMENT_RUNNER_SOCKET = "/run/forgezero-deploy/runner.sock";
607
608
  var ENROLMENT_UNIT_PATH = "/etc/systemd/system/forgezero-agent-enrol.service";
608
609
  var LIFECYCLE_HELPER_UNIT_PATH = "/etc/systemd/system/forgezero-lifecycle-helper.service";
@@ -692,17 +693,55 @@ SocketGroup=${VAULT_GROUP}
692
693
  SocketMode=0660
693
694
  DirectoryMode=0750
694
695
  RemoveOnStop=true
695
- Service=forgezero-agent.service
696
+ Service=forgezero-agent-proxy.service
696
697
 
697
698
  [Install]
698
699
  WantedBy=sockets.target
699
700
  `;
700
701
  }
702
+ function agentSocketProxyUnit(options) {
703
+ const backend = agentBackendSocketPath(options.socketPath);
704
+ const user = options.user ?? "forgezero";
705
+ return `[Unit]
706
+ Description=ForgeZero application Vault socket proxy
707
+ Documentation=https://www.forgezero.net/docs/agent
708
+ Requires=forgezero-agent.service
709
+ After=forgezero-agent.service
710
+
711
+ [Service]
712
+ User=${user}
713
+ Group=${VAULT_GROUP}
714
+ ExecStart=/usr/lib/systemd/systemd-socket-proxyd ${backend}
715
+ NoNewPrivileges=true
716
+ PrivateTmp=true
717
+ ProtectSystem=strict
718
+ ProtectHome=true
719
+ ProtectKernelTunables=true
720
+ ProtectKernelModules=true
721
+ ProtectControlGroups=true
722
+ RestrictSUIDSGID=true
723
+ RestrictRealtime=true
724
+ MemoryDenyWriteExecute=true
725
+ LockPersonality=true
726
+ RestrictAddressFamilies=AF_UNIX
727
+ `;
728
+ }
729
+ function agentBackendSocketPath(publicSocketPath) {
730
+ const socket = systemdPath(publicSocketPath, "agent socket");
731
+ const backend = `${socket}.backend`;
732
+ if (Buffer.byteLength(backend) > 100)
733
+ throw new Error("agent socket path is too long for a Unix socket");
734
+ return backend;
735
+ }
701
736
  var systemdPath = (value, label) => {
702
737
  if (!value || !/^\/[A-Za-z0-9._@/-]+$/.test(value))
703
738
  throw new Error(`invalid ${label} path`);
704
739
  return value;
705
740
  };
741
+ var awaitSocketCommand = (path) => {
742
+ const socket = systemdPath(path, "readiness socket");
743
+ return `for attempt in $(seq 1 100); do test -S ${socket} && exit 0; sleep 0.1; done; exit 1`;
744
+ };
706
745
  var validNodeHostname = (value) => !value || value.length <= 253 && value === value.toLowerCase() && value.split(".").length >= 3 && value.split(".").every((label) => /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/.test(label));
707
746
  function warpConfigUnit(options) {
708
747
  if (!options.warpOrganization || !/^[a-z0-9][a-z0-9-]{0,62}$/i.test(options.warpOrganization)) {
@@ -941,7 +980,7 @@ function agentUnit(options) {
941
980
  }
942
981
  }
943
982
  const environment = [
944
- `FZ_SOCKET_PATH=${options.socketPath}`,
983
+ `FZ_SOCKET_PATH=${agentBackendSocketPath(options.socketPath)}`,
945
984
  `FZ_CONTROL_SOCKET=${controlSocketPath}`,
946
985
  `FZ_SEED_CREDENTIAL=agent-seed`,
947
986
  `FZ_AGENT_MODE=${options.mode}`,
@@ -1021,7 +1060,6 @@ Type=simple
1021
1060
  User=${user}
1022
1061
  Group=${VAULT_GROUP}
1023
1062
  ${deploymentGroup}
1024
- Sockets=forgezero-agent.socket
1025
1063
  LoadCredentialEncrypted=agent-seed:${seedCredentialPath}
1026
1064
  ${gitCredential}${projectCredentials}${projectCredentials ? `
1027
1065
  ` : ""}${snpPrepare}ExecStart=${bin}
@@ -1109,6 +1147,7 @@ function planProvision(options) {
1109
1147
  unit: agentUnit({ ...options, mode, lifecycleProfilePath, lifecycleHelperSocketPath }),
1110
1148
  auxiliaryUnits: [
1111
1149
  { path: AGENT_SOCKET_UNIT_PATH, unit: agentSocketUnit(options) },
1150
+ { path: AGENT_SOCKET_PROXY_UNIT_PATH, unit: agentSocketProxyUnit(options) },
1112
1151
  { path: AGENT_UPDATE_HELPER_UNIT_PATH, unit: agentUpdateHelperUnit(options) },
1113
1152
  ...deploymentEnabled ? [
1114
1153
  { path: DEPLOYMENT_RUNNER_UNIT_PATH, unit: deploymentRunnerUnit(options) },
@@ -1184,6 +1223,10 @@ function planProvision(options) {
1184
1223
  label: "credential directory",
1185
1224
  command: `install -d -o root -g root -m 0700 ${credentialDir}`
1186
1225
  },
1226
+ {
1227
+ label: "Agent state directory",
1228
+ command: "install -d -o root -g root -m 0750 /var/lib/forgezero"
1229
+ },
1187
1230
  {
1188
1231
  label: "encrypted node identity",
1189
1232
  command: `test -s ${seedCredentialPath} || { ` + `openssl rand -base64 32 | tr '+/' '-_' | tr -d '=\\n' | ` + `systemd-creds encrypt --name=agent-seed - ${seedCredentialPath}; ` + `chmod 0400 ${seedCredentialPath}; }`
@@ -1218,8 +1261,8 @@ function planProvision(options) {
1218
1261
  command: "systemctl disable --now forgezero-deploy-runner.socket 2>/dev/null || true; rm -f /etc/systemd/system/forgezero-deploy-runner.socket; systemctl daemon-reload"
1219
1262
  }] : [],
1220
1263
  {
1221
- label: "enable and start",
1222
- command: `systemctl enable --now ${[
1264
+ label: "enable and converge services",
1265
+ command: `systemctl enable ${[
1223
1266
  "forgezero-agent.socket",
1224
1267
  "forgezero-agent-update-helper.service",
1225
1268
  ...deploymentEnabled ? ["forgezero-deploy-runner.service", "forgezero-software-helper.service"] : [],
@@ -1227,25 +1270,32 @@ function planProvision(options) {
1227
1270
  ...warpEnabled ? ["forgezero-warp-config.service", "warp-svc.service"] : [],
1228
1271
  ...enrolmentEnabled ? ["forgezero-agent-enrol.service"] : [],
1229
1272
  "forgezero-agent.service"
1230
- ].join(" ")}`
1273
+ ].join(" ")}; systemctl reset-failed forgezero-agent.service || true; systemctl restart ${[
1274
+ "forgezero-agent-update-helper.service",
1275
+ ...deploymentEnabled ? ["forgezero-deploy-runner.service", "forgezero-software-helper.service"] : [],
1276
+ ...lifecycleEnabled ? ["forgezero-lifecycle-helper.service"] : [],
1277
+ ...warpEnabled ? ["forgezero-warp-config.service", "warp-svc.service"] : [],
1278
+ ...enrolmentEnabled ? ["forgezero-agent-enrol.service"] : []
1279
+ ].join(" ")}; systemctl restart forgezero-agent.socket; systemctl reset-failed forgezero-agent.service || true; systemctl restart forgezero-agent.service`
1231
1280
  },
1232
1281
  ...enrolmentEnabled ? [{
1233
1282
  label: "prove the compute binding is durable",
1234
1283
  command: `test -s ${enrolStatePath}`
1235
1284
  }] : [],
1236
1285
  { label: "prove it is running", command: "systemctl is-active forgezero-agent.service" },
1237
- { label: "prove the vault socket exists", command: `test -S ${options.socketPath}` },
1238
- { label: "prove the Agent update helper exists", command: `test -S ${DEFAULT_AGENT_UPDATE_SOCKET}` },
1286
+ { label: "prove the public Vault socket exists", command: awaitSocketCommand(options.socketPath) },
1287
+ { label: "prove the Agent Vault backend exists", command: awaitSocketCommand(agentBackendSocketPath(options.socketPath)) },
1288
+ { label: "prove the Agent update helper exists", command: awaitSocketCommand(DEFAULT_AGENT_UPDATE_SOCKET) },
1239
1289
  ...deploymentEnabled ? [{
1240
1290
  label: "prove the deployment runner socket exists",
1241
- command: `test -S ${DEPLOYMENT_RUNNER_SOCKET}`
1291
+ command: awaitSocketCommand(DEPLOYMENT_RUNNER_SOCKET)
1242
1292
  }, {
1243
1293
  label: "prove the software strategy helper socket exists",
1244
- command: `test -S ${DEFAULT_SOFTWARE_HELPER_SOCKET}`
1294
+ command: awaitSocketCommand(DEFAULT_SOFTWARE_HELPER_SOCKET)
1245
1295
  }] : [],
1246
1296
  ...lifecycleEnabled ? [{
1247
1297
  label: "prove the lifecycle helper socket exists",
1248
- command: `test -S ${lifecycleHelperSocketPath}`
1298
+ command: awaitSocketCommand(lifecycleHelperSocketPath)
1249
1299
  }] : [],
1250
1300
  ...warpEnabled ? [{
1251
1301
  label: "prove Cloudflare WARP is connected",
@@ -1253,7 +1303,7 @@ function planProvision(options) {
1253
1303
  }] : [],
1254
1304
  ...options.repository ? [{
1255
1305
  label: "prove the deployment control socket exists",
1256
- command: `test -S ${options.controlSocketPath ?? "/run/forgezero/control.sock"}`
1306
+ command: awaitSocketCommand(options.controlSocketPath ?? "/run/forgezero/control.sock")
1257
1307
  }] : []
1258
1308
  ]
1259
1309
  };
@@ -1271,7 +1321,9 @@ export {
1271
1321
  agentUpdateHelperUnit,
1272
1322
  agentUnit,
1273
1323
  agentSocketUnit,
1324
+ agentSocketProxyUnit,
1274
1325
  agentEnrolmentUnit,
1326
+ agentBackendSocketPath,
1275
1327
  WARP_SERVICE_DROP_IN_PATH,
1276
1328
  WARP_CONFIG_UNIT_PATH,
1277
1329
  VAULT_GROUP,
@@ -1285,5 +1337,6 @@ export {
1285
1337
  DEPLOYMENT_RUNNER_SOCKET,
1286
1338
  DEPLOYMENT_GROUP,
1287
1339
  CAPABILITY_CHECKS,
1288
- AGENT_SOCKET_UNIT_PATH
1340
+ AGENT_SOCKET_UNIT_PATH,
1341
+ AGENT_SOCKET_PROXY_UNIT_PATH
1289
1342
  };
package/dist/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  /** One package version shared by both public binaries. Pinned to package.json by tests. */
2
- export declare const VERSION = "0.1.28";
2
+ export declare const VERSION = "0.1.29";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "//": "Publishing happens from an operator's machine, not CI \u2014 CLAUDE.md records that the absence of CI is deliberate. npm's `provenance` attests a tarball was built by a recognised CI provider from a named commit, so it cannot be produced here: it was set, and the first publish failed with `Automatic provenance generation not supported for provider: null`. A setting that can never be satisfied is worse than none, because it reads as a guarantee nobody is getting. Restore it the day this publishes from CI, and not before.",
3
3
  "name": "@forgezero/agent",
4
- "version": "0.1.28",
4
+ "version": "0.1.29",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "check": "tsc --noEmit",