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