@forgezero/agent 0.1.62 → 0.1.63
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/README.md +36 -11
- package/dist/agent-heartbeat.js +1 -1
- package/dist/bootstrap-bundle.d.ts +31 -0
- package/dist/bootstrap-bundle.js +165 -0
- package/dist/bootstrap.d.ts +7 -17
- package/dist/bootstrap.js +407 -214
- package/dist/cli/agent-install.d.ts +2 -0
- package/dist/community-rehearsal-host.js +7 -5
- package/dist/definition.js +7 -5
- package/dist/deploy-file.js +7 -5
- package/dist/deployment.d.ts +16 -0
- package/dist/fz-agent.js +486 -363
- package/dist/fz.js +499 -305
- package/dist/metal-bootstrap.js +1 -1
- package/dist/metal-helper-socket.js +0 -2
- package/dist/metal-provision.js +0 -2
- package/dist/operator-bootstrap.d.ts +1 -1
- package/dist/operator-bootstrap.js +509 -307
- package/dist/platform-bootstrap-runtime.d.ts +0 -2
- package/dist/platform-bootstrap-runtime.js +0 -4
- package/dist/platform-fleet-verification.js +110 -44
- package/dist/provision.d.ts +4 -1
- package/dist/provision.js +15 -7
- package/dist/software-helper.js +7 -5
- package/dist/software.d.ts +1 -1
- package/dist/software.js +7 -5
- package/dist/version.d.ts +1 -1
- package/package.json +5 -1
|
@@ -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.
|
|
2091
|
+
var VERSION3 = "0.1.63";
|
|
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
|
|
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) {
|
|
@@ -2685,6 +2691,8 @@ function agentUnit(options) {
|
|
|
2685
2691
|
options.gitPublicKeyPath ? `FZ_GIT_PUBLIC_KEY_FILE=${options.gitPublicKeyPath}` : null,
|
|
2686
2692
|
options.repository ? `FZ_DEPLOY_REPO=${options.repository}` : null,
|
|
2687
2693
|
options.branch ? `FZ_DEPLOY_BRANCH=${options.branch}` : null,
|
|
2694
|
+
options.bootstrapBundlePath ? `FZ_BOOTSTRAP_BUNDLE=${options.bootstrapBundlePath}` : null,
|
|
2695
|
+
options.bootstrapBundleManifestPath ? `FZ_BOOTSTRAP_BUNDLE_MANIFEST=${options.bootstrapBundleManifestPath}` : null,
|
|
2688
2696
|
options.profile ? `FZ_DEPLOY_PROFILE=${options.profile}` : null,
|
|
2689
2697
|
options.repository && options.branch ? `FZ_DEPLOY_KEY=${options.project ?? "platform"}:${options.environment ?? "production"}` : null,
|
|
2690
2698
|
deploymentEnabled ? `FZ_DEPLOY_ROOT=${deployRoot}` : null,
|
|
@@ -3168,8 +3176,6 @@ function validatePlatformSharedEnvironment(input) {
|
|
|
3168
3176
|
databaseUser: input.databaseUser,
|
|
3169
3177
|
sharedDirectory: input.sharedDirectory,
|
|
3170
3178
|
seedSyncEpoch: input.seedSyncEpoch,
|
|
3171
|
-
repository: input.repository,
|
|
3172
|
-
branch: input.branch,
|
|
3173
3179
|
deployProfile: input.deployProfile
|
|
3174
3180
|
}))
|
|
3175
3181
|
safeAtom(name, value);
|
|
@@ -3252,8 +3258,6 @@ function renderPlatformSharedEnvironment(input) {
|
|
|
3252
3258
|
FZ_AGENT_OTLP_ENDPOINT: value.agentOtlpEndpoint,
|
|
3253
3259
|
FZ_CUSTODIAN_EMAIL: value.custodianEmail ?? "",
|
|
3254
3260
|
FZ_PROFILE: value.deployProfile,
|
|
3255
|
-
FZ_REPO: value.repository,
|
|
3256
|
-
FZ_BRANCH: value.branch,
|
|
3257
3261
|
FZ_EMAIL_PROVIDER: value.email?.provider ?? "",
|
|
3258
3262
|
FZ_SMTP_HOST: value.email?.provider === "smtp" ? value.email.host : "",
|
|
3259
3263
|
FZ_SMTP_PORT: value.email?.provider === "smtp" ? String(value.email.port) : "",
|
|
@@ -3592,21 +3596,21 @@ function planLocalOtlpProof(endpoint, collectorUnit) {
|
|
|
3592
3596
|
}
|
|
3593
3597
|
|
|
3594
3598
|
// src/platform-fleet-verification.ts
|
|
3595
|
-
import { lstatSync as
|
|
3599
|
+
import { lstatSync as lstatSync5 } from "node:fs";
|
|
3596
3600
|
|
|
3597
3601
|
// src/bootstrap.ts
|
|
3598
|
-
import { createHash as
|
|
3602
|
+
import { createHash as createHash6, createHmac as createHmac2, randomBytes as randomBytes3 } from "node:crypto";
|
|
3599
3603
|
import {
|
|
3600
|
-
chmodSync as
|
|
3601
|
-
existsSync as
|
|
3602
|
-
lstatSync as
|
|
3603
|
-
mkdirSync as
|
|
3604
|
-
readFileSync as
|
|
3605
|
-
renameSync as
|
|
3606
|
-
rmSync as
|
|
3607
|
-
writeFileSync as
|
|
3604
|
+
chmodSync as chmodSync8,
|
|
3605
|
+
existsSync as existsSync10,
|
|
3606
|
+
lstatSync as lstatSync4,
|
|
3607
|
+
mkdirSync as mkdirSync10,
|
|
3608
|
+
readFileSync as readFileSync9,
|
|
3609
|
+
renameSync as renameSync9,
|
|
3610
|
+
rmSync as rmSync9,
|
|
3611
|
+
writeFileSync as writeFileSync9
|
|
3608
3612
|
} from "node:fs";
|
|
3609
|
-
import { dirname as
|
|
3613
|
+
import { dirname as dirname9 } from "node:path";
|
|
3610
3614
|
import { fileURLToPath } from "node:url";
|
|
3611
3615
|
|
|
3612
3616
|
// src/cli/agent-install.ts
|
|
@@ -3918,6 +3922,58 @@ var UNIT = `/etc/systemd/system/${FORGEZERO_OTEL_COLLECTOR_UNIT}`;
|
|
|
3918
3922
|
|
|
3919
3923
|
// src/bootstrap.ts
|
|
3920
3924
|
import { DEFAULT_SOCKET as DEFAULT_SOCKET2 } from "@forgezero/vault";
|
|
3925
|
+
|
|
3926
|
+
// src/bootstrap-bundle.ts
|
|
3927
|
+
import { createHash as createHash5, randomBytes as randomBytes2 } from "node:crypto";
|
|
3928
|
+
import {
|
|
3929
|
+
chmodSync as chmodSync7,
|
|
3930
|
+
createReadStream,
|
|
3931
|
+
existsSync as existsSync9,
|
|
3932
|
+
lstatSync as lstatSync3,
|
|
3933
|
+
mkdirSync as mkdirSync9,
|
|
3934
|
+
readFileSync as readFileSync8,
|
|
3935
|
+
renameSync as renameSync8,
|
|
3936
|
+
rmSync as rmSync8,
|
|
3937
|
+
writeFileSync as writeFileSync8
|
|
3938
|
+
} from "node:fs";
|
|
3939
|
+
import { dirname as dirname8, isAbsolute, resolve as resolve6 } from "node:path";
|
|
3940
|
+
var BOOTSTRAP_BUNDLE_FORMAT = 1;
|
|
3941
|
+
var BOOTSTRAP_BUNDLE_KIND = "forgezero-api-git-bundle";
|
|
3942
|
+
var MAX_BOOTSTRAP_BUNDLE_BYTES = 512 * 1024 * 1024;
|
|
3943
|
+
var branchName = (value) => {
|
|
3944
|
+
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("-")) {
|
|
3945
|
+
throw new Error("bootstrap bundle branch is malformed");
|
|
3946
|
+
}
|
|
3947
|
+
return value;
|
|
3948
|
+
};
|
|
3949
|
+
function parseBootstrapBundleManifest(value) {
|
|
3950
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
3951
|
+
throw new Error("bootstrap bundle manifest must be an object");
|
|
3952
|
+
const source = value;
|
|
3953
|
+
const allowed = ["format", "kind", "branch", "revision", "sha256", "bytes", "createdAt"];
|
|
3954
|
+
const unknown = Object.keys(source).filter((key) => !allowed.includes(key));
|
|
3955
|
+
if (unknown.length)
|
|
3956
|
+
throw new Error(`bootstrap bundle manifest contains unknown field ${unknown[0]}`);
|
|
3957
|
+
if (source.format !== BOOTSTRAP_BUNDLE_FORMAT || source.kind !== BOOTSTRAP_BUNDLE_KIND) {
|
|
3958
|
+
throw new Error("bootstrap bundle manifest format is unsupported");
|
|
3959
|
+
}
|
|
3960
|
+
branchName(source.branch);
|
|
3961
|
+
if (typeof source.revision !== "string" || !/^[a-f0-9]{40}$/.test(source.revision)) {
|
|
3962
|
+
throw new Error("bootstrap bundle revision must be an exact lowercase Git commit");
|
|
3963
|
+
}
|
|
3964
|
+
if (typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256)) {
|
|
3965
|
+
throw new Error("bootstrap bundle digest is malformed");
|
|
3966
|
+
}
|
|
3967
|
+
if (!Number.isSafeInteger(source.bytes) || Number(source.bytes) < 1 || Number(source.bytes) > MAX_BOOTSTRAP_BUNDLE_BYTES) {
|
|
3968
|
+
throw new Error("bootstrap bundle size is outside the supported boundary");
|
|
3969
|
+
}
|
|
3970
|
+
if (typeof source.createdAt !== "string" || Number.isNaN(Date.parse(source.createdAt))) {
|
|
3971
|
+
throw new Error("bootstrap bundle creation time is malformed");
|
|
3972
|
+
}
|
|
3973
|
+
return source;
|
|
3974
|
+
}
|
|
3975
|
+
|
|
3976
|
+
// src/bootstrap.ts
|
|
3921
3977
|
var platformBootstrapRunner = (config) => config.kind === "platform" && config.database.role === "master";
|
|
3922
3978
|
var BOOTSTRAP_STATE_PATH = "/var/lib/forgezero/bootstrap.json";
|
|
3923
3979
|
var STATE_PATH = BOOTSTRAP_STATE_PATH;
|
|
@@ -3934,6 +3990,7 @@ var SEED_CREDENTIAL = `${CREDS}/seed-sync-root.cred`;
|
|
|
3934
3990
|
var BACKUP_RECOVERY_CREDENTIAL = `${CREDS}/backup-recovery-root.cred`;
|
|
3935
3991
|
var BOOTSTRAP_SSH_CREDENTIAL = `${CREDS}/bootstrap-ssh-key.cred`;
|
|
3936
3992
|
var BOOTSTRAP_SSH_PUBLIC_KEY = "/etc/forgezero/bootstrap/runner.pub";
|
|
3993
|
+
var BOOTSTRAP_RELEASE_EVIDENCE = "/var/lib/forgezero/bootstrap-release.json";
|
|
3937
3994
|
var LIFECYCLE_PROFILE = "/etc/forgezero/lifecycle.json";
|
|
3938
3995
|
var CONTROL_SOCKET = "/run/forgezero/control.sock";
|
|
3939
3996
|
var CLOUDFLARED_METRICS_ADDRESS = "127.0.0.1:20241";
|
|
@@ -4126,19 +4183,19 @@ function localBootstrapHost() {
|
|
|
4126
4183
|
};
|
|
4127
4184
|
return {
|
|
4128
4185
|
uid: () => process.getuid?.() ?? -1,
|
|
4129
|
-
exists:
|
|
4130
|
-
read: (path2) =>
|
|
4186
|
+
exists: existsSync10,
|
|
4187
|
+
read: (path2) => readFileSync9(path2, "utf8"),
|
|
4131
4188
|
write(path2, content, mode) {
|
|
4132
|
-
|
|
4189
|
+
mkdirSync10(dirname9(path2), { recursive: true, mode: 493 });
|
|
4133
4190
|
const temporary = `${path2}.next.${process.pid}`;
|
|
4134
|
-
|
|
4135
|
-
|
|
4136
|
-
|
|
4191
|
+
writeFileSync9(temporary, content, { mode });
|
|
4192
|
+
chmodSync8(temporary, mode);
|
|
4193
|
+
renameSync9(temporary, path2);
|
|
4137
4194
|
},
|
|
4138
|
-
mkdir: (path2, mode) =>
|
|
4139
|
-
remove: (path2) =>
|
|
4195
|
+
mkdir: (path2, mode) => mkdirSync10(path2, { recursive: true, mode }),
|
|
4196
|
+
remove: (path2) => rmSync9(path2, { force: true }),
|
|
4140
4197
|
inspect(path2) {
|
|
4141
|
-
const value =
|
|
4198
|
+
const value = lstatSync4(path2);
|
|
4142
4199
|
return { regular: value.isFile(), symbolic: value.isSymbolicLink(), uid: value.uid, mode: value.mode, links: value.nlink, size: value.size };
|
|
4143
4200
|
},
|
|
4144
4201
|
exec: execute,
|
|
@@ -4160,7 +4217,12 @@ function localBootstrapHost() {
|
|
|
4160
4217
|
async installAgent(config) {
|
|
4161
4218
|
const capabilities = await readCapabilities(localRunner);
|
|
4162
4219
|
const deployRoot = config.deployRoot ?? "/opt/forgezero";
|
|
4163
|
-
const hasBinding =
|
|
4220
|
+
const hasBinding = existsSync10("/var/lib/forgezero/enrolment.json");
|
|
4221
|
+
const initialBundle = config.kind === "platform" && !existsSync10(BOOTSTRAP_RELEASE_EVIDENCE) ? {
|
|
4222
|
+
path: config.bootstrapBundle.bundleFile,
|
|
4223
|
+
manifestPath: config.bootstrapBundle.manifestFile,
|
|
4224
|
+
manifest: parseBootstrapBundleManifest(JSON.parse(readFileSync9(config.bootstrapBundle.manifestFile, "utf8")))
|
|
4225
|
+
} : undefined;
|
|
4164
4226
|
if (config.kind === "platform") {
|
|
4165
4227
|
const lifecycle = config.database.role === "none" ? {
|
|
4166
4228
|
apiUnits: ["forgezero@blue.service", "forgezero@green.service"],
|
|
@@ -4172,8 +4234,8 @@ function localBootstrapHost() {
|
|
|
4172
4234
|
databaseHealthUrl: `http://${config.database.address}:8529/_api/version`,
|
|
4173
4235
|
databasePorts: [8529]
|
|
4174
4236
|
};
|
|
4175
|
-
|
|
4176
|
-
|
|
4237
|
+
mkdirSync10(dirname9(LIFECYCLE_PROFILE), { recursive: true, mode: 493 });
|
|
4238
|
+
writeFileSync9(LIFECYCLE_PROFILE, `${JSON.stringify(lifecycle, null, 2)}
|
|
4177
4239
|
`, { mode: 256 });
|
|
4178
4240
|
}
|
|
4179
4241
|
const plan = planInstall({
|
|
@@ -4181,15 +4243,17 @@ function localBootstrapHost() {
|
|
|
4181
4243
|
socketPath: DEFAULT_SOCKET2,
|
|
4182
4244
|
seedPath: "/var/lib/forgezero/node.seed",
|
|
4183
4245
|
controlSocketPath: "/run/forgezero/control.sock",
|
|
4184
|
-
repository: config.repository,
|
|
4185
|
-
branch: config.branch,
|
|
4246
|
+
repository: initialBundle?.path ?? (config.kind === "enrolled-compute" ? config.repository : undefined),
|
|
4247
|
+
branch: initialBundle?.manifest.branch ?? (config.kind === "enrolled-compute" ? config.branch : undefined),
|
|
4248
|
+
bootstrapBundlePath: initialBundle?.path,
|
|
4249
|
+
bootstrapBundleManifestPath: initialBundle?.manifestPath,
|
|
4186
4250
|
profile: config.kind === "platform" ? config.profile : config.profile,
|
|
4187
4251
|
deployRoot,
|
|
4188
4252
|
deploymentCredentials: config.deploymentCredentials,
|
|
4189
4253
|
publicApiUrl: config.apiUrl,
|
|
4190
|
-
gitCredentialPath: "/etc/forgezero/creds/git-deploy-key.cred",
|
|
4191
|
-
gitPublicKeyPath: "/etc/forgezero/git/deploy.pub",
|
|
4192
|
-
generateGitIdentity: true,
|
|
4254
|
+
gitCredentialPath: config.kind === "enrolled-compute" && config.gitDeployKey ? "/etc/forgezero/creds/git-deploy-key.cred" : undefined,
|
|
4255
|
+
gitPublicKeyPath: config.kind === "enrolled-compute" && config.gitDeployKey ? "/etc/forgezero/git/deploy.pub" : undefined,
|
|
4256
|
+
generateGitIdentity: config.kind === "enrolled-compute" && config.gitDeployKey === true,
|
|
4193
4257
|
pullDeployments: hasBinding,
|
|
4194
4258
|
pullMigrations: config.kind === "platform" && hasBinding,
|
|
4195
4259
|
pullBootstrap: platformBootstrapRunner(config) || config.kind === "enrolled-compute" && Boolean(config.bootstrapRunner),
|
|
@@ -4203,9 +4267,11 @@ function localBootstrapHost() {
|
|
|
4203
4267
|
telemetryEndpoint: config.telemetryEndpoint,
|
|
4204
4268
|
binPath: "/usr/local/lib/forgezero/agent/fz-agent",
|
|
4205
4269
|
sourceBinPath: PACKAGED_AGENT_BIN,
|
|
4270
|
+
...existsSync10(ENROL_CREDENTIAL) || hasBinding ? {
|
|
4271
|
+
enrolTokenCredentialPath: existsSync10(ENROL_CREDENTIAL) ? ENROL_CREDENTIAL : undefined,
|
|
4272
|
+
enrolStatePath: "/var/lib/forgezero/enrolment.json"
|
|
4273
|
+
} : {},
|
|
4206
4274
|
...hasBinding ? {
|
|
4207
|
-
enrolTokenCredentialPath: ENROL_CREDENTIAL,
|
|
4208
|
-
enrolStatePath: "/var/lib/forgezero/enrolment.json",
|
|
4209
4275
|
apiUrl: config.apiUrl,
|
|
4210
4276
|
project: config.kind === "enrolled-compute" ? config.realm : "platform",
|
|
4211
4277
|
environment: config.kind === "enrolled-compute" ? undefined : config.environment,
|
|
@@ -4213,8 +4279,8 @@ function localBootstrapHost() {
|
|
|
4213
4279
|
} : {}
|
|
4214
4280
|
});
|
|
4215
4281
|
for (const unit2 of [{ path: plan.unitPath, unit: plan.unit }, ...plan.auxiliaryUnits]) {
|
|
4216
|
-
|
|
4217
|
-
|
|
4282
|
+
mkdirSync10(dirname9(unit2.path), { recursive: true, mode: 493 });
|
|
4283
|
+
writeFileSync9(unit2.path, unit2.unit, { mode: 420 });
|
|
4218
4284
|
}
|
|
4219
4285
|
await applyPlan(plan, localRunner);
|
|
4220
4286
|
return plan;
|
|
@@ -4228,7 +4294,7 @@ var localRuntime = () => ({
|
|
|
4228
4294
|
bootstrapStatus: () => bootstrapStatus(),
|
|
4229
4295
|
characterDevice(path2) {
|
|
4230
4296
|
try {
|
|
4231
|
-
return
|
|
4297
|
+
return lstatSync5(path2).isCharacterDevice();
|
|
4232
4298
|
} catch {
|
|
4233
4299
|
return false;
|
|
4234
4300
|
}
|
package/dist/provision.d.ts
CHANGED
|
@@ -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. */
|
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.
|
|
2091
|
+
var VERSION3 = "0.1.63";
|
|
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
|
|
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) {
|
|
@@ -2685,6 +2691,8 @@ function agentUnit(options) {
|
|
|
2685
2691
|
options.gitPublicKeyPath ? `FZ_GIT_PUBLIC_KEY_FILE=${options.gitPublicKeyPath}` : null,
|
|
2686
2692
|
options.repository ? `FZ_DEPLOY_REPO=${options.repository}` : null,
|
|
2687
2693
|
options.branch ? `FZ_DEPLOY_BRANCH=${options.branch}` : null,
|
|
2694
|
+
options.bootstrapBundlePath ? `FZ_BOOTSTRAP_BUNDLE=${options.bootstrapBundlePath}` : null,
|
|
2695
|
+
options.bootstrapBundleManifestPath ? `FZ_BOOTSTRAP_BUNDLE_MANIFEST=${options.bootstrapBundleManifestPath}` : null,
|
|
2688
2696
|
options.profile ? `FZ_DEPLOY_PROFILE=${options.profile}` : null,
|
|
2689
2697
|
options.repository && options.branch ? `FZ_DEPLOY_KEY=${options.project ?? "platform"}:${options.environment ?? "production"}` : null,
|
|
2690
2698
|
deploymentEnabled ? `FZ_DEPLOY_ROOT=${deployRoot}` : null,
|
package/dist/software-helper.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/software.d.ts
CHANGED
|
@@ -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.
|
|
2
|
+
export declare const VERSION = "0.1.63";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forgezero/agent",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.63",
|
|
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"
|