@forgezero/agent 0.1.134 → 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 +2 -0
- package/dist/deploy-compiler.js +28 -5
- package/dist/deploy-plan-runner.js +16 -3
- package/dist/deploy-plan.d.ts +3 -1
- package/dist/deploy-plan.js +17 -3
- package/dist/deploy.d.ts +5 -0
- package/dist/deployment-pull.d.ts +1 -0
- package/dist/deployment.d.ts +3 -0
- package/dist/fz-agent.js +148 -49
- package/dist/fz.js +53 -8
- 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/README.md
CHANGED
|
@@ -101,7 +101,7 @@ export default defineDeployment({
|
|
|
101
101
|
provisioning: {
|
|
102
102
|
regionKey: 'default', imageKey: 'ubuntu-24.04-x64', environmentKey: 'production', ownership: 'platform',
|
|
103
103
|
resources: {
|
|
104
|
-
physicalCores: 1, vcpu: 2, memoryGib: 2, diskGib: 16,
|
|
104
|
+
physicalCores: 1, vcpu: 2, memoryGib: 2, diskGib: 16, diskEncryption: 'luks2',
|
|
105
105
|
egressGuaranteedMbps: 100, egressBurstMbps: 200, confidential: false
|
|
106
106
|
},
|
|
107
107
|
monthlyAmountCents: '1200', maxMonthlySpendMinor: '25000'
|
package/dist/agent-heartbeat.js
CHANGED
package/dist/bootstrap.js
CHANGED
|
@@ -1460,7 +1460,7 @@ var UPDATE_RETRY_BASE_MS = 5 * 60000;
|
|
|
1460
1460
|
var UPDATE_RETRY_MAX_MS = 24 * 60 * 60000;
|
|
1461
1461
|
|
|
1462
1462
|
// src/version.ts
|
|
1463
|
-
var VERSION = "0.1.
|
|
1463
|
+
var VERSION = "0.1.136";
|
|
1464
1464
|
|
|
1465
1465
|
// src/software.ts
|
|
1466
1466
|
var PINNED_BUN_VERSION = "1.3.14";
|
|
@@ -3070,6 +3070,10 @@ function validatePlatformGenesisGuests(guests, expectedCount = 3) {
|
|
|
3070
3070
|
throw new Error("platform genesis vCPU count cannot be smaller than physical cores");
|
|
3071
3071
|
const memoryGib = integer(input.memoryGib, 1, 8192, "memory");
|
|
3072
3072
|
const diskGib = integer(input.diskGib, 8, 65536, "disk");
|
|
3073
|
+
const diskEncryption = input.diskEncryption ?? "none";
|
|
3074
|
+
if (!["none", "luks2"].includes(diskEncryption)) {
|
|
3075
|
+
throw new Error("platform genesis disk encryption mode is unsupported");
|
|
3076
|
+
}
|
|
3073
3077
|
const egressGuaranteedMbps = integer(input.egressGuaranteedMbps, 0, 1e6, "guaranteed egress");
|
|
3074
3078
|
const egressBurstMbps = integer(input.egressBurstMbps, egressGuaranteedMbps, 1e6, "burst egress");
|
|
3075
3079
|
return {
|
|
@@ -3081,6 +3085,7 @@ function validatePlatformGenesisGuests(guests, expectedCount = 3) {
|
|
|
3081
3085
|
vcpu,
|
|
3082
3086
|
memoryGib,
|
|
3083
3087
|
diskGib,
|
|
3088
|
+
diskEncryption,
|
|
3084
3089
|
egressGuaranteedMbps,
|
|
3085
3090
|
egressBurstMbps,
|
|
3086
3091
|
confidential: input.confidential
|
|
@@ -3111,6 +3116,7 @@ var claimFor = (guest, keys, action) => {
|
|
|
3111
3116
|
vcpu: guest.vcpu,
|
|
3112
3117
|
memoryGib: guest.memoryGib,
|
|
3113
3118
|
diskGib: guest.diskGib,
|
|
3119
|
+
diskEncryption: guest.diskEncryption,
|
|
3114
3120
|
egressGuaranteedMbps: guest.egressGuaranteedMbps,
|
|
3115
3121
|
egressBurstMbps: guest.egressBurstMbps,
|
|
3116
3122
|
confidential: guest.confidential
|
|
@@ -3200,6 +3206,7 @@ function validatePlatformInitialInventory(value) {
|
|
|
3200
3206
|
"vcpu",
|
|
3201
3207
|
"memoryGib",
|
|
3202
3208
|
"diskGib",
|
|
3209
|
+
"diskEncryption",
|
|
3203
3210
|
"egressGuaranteedMbps",
|
|
3204
3211
|
"egressBurstMbps",
|
|
3205
3212
|
"confidential",
|
|
@@ -5230,6 +5237,7 @@ function strictBootstrapDocument(value) {
|
|
|
5230
5237
|
"vcpu",
|
|
5231
5238
|
"memoryGib",
|
|
5232
5239
|
"diskGib",
|
|
5240
|
+
"diskEncryption",
|
|
5233
5241
|
"egressGuaranteedMbps",
|
|
5234
5242
|
"egressBurstMbps",
|
|
5235
5243
|
"confidential",
|
package/dist/compute.d.ts
CHANGED
|
@@ -35,6 +35,13 @@ export interface GuestSpec {
|
|
|
35
35
|
memoryGib: number;
|
|
36
36
|
/** Block device or image path. Raw LVM on our metal; a file is allowed. */
|
|
37
37
|
disk: string;
|
|
38
|
+
/** Host-at-rest LUKS2 envelope. The key is a host-sealed systemd credential. */
|
|
39
|
+
diskEncryption?: {
|
|
40
|
+
source: string;
|
|
41
|
+
mapper: string;
|
|
42
|
+
credentialName: string;
|
|
43
|
+
credentialPath: string;
|
|
44
|
+
};
|
|
38
45
|
/** cloud-init seed, attached read-only. */
|
|
39
46
|
seed: string;
|
|
40
47
|
bridge: string;
|
package/dist/compute.js
CHANGED
|
@@ -56,6 +56,10 @@ function guestUnit(spec) {
|
|
|
56
56
|
`ExecStopPost=-/usr/sbin/ip link del ${spec.tap}`
|
|
57
57
|
].join(`
|
|
58
58
|
`) : "";
|
|
59
|
+
const encryptedDisk = spec.diskEncryption ? `LoadCredentialEncrypted=${spec.diskEncryption.credentialName}:${spec.diskEncryption.credentialPath}
|
|
60
|
+
ExecStartPre=/usr/sbin/cryptsetup open --type luks2 --key-file %d/${spec.diskEncryption.credentialName} ${spec.diskEncryption.source} ${spec.diskEncryption.mapper}
|
|
61
|
+
ExecStopPost=-/usr/sbin/cryptsetup close ${spec.diskEncryption.mapper}
|
|
62
|
+
` : "";
|
|
59
63
|
return `[Unit]
|
|
60
64
|
Description=ForgeZero guest ${spec.name}
|
|
61
65
|
Documentation=https://www.forgezero.net
|
|
@@ -65,7 +69,7 @@ Wants=network-online.target
|
|
|
65
69
|
[Service]
|
|
66
70
|
Type=simple
|
|
67
71
|
Slice=forgezero-guests.slice
|
|
68
|
-
${tapSetup}
|
|
72
|
+
${encryptedDisk}${tapSetup}
|
|
69
73
|
ExecStart=${argv}
|
|
70
74
|
Restart=always
|
|
71
75
|
RestartSec=5
|
|
@@ -20,6 +20,7 @@ export interface DeploymentInitProvisioning {
|
|
|
20
20
|
vcpu: number;
|
|
21
21
|
memoryGib: number;
|
|
22
22
|
diskGib: number;
|
|
23
|
+
diskEncryption?: 'none' | 'luks2';
|
|
23
24
|
egressGuaranteedMbps: number;
|
|
24
25
|
egressBurstMbps: number;
|
|
25
26
|
confidential: boolean;
|
|
@@ -28,6 +29,7 @@ export interface DeploymentInitProvisioning {
|
|
|
28
29
|
maxMonthlySpendMinor: string;
|
|
29
30
|
}
|
|
30
31
|
export interface DeploymentInitOptions {
|
|
32
|
+
branch?: string;
|
|
31
33
|
runtime?: DeploymentInitRuntime;
|
|
32
34
|
operatingSystem?: 'ubuntu-24.04' | 'ubuntu-26.04';
|
|
33
35
|
isolation?: 'standard' | 'sev-snp';
|
package/dist/deploy-compiler.js
CHANGED
|
@@ -172,7 +172,7 @@ function validateCapacityCalibrationOptions(options) {
|
|
|
172
172
|
|
|
173
173
|
// src/deploy-plan.ts
|
|
174
174
|
var DEPLOY_PLAN_FORMAT = "forgezero-deployment-plan";
|
|
175
|
-
var DEPLOY_PLAN_VERSION =
|
|
175
|
+
var DEPLOY_PLAN_VERSION = 2;
|
|
176
176
|
|
|
177
177
|
class DeploymentPlanError extends Error {
|
|
178
178
|
constructor(message) {
|
|
@@ -186,6 +186,13 @@ var ACTION = /^[a-z][a-z0-9.-]{0,127}\/[a-z][a-z0-9.-]{0,127}@[1-9][0-9]{0,5}$/;
|
|
|
186
186
|
var VERSION = /^[A-Za-z0-9][A-Za-z0-9.+_-]{0,63}$/;
|
|
187
187
|
var ABSOLUTE_PATH = /^\/(?:[A-Za-z0-9._-]+\/?)*$/;
|
|
188
188
|
var HEALTH_PATH = /^\/[A-Za-z0-9._~!$&'()*+,;=:@%/-]{0,255}$/;
|
|
189
|
+
function deploymentBranch(value, where = "deployment.spec.source.branch") {
|
|
190
|
+
const branch = boundedString(value, where, 255);
|
|
191
|
+
if (branch === "@" || branch.startsWith("/") || branch.endsWith("/") || branch.startsWith(".") || branch.endsWith(".") || branch.endsWith(".lock") || branch.includes("..") || branch.includes("//") || branch.includes("@{") || /[\x00-\x20~^:?*\[\\]/.test(branch)) {
|
|
192
|
+
fail(where, "must be one exact valid Git branch name.");
|
|
193
|
+
}
|
|
194
|
+
return branch;
|
|
195
|
+
}
|
|
189
196
|
var fail = (where, message) => {
|
|
190
197
|
throw new DeploymentPlanError(`${where} ${message}`);
|
|
191
198
|
};
|
|
@@ -821,7 +828,10 @@ function compileDeployment(sourceValue) {
|
|
|
821
828
|
if (metadata.description !== undefined)
|
|
822
829
|
boundedString(metadata.description, "deployment.metadata.description", 1024);
|
|
823
830
|
const spec = object(source.spec, "deployment.spec");
|
|
824
|
-
exact3(spec, ["security", "inputs", "credentials", "targets", "requirements", "components", "workflows"], "deployment.spec");
|
|
831
|
+
exact3(spec, ["source", "security", "inputs", "credentials", "targets", "requirements", "components", "workflows"], "deployment.spec");
|
|
832
|
+
const sourceSelector = object(spec.source, "deployment.spec.source");
|
|
833
|
+
exact3(sourceSelector, ["branch"], "deployment.spec.source");
|
|
834
|
+
deploymentBranch(sourceSelector.branch);
|
|
825
835
|
if (spec.security !== undefined) {
|
|
826
836
|
const security = object(spec.security, "deployment.spec.security");
|
|
827
837
|
exact3(security, ["attestation"], "deployment.spec.security");
|
|
@@ -918,11 +928,13 @@ function compileDeployment(sourceValue) {
|
|
|
918
928
|
if (provisioning.metalHostname !== undefined && !/^(?=.{1,253}$)[A-Za-z0-9](?:[A-Za-z0-9.-]*[A-Za-z0-9])?$/.test(String(provisioning.metalHostname)))
|
|
919
929
|
fail(`deployment.spec.targets.${targetName}.provisioning.metalHostname`, "is invalid.");
|
|
920
930
|
const provisionedResources = object(provisioning.resources, `deployment.spec.targets.${targetName}.provisioning.resources`);
|
|
921
|
-
exact3(provisionedResources, ["physicalCores", "vcpu", "memoryGib", "diskGib", "egressGuaranteedMbps", "egressBurstMbps", "confidential"], `deployment.spec.targets.${targetName}.provisioning.resources`);
|
|
931
|
+
exact3(provisionedResources, ["physicalCores", "vcpu", "memoryGib", "diskGib", "diskEncryption", "egressGuaranteedMbps", "egressBurstMbps", "confidential"], `deployment.spec.targets.${targetName}.provisioning.resources`);
|
|
922
932
|
integer(provisionedResources.physicalCores, `deployment.spec.targets.${targetName}.provisioning.resources.physicalCores`, 1, 1024);
|
|
923
933
|
integer(provisionedResources.vcpu, `deployment.spec.targets.${targetName}.provisioning.resources.vcpu`, 1, 4096);
|
|
924
934
|
integer(provisionedResources.memoryGib, `deployment.spec.targets.${targetName}.provisioning.resources.memoryGib`, 1, 4194304);
|
|
925
935
|
integer(provisionedResources.diskGib, `deployment.spec.targets.${targetName}.provisioning.resources.diskGib`, 1, 1048576);
|
|
936
|
+
if (provisionedResources.diskEncryption !== undefined && !["none", "luks2"].includes(String(provisionedResources.diskEncryption)))
|
|
937
|
+
fail(`deployment.spec.targets.${targetName}.provisioning.resources.diskEncryption`, "must be none or luks2.");
|
|
926
938
|
integer(provisionedResources.egressGuaranteedMbps, `deployment.spec.targets.${targetName}.provisioning.resources.egressGuaranteedMbps`, 0, 1e7);
|
|
927
939
|
integer(provisionedResources.egressBurstMbps, `deployment.spec.targets.${targetName}.provisioning.resources.egressBurstMbps`, Number(provisionedResources.egressGuaranteedMbps), 1e7);
|
|
928
940
|
if (typeof provisionedResources.confidential !== "boolean")
|
|
@@ -1152,6 +1164,7 @@ function compileDeployment(sourceValue) {
|
|
|
1152
1164
|
...metadata.description ? { description: metadata.description } : {},
|
|
1153
1165
|
requiredProviders: [...requiredProviders.values()].sort((left, right) => `${left.provider}:${left.contract}:${left.capability}`.localeCompare(`${right.provider}:${right.contract}:${right.capability}`)),
|
|
1154
1166
|
spec: {
|
|
1167
|
+
source: sourceSelector,
|
|
1155
1168
|
...spec.security ? { security: spec.security } : {},
|
|
1156
1169
|
inputs,
|
|
1157
1170
|
credentials,
|
|
@@ -1248,6 +1261,7 @@ function initCoordinates(options) {
|
|
|
1248
1261
|
const isolation = options.isolation ?? (runtime === "kata-snp" ? "sev-snp" : "standard");
|
|
1249
1262
|
const operatingSystem = options.operatingSystem ?? (isolation === "sev-snp" ? "ubuntu-26.04" : "ubuntu-24.04");
|
|
1250
1263
|
const result = {
|
|
1264
|
+
branch: options.branch ?? "main",
|
|
1251
1265
|
runtime,
|
|
1252
1266
|
isolation,
|
|
1253
1267
|
operatingSystem,
|
|
@@ -1261,6 +1275,9 @@ function initCoordinates(options) {
|
|
|
1261
1275
|
};
|
|
1262
1276
|
if (!/^[a-z][a-z0-9-]{0,62}$/.test(result.profile))
|
|
1263
1277
|
throw new Error("deployment profile must be a lowercase typed name");
|
|
1278
|
+
if (result.branch.length < 1 || result.branch.length > 255 || result.branch === "@" || result.branch.startsWith("/") || result.branch.endsWith("/") || result.branch.startsWith(".") || result.branch.endsWith(".") || result.branch.endsWith(".lock") || result.branch.includes("..") || result.branch.includes("//") || result.branch.includes("@{") || /[\x00-\x20~^:?*\[\\]/.test(result.branch)) {
|
|
1279
|
+
throw new Error("deployment branch must be one exact valid Git branch name");
|
|
1280
|
+
}
|
|
1264
1281
|
if (!Number.isSafeInteger(result.replicas) || result.replicas < 1 || result.replicas > 1024)
|
|
1265
1282
|
throw new Error("deployment replicas must be an integer from 1 to 1024");
|
|
1266
1283
|
if (!Number.isSafeInteger(result.cpuCores) || result.cpuCores < 1 || result.cpuCores > 1024)
|
|
@@ -1290,7 +1307,7 @@ function initCoordinates(options) {
|
|
|
1290
1307
|
if (!/^[a-z][a-z0-9-]{0,62}$/.test(value))
|
|
1291
1308
|
throw new Error(`deployment provisioning ${label} must be a lowercase typed name`);
|
|
1292
1309
|
const resources = options.provisioning.resources;
|
|
1293
|
-
for (const [label, value] of Object.entries(resources).filter(([key]) =>
|
|
1310
|
+
for (const [label, value] of Object.entries(resources).filter(([key]) => !["confidential", "diskEncryption"].includes(key))) {
|
|
1294
1311
|
if (!Number.isSafeInteger(value) || Number(value) < 0)
|
|
1295
1312
|
throw new Error(`deployment provisioning ${label} must be a non-negative integer`);
|
|
1296
1313
|
}
|
|
@@ -1299,6 +1316,8 @@ function initCoordinates(options) {
|
|
|
1299
1316
|
}
|
|
1300
1317
|
if (result.isolation === "sev-snp" && !resources.confidential)
|
|
1301
1318
|
throw new Error("deployment provisioning must provide confidential capacity for sev-snp");
|
|
1319
|
+
if (resources.diskEncryption !== undefined && !["none", "luks2"].includes(resources.diskEncryption))
|
|
1320
|
+
throw new Error("deployment provisioning disk encryption mode is unsupported");
|
|
1302
1321
|
if (!/^\d{1,18}$/.test(options.provisioning.monthlyAmountCents))
|
|
1303
1322
|
throw new Error("deployment provisioning monthly amount must be a bounded USD-cent amount");
|
|
1304
1323
|
if (!/^\d{1,18}$/.test(options.provisioning.maxMonthlySpendMinor))
|
|
@@ -1310,7 +1329,10 @@ function initCoordinates(options) {
|
|
|
1310
1329
|
if (options.provisioning.metalHostname && !/^(?=.{1,253}$)[A-Za-z0-9](?:[A-Za-z0-9.-]*[A-Za-z0-9])?$/.test(options.provisioning.metalHostname))
|
|
1311
1330
|
throw new Error("deployment provisioning metal hostname is invalid");
|
|
1312
1331
|
}
|
|
1313
|
-
return { ...result, ...options.provisioning ? { provisioning:
|
|
1332
|
+
return { ...result, ...options.provisioning ? { provisioning: {
|
|
1333
|
+
...options.provisioning,
|
|
1334
|
+
resources: { ...options.provisioning.resources, diskEncryption: options.provisioning.resources.diskEncryption ?? "luks2" }
|
|
1335
|
+
} } : {} };
|
|
1314
1336
|
}
|
|
1315
1337
|
function defaultTypeScriptDeployment(name, options = {}) {
|
|
1316
1338
|
const selected = initCoordinates(options);
|
|
@@ -1379,6 +1401,7 @@ export default defineDeployment({
|
|
|
1379
1401
|
kind: 'Deployment',
|
|
1380
1402
|
metadata: { name: '${safeName(name)}' },
|
|
1381
1403
|
spec: {
|
|
1404
|
+
source: { branch: '${selected.branch}' },
|
|
1382
1405
|
security: { attestation: '${selected.isolation === "sev-snp" ? "required" : "preferred"}' },
|
|
1383
1406
|
targets: {
|
|
1384
1407
|
app: target.compute({
|
|
@@ -172,7 +172,7 @@ function validateCapacityCalibrationOptions(options) {
|
|
|
172
172
|
|
|
173
173
|
// src/deploy-plan.ts
|
|
174
174
|
var DEPLOY_PLAN_FORMAT = "forgezero-deployment-plan";
|
|
175
|
-
var DEPLOY_PLAN_VERSION =
|
|
175
|
+
var DEPLOY_PLAN_VERSION = 2;
|
|
176
176
|
|
|
177
177
|
class DeploymentPlanError extends Error {
|
|
178
178
|
constructor(message) {
|
|
@@ -186,6 +186,13 @@ var ACTION = /^[a-z][a-z0-9.-]{0,127}\/[a-z][a-z0-9.-]{0,127}@[1-9][0-9]{0,5}$/;
|
|
|
186
186
|
var VERSION = /^[A-Za-z0-9][A-Za-z0-9.+_-]{0,63}$/;
|
|
187
187
|
var ABSOLUTE_PATH = /^\/(?:[A-Za-z0-9._-]+\/?)*$/;
|
|
188
188
|
var HEALTH_PATH = /^\/[A-Za-z0-9._~!$&'()*+,;=:@%/-]{0,255}$/;
|
|
189
|
+
function deploymentBranch(value, where = "deployment.spec.source.branch") {
|
|
190
|
+
const branch = boundedString(value, where, 255);
|
|
191
|
+
if (branch === "@" || branch.startsWith("/") || branch.endsWith("/") || branch.startsWith(".") || branch.endsWith(".") || branch.endsWith(".lock") || branch.includes("..") || branch.includes("//") || branch.includes("@{") || /[\x00-\x20~^:?*\[\\]/.test(branch)) {
|
|
192
|
+
fail(where, "must be one exact valid Git branch name.");
|
|
193
|
+
}
|
|
194
|
+
return branch;
|
|
195
|
+
}
|
|
189
196
|
var fail = (where, message) => {
|
|
190
197
|
throw new DeploymentPlanError(`${where} ${message}`);
|
|
191
198
|
};
|
|
@@ -821,7 +828,10 @@ function compileDeployment(sourceValue) {
|
|
|
821
828
|
if (metadata.description !== undefined)
|
|
822
829
|
boundedString(metadata.description, "deployment.metadata.description", 1024);
|
|
823
830
|
const spec = object(source.spec, "deployment.spec");
|
|
824
|
-
exact3(spec, ["security", "inputs", "credentials", "targets", "requirements", "components", "workflows"], "deployment.spec");
|
|
831
|
+
exact3(spec, ["source", "security", "inputs", "credentials", "targets", "requirements", "components", "workflows"], "deployment.spec");
|
|
832
|
+
const sourceSelector = object(spec.source, "deployment.spec.source");
|
|
833
|
+
exact3(sourceSelector, ["branch"], "deployment.spec.source");
|
|
834
|
+
deploymentBranch(sourceSelector.branch);
|
|
825
835
|
if (spec.security !== undefined) {
|
|
826
836
|
const security = object(spec.security, "deployment.spec.security");
|
|
827
837
|
exact3(security, ["attestation"], "deployment.spec.security");
|
|
@@ -918,11 +928,13 @@ function compileDeployment(sourceValue) {
|
|
|
918
928
|
if (provisioning.metalHostname !== undefined && !/^(?=.{1,253}$)[A-Za-z0-9](?:[A-Za-z0-9.-]*[A-Za-z0-9])?$/.test(String(provisioning.metalHostname)))
|
|
919
929
|
fail(`deployment.spec.targets.${targetName}.provisioning.metalHostname`, "is invalid.");
|
|
920
930
|
const provisionedResources = object(provisioning.resources, `deployment.spec.targets.${targetName}.provisioning.resources`);
|
|
921
|
-
exact3(provisionedResources, ["physicalCores", "vcpu", "memoryGib", "diskGib", "egressGuaranteedMbps", "egressBurstMbps", "confidential"], `deployment.spec.targets.${targetName}.provisioning.resources`);
|
|
931
|
+
exact3(provisionedResources, ["physicalCores", "vcpu", "memoryGib", "diskGib", "diskEncryption", "egressGuaranteedMbps", "egressBurstMbps", "confidential"], `deployment.spec.targets.${targetName}.provisioning.resources`);
|
|
922
932
|
integer(provisionedResources.physicalCores, `deployment.spec.targets.${targetName}.provisioning.resources.physicalCores`, 1, 1024);
|
|
923
933
|
integer(provisionedResources.vcpu, `deployment.spec.targets.${targetName}.provisioning.resources.vcpu`, 1, 4096);
|
|
924
934
|
integer(provisionedResources.memoryGib, `deployment.spec.targets.${targetName}.provisioning.resources.memoryGib`, 1, 4194304);
|
|
925
935
|
integer(provisionedResources.diskGib, `deployment.spec.targets.${targetName}.provisioning.resources.diskGib`, 1, 1048576);
|
|
936
|
+
if (provisionedResources.diskEncryption !== undefined && !["none", "luks2"].includes(String(provisionedResources.diskEncryption)))
|
|
937
|
+
fail(`deployment.spec.targets.${targetName}.provisioning.resources.diskEncryption`, "must be none or luks2.");
|
|
926
938
|
integer(provisionedResources.egressGuaranteedMbps, `deployment.spec.targets.${targetName}.provisioning.resources.egressGuaranteedMbps`, 0, 1e7);
|
|
927
939
|
integer(provisionedResources.egressBurstMbps, `deployment.spec.targets.${targetName}.provisioning.resources.egressBurstMbps`, Number(provisionedResources.egressGuaranteedMbps), 1e7);
|
|
928
940
|
if (typeof provisionedResources.confidential !== "boolean")
|
|
@@ -1152,6 +1164,7 @@ function compileDeployment(sourceValue) {
|
|
|
1152
1164
|
...metadata.description ? { description: metadata.description } : {},
|
|
1153
1165
|
requiredProviders: [...requiredProviders.values()].sort((left, right) => `${left.provider}:${left.contract}:${left.capability}`.localeCompare(`${right.provider}:${right.contract}:${right.capability}`)),
|
|
1154
1166
|
spec: {
|
|
1167
|
+
source: sourceSelector,
|
|
1155
1168
|
...spec.security ? { security: spec.security } : {},
|
|
1156
1169
|
inputs,
|
|
1157
1170
|
credentials,
|
package/dist/deploy-plan.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { DeploymentSource, StageDefinition, WorkflowStepDefinition } from './deploy';
|
|
2
2
|
export declare const DEPLOY_PLAN_FORMAT: "forgezero-deployment-plan";
|
|
3
|
-
export declare const DEPLOY_PLAN_VERSION:
|
|
3
|
+
export declare const DEPLOY_PLAN_VERSION: 2;
|
|
4
4
|
export interface PlannedStep extends WorkflowStepDefinition {
|
|
5
5
|
id: string;
|
|
6
6
|
}
|
|
@@ -34,6 +34,8 @@ export interface DeploymentPlan {
|
|
|
34
34
|
export declare class DeploymentPlanError extends Error {
|
|
35
35
|
constructor(message: string);
|
|
36
36
|
}
|
|
37
|
+
/** Git check-ref-format compatible branch subset accepted by every source adapter. */
|
|
38
|
+
export declare function deploymentBranch(value: unknown, where?: string): string;
|
|
37
39
|
export declare function canonicalJson(value: unknown): string;
|
|
38
40
|
export declare function deploymentSourceDigest(source: DeploymentSource): `sha256:${string}`;
|
|
39
41
|
export declare function compileDeployment(sourceValue: unknown): DeploymentPlan;
|
package/dist/deploy-plan.js
CHANGED
|
@@ -172,7 +172,7 @@ function validateCapacityCalibrationOptions(options) {
|
|
|
172
172
|
|
|
173
173
|
// src/deploy-plan.ts
|
|
174
174
|
var DEPLOY_PLAN_FORMAT = "forgezero-deployment-plan";
|
|
175
|
-
var DEPLOY_PLAN_VERSION =
|
|
175
|
+
var DEPLOY_PLAN_VERSION = 2;
|
|
176
176
|
|
|
177
177
|
class DeploymentPlanError extends Error {
|
|
178
178
|
constructor(message) {
|
|
@@ -186,6 +186,13 @@ var ACTION = /^[a-z][a-z0-9.-]{0,127}\/[a-z][a-z0-9.-]{0,127}@[1-9][0-9]{0,5}$/;
|
|
|
186
186
|
var VERSION = /^[A-Za-z0-9][A-Za-z0-9.+_-]{0,63}$/;
|
|
187
187
|
var ABSOLUTE_PATH = /^\/(?:[A-Za-z0-9._-]+\/?)*$/;
|
|
188
188
|
var HEALTH_PATH = /^\/[A-Za-z0-9._~!$&'()*+,;=:@%/-]{0,255}$/;
|
|
189
|
+
function deploymentBranch(value, where = "deployment.spec.source.branch") {
|
|
190
|
+
const branch = boundedString(value, where, 255);
|
|
191
|
+
if (branch === "@" || branch.startsWith("/") || branch.endsWith("/") || branch.startsWith(".") || branch.endsWith(".") || branch.endsWith(".lock") || branch.includes("..") || branch.includes("//") || branch.includes("@{") || /[\x00-\x20~^:?*\[\\]/.test(branch)) {
|
|
192
|
+
fail(where, "must be one exact valid Git branch name.");
|
|
193
|
+
}
|
|
194
|
+
return branch;
|
|
195
|
+
}
|
|
189
196
|
var fail = (where, message) => {
|
|
190
197
|
throw new DeploymentPlanError(`${where} ${message}`);
|
|
191
198
|
};
|
|
@@ -821,7 +828,10 @@ function compileDeployment(sourceValue) {
|
|
|
821
828
|
if (metadata.description !== undefined)
|
|
822
829
|
boundedString(metadata.description, "deployment.metadata.description", 1024);
|
|
823
830
|
const spec = object(source.spec, "deployment.spec");
|
|
824
|
-
exact3(spec, ["security", "inputs", "credentials", "targets", "requirements", "components", "workflows"], "deployment.spec");
|
|
831
|
+
exact3(spec, ["source", "security", "inputs", "credentials", "targets", "requirements", "components", "workflows"], "deployment.spec");
|
|
832
|
+
const sourceSelector = object(spec.source, "deployment.spec.source");
|
|
833
|
+
exact3(sourceSelector, ["branch"], "deployment.spec.source");
|
|
834
|
+
deploymentBranch(sourceSelector.branch);
|
|
825
835
|
if (spec.security !== undefined) {
|
|
826
836
|
const security = object(spec.security, "deployment.spec.security");
|
|
827
837
|
exact3(security, ["attestation"], "deployment.spec.security");
|
|
@@ -918,11 +928,13 @@ function compileDeployment(sourceValue) {
|
|
|
918
928
|
if (provisioning.metalHostname !== undefined && !/^(?=.{1,253}$)[A-Za-z0-9](?:[A-Za-z0-9.-]*[A-Za-z0-9])?$/.test(String(provisioning.metalHostname)))
|
|
919
929
|
fail(`deployment.spec.targets.${targetName}.provisioning.metalHostname`, "is invalid.");
|
|
920
930
|
const provisionedResources = object(provisioning.resources, `deployment.spec.targets.${targetName}.provisioning.resources`);
|
|
921
|
-
exact3(provisionedResources, ["physicalCores", "vcpu", "memoryGib", "diskGib", "egressGuaranteedMbps", "egressBurstMbps", "confidential"], `deployment.spec.targets.${targetName}.provisioning.resources`);
|
|
931
|
+
exact3(provisionedResources, ["physicalCores", "vcpu", "memoryGib", "diskGib", "diskEncryption", "egressGuaranteedMbps", "egressBurstMbps", "confidential"], `deployment.spec.targets.${targetName}.provisioning.resources`);
|
|
922
932
|
integer(provisionedResources.physicalCores, `deployment.spec.targets.${targetName}.provisioning.resources.physicalCores`, 1, 1024);
|
|
923
933
|
integer(provisionedResources.vcpu, `deployment.spec.targets.${targetName}.provisioning.resources.vcpu`, 1, 4096);
|
|
924
934
|
integer(provisionedResources.memoryGib, `deployment.spec.targets.${targetName}.provisioning.resources.memoryGib`, 1, 4194304);
|
|
925
935
|
integer(provisionedResources.diskGib, `deployment.spec.targets.${targetName}.provisioning.resources.diskGib`, 1, 1048576);
|
|
936
|
+
if (provisionedResources.diskEncryption !== undefined && !["none", "luks2"].includes(String(provisionedResources.diskEncryption)))
|
|
937
|
+
fail(`deployment.spec.targets.${targetName}.provisioning.resources.diskEncryption`, "must be none or luks2.");
|
|
926
938
|
integer(provisionedResources.egressGuaranteedMbps, `deployment.spec.targets.${targetName}.provisioning.resources.egressGuaranteedMbps`, 0, 1e7);
|
|
927
939
|
integer(provisionedResources.egressBurstMbps, `deployment.spec.targets.${targetName}.provisioning.resources.egressBurstMbps`, Number(provisionedResources.egressGuaranteedMbps), 1e7);
|
|
928
940
|
if (typeof provisionedResources.confidential !== "boolean")
|
|
@@ -1152,6 +1164,7 @@ function compileDeployment(sourceValue) {
|
|
|
1152
1164
|
...metadata.description ? { description: metadata.description } : {},
|
|
1153
1165
|
requiredProviders: [...requiredProviders.values()].sort((left, right) => `${left.provider}:${left.contract}:${left.capability}`.localeCompare(`${right.provider}:${right.contract}:${right.capability}`)),
|
|
1154
1166
|
spec: {
|
|
1167
|
+
source: sourceSelector,
|
|
1155
1168
|
...spec.security ? { security: spec.security } : {},
|
|
1156
1169
|
inputs,
|
|
1157
1170
|
credentials,
|
|
@@ -1235,6 +1248,7 @@ export {
|
|
|
1235
1248
|
parseDeploymentPlan,
|
|
1236
1249
|
deploymentSourceDigest,
|
|
1237
1250
|
deploymentPlanDigest,
|
|
1251
|
+
deploymentBranch,
|
|
1238
1252
|
compileDeployment,
|
|
1239
1253
|
canonicalJson,
|
|
1240
1254
|
DeploymentPlanError,
|
package/dist/deploy.d.ts
CHANGED
|
@@ -195,6 +195,7 @@ export interface TargetDefinition {
|
|
|
195
195
|
vcpu: number;
|
|
196
196
|
memoryGib: number;
|
|
197
197
|
diskGib: number;
|
|
198
|
+
diskEncryption?: 'none' | 'luks2';
|
|
198
199
|
egressGuaranteedMbps: number;
|
|
199
200
|
egressBurstMbps: number;
|
|
200
201
|
confidential: boolean;
|
|
@@ -466,6 +467,10 @@ export interface DeploymentSource {
|
|
|
466
467
|
description?: string;
|
|
467
468
|
};
|
|
468
469
|
spec: {
|
|
470
|
+
/** Exact Git branch this checked-in plan is valid for. */
|
|
471
|
+
source: {
|
|
472
|
+
branch: string;
|
|
473
|
+
};
|
|
469
474
|
security?: {
|
|
470
475
|
attestation?: 'required' | 'preferred' | 'disabled';
|
|
471
476
|
};
|
|
@@ -12,6 +12,7 @@ export interface RemoteDeploymentClaim {
|
|
|
12
12
|
releaseExecutor: boolean;
|
|
13
13
|
assignment?: NonNullable<import('./deployment').DeploymentRequest['assignment']>;
|
|
14
14
|
connectivityCapabilities?: import('./deployment-connectivity').DeploymentConnectivityCapabilities;
|
|
15
|
+
credentialBindings?: Readonly<Record<string, string>>;
|
|
15
16
|
source: {
|
|
16
17
|
repository: string;
|
|
17
18
|
branch: string;
|
package/dist/deployment.d.ts
CHANGED
|
@@ -62,6 +62,8 @@ export interface DeploymentRequest {
|
|
|
62
62
|
};
|
|
63
63
|
/** Connector-scoped, one-claim capabilities. Never the project Cloudflare management token. */
|
|
64
64
|
connectivityCapabilities?: DeploymentConnectivityCapabilities;
|
|
65
|
+
/** Server-owned alias to scoped Vault entry-name overrides. */
|
|
66
|
+
credentialBindings?: Readonly<Record<string, string>>;
|
|
65
67
|
}
|
|
66
68
|
export interface DeploymentResult {
|
|
67
69
|
key: string;
|
|
@@ -137,6 +139,7 @@ export interface ResolvedDeploymentTarget {
|
|
|
137
139
|
vcpu: number;
|
|
138
140
|
memoryGib: number;
|
|
139
141
|
diskGib: number;
|
|
142
|
+
diskEncryption?: 'none' | 'luks2';
|
|
140
143
|
egressGuaranteedMbps: number;
|
|
141
144
|
egressBurstMbps: number;
|
|
142
145
|
confidential: boolean;
|