@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 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'
@@ -917,7 +917,7 @@ async function postSignedNode(options, path, body) {
917
917
  }
918
918
 
919
919
  // src/version.ts
920
- var VERSION3 = "0.1.134";
920
+ var VERSION3 = "0.1.136";
921
921
 
922
922
  // src/agent-heartbeat.ts
923
923
  function readAgentHostMetrics() {
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.134";
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';
@@ -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 = 1;
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]) => key !== "confidential")) {
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: options.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 = 1;
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,
@@ -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: 1;
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;
@@ -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 = 1;
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;
@@ -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;