@forgezero/agent 0.1.62 → 0.1.64

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.
@@ -60,8 +60,6 @@ export interface PlatformSharedEnvironment {
60
60
  endpoint: string;
61
61
  producer: string;
62
62
  };
63
- repository: string;
64
- branch: string;
65
63
  deployProfile: string;
66
64
  }
67
65
  export declare function validatePlatformSharedEnvironment(input: PlatformSharedEnvironment): PlatformSharedEnvironment;
@@ -100,8 +100,6 @@ function validatePlatformSharedEnvironment(input) {
100
100
  databaseUser: input.databaseUser,
101
101
  sharedDirectory: input.sharedDirectory,
102
102
  seedSyncEpoch: input.seedSyncEpoch,
103
- repository: input.repository,
104
- branch: input.branch,
105
103
  deployProfile: input.deployProfile
106
104
  }))
107
105
  safeAtom(name, value);
@@ -184,8 +182,6 @@ function renderPlatformSharedEnvironment(input) {
184
182
  FZ_AGENT_OTLP_ENDPOINT: value.agentOtlpEndpoint,
185
183
  FZ_CUSTODIAN_EMAIL: value.custodianEmail ?? "",
186
184
  FZ_PROFILE: value.deployProfile,
187
- FZ_REPO: value.repository,
188
- FZ_BRANCH: value.branch,
189
185
  FZ_EMAIL_PROVIDER: value.email?.provider ?? "",
190
186
  FZ_SMTP_HOST: value.email?.provider === "smtp" ? value.email.host : "",
191
187
  FZ_SMTP_PORT: value.email?.provider === "smtp" ? String(value.email.port) : "",
@@ -709,7 +709,8 @@ var SOFTWARE_CATALOG = [
709
709
  { id: "cloudflared", version: "2026.7.3", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
710
710
  { id: "cloudflare-warp", version: "2026.6.822.0-min", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
711
711
  { id: "ufw", version: "ubuntu-26.04", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
712
- { id: "openssh-client", version: "ubuntu-26.04", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" }
712
+ { id: "openssh-client", version: "ubuntu-26.04", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
713
+ { id: "git", version: "ubuntu-26.04", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" }
713
714
  ];
714
715
  var UBUNTU_2604_X64 = [
715
716
  { requirement: { id: "bun", version: "1.3.14" } },
@@ -719,7 +720,8 @@ var UBUNTU_2604_X64 = [
719
720
  { requirement: { id: "cloudflared", version: "2026.7.3" } },
720
721
  { requirement: { id: "cloudflare-warp", version: "2026.6.822.0-min" } },
721
722
  { requirement: { id: "ufw", version: "ubuntu-26.04" } },
722
- { requirement: { id: "openssh-client", version: "ubuntu-26.04" } }
723
+ { requirement: { id: "openssh-client", version: "ubuntu-26.04" } },
724
+ { requirement: { id: "git", version: "ubuntu-26.04" } }
723
725
  ];
724
726
  var path = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
725
727
  var DOCKER_DAEMON_PATH = "/etc/docker/daemon.json";
@@ -806,7 +808,7 @@ async function executeSoftwareOperation(operation) {
806
808
  const supported = observed && observed.some((part, index) => part > minimum[index] && observed.slice(0, index).every((prior, priorIndex) => prior === minimum[priorIndex])) || observed?.every((part, index) => part === minimum[index]);
807
809
  return { ...result, exitCode: result.exitCode === 0 && supported ? 0 : 1 };
808
810
  });
809
- const binaries = software === "ufw" ? ["/usr/sbin/ufw"] : ["/usr/bin/ssh", "/usr/bin/scp", "/usr/bin/ssh-keyscan", "/usr/bin/ssh-keygen"];
811
+ const binaries = software === "ufw" ? ["/usr/sbin/ufw"] : software === "git" ? ["/usr/bin/git"] : ["/usr/bin/ssh", "/usr/bin/scp", "/usr/bin/ssh-keyscan", "/usr/bin/ssh-keygen"];
810
812
  try {
811
813
  binaries.forEach((binary) => accessSync(binary));
812
814
  return { exitCode: 0, output: "" };
@@ -814,7 +816,7 @@ async function executeSoftwareOperation(operation) {
814
816
  return { exitCode: 1, output: cause instanceof Error ? cause.message : String(cause) };
815
817
  }
816
818
  }
817
- if (software === "docker" || software === "nginx" || software === "ufw" || software === "openssh-client") {
819
+ if (software === "docker" || software === "nginx" || software === "ufw" || software === "openssh-client" || software === "git") {
818
820
  const packageName = software === "openssh-client" ? "openssh-client" : software === "docker" ? "docker.io" : software;
819
821
  const installed = await aptInstall(packageName);
820
822
  if (installed.exitCode !== 0 || software !== "nginx" && software !== "docker")
@@ -914,7 +916,7 @@ function validateSoftwareRequirements(value, _options = {}) {
914
916
  if (Object.keys(row).some((key) => key !== "id" && key !== "version")) {
915
917
  throw new Error("software requirement contains an unknown field");
916
918
  }
917
- if (!["bun", "docker", "nginx", "arangodb", "cloudflared", "cloudflare-warp", "ufw", "openssh-client"].includes(String(row.id)) || typeof row.version !== "string" || !/^[A-Za-z0-9][A-Za-z0-9.-]{0,31}$/.test(row.version)) {
919
+ if (!["bun", "docker", "nginx", "arangodb", "cloudflared", "cloudflare-warp", "ufw", "openssh-client", "git"].includes(String(row.id)) || typeof row.version !== "string" || !/^[A-Za-z0-9][A-Za-z0-9.-]{0,31}$/.test(row.version)) {
918
920
  throw new Error("software requirement coordinate is invalid");
919
921
  }
920
922
  const requirement = { id: row.id, version: row.version };
@@ -2086,7 +2088,7 @@ function requestSoftware(requirements, socketPath = DEFAULT_SOFTWARE_HELPER_SOCK
2086
2088
  }
2087
2089
 
2088
2090
  // src/version.ts
2089
- var VERSION3 = "0.1.62";
2091
+ var VERSION3 = "0.1.64";
2090
2092
 
2091
2093
  // src/egress-policy.ts
2092
2094
  import { realpathSync as realpathSync3 } from "node:fs";
@@ -2215,7 +2217,11 @@ function agentEgressUnit(options) {
2215
2217
  const user = options.user ?? "forgezero";
2216
2218
  if (!/^[a-z_][a-z0-9_-]{0,30}$/.test(user))
2217
2219
  throw new Error("invalid Agent service user");
2218
- const deploymentEnabled = Boolean(options.repository || options.pullDeployments);
2220
+ const bootstrapBundleEnabled = Boolean(options.bootstrapBundlePath && options.bootstrapBundleManifestPath);
2221
+ if (Boolean(options.bootstrapBundlePath) !== Boolean(options.bootstrapBundleManifestPath) || bootstrapBundleEnabled && ![options.bootstrapBundlePath, options.bootstrapBundleManifestPath].every((path2) => path2.startsWith("/") && !/[\r\n\0:]/.test(path2))) {
2222
+ throw new Error("bootstrap bundle and manifest must be supplied together as absolute paths");
2223
+ }
2224
+ const deploymentEnabled = Boolean(options.repository || bootstrapBundleEnabled || options.pullDeployments);
2219
2225
  const runnerLoopbackPorts = normalizeEgressTcpPorts(options.runnerLoopbackPorts ?? []);
2220
2226
  const runnerPublicTcpPorts = normalizeEgressTcpPorts(options.runnerPublicTcpPorts ?? DEFAULT_RUNNER_PUBLIC_TCP_PORTS);
2221
2227
  if (deploymentEnabled && runnerPublicTcpPorts.length < 1) {
@@ -2621,17 +2627,16 @@ function agentUnit(options) {
2621
2627
  if (Boolean(options.pullMigrations) !== Boolean(options.lifecycleProfilePath)) {
2622
2628
  throw new Error("migration pull and lifecycle profile must be supplied together");
2623
2629
  }
2624
- const bootstrapEnabled = Boolean(options.pullBootstrap && options.bootstrapSshCredentialPath && options.bootstrapSshPublicKeyPath && options.bootstrapTargetTelemetryEndpoint);
2625
- if ([
2626
- options.pullBootstrap,
2627
- options.bootstrapSshCredentialPath,
2628
- options.bootstrapSshPublicKeyPath,
2629
- options.bootstrapTargetTelemetryEndpoint
2630
- ].some(Boolean) && !bootstrapEnabled) {
2631
- throw new Error("bootstrap pull, SSH credential, public key and target telemetry endpoint must be supplied together");
2630
+ const bootstrapIdentityEnabled = Boolean(options.bootstrapSshCredentialPath && options.bootstrapSshPublicKeyPath);
2631
+ if (Boolean(options.bootstrapSshCredentialPath) !== Boolean(options.bootstrapSshPublicKeyPath)) {
2632
+ throw new Error("bootstrap SSH credential and public key paths must be supplied together");
2633
+ }
2634
+ const bootstrapEnabled = Boolean(options.pullBootstrap);
2635
+ if (bootstrapEnabled && (!bootstrapIdentityEnabled || !options.bootstrapTargetTelemetryEndpoint) || !bootstrapEnabled && options.bootstrapTargetTelemetryEndpoint) {
2636
+ throw new Error("bootstrap pull, SSH identity and target telemetry endpoint must be supplied together");
2632
2637
  }
2633
2638
  const lifecycleHelperSocketPath = lifecycleEnabled ? systemdPath(options.lifecycleHelperSocketPath ?? LIFECYCLE_HELPER_SOCKET, "lifecycle helper socket") : undefined;
2634
- const bootstrapSshCredentialPath = bootstrapEnabled ? systemdPath(options.bootstrapSshCredentialPath, "bootstrap SSH credential") : undefined;
2639
+ const bootstrapSshCredentialPath = bootstrapIdentityEnabled ? systemdPath(options.bootstrapSshCredentialPath, "bootstrap SSH credential") : undefined;
2635
2640
  const warpValues = [
2636
2641
  options.warpOrganization,
2637
2642
  options.warpClientIdCredentialPath,
@@ -2685,6 +2690,8 @@ function agentUnit(options) {
2685
2690
  options.gitPublicKeyPath ? `FZ_GIT_PUBLIC_KEY_FILE=${options.gitPublicKeyPath}` : null,
2686
2691
  options.repository ? `FZ_DEPLOY_REPO=${options.repository}` : null,
2687
2692
  options.branch ? `FZ_DEPLOY_BRANCH=${options.branch}` : null,
2693
+ options.bootstrapBundlePath ? `FZ_BOOTSTRAP_BUNDLE=${options.bootstrapBundlePath}` : null,
2694
+ options.bootstrapBundleManifestPath ? `FZ_BOOTSTRAP_BUNDLE_MANIFEST=${options.bootstrapBundleManifestPath}` : null,
2688
2695
  options.profile ? `FZ_DEPLOY_PROFILE=${options.profile}` : null,
2689
2696
  options.repository && options.branch ? `FZ_DEPLOY_KEY=${options.project ?? "platform"}:${options.environment ?? "production"}` : null,
2690
2697
  deploymentEnabled ? `FZ_DEPLOY_ROOT=${deployRoot}` : null,
@@ -2868,15 +2875,13 @@ function planProvision(options) {
2868
2875
  if (Boolean(options.pullMigrations) !== Boolean(options.lifecycleProfilePath)) {
2869
2876
  throw new Error("migration pull and lifecycle profile must be supplied together");
2870
2877
  }
2871
- const bootstrapEnabled = Boolean(options.pullBootstrap && options.bootstrapSshCredentialPath && options.bootstrapSshPublicKeyPath && options.bootstrapTargetTelemetryEndpoint);
2872
- if ([
2873
- options.pullBootstrap,
2874
- options.bootstrapSshCredentialPath,
2875
- options.bootstrapSshPublicKeyPath,
2876
- options.bootstrapSshSourcePath,
2877
- options.bootstrapTargetTelemetryEndpoint
2878
- ].some(Boolean) && !bootstrapEnabled) {
2879
- throw new Error("bootstrap pull, SSH credential, public key and target telemetry endpoint must be supplied together");
2878
+ const bootstrapIdentityEnabled = Boolean(options.bootstrapSshCredentialPath && options.bootstrapSshPublicKeyPath);
2879
+ if (Boolean(options.bootstrapSshCredentialPath) !== Boolean(options.bootstrapSshPublicKeyPath) || options.bootstrapSshSourcePath && !bootstrapIdentityEnabled) {
2880
+ throw new Error("bootstrap SSH credential and public key paths must be supplied together");
2881
+ }
2882
+ const bootstrapEnabled = Boolean(options.pullBootstrap);
2883
+ if (bootstrapEnabled && (!bootstrapIdentityEnabled || !options.bootstrapTargetTelemetryEndpoint) || !bootstrapEnabled && options.bootstrapTargetTelemetryEndpoint) {
2884
+ throw new Error("bootstrap pull, SSH identity and target telemetry endpoint must be supplied together");
2880
2885
  }
2881
2886
  const warpValues = [
2882
2887
  options.warpOrganization,
@@ -2886,13 +2891,13 @@ function planProvision(options) {
2886
2891
  const warpEnabled = warpValues.every(Boolean);
2887
2892
  if (warpValues.some(Boolean) && !warpEnabled)
2888
2893
  throw new Error("WARP configuration must be supplied together");
2889
- const enrolmentEnabled = Boolean(options.enrolTokenCredentialPath && options.enrolStatePath);
2890
- if (Boolean(options.enrolTokenCredentialPath) !== Boolean(options.enrolStatePath) || options.enrolTokenSourcePath && !enrolmentEnabled) {
2891
- throw new Error("direct enrolment credential and state paths must be supplied together");
2894
+ const enrolmentEnabled = Boolean(options.enrolTokenCredentialPath);
2895
+ if (options.enrolTokenCredentialPath && !options.enrolStatePath || options.enrolTokenSourcePath && (!options.enrolTokenCredentialPath || !options.enrolStatePath)) {
2896
+ throw new Error("direct enrolment credential requires its durable state path");
2892
2897
  }
2893
2898
  const enrolTokenSourcePath = options.enrolTokenSourcePath ? systemdPath(options.enrolTokenSourcePath, "enrolment source") : undefined;
2894
2899
  const enrolTokenCredentialPath = enrolmentEnabled ? systemdPath(options.enrolTokenCredentialPath, "enrolment credential") : undefined;
2895
- const enrolStatePath = enrolmentEnabled ? systemdPath(options.enrolStatePath, "enrolment state") : undefined;
2900
+ const enrolStatePath = options.enrolStatePath ? systemdPath(options.enrolStatePath, "enrolment state") : undefined;
2896
2901
  const enrolStateDir = enrolStatePath?.replace(/\/[^/]+$/, "");
2897
2902
  const sourceBinPath = options.sourceBinPath ? systemdPath(options.sourceBinPath, "agent source binary") : undefined;
2898
2903
  const binPath = options.binPath ? systemdPath(options.binPath, "agent binary") : undefined;
@@ -2904,8 +2909,8 @@ function planProvision(options) {
2904
2909
  const gitPublicKeyDir = gitPublicKeyPath?.replace(/\/[^/]+$/, "");
2905
2910
  const lifecycleProfilePath = lifecycleEnabled ? systemdPath(options.lifecycleProfilePath, "lifecycle profile") : undefined;
2906
2911
  const lifecycleHelperSocketPath = lifecycleEnabled ? systemdPath(options.lifecycleHelperSocketPath ?? LIFECYCLE_HELPER_SOCKET, "lifecycle helper socket") : undefined;
2907
- const bootstrapSshCredentialPath = bootstrapEnabled ? systemdPath(options.bootstrapSshCredentialPath, "bootstrap SSH credential") : undefined;
2908
- const bootstrapSshPublicKeyPath = bootstrapEnabled ? systemdPath(options.bootstrapSshPublicKeyPath, "bootstrap SSH public key") : undefined;
2912
+ const bootstrapSshCredentialPath = bootstrapIdentityEnabled ? systemdPath(options.bootstrapSshCredentialPath, "bootstrap SSH credential") : undefined;
2913
+ const bootstrapSshPublicKeyPath = bootstrapIdentityEnabled ? systemdPath(options.bootstrapSshPublicKeyPath, "bootstrap SSH public key") : undefined;
2909
2914
  const bootstrapSshSourcePath = options.bootstrapSshSourcePath ? systemdPath(options.bootstrapSshSourcePath, "bootstrap SSH private-key source") : undefined;
2910
2915
  const bootstrapSshPublicKeyDir = bootstrapSshPublicKeyPath?.replace(/\/[^/]+$/, "");
2911
2916
  const warpClientIdCredentialPath = warpEnabled ? systemdPath(options.warpClientIdCredentialPath, "WARP client-id credential") : undefined;
@@ -3005,7 +3010,7 @@ function planProvision(options) {
3005
3010
  step("Git deploy identity directory", { kind: "directories", directories: [{ path: gitPublicKeyDir, mode: 493, owner: "root", group: "root" }] }),
3006
3011
  step("unique encrypted Git deploy identity", { kind: "ensure-git-identity", credential: gitCredentialPath, publicKey: gitPublicKeyPath })
3007
3012
  ] : [],
3008
- ...bootstrapEnabled ? [
3013
+ ...bootstrapIdentityEnabled ? [
3009
3014
  step("bootstrap SSH public identity directory", { kind: "directories", directories: [
3010
3015
  { path: bootstrapSshPublicKeyDir, mode: 493, owner: "root", group: "root" }
3011
3016
  ] }),
@@ -3041,6 +3046,10 @@ function planProvision(options) {
3041
3046
  { argv: ["/usr/bin/rm", "-f", "/etc/systemd/system/forgezero-deploy-runner.socket"] },
3042
3047
  { argv: ["/usr/bin/systemctl", "daemon-reload"] }
3043
3048
  ] })] : [],
3049
+ ...enrolStatePath && !enrolmentEnabled ? [step("retire consumed enrolment unit", { kind: "commands", commands: [
3050
+ { argv: ["/usr/bin/systemctl", "disable", "--now", "forgezero-agent-enrol.service"], acceptedExitCodes: [0, 1, 5] },
3051
+ { argv: ["/usr/bin/rm", "-f", ENROLMENT_UNIT_PATH] }
3052
+ ] })] : [],
3044
3053
  step("enable and converge services", { kind: "commands", commands: [
3045
3054
  { argv: ["/usr/bin/systemctl", "enable", ...enabledUnits] },
3046
3055
  { argv: ["/usr/bin/systemctl", "reset-failed", "forgezero-agent.service"], acceptedExitCodes: [0, 1] },
@@ -3168,8 +3177,6 @@ function validatePlatformSharedEnvironment(input) {
3168
3177
  databaseUser: input.databaseUser,
3169
3178
  sharedDirectory: input.sharedDirectory,
3170
3179
  seedSyncEpoch: input.seedSyncEpoch,
3171
- repository: input.repository,
3172
- branch: input.branch,
3173
3180
  deployProfile: input.deployProfile
3174
3181
  }))
3175
3182
  safeAtom(name, value);
@@ -3252,8 +3259,6 @@ function renderPlatformSharedEnvironment(input) {
3252
3259
  FZ_AGENT_OTLP_ENDPOINT: value.agentOtlpEndpoint,
3253
3260
  FZ_CUSTODIAN_EMAIL: value.custodianEmail ?? "",
3254
3261
  FZ_PROFILE: value.deployProfile,
3255
- FZ_REPO: value.repository,
3256
- FZ_BRANCH: value.branch,
3257
3262
  FZ_EMAIL_PROVIDER: value.email?.provider ?? "",
3258
3263
  FZ_SMTP_HOST: value.email?.provider === "smtp" ? value.email.host : "",
3259
3264
  FZ_SMTP_PORT: value.email?.provider === "smtp" ? String(value.email.port) : "",
@@ -3592,21 +3597,21 @@ function planLocalOtlpProof(endpoint, collectorUnit) {
3592
3597
  }
3593
3598
 
3594
3599
  // src/platform-fleet-verification.ts
3595
- import { lstatSync as lstatSync4 } from "node:fs";
3600
+ import { lstatSync as lstatSync5 } from "node:fs";
3596
3601
 
3597
3602
  // src/bootstrap.ts
3598
- import { createHash as createHash5, createHmac as createHmac2, randomBytes as randomBytes2 } from "node:crypto";
3603
+ import { createHash as createHash6, createHmac as createHmac2, randomBytes as randomBytes3 } from "node:crypto";
3599
3604
  import {
3600
- chmodSync as chmodSync7,
3601
- existsSync as existsSync9,
3602
- lstatSync as lstatSync3,
3603
- mkdirSync as mkdirSync9,
3604
- readFileSync as readFileSync8,
3605
- renameSync as renameSync8,
3606
- rmSync as rmSync8,
3607
- writeFileSync as writeFileSync8
3605
+ chmodSync as chmodSync8,
3606
+ existsSync as existsSync10,
3607
+ lstatSync as lstatSync4,
3608
+ mkdirSync as mkdirSync10,
3609
+ readFileSync as readFileSync9,
3610
+ renameSync as renameSync9,
3611
+ rmSync as rmSync9,
3612
+ writeFileSync as writeFileSync9
3608
3613
  } from "node:fs";
3609
- import { dirname as dirname8 } from "node:path";
3614
+ import { dirname as dirname9 } from "node:path";
3610
3615
  import { fileURLToPath } from "node:url";
3611
3616
 
3612
3617
  // src/cli/agent-install.ts
@@ -3918,6 +3923,58 @@ var UNIT = `/etc/systemd/system/${FORGEZERO_OTEL_COLLECTOR_UNIT}`;
3918
3923
 
3919
3924
  // src/bootstrap.ts
3920
3925
  import { DEFAULT_SOCKET as DEFAULT_SOCKET2 } from "@forgezero/vault";
3926
+
3927
+ // src/bootstrap-bundle.ts
3928
+ import { createHash as createHash5, randomBytes as randomBytes2 } from "node:crypto";
3929
+ import {
3930
+ chmodSync as chmodSync7,
3931
+ createReadStream,
3932
+ existsSync as existsSync9,
3933
+ lstatSync as lstatSync3,
3934
+ mkdirSync as mkdirSync9,
3935
+ readFileSync as readFileSync8,
3936
+ renameSync as renameSync8,
3937
+ rmSync as rmSync8,
3938
+ writeFileSync as writeFileSync8
3939
+ } from "node:fs";
3940
+ import { dirname as dirname8, isAbsolute, resolve as resolve6 } from "node:path";
3941
+ var BOOTSTRAP_BUNDLE_FORMAT = 1;
3942
+ var BOOTSTRAP_BUNDLE_KIND = "forgezero-api-git-bundle";
3943
+ var MAX_BOOTSTRAP_BUNDLE_BYTES = 512 * 1024 * 1024;
3944
+ var branchName = (value) => {
3945
+ if (typeof value !== "string" || !/^[A-Za-z0-9](?:[A-Za-z0-9._/-]{0,126}[A-Za-z0-9])?$/.test(value) || value.includes("..") || value.includes("//") || value.startsWith("-")) {
3946
+ throw new Error("bootstrap bundle branch is malformed");
3947
+ }
3948
+ return value;
3949
+ };
3950
+ function parseBootstrapBundleManifest(value) {
3951
+ if (!value || typeof value !== "object" || Array.isArray(value))
3952
+ throw new Error("bootstrap bundle manifest must be an object");
3953
+ const source = value;
3954
+ const allowed = ["format", "kind", "branch", "revision", "sha256", "bytes", "createdAt"];
3955
+ const unknown = Object.keys(source).filter((key) => !allowed.includes(key));
3956
+ if (unknown.length)
3957
+ throw new Error(`bootstrap bundle manifest contains unknown field ${unknown[0]}`);
3958
+ if (source.format !== BOOTSTRAP_BUNDLE_FORMAT || source.kind !== BOOTSTRAP_BUNDLE_KIND) {
3959
+ throw new Error("bootstrap bundle manifest format is unsupported");
3960
+ }
3961
+ branchName(source.branch);
3962
+ if (typeof source.revision !== "string" || !/^[a-f0-9]{40}$/.test(source.revision)) {
3963
+ throw new Error("bootstrap bundle revision must be an exact lowercase Git commit");
3964
+ }
3965
+ if (typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256)) {
3966
+ throw new Error("bootstrap bundle digest is malformed");
3967
+ }
3968
+ if (!Number.isSafeInteger(source.bytes) || Number(source.bytes) < 1 || Number(source.bytes) > MAX_BOOTSTRAP_BUNDLE_BYTES) {
3969
+ throw new Error("bootstrap bundle size is outside the supported boundary");
3970
+ }
3971
+ if (typeof source.createdAt !== "string" || Number.isNaN(Date.parse(source.createdAt))) {
3972
+ throw new Error("bootstrap bundle creation time is malformed");
3973
+ }
3974
+ return source;
3975
+ }
3976
+
3977
+ // src/bootstrap.ts
3921
3978
  var platformBootstrapRunner = (config) => config.kind === "platform" && config.database.role === "master";
3922
3979
  var BOOTSTRAP_STATE_PATH = "/var/lib/forgezero/bootstrap.json";
3923
3980
  var STATE_PATH = BOOTSTRAP_STATE_PATH;
@@ -3934,6 +3991,7 @@ var SEED_CREDENTIAL = `${CREDS}/seed-sync-root.cred`;
3934
3991
  var BACKUP_RECOVERY_CREDENTIAL = `${CREDS}/backup-recovery-root.cred`;
3935
3992
  var BOOTSTRAP_SSH_CREDENTIAL = `${CREDS}/bootstrap-ssh-key.cred`;
3936
3993
  var BOOTSTRAP_SSH_PUBLIC_KEY = "/etc/forgezero/bootstrap/runner.pub";
3994
+ var BOOTSTRAP_RELEASE_EVIDENCE = "/var/lib/forgezero/bootstrap-release.json";
3937
3995
  var LIFECYCLE_PROFILE = "/etc/forgezero/lifecycle.json";
3938
3996
  var CONTROL_SOCKET = "/run/forgezero/control.sock";
3939
3997
  var CLOUDFLARED_METRICS_ADDRESS = "127.0.0.1:20241";
@@ -4110,6 +4168,65 @@ async function bootstrapStatus(host = localBootstrapHost()) {
4110
4168
  problems.push("durable Agent enrolment state is missing");
4111
4169
  return { initialized: problems.length === 0, kind: state.kind, profile: state.profile, services, problems };
4112
4170
  }
4171
+ function planBootstrapAgentInstall(config, phase, context) {
4172
+ const { capabilities, hasBinding, hasEnrolCredential, initialBundle } = context;
4173
+ if (phase === "bootstrap") {
4174
+ if (config.kind !== "platform" || hasBinding || !initialBundle) {
4175
+ throw new Error("release-one Agent install requires an unbound platform host and verified bootstrap bundle");
4176
+ }
4177
+ } else if (phase === "enrol") {
4178
+ if (hasBinding || !hasEnrolCredential) {
4179
+ throw new Error("Agent enrolment requires one unbound host and its sealed one-use credential");
4180
+ }
4181
+ } else if (!hasBinding) {
4182
+ throw new Error("bound Agent convergence requires durable enrolment state");
4183
+ }
4184
+ const bound = phase === "bound";
4185
+ const enrolling = phase === "enrol";
4186
+ const authenticated = enrolling || bound;
4187
+ const bootstrapRunner = platformBootstrapRunner(config) || config.kind === "enrolled-compute" && Boolean(config.bootstrapRunner);
4188
+ const options = {
4189
+ capabilities,
4190
+ socketPath: DEFAULT_SOCKET2,
4191
+ seedPath: "/var/lib/forgezero/node.seed",
4192
+ controlSocketPath: CONTROL_SOCKET,
4193
+ repository: phase === "bootstrap" ? initialBundle.path : bound && config.kind === "enrolled-compute" ? config.repository : undefined,
4194
+ branch: phase === "bootstrap" ? initialBundle.manifest.branch : bound && config.kind === "enrolled-compute" ? config.branch : undefined,
4195
+ bootstrapBundlePath: phase === "bootstrap" ? initialBundle.path : undefined,
4196
+ bootstrapBundleManifestPath: phase === "bootstrap" ? initialBundle.manifestPath : undefined,
4197
+ profile: config.profile,
4198
+ deployRoot: config.deployRoot ?? "/opt/forgezero",
4199
+ deploymentCredentials: config.deploymentCredentials,
4200
+ publicApiUrl: config.apiUrl,
4201
+ gitCredentialPath: authenticated && config.kind === "enrolled-compute" && config.gitDeployKey ? "/etc/forgezero/creds/git-deploy-key.cred" : undefined,
4202
+ gitPublicKeyPath: authenticated && config.kind === "enrolled-compute" && config.gitDeployKey ? "/etc/forgezero/git/deploy.pub" : undefined,
4203
+ generateGitIdentity: authenticated && config.kind === "enrolled-compute" && config.gitDeployKey === true,
4204
+ pullDeployments: bound,
4205
+ pullMigrations: bound && config.kind === "platform",
4206
+ pullBootstrap: bound && bootstrapRunner,
4207
+ bootstrapSshCredentialPath: authenticated && bootstrapRunner ? BOOTSTRAP_SSH_CREDENTIAL : undefined,
4208
+ bootstrapSshSourcePath: enrolling && config.kind === "enrolled-compute" ? config.bootstrapRunner?.sshPrivateKeyFile : undefined,
4209
+ bootstrapSshPublicKeyPath: authenticated && bootstrapRunner ? BOOTSTRAP_SSH_PUBLIC_KEY : undefined,
4210
+ bootstrapTargetTelemetryEndpoint: bound && bootstrapRunner ? platformBootstrapRunner(config) ? config.telemetryEndpoint : config.kind === "enrolled-compute" ? config.bootstrapRunner?.targetTelemetryEndpoint : undefined : undefined,
4211
+ lifecycleProfilePath: bound && config.kind === "platform" ? LIFECYCLE_PROFILE : undefined,
4212
+ enforceEgress: true,
4213
+ nodeHostname: config.nodeHostname,
4214
+ telemetryEndpoint: config.telemetryEndpoint,
4215
+ binPath: "/usr/local/lib/forgezero/agent/fz-agent",
4216
+ sourceBinPath: PACKAGED_AGENT_BIN,
4217
+ ...enrolling ? {
4218
+ enrolTokenCredentialPath: ENROL_CREDENTIAL,
4219
+ enrolStatePath: "/var/lib/forgezero/enrolment.json"
4220
+ } : bound ? { enrolStatePath: "/var/lib/forgezero/enrolment.json" } : {},
4221
+ ...authenticated ? {
4222
+ apiUrl: config.apiUrl,
4223
+ project: config.kind === "enrolled-compute" ? config.realm : "platform",
4224
+ environment: config.kind === "enrolled-compute" ? undefined : config.environment,
4225
+ nodeLabel: config.kind === "enrolled-compute" ? config.nodeHostname : config.computeReference
4226
+ } : {}
4227
+ };
4228
+ return planInstall(options);
4229
+ }
4113
4230
  function localBootstrapHost() {
4114
4231
  const execute = async (argv2, options = {}) => {
4115
4232
  const child = Bun.spawn([...argv2], { stdin: options.stdin === undefined ? "ignore" : "pipe", stdout: "pipe", stderr: "pipe" });
@@ -4126,19 +4243,19 @@ function localBootstrapHost() {
4126
4243
  };
4127
4244
  return {
4128
4245
  uid: () => process.getuid?.() ?? -1,
4129
- exists: existsSync9,
4130
- read: (path2) => readFileSync8(path2, "utf8"),
4246
+ exists: existsSync10,
4247
+ read: (path2) => readFileSync9(path2, "utf8"),
4131
4248
  write(path2, content, mode) {
4132
- mkdirSync9(dirname8(path2), { recursive: true, mode: 493 });
4249
+ mkdirSync10(dirname9(path2), { recursive: true, mode: 493 });
4133
4250
  const temporary = `${path2}.next.${process.pid}`;
4134
- writeFileSync8(temporary, content, { mode });
4135
- chmodSync7(temporary, mode);
4136
- renameSync8(temporary, path2);
4251
+ writeFileSync9(temporary, content, { mode });
4252
+ chmodSync8(temporary, mode);
4253
+ renameSync9(temporary, path2);
4137
4254
  },
4138
- mkdir: (path2, mode) => mkdirSync9(path2, { recursive: true, mode }),
4139
- remove: (path2) => rmSync8(path2, { force: true }),
4255
+ mkdir: (path2, mode) => mkdirSync10(path2, { recursive: true, mode }),
4256
+ remove: (path2) => rmSync9(path2, { force: true }),
4140
4257
  inspect(path2) {
4141
- const value = lstatSync3(path2);
4258
+ const value = lstatSync4(path2);
4142
4259
  return { regular: value.isFile(), symbolic: value.isSymbolicLink(), uid: value.uid, mode: value.mode, links: value.nlink, size: value.size };
4143
4260
  },
4144
4261
  exec: execute,
@@ -4157,10 +4274,15 @@ function localBootstrapHost() {
4157
4274
  throw new Error(`Agent software requirements failed: ${result.output.trim()}`);
4158
4275
  return result;
4159
4276
  },
4160
- async installAgent(config) {
4277
+ async installAgent(config, phase) {
4161
4278
  const capabilities = await readCapabilities(localRunner);
4162
- const deployRoot = config.deployRoot ?? "/opt/forgezero";
4163
- const hasBinding = config.kind === "enrolled-compute" || existsSync9(ENROL_CREDENTIAL) || existsSync9("/var/lib/forgezero/enrolment.json");
4279
+ const hasBinding = existsSync10("/var/lib/forgezero/enrolment.json");
4280
+ const hasEnrolCredential = existsSync10(ENROL_CREDENTIAL);
4281
+ const initialBundle = config.kind === "platform" && !existsSync10(BOOTSTRAP_RELEASE_EVIDENCE) ? {
4282
+ path: config.bootstrapBundle.bundleFile,
4283
+ manifestPath: config.bootstrapBundle.manifestFile,
4284
+ manifest: parseBootstrapBundleManifest(JSON.parse(readFileSync9(config.bootstrapBundle.manifestFile, "utf8")))
4285
+ } : undefined;
4164
4286
  if (config.kind === "platform") {
4165
4287
  const lifecycle = config.database.role === "none" ? {
4166
4288
  apiUnits: ["forgezero@blue.service", "forgezero@green.service"],
@@ -4172,49 +4294,19 @@ function localBootstrapHost() {
4172
4294
  databaseHealthUrl: `http://${config.database.address}:8529/_api/version`,
4173
4295
  databasePorts: [8529]
4174
4296
  };
4175
- mkdirSync9(dirname8(LIFECYCLE_PROFILE), { recursive: true, mode: 493 });
4176
- writeFileSync8(LIFECYCLE_PROFILE, `${JSON.stringify(lifecycle, null, 2)}
4297
+ mkdirSync10(dirname9(LIFECYCLE_PROFILE), { recursive: true, mode: 493 });
4298
+ writeFileSync9(LIFECYCLE_PROFILE, `${JSON.stringify(lifecycle, null, 2)}
4177
4299
  `, { mode: 256 });
4178
4300
  }
4179
- const plan = planInstall({
4301
+ const plan = planBootstrapAgentInstall(config, phase, {
4180
4302
  capabilities,
4181
- socketPath: DEFAULT_SOCKET2,
4182
- seedPath: "/var/lib/forgezero/node.seed",
4183
- controlSocketPath: "/run/forgezero/control.sock",
4184
- repository: config.repository,
4185
- branch: config.branch,
4186
- profile: config.kind === "platform" ? config.profile : config.profile,
4187
- deployRoot,
4188
- deploymentCredentials: config.deploymentCredentials,
4189
- publicApiUrl: config.apiUrl,
4190
- gitCredentialPath: "/etc/forgezero/creds/git-deploy-key.cred",
4191
- gitPublicKeyPath: "/etc/forgezero/git/deploy.pub",
4192
- generateGitIdentity: true,
4193
- pullDeployments: hasBinding,
4194
- pullMigrations: config.kind === "platform" && hasBinding,
4195
- pullBootstrap: platformBootstrapRunner(config) || config.kind === "enrolled-compute" && Boolean(config.bootstrapRunner),
4196
- bootstrapSshCredentialPath: platformBootstrapRunner(config) || config.kind === "enrolled-compute" && config.bootstrapRunner ? BOOTSTRAP_SSH_CREDENTIAL : undefined,
4197
- bootstrapSshSourcePath: config.kind === "enrolled-compute" ? config.bootstrapRunner?.sshPrivateKeyFile : undefined,
4198
- bootstrapSshPublicKeyPath: platformBootstrapRunner(config) || config.kind === "enrolled-compute" && config.bootstrapRunner ? BOOTSTRAP_SSH_PUBLIC_KEY : undefined,
4199
- bootstrapTargetTelemetryEndpoint: platformBootstrapRunner(config) ? config.telemetryEndpoint : config.kind === "enrolled-compute" ? config.bootstrapRunner?.targetTelemetryEndpoint : undefined,
4200
- lifecycleProfilePath: config.kind === "platform" ? LIFECYCLE_PROFILE : undefined,
4201
- enforceEgress: true,
4202
- nodeHostname: config.nodeHostname,
4203
- telemetryEndpoint: config.telemetryEndpoint,
4204
- binPath: "/usr/local/lib/forgezero/agent/fz-agent",
4205
- sourceBinPath: PACKAGED_AGENT_BIN,
4206
- ...hasBinding ? {
4207
- enrolTokenCredentialPath: ENROL_CREDENTIAL,
4208
- enrolStatePath: "/var/lib/forgezero/enrolment.json",
4209
- apiUrl: config.apiUrl,
4210
- project: config.kind === "enrolled-compute" ? config.realm : "platform",
4211
- environment: config.kind === "enrolled-compute" ? undefined : config.environment,
4212
- nodeLabel: config.kind === "enrolled-compute" ? config.nodeHostname : config.computeReference
4213
- } : {}
4303
+ hasBinding,
4304
+ hasEnrolCredential,
4305
+ initialBundle
4214
4306
  });
4215
4307
  for (const unit2 of [{ path: plan.unitPath, unit: plan.unit }, ...plan.auxiliaryUnits]) {
4216
- mkdirSync9(dirname8(unit2.path), { recursive: true, mode: 493 });
4217
- writeFileSync8(unit2.path, unit2.unit, { mode: 420 });
4308
+ mkdirSync10(dirname9(unit2.path), { recursive: true, mode: 493 });
4309
+ writeFileSync9(unit2.path, unit2.unit, { mode: 420 });
4218
4310
  }
4219
4311
  await applyPlan(plan, localRunner);
4220
4312
  return plan;
@@ -4228,7 +4320,7 @@ var localRuntime = () => ({
4228
4320
  bootstrapStatus: () => bootstrapStatus(),
4229
4321
  characterDevice(path2) {
4230
4322
  try {
4231
- return lstatSync4(path2).isCharacterDevice();
4323
+ return lstatSync5(path2).isCharacterDevice();
4232
4324
  } catch {
4233
4325
  return false;
4234
4326
  }
@@ -92,6 +92,9 @@ export interface UnitOptions {
92
92
  controlSocketPath?: string;
93
93
  repository?: string;
94
94
  branch?: string;
95
+ /** Attended release-generation-one artifact; both coordinates are required together. */
96
+ bootstrapBundlePath?: string;
97
+ bootstrapBundleManifestPath?: string;
95
98
  profile?: string;
96
99
  deployRoot?: string;
97
100
  publicApiUrl?: string;
@@ -164,7 +167,7 @@ export declare const WARP_SERVICE_DROP_IN_PATH = "/etc/systemd/system/warp-svc.s
164
167
  export declare const AGENT_EGRESS_UNIT_PATH = "/etc/systemd/system/forgezero-agent-egress.service";
165
168
  export declare const DEFAULT_RUNNER_PUBLIC_TCP_PORTS: readonly [443];
166
169
  /** Root-owned policy monitor. The credential-bearing Agent is bound to it. */
167
- export declare function agentEgressUnit(options: Pick<UnitOptions, 'binPath' | 'user' | 'repository' | 'pullDeployments' | 'runnerLoopbackPorts' | 'runnerPublicTcpPorts'>): string;
170
+ export declare function agentEgressUnit(options: Pick<UnitOptions, 'binPath' | 'user' | 'repository' | 'pullDeployments' | 'bootstrapBundlePath' | 'bootstrapBundleManifestPath' | 'runnerLoopbackPorts' | 'runnerPublicTcpPorts'>): string;
168
171
  /** Root may execute only package-owned OS strategies selected by id + version. */
169
172
  export declare function softwareHelperUnit(options: Pick<UnitOptions, 'binPath' | 'deployRoot'>): string;
170
173
  /** Fixed root boundary for verified, health-gated Agent replacement. */