@forgezero/agent 0.1.65 → 0.1.67
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 +745 -157
- package/dist/agent-heartbeat.js +1 -1
- package/dist/bootstrap-bundle.d.ts +1 -0
- package/dist/bootstrap-bundle.js +4 -3
- package/dist/bootstrap.d.ts +7 -1
- package/dist/bootstrap.js +264 -13
- package/dist/community-rehearsal-host.d.ts +12 -0
- package/dist/community-rehearsal-host.js +99 -36
- package/dist/definition.js +41 -4
- package/dist/deploy-compiler.js +4 -4
- package/dist/deploy-file.js +41 -4
- package/dist/deploy-plan-runner.js +4 -4
- package/dist/deploy-plan.js +4 -4
- package/dist/fz-agent.js +165 -76
- package/dist/fz.js +487 -251
- package/dist/index.d.ts +1 -1
- package/dist/metal-bootstrap.js +120 -46
- package/dist/metal-helper-socket.js +406 -65
- package/dist/metal-provision.js +402 -61
- package/dist/operator-bootstrap.d.ts +20 -4
- package/dist/operator-bootstrap.js +429 -203
- package/dist/platform-bootstrap-runtime.d.ts +33 -0
- package/dist/platform-bootstrap-runtime.js +551 -44
- package/dist/platform-fleet-verification.js +242 -18
- package/dist/platform-genesis-config.d.ts +7 -1
- package/dist/platform-genesis.d.ts +16 -17
- package/dist/platform-genesis.js +464 -0
- package/dist/provision.js +42 -5
- package/dist/software-helper.js +41 -4
- package/dist/software.d.ts +8 -2
- package/dist/software.js +41 -4
- package/dist/ssh-bootstrap.d.ts +5 -0
- package/dist/ubuntu.d.ts +15 -14
- package/dist/ubuntu.js +345 -9
- package/dist/version.d.ts +1 -1
- package/package.json +8 -4
|
@@ -699,7 +699,30 @@ var BUN_RELEASE_SHA256 = "951ee2aee855f08595aeec6225226a298d3fea83a3dcd6465c09cb
|
|
|
699
699
|
var ARANGO_SHA256 = "b5a9197b4343f2ed554e1ebc1ef8e6529c7c39cde0035cdc311a4747a3355066";
|
|
700
700
|
var CLOUDFLARED_SHA256 = "9d71c677db00134c1bd4144b7783486b654ad281b1ea62b4972098d19f770f17";
|
|
701
701
|
var OS_CATALOG = [
|
|
702
|
-
{
|
|
702
|
+
{
|
|
703
|
+
id: "ubuntu",
|
|
704
|
+
version: "26.04",
|
|
705
|
+
architecture: "x64",
|
|
706
|
+
status: "active",
|
|
707
|
+
imageKey: "ubuntu-resolute-20260731",
|
|
708
|
+
imageLabel: "Ubuntu 26.04 LTS Resolute",
|
|
709
|
+
imageVersion: "2026-07-31",
|
|
710
|
+
imageUrl: "https://cloud-images.ubuntu.com/releases/resolute/release-20260731/ubuntu-26.04-server-cloudimg-amd64.img",
|
|
711
|
+
imageSha256: "9dc7c5363c0146a08ba0c9aa834d82c2c6dfbb1c471ad9a2f0aba1189e21be05",
|
|
712
|
+
confidentialModes: ["sev-snp"]
|
|
713
|
+
},
|
|
714
|
+
{
|
|
715
|
+
id: "ubuntu",
|
|
716
|
+
version: "24.04",
|
|
717
|
+
architecture: "x64",
|
|
718
|
+
status: "active",
|
|
719
|
+
imageKey: "ubuntu-noble-20260705",
|
|
720
|
+
imageLabel: "Ubuntu 24.04 LTS Noble",
|
|
721
|
+
imageVersion: "2026-07-05",
|
|
722
|
+
imageUrl: "https://cloud-images.ubuntu.com/releases/noble/release-20260705/ubuntu-24.04-server-cloudimg-amd64.img",
|
|
723
|
+
imageSha256: "ffe6203da54deeb6db5d2a98a83f9ec8e55f149d3f7ba622e1abe5fa966ee3d6",
|
|
724
|
+
confidentialModes: []
|
|
725
|
+
}
|
|
703
726
|
];
|
|
704
727
|
var SOFTWARE_CATALOG = [
|
|
705
728
|
{ id: "bun", version: "1.3.14", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
|
|
@@ -710,7 +733,12 @@ var SOFTWARE_CATALOG = [
|
|
|
710
733
|
{ id: "cloudflare-warp", version: "2026.6.822.0-min", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
|
|
711
734
|
{ id: "ufw", version: "ubuntu-26.04", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
|
|
712
735
|
{ 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" }
|
|
736
|
+
{ id: "git", version: "ubuntu-26.04", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
|
|
737
|
+
{ id: "docker", version: "ubuntu-24.04", status: "active", os: "ubuntu", osVersion: "24.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
|
|
738
|
+
{ id: "nginx", version: "ubuntu-24.04", status: "active", os: "ubuntu", osVersion: "24.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
|
|
739
|
+
{ id: "ufw", version: "ubuntu-24.04", status: "active", os: "ubuntu", osVersion: "24.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
|
|
740
|
+
{ id: "openssh-client", version: "ubuntu-24.04", status: "active", os: "ubuntu", osVersion: "24.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
|
|
741
|
+
{ id: "git", version: "ubuntu-24.04", status: "active", os: "ubuntu", osVersion: "24.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" }
|
|
714
742
|
];
|
|
715
743
|
var UBUNTU_2604_X64 = [
|
|
716
744
|
{ requirement: { id: "bun", version: "1.3.14" } },
|
|
@@ -723,6 +751,15 @@ var UBUNTU_2604_X64 = [
|
|
|
723
751
|
{ requirement: { id: "openssh-client", version: "ubuntu-26.04" } },
|
|
724
752
|
{ requirement: { id: "git", version: "ubuntu-26.04" } }
|
|
725
753
|
];
|
|
754
|
+
var UBUNTU_2404_X64 = [
|
|
755
|
+
{ requirement: { id: "bun", version: "1.3.14" } },
|
|
756
|
+
{ requirement: { id: "docker", version: "ubuntu-24.04" } },
|
|
757
|
+
{ requirement: { id: "nginx", version: "ubuntu-24.04" } },
|
|
758
|
+
{ requirement: { id: "ufw", version: "ubuntu-24.04" } },
|
|
759
|
+
{ requirement: { id: "openssh-client", version: "ubuntu-24.04" } },
|
|
760
|
+
{ requirement: { id: "git", version: "ubuntu-24.04" } }
|
|
761
|
+
];
|
|
762
|
+
var strategiesFor = (observation) => observation.os.id === "ubuntu" && observation.architecture === "x64" ? observation.os.versionId === "26.04" ? UBUNTU_2604_X64 : observation.os.versionId === "24.04" ? UBUNTU_2404_X64 : undefined : undefined;
|
|
726
763
|
var path = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
|
|
727
764
|
var DOCKER_DAEMON_PATH = "/etc/docker/daemon.json";
|
|
728
765
|
var DOCKER_DAEMON_CONFIG = `${JSON.stringify({
|
|
@@ -769,7 +806,7 @@ var aptInstall = async (name) => {
|
|
|
769
806
|
};
|
|
770
807
|
async function executeSoftwareOperation(operation) {
|
|
771
808
|
const { software, version } = operation;
|
|
772
|
-
if (!UBUNTU_2604_X64.some(({ requirement }) => requirement.id === software && requirement.version === version)) {
|
|
809
|
+
if (![...UBUNTU_2604_X64, ...UBUNTU_2404_X64].some(({ requirement }) => requirement.id === software && requirement.version === version)) {
|
|
773
810
|
return { exitCode: 2, output: "unsupported software operation" };
|
|
774
811
|
}
|
|
775
812
|
if (operation.kind === "check") {
|
|
@@ -939,7 +976,7 @@ async function ensureSoftwareRequirements(requirementsInput, options) {
|
|
|
939
976
|
}
|
|
940
977
|
const results = [];
|
|
941
978
|
for (const requirement of requirements) {
|
|
942
|
-
const strategy =
|
|
979
|
+
const strategy = strategiesFor(observation)?.find(({ requirement: candidate }) => candidate.id === requirement.id && candidate.version === requirement.version);
|
|
943
980
|
if (!strategy)
|
|
944
981
|
throw new Error(`unsupported software requirement: ${requirement.id}@${requirement.version}`);
|
|
945
982
|
const before = await options.exec({ kind: "check", software: requirement.id, version: requirement.version });
|
|
@@ -2088,7 +2125,7 @@ function requestSoftware(requirements, socketPath = DEFAULT_SOFTWARE_HELPER_SOCK
|
|
|
2088
2125
|
}
|
|
2089
2126
|
|
|
2090
2127
|
// src/version.ts
|
|
2091
|
-
var VERSION3 = "0.1.
|
|
2128
|
+
var VERSION3 = "0.1.67";
|
|
2092
2129
|
|
|
2093
2130
|
// src/egress-policy.ts
|
|
2094
2131
|
import { realpathSync as realpathSync3 } from "node:fs";
|
|
@@ -3075,6 +3112,146 @@ function planProvision(options) {
|
|
|
3075
3112
|
};
|
|
3076
3113
|
}
|
|
3077
3114
|
|
|
3115
|
+
// src/ubuntu.ts
|
|
3116
|
+
var current = OS_CATALOG[0];
|
|
3117
|
+
var SUPPORTED_GUEST_IMAGE = Object.freeze({
|
|
3118
|
+
key: current.imageKey,
|
|
3119
|
+
family: `${current.id}-${current.version}`,
|
|
3120
|
+
version: current.imageVersion,
|
|
3121
|
+
label: current.imageLabel,
|
|
3122
|
+
url: current.imageUrl,
|
|
3123
|
+
sha256: current.imageSha256
|
|
3124
|
+
});
|
|
3125
|
+
var SUPPORTED_GUEST_IMAGES = Object.freeze(OS_CATALOG.filter(({ status }) => status === "active").map(({ id, imageKey, imageLabel, imageVersion, version, confidentialModes }) => ({
|
|
3126
|
+
key: imageKey,
|
|
3127
|
+
label: imageLabel,
|
|
3128
|
+
family: `${id}-${version}`,
|
|
3129
|
+
version: imageVersion,
|
|
3130
|
+
confidential: confidentialModes.some((mode) => mode === "sev-snp")
|
|
3131
|
+
})));
|
|
3132
|
+
function supportedGuestImage(imageKey) {
|
|
3133
|
+
return SUPPORTED_GUEST_IMAGES.find(({ key }) => key === imageKey);
|
|
3134
|
+
}
|
|
3135
|
+
function assertSupportedGuestImage(imageKey, confidential = false) {
|
|
3136
|
+
const selected = OS_CATALOG.find((entry) => entry.status === "active" && entry.imageKey === imageKey);
|
|
3137
|
+
if (!selected) {
|
|
3138
|
+
throw new Error(`unsupported guest image ${imageKey}; supported images: ${SUPPORTED_GUEST_IMAGES.map(({ key }) => key).join(", ")}`);
|
|
3139
|
+
}
|
|
3140
|
+
if (confidential && !selected.confidentialModes.some((mode) => mode === "sev-snp")) {
|
|
3141
|
+
throw new Error(`guest image ${imageKey} is not approved for SEV-SNP`);
|
|
3142
|
+
}
|
|
3143
|
+
}
|
|
3144
|
+
|
|
3145
|
+
// src/platform-genesis.ts
|
|
3146
|
+
var SAFE_NAME = /^[a-z][a-z0-9-]{0,62}$/;
|
|
3147
|
+
var SAFE_POOL = /^[A-Za-z0-9][A-Za-z0-9._-]{0,62}$/;
|
|
3148
|
+
var PRIVATE_V4 = /^(?:10\.(?:\d{1,3}\.){2}\d{1,3}|192\.168\.(?:\d{1,3})\.(?:\d{1,3})|172\.(?:1[6-9]|2\d|3[01])\.(?:\d{1,3})\.(?:\d{1,3}))$/;
|
|
3149
|
+
var integer = (value, minimum, maximum, label) => {
|
|
3150
|
+
if (!Number.isInteger(value) || value < minimum || value > maximum) {
|
|
3151
|
+
throw new Error(`platform genesis ${label} is outside the supported range`);
|
|
3152
|
+
}
|
|
3153
|
+
return value;
|
|
3154
|
+
};
|
|
3155
|
+
function validatePlatformGenesisGuests(guests, expectedCount = 3) {
|
|
3156
|
+
if (!Array.isArray(guests) || guests.length !== expectedCount) {
|
|
3157
|
+
throw new Error(`platform genesis requires exactly ${expectedCount} reviewed guest requests`);
|
|
3158
|
+
}
|
|
3159
|
+
const names = new Set;
|
|
3160
|
+
const addresses = new Set;
|
|
3161
|
+
const pools = new Set;
|
|
3162
|
+
return guests.map((input) => {
|
|
3163
|
+
if (!input || typeof input !== "object" || !SAFE_NAME.test(input.name)) {
|
|
3164
|
+
throw new Error("platform genesis guest name is malformed");
|
|
3165
|
+
}
|
|
3166
|
+
if (!PRIVATE_V4.test(input.address))
|
|
3167
|
+
throw new Error("platform genesis guest address must be private IPv4");
|
|
3168
|
+
if (typeof input.confidential !== "boolean")
|
|
3169
|
+
throw new Error("platform genesis confidential requirement is missing");
|
|
3170
|
+
assertSupportedGuestImage(input.imageKey, input.confidential);
|
|
3171
|
+
if (input.cpuPoolKey !== undefined && !SAFE_POOL.test(input.cpuPoolKey)) {
|
|
3172
|
+
throw new Error("platform genesis CPU pool key is malformed");
|
|
3173
|
+
}
|
|
3174
|
+
if (names.has(input.name) || addresses.has(input.address) || input.cpuPoolKey !== undefined && pools.has(input.cpuPoolKey)) {
|
|
3175
|
+
throw new Error("platform genesis guest names, addresses and explicit CPU pools must be unique");
|
|
3176
|
+
}
|
|
3177
|
+
names.add(input.name);
|
|
3178
|
+
addresses.add(input.address);
|
|
3179
|
+
if (input.cpuPoolKey !== undefined)
|
|
3180
|
+
pools.add(input.cpuPoolKey);
|
|
3181
|
+
const physicalCores = integer(input.physicalCores, 1, 256, "physical core count");
|
|
3182
|
+
const vcpu = integer(input.vcpu, 1, 512, "vCPU count");
|
|
3183
|
+
if (vcpu < physicalCores)
|
|
3184
|
+
throw new Error("platform genesis vCPU count cannot be smaller than physical cores");
|
|
3185
|
+
const memoryGib = integer(input.memoryGib, 1, 8192, "memory");
|
|
3186
|
+
const diskGib = integer(input.diskGib, 8, 65536, "disk");
|
|
3187
|
+
const egressGuaranteedMbps = integer(input.egressGuaranteedMbps, 0, 1e6, "guaranteed egress");
|
|
3188
|
+
const egressBurstMbps = integer(input.egressBurstMbps, egressGuaranteedMbps, 1e6, "burst egress");
|
|
3189
|
+
return {
|
|
3190
|
+
name: input.name,
|
|
3191
|
+
address: input.address,
|
|
3192
|
+
imageKey: input.imageKey,
|
|
3193
|
+
...input.cpuPoolKey ? { cpuPoolKey: input.cpuPoolKey } : {},
|
|
3194
|
+
physicalCores,
|
|
3195
|
+
vcpu,
|
|
3196
|
+
memoryGib,
|
|
3197
|
+
diskGib,
|
|
3198
|
+
egressGuaranteedMbps,
|
|
3199
|
+
egressBurstMbps,
|
|
3200
|
+
confidential: input.confidential
|
|
3201
|
+
};
|
|
3202
|
+
});
|
|
3203
|
+
}
|
|
3204
|
+
var publicKey = (value) => {
|
|
3205
|
+
const normalized = value.trim();
|
|
3206
|
+
if (!/^ssh-(?:ed25519|rsa) [A-Za-z0-9+/]+={0,3}(?: [^\r\n]+)?$/.test(normalized)) {
|
|
3207
|
+
throw new Error("platform genesis SSH public key is malformed");
|
|
3208
|
+
}
|
|
3209
|
+
return normalized;
|
|
3210
|
+
};
|
|
3211
|
+
var claimFor = (guest, keys, action) => {
|
|
3212
|
+
const common = {
|
|
3213
|
+
computeKey: `platform:${guest.name}`,
|
|
3214
|
+
claimToken: "offline-platform-genesis",
|
|
3215
|
+
claimExpiresAtTs: Number.MAX_SAFE_INTEGER,
|
|
3216
|
+
attempt: 1,
|
|
3217
|
+
bootstrap: { kind: "platform-genesis" },
|
|
3218
|
+
spec: {
|
|
3219
|
+
reference: `platform:${guest.name}`,
|
|
3220
|
+
imageKey: guest.imageKey,
|
|
3221
|
+
guestName: guest.name,
|
|
3222
|
+
guestAddress: guest.address,
|
|
3223
|
+
...guest.cpuPoolKey ? { cpuPoolKey: guest.cpuPoolKey } : {},
|
|
3224
|
+
physicalCores: guest.physicalCores,
|
|
3225
|
+
vcpu: guest.vcpu,
|
|
3226
|
+
memoryGib: guest.memoryGib,
|
|
3227
|
+
diskGib: guest.diskGib,
|
|
3228
|
+
egressGuaranteedMbps: guest.egressGuaranteedMbps,
|
|
3229
|
+
egressBurstMbps: guest.egressBurstMbps,
|
|
3230
|
+
confidential: guest.confidential
|
|
3231
|
+
}
|
|
3232
|
+
};
|
|
3233
|
+
if (action === "delete")
|
|
3234
|
+
return { ...common, action: "delete" };
|
|
3235
|
+
return { ...common, action: "create", access: { sshUser: "forgezero", sshPublicKeys: [...keys] } };
|
|
3236
|
+
};
|
|
3237
|
+
function platformGenesisClaims(guests, sshPublicKeys) {
|
|
3238
|
+
const reviewed = validatePlatformGenesisGuests(guests);
|
|
3239
|
+
const keys = [...new Set(sshPublicKeys.map(publicKey))];
|
|
3240
|
+
if (keys.length === 0)
|
|
3241
|
+
throw new Error("platform genesis requires at least one operator SSH public key");
|
|
3242
|
+
return reviewed.map((guest) => claimFor(guest, keys, "create"));
|
|
3243
|
+
}
|
|
3244
|
+
function platformCommunityRehearsalClaims(seedGuests, rehearsalGuest, sshPublicKeys) {
|
|
3245
|
+
const reviewed = validatePlatformGenesisGuests([...seedGuests, rehearsalGuest], 4);
|
|
3246
|
+
const keys = [...new Set(sshPublicKeys.map(publicKey))];
|
|
3247
|
+
if (keys.length === 0)
|
|
3248
|
+
throw new Error("platform genesis requires at least one operator SSH public key");
|
|
3249
|
+
return reviewed.map((guest) => claimFor(guest, keys, "create"));
|
|
3250
|
+
}
|
|
3251
|
+
function platformCommunityRehearsalDeletionClaims(seedGuests, rehearsalGuest) {
|
|
3252
|
+
return validatePlatformGenesisGuests([...seedGuests, rehearsalGuest], 4).map((guest) => claimFor(guest, [], "delete"));
|
|
3253
|
+
}
|
|
3254
|
+
|
|
3078
3255
|
// src/platform-bootstrap-runtime.ts
|
|
3079
3256
|
import {
|
|
3080
3257
|
chmodSync as chmodSync5,
|
|
@@ -3123,6 +3300,50 @@ var httpsOrigin = (name, raw) => {
|
|
|
3123
3300
|
}
|
|
3124
3301
|
return value.origin;
|
|
3125
3302
|
};
|
|
3303
|
+
function validatePlatformInitialInventory(value) {
|
|
3304
|
+
if (!value || typeof value !== "object" || Array.isArray(value) || Object.keys(value).some((key) => !["metalHostname", "region", "computes"].includes(key)) || !/^[A-Za-z0-9][A-Za-z0-9.-]{1,252}$/.test(value.metalHostname) || !value.region || typeof value.region !== "object" || Array.isArray(value.region) || Object.keys(value.region).some((key) => !["key", "label", "country", "city", "confidentialCapable"].includes(key)) || !/^[a-z0-9][a-z0-9-]{0,62}$/.test(value.region.key) || !/^[A-Z]{2}$/.test(value.region.country) || value.region.confidentialCapable !== true || !Array.isArray(value.computes)) {
|
|
3305
|
+
throw new Error("initial platform inventory coordinates are invalid");
|
|
3306
|
+
}
|
|
3307
|
+
safeAtom("initialInventory.region.label", value.region.label);
|
|
3308
|
+
if (value.region.city !== undefined)
|
|
3309
|
+
safeAtom("initialInventory.region.city", value.region.city);
|
|
3310
|
+
const computes = validatePlatformGenesisGuests(value.computes.map((compute) => {
|
|
3311
|
+
if (!compute || typeof compute !== "object" || Array.isArray(compute) || Object.keys(compute).some((key) => ![
|
|
3312
|
+
"name",
|
|
3313
|
+
"address",
|
|
3314
|
+
"imageKey",
|
|
3315
|
+
"cpuPoolKey",
|
|
3316
|
+
"physicalCores",
|
|
3317
|
+
"vcpu",
|
|
3318
|
+
"memoryGib",
|
|
3319
|
+
"diskGib",
|
|
3320
|
+
"egressGuaranteedMbps",
|
|
3321
|
+
"egressBurstMbps",
|
|
3322
|
+
"confidential",
|
|
3323
|
+
"databaseRole",
|
|
3324
|
+
"databaseAgency"
|
|
3325
|
+
].includes(key)))
|
|
3326
|
+
throw new Error("initial platform compute contains unknown fields");
|
|
3327
|
+
return compute;
|
|
3328
|
+
}));
|
|
3329
|
+
for (let index = 0;index < computes.length; index += 1) {
|
|
3330
|
+
const declared = value.computes[index];
|
|
3331
|
+
const expectedRole = index === 0 ? "master" : "joiner";
|
|
3332
|
+
if (declared.databaseRole !== expectedRole || declared.databaseAgency !== "member" || declared.confidential !== true) {
|
|
3333
|
+
throw new Error("initial platform inventory requires one master, two joiners, three Agency members and confidential compute");
|
|
3334
|
+
}
|
|
3335
|
+
}
|
|
3336
|
+
return {
|
|
3337
|
+
metalHostname: value.metalHostname,
|
|
3338
|
+
region: { ...value.region },
|
|
3339
|
+
computes: value.computes.map((compute, index) => ({
|
|
3340
|
+
...computes[index],
|
|
3341
|
+
databaseRole: compute.databaseRole,
|
|
3342
|
+
databaseAgency: compute.databaseAgency,
|
|
3343
|
+
confidential: true
|
|
3344
|
+
}))
|
|
3345
|
+
};
|
|
3346
|
+
}
|
|
3126
3347
|
var systemdValue = (name, raw) => {
|
|
3127
3348
|
if (/[\0\r\n]/.test(raw))
|
|
3128
3349
|
throw new Error(`${name} must be single-line.`);
|
|
@@ -3208,12 +3429,14 @@ function validatePlatformSharedEnvironment(input) {
|
|
|
3208
3429
|
throw new Error("realtime.producer is invalid.");
|
|
3209
3430
|
}
|
|
3210
3431
|
}
|
|
3432
|
+
const initialInventory = input.initialInventory ? validatePlatformInitialInventory(input.initialInventory) : undefined;
|
|
3211
3433
|
return {
|
|
3212
3434
|
...input,
|
|
3213
3435
|
databaseCoordinators: coordinators,
|
|
3214
3436
|
appOrigin: httpsOrigin("appOrigin", input.appOrigin),
|
|
3215
3437
|
apiOrigin: httpsOrigin("apiOrigin", input.apiOrigin),
|
|
3216
|
-
agentOtlpEndpoint: httpsOrigin("agentOtlpEndpoint", input.agentOtlpEndpoint)
|
|
3438
|
+
agentOtlpEndpoint: httpsOrigin("agentOtlpEndpoint", input.agentOtlpEndpoint),
|
|
3439
|
+
...initialInventory ? { initialInventory } : {}
|
|
3217
3440
|
};
|
|
3218
3441
|
}
|
|
3219
3442
|
function renderPlatformSharedEnvironment(input) {
|
|
@@ -3276,7 +3499,8 @@ function renderPlatformSharedEnvironment(input) {
|
|
|
3276
3499
|
FZ_CF_TUNNEL_SERVICE: value.cloudflare?.tunnelService ?? "",
|
|
3277
3500
|
FZ_REALTIME_WORKER_SCRIPT: value.realtime?.workerScriptName ?? "",
|
|
3278
3501
|
FZ_REALTIME_ENDPOINT: value.realtime?.endpoint ?? "",
|
|
3279
|
-
FZ_REALTIME_PRODUCER: value.realtime?.producer ?? ""
|
|
3502
|
+
FZ_REALTIME_PRODUCER: value.realtime?.producer ?? "",
|
|
3503
|
+
FZ_PLATFORM_INITIAL_INVENTORY: value.initialInventory ? JSON.stringify(value.initialInventory) : ""
|
|
3280
3504
|
};
|
|
3281
3505
|
return `# Generated by fz bootstrap platform. Non-secret coordinates only.
|
|
3282
3506
|
` + Object.entries(entries).map(([key, entry]) => `${key}=${systemdValue(key, entry)}`).join(`
|
|
@@ -3458,15 +3682,15 @@ var replaceLink = (path2, target) => {
|
|
|
3458
3682
|
renameSync6(pending, path2);
|
|
3459
3683
|
};
|
|
3460
3684
|
var secureRelease = (path2, uid, gid) => {
|
|
3461
|
-
const visit = (
|
|
3462
|
-
const metadata = lstatSync(
|
|
3685
|
+
const visit = (current2) => {
|
|
3686
|
+
const metadata = lstatSync(current2);
|
|
3463
3687
|
if (metadata.isSymbolicLink())
|
|
3464
3688
|
throw new Error("release contains a symbolic link");
|
|
3465
|
-
chownSync(
|
|
3466
|
-
chmodSync5(
|
|
3689
|
+
chownSync(current2, uid, gid);
|
|
3690
|
+
chmodSync5(current2, metadata.isDirectory() ? 365 : 292);
|
|
3467
3691
|
if (metadata.isDirectory())
|
|
3468
|
-
for (const name of readdirSync3(
|
|
3469
|
-
visit(join5(
|
|
3692
|
+
for (const name of readdirSync3(current2))
|
|
3693
|
+
visit(join5(current2, name));
|
|
3470
3694
|
};
|
|
3471
3695
|
visit(path2);
|
|
3472
3696
|
};
|
|
@@ -3719,11 +3943,11 @@ var runProvisionOperation = async (operation) => {
|
|
|
3719
3943
|
}
|
|
3720
3944
|
if (operation.kind === "ensure-git-identity") {
|
|
3721
3945
|
const key = "/run/forgezero-git-deploy-key";
|
|
3722
|
-
const
|
|
3946
|
+
const publicKey2 = `${key}.pub`;
|
|
3723
3947
|
try {
|
|
3724
3948
|
if (!existsSync8(operation.credential) || lstatSync2(operation.credential).size < 1) {
|
|
3725
3949
|
rmSync7(key, { force: true });
|
|
3726
|
-
rmSync7(
|
|
3950
|
+
rmSync7(publicKey2, { force: true });
|
|
3727
3951
|
let result = await fixed(["/usr/bin/ssh-keygen", "-q", "-t", "ed25519", "-N", "", "-C", "forgezero-compute", "-f", key]);
|
|
3728
3952
|
if (result.exitCode !== 0)
|
|
3729
3953
|
return result;
|
|
@@ -3747,7 +3971,7 @@ var runProvisionOperation = async (operation) => {
|
|
|
3747
3971
|
return { stdout: "", exitCode: 0 };
|
|
3748
3972
|
} finally {
|
|
3749
3973
|
rmSync7(key, { force: true });
|
|
3750
|
-
rmSync7(
|
|
3974
|
+
rmSync7(publicKey2, { force: true });
|
|
3751
3975
|
}
|
|
3752
3976
|
}
|
|
3753
3977
|
if (operation.kind === "ensure-bootstrap-ssh-identity") {
|
|
@@ -3941,7 +4165,7 @@ import { dirname as dirname8, isAbsolute, resolve as resolve6 } from "node:path"
|
|
|
3941
4165
|
var BOOTSTRAP_BUNDLE_FORMAT = 1;
|
|
3942
4166
|
var BOOTSTRAP_BUNDLE_KIND = "forgezero-api-git-bundle";
|
|
3943
4167
|
var MAX_BOOTSTRAP_BUNDLE_BYTES = 512 * 1024 * 1024;
|
|
3944
|
-
var
|
|
4168
|
+
var bootstrapBundleBranch = (value) => {
|
|
3945
4169
|
if (typeof value !== "string" || !/^[A-Za-z0-9](?:[A-Za-z0-9._/-]{0,126}[A-Za-z0-9])?$/.test(value) || value.includes("..") || value.includes("//") || value.startsWith("-")) {
|
|
3946
4170
|
throw new Error("bootstrap bundle branch is malformed");
|
|
3947
4171
|
}
|
|
@@ -3958,7 +4182,7 @@ function parseBootstrapBundleManifest(value) {
|
|
|
3958
4182
|
if (source.format !== BOOTSTRAP_BUNDLE_FORMAT || source.kind !== BOOTSTRAP_BUNDLE_KIND) {
|
|
3959
4183
|
throw new Error("bootstrap bundle manifest format is unsupported");
|
|
3960
4184
|
}
|
|
3961
|
-
|
|
4185
|
+
bootstrapBundleBranch(source.branch);
|
|
3962
4186
|
if (typeof source.revision !== "string" || !/^[a-f0-9]{40}$/.test(source.revision)) {
|
|
3963
4187
|
throw new Error("bootstrap bundle revision must be an exact lowercase Git commit");
|
|
3964
4188
|
}
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import { type PlatformBootstrapConfig } from './bootstrap';
|
|
2
|
+
import { type PlatformGenesisGuest } from './platform-genesis';
|
|
2
3
|
export interface PlatformGenesisNodeConfigInput {
|
|
3
4
|
nodeHostname: string;
|
|
4
5
|
cloudflareHandoffFile: string;
|
|
5
6
|
}
|
|
7
|
+
export interface PlatformGenesisRegionInput {
|
|
8
|
+
label: string;
|
|
9
|
+
country: string;
|
|
10
|
+
city?: string;
|
|
11
|
+
}
|
|
6
12
|
/** Expand one reviewed common template into the exact three genesis hosts. */
|
|
7
|
-
export declare function platformGenesisBootstrapConfigs(template: PlatformBootstrapConfig, nodes: readonly PlatformGenesisNodeConfigInput[]): readonly PlatformBootstrapConfig[];
|
|
13
|
+
export declare function platformGenesisBootstrapConfigs(template: PlatformBootstrapConfig, guests: readonly PlatformGenesisGuest[], nodes: readonly PlatformGenesisNodeConfigInput[], metalHostname: string, region: PlatformGenesisRegionInput): readonly PlatformBootstrapConfig[];
|
|
@@ -1,28 +1,27 @@
|
|
|
1
1
|
import type { RemoteProvisionClaim } from './provisioning-pull';
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
/**
|
|
3
|
+
* One reviewed guest request. The Metal Agent does not know or infer an
|
|
4
|
+
* environment, product tier, tenant, or development shape: all differences are
|
|
5
|
+
* desired-state coordinates supplied by the same authority that requests the
|
|
6
|
+
* compute.
|
|
7
|
+
*/
|
|
4
8
|
export interface PlatformGenesisGuest {
|
|
5
9
|
name: string;
|
|
6
10
|
address: string;
|
|
7
|
-
|
|
11
|
+
imageKey: string;
|
|
12
|
+
cpuPoolKey?: string;
|
|
8
13
|
physicalCores: number;
|
|
9
14
|
vcpu: number;
|
|
10
15
|
memoryGib: number;
|
|
11
16
|
diskGib: number;
|
|
12
17
|
egressGuaranteedMbps: number;
|
|
13
18
|
egressBurstMbps: number;
|
|
19
|
+
confidential: boolean;
|
|
14
20
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
*/
|
|
23
|
-
export declare const DEVELOPMENT_COMMUNITY_REHEARSAL_GUEST: PlatformGenesisGuest;
|
|
24
|
-
export declare function platformGenesisClaims(environment: PlatformGenesisEnvironment, sshPublicKeys: readonly string[]): readonly RemoteProvisionClaim[];
|
|
25
|
-
/** Exact disposable four-host development fleet: three seed guests plus n4. */
|
|
26
|
-
export declare function platformCommunityRehearsalClaims(sshPublicKeys: readonly string[]): readonly RemoteProvisionClaim[];
|
|
27
|
-
/** Exact inverse of the disposable four-host rehearsal claims. */
|
|
28
|
-
export declare function platformCommunityRehearsalDeletionClaims(sshPublicKeys: readonly string[]): readonly RemoteProvisionClaim[];
|
|
21
|
+
export declare function validatePlatformGenesisGuests(guests: readonly PlatformGenesisGuest[], expectedCount?: number): readonly PlatformGenesisGuest[];
|
|
22
|
+
/** Convert reviewed desired state into the ordinary Metal provisioning claim. */
|
|
23
|
+
export declare function platformGenesisClaims(guests: readonly PlatformGenesisGuest[], sshPublicKeys: readonly string[]): readonly RemoteProvisionClaim[];
|
|
24
|
+
/** Add one explicitly reviewed disposable node to the same three guest requests. */
|
|
25
|
+
export declare function platformCommunityRehearsalClaims(seedGuests: readonly PlatformGenesisGuest[], rehearsalGuest: PlatformGenesisGuest, sshPublicKeys: readonly string[]): readonly RemoteProvisionClaim[];
|
|
26
|
+
/** Exact inverse of the reviewed disposable four-host request. */
|
|
27
|
+
export declare function platformCommunityRehearsalDeletionClaims(seedGuests: readonly PlatformGenesisGuest[], rehearsalGuest: PlatformGenesisGuest): readonly RemoteProvisionClaim[];
|