@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.
package/dist/provision.js CHANGED
@@ -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] },
@@ -31,7 +31,8 @@ var SOFTWARE_CATALOG = [
31
31
  { id: "cloudflared", version: "2026.7.3", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
32
32
  { id: "cloudflare-warp", version: "2026.6.822.0-min", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
33
33
  { id: "ufw", version: "ubuntu-26.04", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
34
- { id: "openssh-client", version: "ubuntu-26.04", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" }
34
+ { id: "openssh-client", version: "ubuntu-26.04", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
35
+ { id: "git", version: "ubuntu-26.04", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" }
35
36
  ];
36
37
  var UBUNTU_2604_X64 = [
37
38
  { requirement: { id: "bun", version: "1.3.14" } },
@@ -41,7 +42,8 @@ var UBUNTU_2604_X64 = [
41
42
  { requirement: { id: "cloudflared", version: "2026.7.3" } },
42
43
  { requirement: { id: "cloudflare-warp", version: "2026.6.822.0-min" } },
43
44
  { requirement: { id: "ufw", version: "ubuntu-26.04" } },
44
- { requirement: { id: "openssh-client", version: "ubuntu-26.04" } }
45
+ { requirement: { id: "openssh-client", version: "ubuntu-26.04" } },
46
+ { requirement: { id: "git", version: "ubuntu-26.04" } }
45
47
  ];
46
48
  var path = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
47
49
  var DOCKER_DAEMON_PATH = "/etc/docker/daemon.json";
@@ -128,7 +130,7 @@ async function executeSoftwareOperation(operation) {
128
130
  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]);
129
131
  return { ...result, exitCode: result.exitCode === 0 && supported ? 0 : 1 };
130
132
  });
131
- const binaries = software === "ufw" ? ["/usr/sbin/ufw"] : ["/usr/bin/ssh", "/usr/bin/scp", "/usr/bin/ssh-keyscan", "/usr/bin/ssh-keygen"];
133
+ 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"];
132
134
  try {
133
135
  binaries.forEach((binary) => accessSync(binary));
134
136
  return { exitCode: 0, output: "" };
@@ -136,7 +138,7 @@ async function executeSoftwareOperation(operation) {
136
138
  return { exitCode: 1, output: cause instanceof Error ? cause.message : String(cause) };
137
139
  }
138
140
  }
139
- if (software === "docker" || software === "nginx" || software === "ufw" || software === "openssh-client") {
141
+ if (software === "docker" || software === "nginx" || software === "ufw" || software === "openssh-client" || software === "git") {
140
142
  const packageName = software === "openssh-client" ? "openssh-client" : software === "docker" ? "docker.io" : software;
141
143
  const installed = await aptInstall(packageName);
142
144
  if (installed.exitCode !== 0 || software !== "nginx" && software !== "docker")
@@ -236,7 +238,7 @@ function validateSoftwareRequirements(value, _options = {}) {
236
238
  if (Object.keys(row).some((key) => key !== "id" && key !== "version")) {
237
239
  throw new Error("software requirement contains an unknown field");
238
240
  }
239
- 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)) {
241
+ 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)) {
240
242
  throw new Error("software requirement coordinate is invalid");
241
243
  }
242
244
  const requirement = { id: row.id, version: row.version };
@@ -1,6 +1,6 @@
1
1
  export type CatalogStatus = 'testing' | 'active' | 'retired';
2
2
  export type DeploymentChannel = 'development' | 'production';
3
- export type SoftwareId = 'bun' | 'docker' | 'nginx' | 'arangodb' | 'cloudflared' | 'cloudflare-warp' | 'ufw' | 'openssh-client';
3
+ export type SoftwareId = 'bun' | 'docker' | 'nginx' | 'arangodb' | 'cloudflared' | 'cloudflare-warp' | 'ufw' | 'openssh-client' | 'git';
4
4
  /** Repository input is a catalogue coordinate, never a root command. */
5
5
  export interface SoftwareRequirement {
6
6
  id: SoftwareId;
package/dist/software.js CHANGED
@@ -31,7 +31,8 @@ var SOFTWARE_CATALOG = [
31
31
  { id: "cloudflared", version: "2026.7.3", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
32
32
  { id: "cloudflare-warp", version: "2026.6.822.0-min", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
33
33
  { id: "ufw", version: "ubuntu-26.04", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
34
- { id: "openssh-client", version: "ubuntu-26.04", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" }
34
+ { id: "openssh-client", version: "ubuntu-26.04", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
35
+ { id: "git", version: "ubuntu-26.04", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" }
35
36
  ];
36
37
  var UBUNTU_2604_X64 = [
37
38
  { requirement: { id: "bun", version: "1.3.14" } },
@@ -41,7 +42,8 @@ var UBUNTU_2604_X64 = [
41
42
  { requirement: { id: "cloudflared", version: "2026.7.3" } },
42
43
  { requirement: { id: "cloudflare-warp", version: "2026.6.822.0-min" } },
43
44
  { requirement: { id: "ufw", version: "ubuntu-26.04" } },
44
- { requirement: { id: "openssh-client", version: "ubuntu-26.04" } }
45
+ { requirement: { id: "openssh-client", version: "ubuntu-26.04" } },
46
+ { requirement: { id: "git", version: "ubuntu-26.04" } }
45
47
  ];
46
48
  var path = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
47
49
  var DOCKER_DAEMON_PATH = "/etc/docker/daemon.json";
@@ -128,7 +130,7 @@ async function executeSoftwareOperation(operation) {
128
130
  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]);
129
131
  return { ...result, exitCode: result.exitCode === 0 && supported ? 0 : 1 };
130
132
  });
131
- const binaries = software === "ufw" ? ["/usr/sbin/ufw"] : ["/usr/bin/ssh", "/usr/bin/scp", "/usr/bin/ssh-keyscan", "/usr/bin/ssh-keygen"];
133
+ 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"];
132
134
  try {
133
135
  binaries.forEach((binary) => accessSync(binary));
134
136
  return { exitCode: 0, output: "" };
@@ -136,7 +138,7 @@ async function executeSoftwareOperation(operation) {
136
138
  return { exitCode: 1, output: cause instanceof Error ? cause.message : String(cause) };
137
139
  }
138
140
  }
139
- if (software === "docker" || software === "nginx" || software === "ufw" || software === "openssh-client") {
141
+ if (software === "docker" || software === "nginx" || software === "ufw" || software === "openssh-client" || software === "git") {
140
142
  const packageName = software === "openssh-client" ? "openssh-client" : software === "docker" ? "docker.io" : software;
141
143
  const installed = await aptInstall(packageName);
142
144
  if (installed.exitCode !== 0 || software !== "nginx" && software !== "docker")
@@ -236,7 +238,7 @@ function validateSoftwareRequirements(value, _options = {}) {
236
238
  if (Object.keys(row).some((key) => key !== "id" && key !== "version")) {
237
239
  throw new Error("software requirement contains an unknown field");
238
240
  }
239
- 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)) {
241
+ 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)) {
240
242
  throw new Error("software requirement coordinate is invalid");
241
243
  }
242
244
  const requirement = { id: row.id, version: row.version };
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.62";
2
+ export declare const VERSION = "0.1.64";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forgezero/agent",
3
- "version": "0.1.62",
3
+ "version": "0.1.64",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "check": "tsc --noEmit",
@@ -56,6 +56,10 @@
56
56
  },
57
57
  "bugs": "https://github.com/forgezero-net/packages/issues",
58
58
  "exports": {
59
+ "./bootstrap-bundle": {
60
+ "types": "./dist/bootstrap-bundle.d.ts",
61
+ "default": "./dist/bootstrap-bundle.js"
62
+ },
59
63
  "./provision": {
60
64
  "types": "./dist/provision.d.ts",
61
65
  "default": "./dist/provision.js"