@forgezero/agent 0.1.135 → 0.1.136
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 +132 -45
- package/dist/fz.js +34 -6
- package/dist/metal-bootstrap.js +2 -1
- package/dist/metal-helper-socket.js +92 -7
- package/dist/metal-provision.d.ts +1 -0
- package/dist/metal-provision.js +90 -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.136";
|
|
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
|
|
@@ -10860,6 +10867,8 @@ function guestBootstrapOperations(profile, attested = Boolean(profile.confidenti
|
|
|
10860
10867
|
validateMetalProfile(profile);
|
|
10861
10868
|
const agentBun = "/usr/local/lib/forgezero/bun";
|
|
10862
10869
|
return [
|
|
10870
|
+
["/usr/sbin/swapoff", "--all"],
|
|
10871
|
+
["/usr/bin/systemctl", "mask", "--now", "swap.target"],
|
|
10863
10872
|
...attested ? [
|
|
10864
10873
|
["/usr/sbin/modprobe", "sev-guest"],
|
|
10865
10874
|
["/usr/bin/test", "-c", "/dev/sev-guest"]
|
|
@@ -10936,6 +10945,7 @@ ${access.sshPublicKeys.map((key) => ` - ${JSON.stringify(key)}`).join(`
|
|
|
10936
10945
|
return {
|
|
10937
10946
|
userData: `#cloud-config
|
|
10938
10947
|
package_update: true
|
|
10948
|
+
swap: { size: 0 }
|
|
10939
10949
|
${users}disable_root: true
|
|
10940
10950
|
# Git is part of the deployment transport, not a tenant-selected prerequisite:
|
|
10941
10951
|
# every dynamically claimed repository must be cloneable on a clean image.
|
|
@@ -10968,7 +10978,8 @@ var checked2 = async (exec, argv2) => {
|
|
|
10968
10978
|
async function provisionMetalGuest(profile, claim, exec) {
|
|
10969
10979
|
validateMetalProfile(profile);
|
|
10970
10980
|
assertSupportedGuestImage(claim.spec.imageKey, claim.spec.confidential);
|
|
10971
|
-
|
|
10981
|
+
const diskEncryption = claim.spec.diskEncryption ?? "none";
|
|
10982
|
+
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
10983
|
throw new MetalProvisionError("invalid compute claim");
|
|
10973
10984
|
const image = profile.images[claim.spec.imageKey];
|
|
10974
10985
|
if (!image || !isAbsolute3(image.path) || !SHA256.test(image.sha256)) {
|
|
@@ -10997,6 +11008,9 @@ async function provisionMetalGuest(profile, claim, exec) {
|
|
|
10997
11008
|
const prior = manifests.find((row2) => row2.computeKey === claim.computeKey);
|
|
10998
11009
|
if (prior && prior.reference !== claim.spec.reference)
|
|
10999
11010
|
throw new MetalProvisionError("compute identity conflicts with host inventory");
|
|
11011
|
+
if (prior && (prior.diskEncryption ?? "none") !== diskEncryption) {
|
|
11012
|
+
throw new MetalProvisionError("an allocated guest disk encryption mode is immutable");
|
|
11013
|
+
}
|
|
11000
11014
|
const address = requestedAddress(profile, claim, manifests);
|
|
11001
11015
|
const cpuPool = allocateCpuPool(profile, claim, manifests);
|
|
11002
11016
|
const manifest = prior ?? {
|
|
@@ -11008,6 +11022,7 @@ async function provisionMetalGuest(profile, claim, exec) {
|
|
|
11008
11022
|
cpuPoolKey: cpuPool.key,
|
|
11009
11023
|
allowedCpus: cpuPool.cpus,
|
|
11010
11024
|
allowedMemoryNodes: cpuPool.memoryNodes,
|
|
11025
|
+
diskEncryption,
|
|
11011
11026
|
phase: "allocating"
|
|
11012
11027
|
};
|
|
11013
11028
|
const save = () => writeFileSync6(manifestPath, `${JSON.stringify(manifest, null, 2)}
|
|
@@ -11017,8 +11032,70 @@ async function provisionMetalGuest(profile, claim, exec) {
|
|
|
11017
11032
|
const exists = (await exec(["lvs", "--noheadings", lv])).exitCode === 0;
|
|
11018
11033
|
if (!exists)
|
|
11019
11034
|
await checked2(exec, ["lvcreate", "-y", "-n", name, "-L", `${claim.spec.diskGib}G`, profile.volumeGroup]);
|
|
11035
|
+
const encrypted = diskEncryption === "luks2";
|
|
11036
|
+
const mapper = `fz-${createHash7("sha256").update(claim.computeKey).digest("hex").slice(0, 20)}`;
|
|
11037
|
+
const mappedDisk = `/dev/mapper/${mapper}`;
|
|
11038
|
+
const credentialName = `guest-disk-${createHash7("sha256").update(claim.computeKey).digest("hex").slice(0, 20)}`;
|
|
11039
|
+
const credentialPath = `/etc/forgezero/creds/${credentialName}.cred`;
|
|
11040
|
+
const keyPath = `/run/forgezero/${credentialName}.key`;
|
|
11041
|
+
let imageTarget = lv;
|
|
11042
|
+
if (encrypted) {
|
|
11043
|
+
mkdirSync5(dirname5(credentialPath), { recursive: true, mode: 448 });
|
|
11044
|
+
mkdirSync5(dirname5(keyPath), { recursive: true, mode: 448 });
|
|
11045
|
+
if (existsSync7(keyPath))
|
|
11046
|
+
unlinkSync5(keyPath);
|
|
11047
|
+
if (!existsSync7(credentialPath)) {
|
|
11048
|
+
if (exists && (await exec(["cryptsetup", "isLuks", lv])).exitCode === 0) {
|
|
11049
|
+
throw new MetalProvisionError("encrypted guest disk exists without its sealed unlock credential");
|
|
11050
|
+
}
|
|
11051
|
+
writeFileSync6(keyPath, randomBytes6(64), { mode: 384, flag: "wx" });
|
|
11052
|
+
try {
|
|
11053
|
+
await checked2(exec, ["systemd-creds", "encrypt", `--name=${credentialName}`, keyPath, credentialPath]);
|
|
11054
|
+
chmodSync8(credentialPath, 384);
|
|
11055
|
+
} catch (cause) {
|
|
11056
|
+
if (existsSync7(credentialPath))
|
|
11057
|
+
unlinkSync5(credentialPath);
|
|
11058
|
+
throw cause;
|
|
11059
|
+
}
|
|
11060
|
+
} else {
|
|
11061
|
+
await checked2(exec, ["systemd-creds", "decrypt", `--name=${credentialName}`, credentialPath, keyPath]);
|
|
11062
|
+
}
|
|
11063
|
+
try {
|
|
11064
|
+
if ((await exec(["cryptsetup", "isLuks", lv])).exitCode !== 0) {
|
|
11065
|
+
await checked2(exec, [
|
|
11066
|
+
"cryptsetup",
|
|
11067
|
+
"luksFormat",
|
|
11068
|
+
"--batch-mode",
|
|
11069
|
+
"--type",
|
|
11070
|
+
"luks2",
|
|
11071
|
+
"--cipher",
|
|
11072
|
+
"aes-xts-plain64",
|
|
11073
|
+
"--key-size",
|
|
11074
|
+
"512",
|
|
11075
|
+
"--key-file",
|
|
11076
|
+
keyPath,
|
|
11077
|
+
lv
|
|
11078
|
+
]);
|
|
11079
|
+
}
|
|
11080
|
+
if ((await exec(["cryptsetup", "status", mapper])).exitCode !== 0) {
|
|
11081
|
+
await checked2(exec, ["cryptsetup", "open", "--type", "luks2", "--key-file", keyPath, lv, mapper]);
|
|
11082
|
+
}
|
|
11083
|
+
imageTarget = mappedDisk;
|
|
11084
|
+
if (manifest.phase === "allocating") {
|
|
11085
|
+
await checked2(exec, ["qemu-img", "convert", "-O", "raw", image.path, imageTarget]);
|
|
11086
|
+
manifest.phase = "image-ready";
|
|
11087
|
+
save();
|
|
11088
|
+
}
|
|
11089
|
+
} finally {
|
|
11090
|
+
if (existsSync7(keyPath))
|
|
11091
|
+
unlinkSync5(keyPath);
|
|
11092
|
+
if ((await exec(["cryptsetup", "status", mapper])).exitCode === 0) {
|
|
11093
|
+
await checked2(exec, ["cryptsetup", "close", mapper]);
|
|
11094
|
+
}
|
|
11095
|
+
}
|
|
11096
|
+
}
|
|
11020
11097
|
if (manifest.phase === "allocating") {
|
|
11021
|
-
await checked2(exec, ["qemu-img", "convert", "-O", "raw", image.path,
|
|
11098
|
+
await checked2(exec, ["qemu-img", "convert", "-O", "raw", image.path, imageTarget]);
|
|
11022
11099
|
manifest.phase = "image-ready";
|
|
11023
11100
|
save();
|
|
11024
11101
|
}
|
|
@@ -11042,7 +11119,8 @@ async function provisionMetalGuest(profile, claim, exec) {
|
|
|
11042
11119
|
memoryGib: claim.spec.memoryGib,
|
|
11043
11120
|
allowedCpus: manifest.allowedCpus,
|
|
11044
11121
|
allowedMemoryNodes: manifest.allowedMemoryNodes,
|
|
11045
|
-
disk: lv,
|
|
11122
|
+
disk: encrypted ? mappedDisk : lv,
|
|
11123
|
+
...encrypted ? { diskEncryption: { source: lv, mapper, credentialName, credentialPath } } : {},
|
|
11046
11124
|
seed,
|
|
11047
11125
|
bridge: profile.bridge,
|
|
11048
11126
|
mac: manifest.mac,
|
|
@@ -11100,6 +11178,7 @@ function legacyPlatformManifest(profile, claim, name) {
|
|
|
11100
11178
|
cpuPoolKey: claim.spec.cpuPoolKey ?? "",
|
|
11101
11179
|
allowedCpus: values.get("CPUSET") ?? "",
|
|
11102
11180
|
allowedMemoryNodes: values.get("NUMA"),
|
|
11181
|
+
diskEncryption: "none",
|
|
11103
11182
|
phase: "running",
|
|
11104
11183
|
disk,
|
|
11105
11184
|
unit: `forgezero-guest@${name}.service`
|
|
@@ -11114,6 +11193,9 @@ async function removeMetalGuest(profile, claim, exec) {
|
|
|
11114
11193
|
const service = `forgezero-guest@${name}.service`;
|
|
11115
11194
|
const unitPath = join4(profile.unitDir, service);
|
|
11116
11195
|
const lv = `/dev/${profile.volumeGroup}/${name}`;
|
|
11196
|
+
const mapper = `fz-${createHash7("sha256").update(claim.computeKey).digest("hex").slice(0, 20)}`;
|
|
11197
|
+
const credentialName = `guest-disk-${createHash7("sha256").update(claim.computeKey).digest("hex").slice(0, 20)}`;
|
|
11198
|
+
const credentialPath = `/etc/forgezero/creds/${credentialName}.cred`;
|
|
11117
11199
|
const manifest = existsSync7(manifestPath) ? JSON.parse(readFileSync6(manifestPath, "utf8")) : legacyPlatformManifest(profile, claim, name);
|
|
11118
11200
|
if (!manifest) {
|
|
11119
11201
|
const seedBase = join4(profile.seedDir, name);
|
|
@@ -11148,9 +11230,14 @@ async function removeMetalGuest(profile, claim, exec) {
|
|
|
11148
11230
|
else if ((await exec(["systemctl", "is-active", service])).exitCode === 0) {
|
|
11149
11231
|
throw new MetalProvisionError("guest unit is active but its owned unit file is missing");
|
|
11150
11232
|
}
|
|
11233
|
+
const encrypted = (manifest.diskEncryption ?? "none") === "luks2";
|
|
11234
|
+
if (encrypted && (await exec(["cryptsetup", "status", mapper])).exitCode === 0) {
|
|
11235
|
+
throw new MetalProvisionError("guest disk mapping remained active after the guest stopped");
|
|
11236
|
+
}
|
|
11151
11237
|
if ((await exec(["lvs", "--noheadings", lv])).exitCode === 0)
|
|
11152
11238
|
await checked2(exec, ["lvremove", "-fy", lv]);
|
|
11153
11239
|
for (const path2 of [
|
|
11240
|
+
...encrypted ? [credentialPath] : [],
|
|
11154
11241
|
unitPath,
|
|
11155
11242
|
join4(profile.seedDir, `${name}-seed.iso`),
|
|
11156
11243
|
join4(profile.seedDir, `${name}-user-data`),
|
|
@@ -11251,7 +11338,7 @@ function startMetalHelper(options) {
|
|
|
11251
11338
|
});
|
|
11252
11339
|
socket.on("error", () => socket.destroy());
|
|
11253
11340
|
});
|
|
11254
|
-
server.listen(socketPath, () =>
|
|
11341
|
+
server.listen(socketPath, () => chmodSync9(socketPath, 432));
|
|
11255
11342
|
return {
|
|
11256
11343
|
server,
|
|
11257
11344
|
async stop() {
|
|
@@ -11291,7 +11378,7 @@ function requestMetalProvision(claim, socketPath = DEFAULT_METAL_HELPER_SOCKET)
|
|
|
11291
11378
|
}
|
|
11292
11379
|
|
|
11293
11380
|
// src/deployment-runner.ts
|
|
11294
|
-
import { chmodSync as
|
|
11381
|
+
import { chmodSync as chmodSync10, existsSync as existsSync9, realpathSync, unlinkSync as unlinkSync7 } from "fs";
|
|
11295
11382
|
import { isAbsolute as isAbsolute4, resolve, sep } from "path";
|
|
11296
11383
|
import { connect as connect3, createServer as createServer4 } from "net";
|
|
11297
11384
|
var DEFAULT_DEPLOYMENT_RUNNER_SOCKET = "/run/forgezero-deploy/runner.sock";
|
|
@@ -11453,7 +11540,7 @@ function startDeploymentRunner(options) {
|
|
|
11453
11540
|
const ready = new Promise((resolveReady, rejectReady) => {
|
|
11454
11541
|
server.once("error", rejectReady);
|
|
11455
11542
|
server.listen(socketPath, () => {
|
|
11456
|
-
|
|
11543
|
+
chmodSync10(socketPath, options.socketMode ?? 432);
|
|
11457
11544
|
server.off("error", rejectReady);
|
|
11458
11545
|
resolveReady();
|
|
11459
11546
|
});
|
|
@@ -11805,7 +11892,7 @@ async function closeServerWithin(server, timeoutMs) {
|
|
|
11805
11892
|
}
|
|
11806
11893
|
|
|
11807
11894
|
// src/lifecycle-helper.ts
|
|
11808
|
-
import { chmodSync as
|
|
11895
|
+
import { chmodSync as chmodSync11, existsSync as existsSync11, readFileSync as readFileSync7, unlinkSync as unlinkSync8 } from "fs";
|
|
11809
11896
|
import { connect as connect4, createConnection, createServer as createServer5, isIP as isIP3 } from "net";
|
|
11810
11897
|
var DEFAULT_LIFECYCLE_HELPER_SOCKET = "/run/forgezero-lifecycle/helper.sock";
|
|
11811
11898
|
var MAX_REQUEST_BYTES4 = 16 * 1024;
|
|
@@ -11987,7 +12074,7 @@ function startLifecycleHelper(options) {
|
|
|
11987
12074
|
});
|
|
11988
12075
|
socket.on("error", () => socket.destroy());
|
|
11989
12076
|
});
|
|
11990
|
-
server.listen(socketPath, () =>
|
|
12077
|
+
server.listen(socketPath, () => chmodSync11(socketPath, 432));
|
|
11991
12078
|
return {
|
|
11992
12079
|
server,
|
|
11993
12080
|
async stop() {
|
|
@@ -12027,7 +12114,7 @@ function requestLifecycleAction(claim, socketPath = DEFAULT_LIFECYCLE_HELPER_SOC
|
|
|
12027
12114
|
}
|
|
12028
12115
|
|
|
12029
12116
|
// src/warp-config.ts
|
|
12030
|
-
import { chmodSync as
|
|
12117
|
+
import { chmodSync as chmodSync12, mkdirSync as mkdirSync7, renameSync as renameSync6, symlinkSync as symlinkSync3, unlinkSync as unlinkSync9, writeFileSync as writeFileSync8 } from "fs";
|
|
12031
12118
|
var xml = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
12032
12119
|
function renderWarpMdm(options) {
|
|
12033
12120
|
if (!/^[a-z0-9][a-z0-9-]{0,62}$/i.test(options.organization))
|
|
@@ -12052,7 +12139,7 @@ function materializeWarpMdm(options) {
|
|
|
12052
12139
|
mkdirSync7(servicePath.replace(/\/[^/]+$/, ""), { recursive: true, mode: 448 });
|
|
12053
12140
|
const next = `${runtimePath}.next`;
|
|
12054
12141
|
writeFileSync8(next, renderWarpMdm(options), { mode: 384 });
|
|
12055
|
-
|
|
12142
|
+
chmodSync12(next, 384);
|
|
12056
12143
|
renameSync6(next, runtimePath);
|
|
12057
12144
|
try {
|
|
12058
12145
|
unlinkSync9(servicePath);
|
|
@@ -12110,7 +12197,7 @@ async function configureMeshConnector(input) {
|
|
|
12110
12197
|
// src/agent-update.ts
|
|
12111
12198
|
import { createHash as createHash8, timingSafeEqual, randomUUID as randomUUID2 } from "crypto";
|
|
12112
12199
|
import {
|
|
12113
|
-
chmodSync as
|
|
12200
|
+
chmodSync as chmodSync13,
|
|
12114
12201
|
closeSync as closeSync2,
|
|
12115
12202
|
existsSync as existsSync12,
|
|
12116
12203
|
fsyncSync,
|
|
@@ -12204,8 +12291,8 @@ var checked4 = async (run2, input, label) => {
|
|
|
12204
12291
|
return result;
|
|
12205
12292
|
};
|
|
12206
12293
|
async function validateReleaseDirectory(directory, release, run2) {
|
|
12207
|
-
|
|
12208
|
-
|
|
12294
|
+
chmodSync13(directory, 493);
|
|
12295
|
+
chmodSync13(join7(directory, "dist"), 493);
|
|
12209
12296
|
const manifest = JSON.parse(readFileSync9(join7(directory, "package.json"), "utf8"));
|
|
12210
12297
|
if (manifest.name !== release.package || manifest.version !== release.version) {
|
|
12211
12298
|
throw new Error("agent update manifest does not match the selected release");
|
|
@@ -12218,7 +12305,7 @@ async function validateReleaseDirectory(directory, release, run2) {
|
|
|
12218
12305
|
`)) {
|
|
12219
12306
|
throw new Error("agent update artifact is not a self-contained Bun executable");
|
|
12220
12307
|
}
|
|
12221
|
-
|
|
12308
|
+
chmodSync13(binary, 493);
|
|
12222
12309
|
}
|
|
12223
12310
|
const version = (await checked4(run2, { command: agent, args: ["--version"] }, "agent update smoke test")).output.trim();
|
|
12224
12311
|
if (version !== release.version)
|
|
@@ -12337,7 +12424,7 @@ function clearAgentCandidate(root = DEFAULT_AGENT_RELEASE_ROOT) {
|
|
|
12337
12424
|
// src/agent-update-helper.ts
|
|
12338
12425
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
12339
12426
|
import {
|
|
12340
|
-
chmodSync as
|
|
12427
|
+
chmodSync as chmodSync15,
|
|
12341
12428
|
closeSync as closeSync3,
|
|
12342
12429
|
existsSync as existsSync14,
|
|
12343
12430
|
fsyncSync as fsyncSync2,
|
|
@@ -12354,7 +12441,7 @@ import { dirname as dirname8, join as join8, resolve as resolve3 } from "path";
|
|
|
12354
12441
|
|
|
12355
12442
|
// src/agent-handover.ts
|
|
12356
12443
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
12357
|
-
import { chmodSync as
|
|
12444
|
+
import { chmodSync as chmodSync14, existsSync as existsSync13, renameSync as renameSync8, rmSync as rmSync6, symlinkSync as symlinkSync5, unlinkSync as unlinkSync10 } from "fs";
|
|
12358
12445
|
import { basename as basename2, dirname as dirname7 } from "path";
|
|
12359
12446
|
import { connect as connect5, createServer as createServer6 } from "net";
|
|
12360
12447
|
var DEFAULT_AGENT_CANDIDATE_READY_SOCKET = "/run/forgezero/candidate-ready.sock";
|
|
@@ -12375,7 +12462,7 @@ function startAgentCandidateReady(ready, socketPath = DEFAULT_AGENT_CANDIDATE_RE
|
|
|
12375
12462
|
unlinkSync10(socketPath);
|
|
12376
12463
|
const server = createServer6((socket) => socket.end(`${JSON.stringify(ready)}
|
|
12377
12464
|
`));
|
|
12378
|
-
server.listen(socketPath, () =>
|
|
12465
|
+
server.listen(socketPath, () => chmodSync14(socketPath, 432));
|
|
12379
12466
|
return server;
|
|
12380
12467
|
}
|
|
12381
12468
|
function probeAgentCandidate(expected, socketPath = DEFAULT_AGENT_CANDIDATE_READY_SOCKET, timeoutMs = 5000) {
|
|
@@ -12928,7 +13015,7 @@ function startAgentUpdateHelper(options = {}) {
|
|
|
12928
13015
|
});
|
|
12929
13016
|
socket.on("error", () => socket.destroy());
|
|
12930
13017
|
});
|
|
12931
|
-
server.listen(socketPath, () =>
|
|
13018
|
+
server.listen(socketPath, () => chmodSync15(socketPath, 432));
|
|
12932
13019
|
return server;
|
|
12933
13020
|
}
|
|
12934
13021
|
function requestAgentUpdate(request, socketPath = DEFAULT_AGENT_UPDATE_SOCKET, timeoutMs = 90000) {
|
|
@@ -13145,7 +13232,7 @@ function startAgentHeartbeat(options) {
|
|
|
13145
13232
|
}
|
|
13146
13233
|
|
|
13147
13234
|
// src/software-helper.ts
|
|
13148
|
-
import { chmodSync as
|
|
13235
|
+
import { chmodSync as chmodSync16, existsSync as existsSync18, mkdirSync as mkdirSync13, unlinkSync as unlinkSync12 } from "fs";
|
|
13149
13236
|
import { connect as connect7, createServer as createServer8 } from "net";
|
|
13150
13237
|
import { dirname as dirname12 } from "path";
|
|
13151
13238
|
|
|
@@ -14133,7 +14220,7 @@ function startSoftwareHelper(options = {}) {
|
|
|
14133
14220
|
});
|
|
14134
14221
|
socket.on("error", () => socket.destroy());
|
|
14135
14222
|
});
|
|
14136
|
-
server.listen(socketPath, () =>
|
|
14223
|
+
server.listen(socketPath, () => chmodSync16(socketPath, 432));
|
|
14137
14224
|
return server;
|
|
14138
14225
|
}
|
|
14139
14226
|
function requestContainer(op, request, socketPath, timeoutMs) {
|
|
@@ -15218,7 +15305,7 @@ var METAL_SYSTEMD_CREDENTIALS = {
|
|
|
15218
15305
|
|
|
15219
15306
|
// src/platform-bootstrap-runtime.ts
|
|
15220
15307
|
import {
|
|
15221
|
-
chmodSync as
|
|
15308
|
+
chmodSync as chmodSync17,
|
|
15222
15309
|
chownSync,
|
|
15223
15310
|
copyFileSync as copyFileSync2,
|
|
15224
15311
|
existsSync as existsSync19,
|
|
@@ -15317,7 +15404,7 @@ var secureRelease = (path2, uid, gid) => {
|
|
|
15317
15404
|
if (metadata.isSymbolicLink())
|
|
15318
15405
|
return;
|
|
15319
15406
|
chownSync(current2, uid, gid);
|
|
15320
|
-
|
|
15407
|
+
chmodSync17(current2, metadata.isDirectory() ? 365 : 292);
|
|
15321
15408
|
if (metadata.isDirectory())
|
|
15322
15409
|
for (const name of readdirSync4(current2))
|
|
15323
15410
|
visit(join10(current2, name));
|
|
@@ -15558,7 +15645,7 @@ import { lstatSync as lstatSync7 } from "fs";
|
|
|
15558
15645
|
|
|
15559
15646
|
// src/bootstrap.ts
|
|
15560
15647
|
import {
|
|
15561
|
-
chmodSync as
|
|
15648
|
+
chmodSync as chmodSync19,
|
|
15562
15649
|
existsSync as existsSync22,
|
|
15563
15650
|
lstatSync as lstatSync6,
|
|
15564
15651
|
mkdirSync as mkdirSync16,
|
|
@@ -16559,9 +16646,9 @@ function planProvision(options) {
|
|
|
16559
16646
|
}
|
|
16560
16647
|
|
|
16561
16648
|
// src/cli/agent-install.ts
|
|
16562
|
-
import { randomBytes as
|
|
16649
|
+
import { randomBytes as randomBytes7 } from "crypto";
|
|
16563
16650
|
import {
|
|
16564
|
-
chmodSync as
|
|
16651
|
+
chmodSync as chmodSync18,
|
|
16565
16652
|
copyFileSync as copyFileSync3,
|
|
16566
16653
|
existsSync as existsSync21,
|
|
16567
16654
|
lstatSync as lstatSync5,
|
|
@@ -16652,12 +16739,12 @@ var runProvisionOperation = async (operation) => {
|
|
|
16652
16739
|
mkdirSync15(`${release}/dist`, { recursive: true, mode: 493 });
|
|
16653
16740
|
mkdirSync15(dirname13(operation.binary), { recursive: true, mode: 493 });
|
|
16654
16741
|
copyFileSync3(operation.source, `${release}/dist/fz-agent.js`);
|
|
16655
|
-
|
|
16742
|
+
chmodSync18(`${release}/dist/fz-agent.js`, 493);
|
|
16656
16743
|
const gitSshSource = `${dirname13(operation.source)}/fz-git-ssh.js`;
|
|
16657
16744
|
if (!existsSync21(gitSshSource))
|
|
16658
16745
|
return { stdout: "packaged fz-git-ssh.js is missing", exitCode: 1 };
|
|
16659
16746
|
copyFileSync3(gitSshSource, `${release}/dist/fz-git-ssh.js`);
|
|
16660
|
-
|
|
16747
|
+
chmodSync18(`${release}/dist/fz-git-ssh.js`, 493);
|
|
16661
16748
|
const pending = "/opt/forgezero/agent/current.next";
|
|
16662
16749
|
rmSync11(pending, { force: true });
|
|
16663
16750
|
symlinkSync7(`versions/${operation.version}`, pending);
|
|
@@ -16672,10 +16759,10 @@ var runProvisionOperation = async (operation) => {
|
|
|
16672
16759
|
if (operation.kind === "ensure-seed") {
|
|
16673
16760
|
if (existsSync21(operation.credential) && lstatSync5(operation.credential).size > 0)
|
|
16674
16761
|
return { stdout: "", exitCode: 0 };
|
|
16675
|
-
const seed =
|
|
16762
|
+
const seed = randomBytes7(32).toString("base64url");
|
|
16676
16763
|
const result = await fixed(["/usr/bin/systemd-creds", "encrypt", "--name=agent-seed", "-", operation.credential], seed);
|
|
16677
16764
|
if (result.exitCode === 0)
|
|
16678
|
-
|
|
16765
|
+
chmodSync18(operation.credential, 256);
|
|
16679
16766
|
return result;
|
|
16680
16767
|
}
|
|
16681
16768
|
if (operation.kind === "ensure-git-identity") {
|
|
@@ -16691,7 +16778,7 @@ var runProvisionOperation = async (operation) => {
|
|
|
16691
16778
|
result = await fixed(["/usr/bin/systemd-creds", "encrypt", "--name=git-deploy-key", key, operation.credential]);
|
|
16692
16779
|
if (result.exitCode !== 0)
|
|
16693
16780
|
return result;
|
|
16694
|
-
|
|
16781
|
+
chmodSync18(operation.credential, 256);
|
|
16695
16782
|
}
|
|
16696
16783
|
if (!existsSync21(operation.publicKey) || lstatSync5(operation.publicKey).size < 1) {
|
|
16697
16784
|
if (!existsSync21(key)) {
|
|
@@ -16725,7 +16812,7 @@ var runProvisionOperation = async (operation) => {
|
|
|
16725
16812
|
return { stdout: "bootstrap SSH private-key source is missing or unsafe", exitCode: 1 };
|
|
16726
16813
|
}
|
|
16727
16814
|
copyFileSync3(operation.source, key);
|
|
16728
|
-
|
|
16815
|
+
chmodSync18(key, 384);
|
|
16729
16816
|
} else {
|
|
16730
16817
|
result = await fixed(["/usr/bin/ssh-keygen", "-q", "-t", "ed25519", "-N", "", "-C", "forgezero-bootstrap-runner", "-f", key]);
|
|
16731
16818
|
if (result.exitCode !== 0)
|
|
@@ -16738,14 +16825,14 @@ var runProvisionOperation = async (operation) => {
|
|
|
16738
16825
|
result = await fixed(["/usr/bin/systemd-creds", "encrypt", "--name=bootstrap-ssh-key", key, operation.credential]);
|
|
16739
16826
|
if (result.exitCode !== 0)
|
|
16740
16827
|
return result;
|
|
16741
|
-
|
|
16828
|
+
chmodSync18(operation.credential, 256);
|
|
16742
16829
|
}
|
|
16743
16830
|
if (!existsSync21(operation.publicKey) || lstatSync5(operation.publicKey).size < 1) {
|
|
16744
16831
|
if (!existsSync21(key)) {
|
|
16745
16832
|
const decrypted = await fixed(["/usr/bin/systemd-creds", "decrypt", "--name=bootstrap-ssh-key", operation.credential, key]);
|
|
16746
16833
|
if (decrypted.exitCode !== 0)
|
|
16747
16834
|
return decrypted;
|
|
16748
|
-
|
|
16835
|
+
chmodSync18(key, 384);
|
|
16749
16836
|
}
|
|
16750
16837
|
const derived = await fixed(["/usr/bin/ssh-keygen", "-y", "-f", key]);
|
|
16751
16838
|
const publicKey = normalizeEd25519PublicKey(derived.stdout);
|
|
@@ -16755,7 +16842,7 @@ var runProvisionOperation = async (operation) => {
|
|
|
16755
16842
|
mkdirSync15(dirname13(operation.publicKey), { recursive: true, mode: 493 });
|
|
16756
16843
|
writeFileSync15(operation.publicKey, `${publicKey} forgezero-bootstrap-runner
|
|
16757
16844
|
`, { mode: 292 });
|
|
16758
|
-
|
|
16845
|
+
chmodSync18(operation.publicKey, 292);
|
|
16759
16846
|
}
|
|
16760
16847
|
if (operation.source)
|
|
16761
16848
|
rmSync11(operation.source, { force: true });
|
|
@@ -16772,7 +16859,7 @@ var runProvisionOperation = async (operation) => {
|
|
|
16772
16859
|
return { stdout: "enrolment source is missing", exitCode: 1 };
|
|
16773
16860
|
const result = await fixed(["/usr/bin/systemd-creds", "encrypt", "--name=enrol-token", operation.source, operation.credential]);
|
|
16774
16861
|
if (result.exitCode === 0) {
|
|
16775
|
-
|
|
16862
|
+
chmodSync18(operation.credential, 256);
|
|
16776
16863
|
rmSync11(operation.source, { force: true });
|
|
16777
16864
|
}
|
|
16778
16865
|
return result;
|
|
@@ -17158,7 +17245,7 @@ function localBootstrapHost() {
|
|
|
17158
17245
|
mkdirSync16(dirname14(path2), { recursive: true, mode: 493 });
|
|
17159
17246
|
const temporary = `${path2}.next.${process.pid}`;
|
|
17160
17247
|
writeFileSync16(temporary, content, { mode });
|
|
17161
|
-
|
|
17248
|
+
chmodSync19(temporary, mode);
|
|
17162
17249
|
renameSync15(temporary, path2);
|
|
17163
17250
|
},
|
|
17164
17251
|
mkdir: (path2, mode) => mkdirSync16(path2, { recursive: true, mode }),
|
|
@@ -18034,9 +18121,9 @@ function loadOrCreateSeed(path2) {
|
|
|
18034
18121
|
return seed2;
|
|
18035
18122
|
}
|
|
18036
18123
|
mkdirSync18(dirname16(path2), { recursive: true });
|
|
18037
|
-
const seed = new Uint8Array(
|
|
18124
|
+
const seed = new Uint8Array(randomBytes8(32));
|
|
18038
18125
|
writeFileSync18(path2, Buffer.from(seed).toString("base64url"), { mode: 384 });
|
|
18039
|
-
|
|
18126
|
+
chmodSync20(path2, 384);
|
|
18040
18127
|
return seed;
|
|
18041
18128
|
}
|
|
18042
18129
|
var DEFAULT_SOCKET_PATH = DEFAULT_SOCKET;
|