@forgezero/agent 0.1.116 → 0.1.118

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
@@ -99,8 +99,12 @@ export default defineDeployment({
99
99
  resources: { cpuCores: input.ref('cpuCores'), memoryMiB: input.ref('memoryMiB'), storageGiB: input.ref('storageGiB') },
100
100
  os: 'ubuntu-24.04', runtime: 'oci-runc', sharing: 'shared', reuse: 'prefer',
101
101
  provisioning: {
102
- planKey: 'app-small', regionKey: 'default', imageKey: 'ubuntu-24.04-x64',
103
- environmentKey: 'production', ownership: 'platform', maxMonthlySpendMinor: '25000'
102
+ regionKey: 'default', imageKey: 'ubuntu-24.04-x64', environmentKey: 'production', ownership: 'platform',
103
+ resources: {
104
+ physicalCores: 1, vcpu: 2, memoryGib: 2, diskGib: 16,
105
+ egressGuaranteedMbps: 100, egressBurstMbps: 200, confidential: false
106
+ },
107
+ monthlyAmountCents: '1200', maxMonthlySpendMinor: '25000'
104
108
  },
105
109
  connectivity: {
106
110
  private: { mode: 'private-lan' },
@@ -229,8 +233,8 @@ import {
229
233
  ForgeZero,
230
234
  } from '@forgezero/vault';
231
235
 
232
- const fz = new ForgeZero({ project: 'altpilot', environment: 'production' });
233
- await fz.get('STRIPE_KEY');
236
+ const fz = new ForgeZero({ project: 'payments-api', environment: 'production' });
237
+ await fz.get('PAYMENT_PROVIDER');
234
238
  ```
235
239
 
236
240
  ## A local copy, not a cache
@@ -917,7 +917,7 @@ async function postSignedNode(options, path, body) {
917
917
  }
918
918
 
919
919
  // src/version.ts
920
- var VERSION3 = "0.1.116";
920
+ var VERSION3 = "0.1.118";
921
921
 
922
922
  // src/agent-heartbeat.ts
923
923
  function readAgentHostMetrics() {
@@ -89,7 +89,7 @@ export interface EnrolledComputeActivationConfig {
89
89
  profile?: string;
90
90
  deployRoot?: string;
91
91
  software?: SoftwareRequirement[];
92
- /** Compatibility-only per-node SSH deploy key. GitHub App is the scalable default. */
92
+ /** Compatibility-only per-node SSH deploy key for non-provider sources. */
93
93
  gitDeployKey?: boolean;
94
94
  installCloudflared?: boolean;
95
95
  installWarp?: boolean;
@@ -115,7 +115,6 @@ export interface PlatformBootstrapSecrets {
115
115
  backupS3Secret?: string;
116
116
  cloudflareTunnelToken?: string;
117
117
  cloudflareApiToken?: string;
118
- githubOAuthClientSecret: string;
119
118
  }
120
119
  export interface EnrolledComputeBootstrapSecrets {
121
120
  enrolmentToken: string;
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.116";
1463
+ var VERSION = "0.1.118";
1464
1464
 
1465
1465
  // src/software.ts
1466
1466
  var PINNED_BUN_VERSION = "1.3.14";
@@ -3272,9 +3272,6 @@ function validatePlatformSharedEnvironment(input) {
3272
3272
  } else if (input.email !== undefined) {
3273
3273
  throw new Error("Bootstrap email provider must be smtp or jetemail.");
3274
3274
  }
3275
- if (!input.githubOAuth || !/^(?:Iv1\.[A-Fa-f0-9]{16}|Ov23li[A-Za-z0-9]{14,})$/.test(input.githubOAuth.clientId)) {
3276
- throw new Error("GitHub OAuth client id is malformed.");
3277
- }
3278
3275
  boundedInteger("publicApiPort", input.publicApiPort, 1024, 65533);
3279
3276
  if (!Array.isArray(input.seedSyncMembers) || input.seedSyncMembers.length < 3 || input.seedSyncMembers.length > 64 || new Set(input.seedSyncMembers).size !== input.seedSyncMembers.length) {
3280
3277
  throw new Error("seedSyncMembers must contain 3 to 64 unique physical host identities.");
@@ -3405,7 +3402,6 @@ function renderPlatformSharedEnvironment(input) {
3405
3402
  FZ_REALTIME_WORKER_SCRIPT: value.realtime?.workerScriptName ?? "",
3406
3403
  FZ_REALTIME_ENDPOINT: value.realtime?.endpoint ?? "",
3407
3404
  FZ_REALTIME_PRODUCER: value.realtime?.producer ?? "",
3408
- FZ_GITHUB_OAUTH_CLIENT_ID: value.githubOAuth.clientId,
3409
3405
  FZ_PLATFORM_INITIAL_INVENTORY: value.initialInventory ? JSON.stringify(value.initialInventory) : ""
3410
3406
  };
3411
3407
  return `# Generated by fz bootstrap platform. Non-secret coordinates only.
@@ -3417,7 +3413,6 @@ function platformApiCredentialSpecs(options) {
3417
3413
  const optional = [
3418
3414
  ["fz_smtp.password", options.emailProvider === "smtp"],
3419
3415
  ["fz_jetemail.apiKey", options.emailProvider === "jetemail"],
3420
- ["fz_oauth.github.clientSecret", options.githubOAuth],
3421
3416
  ["CF_API_TOKEN", options.cloudflareKv],
3422
3417
  ["CF_TUNNEL_TOKEN", options.cloudflareKv],
3423
3418
  ["REALTIME_PUBLISH_SECRET", options.realtime],
@@ -3814,15 +3809,7 @@ function validatePlatformBootstrapSecrets(config, input) {
3814
3809
  if (!input || typeof input !== "object" || Array.isArray(input))
3815
3810
  throw new Error("bootstrap credential input must be an object");
3816
3811
  const source = input;
3817
- const allowed = [
3818
- "clusterBootstrapCode",
3819
- "emailSecret",
3820
- "enrolmentToken",
3821
- "backupS3Secret",
3822
- "cloudflareTunnelToken",
3823
- "cloudflareApiToken",
3824
- "githubOAuthClientSecret"
3825
- ];
3812
+ const allowed = ["clusterBootstrapCode", "emailSecret", "enrolmentToken", "backupS3Secret", "cloudflareTunnelToken", "cloudflareApiToken"];
3826
3813
  const unknown = Object.keys(source).filter((key) => !allowed.includes(key));
3827
3814
  if (unknown.length)
3828
3815
  throw new Error(`bootstrap credential input contains unsupported field ${unknown[0]}`);
@@ -3832,7 +3819,6 @@ function validatePlatformBootstrapSecrets(config, input) {
3832
3819
  const backupS3Secret = typeof source.backupS3Secret === "string" ? source.backupS3Secret.trim() : undefined;
3833
3820
  const cloudflareTunnelToken = typeof source.cloudflareTunnelToken === "string" ? source.cloudflareTunnelToken.trim() : undefined;
3834
3821
  const cloudflareApiToken = typeof source.cloudflareApiToken === "string" ? source.cloudflareApiToken.trim() : undefined;
3835
- const githubOAuthClientSecret = typeof source.githubOAuthClientSecret === "string" ? source.githubOAuthClientSecret.trim() : "";
3836
3822
  if (!/^[a-f0-9]{64}$/i.test(clusterBootstrapCode))
3837
3823
  throw new Error("cluster bootstrap code must contain exactly 64 hexadecimal characters");
3838
3824
  if (!emailSecret || emailSecret.length > 16384 || /[\r\n\0]/.test(emailSecret))
@@ -3852,16 +3838,12 @@ function validatePlatformBootstrapSecrets(config, input) {
3852
3838
  }
3853
3839
  if (cloudflareTunnelToken)
3854
3840
  validateCloudflareBootstrapSecretPair({ cloudflareTunnelToken, cloudflareApiToken });
3855
- if (githubOAuthClientSecret.length < 20 || githubOAuthClientSecret.length > 512 || /[\r\n\0]/.test(githubOAuthClientSecret)) {
3856
- throw new Error("GitHub OAuth client secret is malformed");
3857
- }
3858
3841
  return {
3859
3842
  clusterBootstrapCode,
3860
3843
  emailSecret,
3861
3844
  ...enrolmentToken ? { enrolmentToken } : {},
3862
3845
  ...backupS3Secret ? { backupS3Secret } : {},
3863
- ...cloudflareTunnelToken ? { cloudflareTunnelToken, cloudflareApiToken } : {},
3864
- githubOAuthClientSecret
3846
+ ...cloudflareTunnelToken ? { cloudflareTunnelToken, cloudflareApiToken } : {}
3865
3847
  };
3866
3848
  }
3867
3849
  var platformBootstrapRunner = (config) => config.kind === "platform" && config.database.role === "master";
@@ -4784,8 +4766,7 @@ async function applyBootstrap(input, host = localBootstrapHost(), secrets, depen
4784
4766
  enrolmentToken: checked4.enrolmentToken,
4785
4767
  backup: checked4.backupS3Secret,
4786
4768
  cloudflareTunnelToken: checked4.cloudflareTunnelToken,
4787
- cloudflareApiToken: checked4.cloudflareApiToken,
4788
- githubOAuthClientSecret: checked4.githubOAuthClientSecret
4769
+ cloudflareApiToken: checked4.cloudflareApiToken
4789
4770
  };
4790
4771
  })() : undefined;
4791
4772
  const enrolledPrivate = config.kind === "enrolled-compute" ? validateEnrolledComputeBootstrapSecrets(config, secrets) : undefined;
@@ -4886,7 +4867,6 @@ async function applyBootstrap(input, host = localBootstrapHost(), secrets, depen
4886
4867
  const emailCredentialName = config.runtime.environment.email?.provider === "smtp" ? "fz_smtp.password" : config.runtime.environment.email?.provider === "jetemail" ? "fz_jetemail.apiKey" : undefined;
4887
4868
  for (const [name, source] of Object.entries({
4888
4869
  ...emailCredentialName ? { [emailCredentialName]: platformPrivate.email } : {},
4889
- "fz_oauth.github.clientSecret": platformPrivate.githubOAuthClientSecret,
4890
4870
  "backup.s3.secretAccessKey": platformPrivate.backup
4891
4871
  })) {
4892
4872
  if (source) {
@@ -4903,7 +4883,6 @@ async function applyBootstrap(input, host = localBootstrapHost(), secrets, depen
4903
4883
  const credentials = platformApiCredentialSpecs({
4904
4884
  emailProvider: runtime.environment.email?.provider,
4905
4885
  cloudflareKv: cloudflareConfigured,
4906
- githubOAuth: true,
4907
4886
  realtime: Boolean(runtime.environment.realtime)
4908
4887
  });
4909
4888
  const units = renderPlatformApiUnits({
@@ -5151,7 +5130,6 @@ function strictBootstrapDocument(value) {
5151
5130
  "agentOtlpEndpoint",
5152
5131
  "custodianEmail",
5153
5132
  "email",
5154
- "githubOAuth",
5155
5133
  "deployProfile",
5156
5134
  "otlpFlushIntervalMs",
5157
5135
  "otlpTraceSampleRatio",
@@ -5162,7 +5140,6 @@ function strictBootstrapDocument(value) {
5162
5140
  "databaseReadPreferredCoordinators"
5163
5141
  ], "runtime environment");
5164
5142
  const environment = runtime.environment;
5165
- exactKeys(environment.githubOAuth, ["clientId"], "GitHub OAuth config");
5166
5143
  if (environment.initialInventory !== undefined) {
5167
5144
  const inventory = exactKeys(environment.initialInventory, ["metalHostname", "metalIdentity", "region", "computes", "attestation", "deployment"], "initial inventory");
5168
5145
  if (inventory.metalIdentity !== undefined) {
@@ -10,12 +10,21 @@ export interface DeploymentCompilation {
10
10
  }
11
11
  export type DeploymentInitRuntime = 'native' | 'containerd' | 'kata-snp';
12
12
  export interface DeploymentInitProvisioning {
13
- planKey: string;
14
13
  regionKey: string;
15
14
  imageKey: string;
16
15
  environmentKey: string;
17
16
  ownership: 'platform' | 'tenant-metal';
18
17
  metalHostname?: string;
18
+ resources: {
19
+ physicalCores: number;
20
+ vcpu: number;
21
+ memoryGib: number;
22
+ diskGib: number;
23
+ egressGuaranteedMbps: number;
24
+ egressBurstMbps: number;
25
+ confidential: boolean;
26
+ };
27
+ monthlyAmountCents: string;
19
28
  maxMonthlySpendMinor: string;
20
29
  }
21
30
  export interface DeploymentInitOptions {
@@ -910,13 +910,30 @@ function compileDeployment(sourceValue) {
910
910
  fail(`deployment.spec.targets.${targetName}.allocation.execution`, "cannot satisfy required confidential compute.");
911
911
  if (target.provisioning !== undefined) {
912
912
  const provisioning = object(target.provisioning, `deployment.spec.targets.${targetName}.provisioning`);
913
- exact3(provisioning, ["planKey", "regionKey", "imageKey", "environmentKey", "ownership", "metalHostname", "maxMonthlySpendMinor"], `deployment.spec.targets.${targetName}.provisioning`);
914
- for (const key of ["planKey", "regionKey", "imageKey", "environmentKey"])
913
+ exact3(provisioning, ["regionKey", "imageKey", "environmentKey", "ownership", "metalHostname", "resources", "monthlyAmountCents", "maxMonthlySpendMinor"], `deployment.spec.targets.${targetName}.provisioning`);
914
+ for (const key of ["regionKey", "imageKey", "environmentKey"])
915
915
  named(provisioning[key], `deployment.spec.targets.${targetName}.provisioning.${key}`);
916
916
  if (!["platform", "tenant-metal"].includes(String(provisioning.ownership)) || provisioning.ownership === "tenant-metal" !== Boolean(provisioning.metalHostname))
917
917
  fail(`deployment.spec.targets.${targetName}.provisioning.ownership`, "must bind platform capacity or one tenant metal hostname.");
918
918
  if (provisioning.metalHostname !== undefined && !/^(?=.{1,253}$)[A-Za-z0-9](?:[A-Za-z0-9.-]*[A-Za-z0-9])?$/.test(String(provisioning.metalHostname)))
919
919
  fail(`deployment.spec.targets.${targetName}.provisioning.metalHostname`, "is invalid.");
920
+ 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`);
922
+ integer(provisionedResources.physicalCores, `deployment.spec.targets.${targetName}.provisioning.resources.physicalCores`, 1, 1024);
923
+ integer(provisionedResources.vcpu, `deployment.spec.targets.${targetName}.provisioning.resources.vcpu`, 1, 4096);
924
+ integer(provisionedResources.memoryGib, `deployment.spec.targets.${targetName}.provisioning.resources.memoryGib`, 1, 4194304);
925
+ integer(provisionedResources.diskGib, `deployment.spec.targets.${targetName}.provisioning.resources.diskGib`, 1, 1048576);
926
+ integer(provisionedResources.egressGuaranteedMbps, `deployment.spec.targets.${targetName}.provisioning.resources.egressGuaranteedMbps`, 0, 1e7);
927
+ integer(provisionedResources.egressBurstMbps, `deployment.spec.targets.${targetName}.provisioning.resources.egressBurstMbps`, Number(provisionedResources.egressGuaranteedMbps), 1e7);
928
+ if (typeof provisionedResources.confidential !== "boolean")
929
+ fail(`deployment.spec.targets.${targetName}.provisioning.resources.confidential`, "must be boolean.");
930
+ if (typeof capacity.cpuCores === "number" && Number(provisionedResources.vcpu) < capacity.cpuCores || typeof capacity.memoryMiB === "number" && Number(provisionedResources.memoryGib) * 1024 < capacity.memoryMiB || typeof capacity.storageGiB === "number" && Number(provisionedResources.diskGib) < capacity.storageGiB) {
931
+ fail(`deployment.spec.targets.${targetName}.provisioning.resources`, "must satisfy the per-slot allocation minimum.");
932
+ }
933
+ if ((selector.confidentialCompute === "required" || allocation.execution === "oci-kata-qemu-snp") && provisionedResources.confidential !== true)
934
+ fail(`deployment.spec.targets.${targetName}.provisioning.resources.confidential`, "must be true for confidential execution.");
935
+ if (typeof provisioning.monthlyAmountCents !== "string" || !/^\d{1,18}$/.test(provisioning.monthlyAmountCents))
936
+ fail(`deployment.spec.targets.${targetName}.provisioning.monthlyAmountCents`, "must be a bounded USD-cent amount.");
920
937
  if (typeof provisioning.maxMonthlySpendMinor !== "string" || !/^\d{1,18}$/.test(provisioning.maxMonthlySpendMinor))
921
938
  fail(`deployment.spec.targets.${targetName}.provisioning.maxMonthlySpendMinor`, "must be a bounded decimal minor-unit amount.");
922
939
  }
@@ -1266,13 +1283,24 @@ function initCoordinates(options) {
1266
1283
  throw new Error("reuse require cannot include provisioning coordinates");
1267
1284
  if (options.provisioning !== undefined) {
1268
1285
  for (const [label, value] of Object.entries({
1269
- plan: options.provisioning.planKey,
1270
1286
  region: options.provisioning.regionKey,
1271
1287
  image: options.provisioning.imageKey,
1272
1288
  environment: options.provisioning.environmentKey
1273
1289
  }))
1274
1290
  if (!/^[a-z][a-z0-9-]{0,62}$/.test(value))
1275
1291
  throw new Error(`deployment provisioning ${label} must be a lowercase typed name`);
1292
+ const resources = options.provisioning.resources;
1293
+ for (const [label, value] of Object.entries(resources).filter(([key]) => key !== "confidential")) {
1294
+ if (!Number.isSafeInteger(value) || Number(value) < 0)
1295
+ throw new Error(`deployment provisioning ${label} must be a non-negative integer`);
1296
+ }
1297
+ if (resources.physicalCores < 1 || resources.vcpu < result.cpuCores || resources.memoryGib * 1024 < result.memoryMiB || resources.diskGib < result.storageGiB || resources.egressBurstMbps < resources.egressGuaranteedMbps) {
1298
+ throw new Error("deployment provisioning resources must satisfy the target allocation and bandwidth bounds");
1299
+ }
1300
+ if (result.isolation === "sev-snp" && !resources.confidential)
1301
+ throw new Error("deployment provisioning must provide confidential capacity for sev-snp");
1302
+ if (!/^\d{1,18}$/.test(options.provisioning.monthlyAmountCents))
1303
+ throw new Error("deployment provisioning monthly amount must be a bounded USD-cent amount");
1276
1304
  if (!/^\d{1,18}$/.test(options.provisioning.maxMonthlySpendMinor))
1277
1305
  throw new Error("deployment provisioning monthly spend must be a bounded decimal minor-unit amount");
1278
1306
  if (options.provisioning.ownership === "tenant-metal" && !options.provisioning.metalHostname)
@@ -1289,7 +1317,7 @@ function defaultTypeScriptDeployment(name, options = {}) {
1289
1317
  const execution = selected.runtime === "native" ? "native" : selected.runtime === "containerd" ? "oci-runc" : "oci-kata-qemu-snp";
1290
1318
  const hostPackageVersion = selected.operatingSystem === "ubuntu-24.04" ? "ubuntu-24.04" : "ubuntu-26.04";
1291
1319
  const provisioningBlock = selected.provisioning === undefined ? "" : `,
1292
- provisioning: { planKey: '${selected.provisioning.planKey}', regionKey: '${selected.provisioning.regionKey}', imageKey: '${selected.provisioning.imageKey}', environmentKey: '${selected.provisioning.environmentKey}', ownership: '${selected.provisioning.ownership}',${selected.provisioning.metalHostname ? ` metalHostname: '${selected.provisioning.metalHostname}',` : ""} maxMonthlySpendMinor: '${selected.provisioning.maxMonthlySpendMinor}' }`;
1320
+ provisioning: { regionKey: '${selected.provisioning.regionKey}', imageKey: '${selected.provisioning.imageKey}', environmentKey: '${selected.provisioning.environmentKey}', ownership: '${selected.provisioning.ownership}',${selected.provisioning.metalHostname ? ` metalHostname: '${selected.provisioning.metalHostname}',` : ""} resources: ${JSON.stringify(selected.provisioning.resources)}, monthlyAmountCents: '${selected.provisioning.monthlyAmountCents}', maxMonthlySpendMinor: '${selected.provisioning.maxMonthlySpendMinor}' }`;
1293
1321
  const requirementBlock = selected.runtime === "native" ? `bun: providers.bun.require()` : selected.runtime === "containerd" ? `containerd: providers.containerd.require({ version: '${hostPackageVersion}' }),
1294
1322
  nginx: providers.nginx.require({ version: '${hostPackageVersion}' })` : `containerd: providers.containerd.require(),
1295
1323
  kata: providers.kata.require(),
@@ -910,13 +910,30 @@ function compileDeployment(sourceValue) {
910
910
  fail(`deployment.spec.targets.${targetName}.allocation.execution`, "cannot satisfy required confidential compute.");
911
911
  if (target.provisioning !== undefined) {
912
912
  const provisioning = object(target.provisioning, `deployment.spec.targets.${targetName}.provisioning`);
913
- exact3(provisioning, ["planKey", "regionKey", "imageKey", "environmentKey", "ownership", "metalHostname", "maxMonthlySpendMinor"], `deployment.spec.targets.${targetName}.provisioning`);
914
- for (const key of ["planKey", "regionKey", "imageKey", "environmentKey"])
913
+ exact3(provisioning, ["regionKey", "imageKey", "environmentKey", "ownership", "metalHostname", "resources", "monthlyAmountCents", "maxMonthlySpendMinor"], `deployment.spec.targets.${targetName}.provisioning`);
914
+ for (const key of ["regionKey", "imageKey", "environmentKey"])
915
915
  named(provisioning[key], `deployment.spec.targets.${targetName}.provisioning.${key}`);
916
916
  if (!["platform", "tenant-metal"].includes(String(provisioning.ownership)) || provisioning.ownership === "tenant-metal" !== Boolean(provisioning.metalHostname))
917
917
  fail(`deployment.spec.targets.${targetName}.provisioning.ownership`, "must bind platform capacity or one tenant metal hostname.");
918
918
  if (provisioning.metalHostname !== undefined && !/^(?=.{1,253}$)[A-Za-z0-9](?:[A-Za-z0-9.-]*[A-Za-z0-9])?$/.test(String(provisioning.metalHostname)))
919
919
  fail(`deployment.spec.targets.${targetName}.provisioning.metalHostname`, "is invalid.");
920
+ 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`);
922
+ integer(provisionedResources.physicalCores, `deployment.spec.targets.${targetName}.provisioning.resources.physicalCores`, 1, 1024);
923
+ integer(provisionedResources.vcpu, `deployment.spec.targets.${targetName}.provisioning.resources.vcpu`, 1, 4096);
924
+ integer(provisionedResources.memoryGib, `deployment.spec.targets.${targetName}.provisioning.resources.memoryGib`, 1, 4194304);
925
+ integer(provisionedResources.diskGib, `deployment.spec.targets.${targetName}.provisioning.resources.diskGib`, 1, 1048576);
926
+ integer(provisionedResources.egressGuaranteedMbps, `deployment.spec.targets.${targetName}.provisioning.resources.egressGuaranteedMbps`, 0, 1e7);
927
+ integer(provisionedResources.egressBurstMbps, `deployment.spec.targets.${targetName}.provisioning.resources.egressBurstMbps`, Number(provisionedResources.egressGuaranteedMbps), 1e7);
928
+ if (typeof provisionedResources.confidential !== "boolean")
929
+ fail(`deployment.spec.targets.${targetName}.provisioning.resources.confidential`, "must be boolean.");
930
+ if (typeof capacity.cpuCores === "number" && Number(provisionedResources.vcpu) < capacity.cpuCores || typeof capacity.memoryMiB === "number" && Number(provisionedResources.memoryGib) * 1024 < capacity.memoryMiB || typeof capacity.storageGiB === "number" && Number(provisionedResources.diskGib) < capacity.storageGiB) {
931
+ fail(`deployment.spec.targets.${targetName}.provisioning.resources`, "must satisfy the per-slot allocation minimum.");
932
+ }
933
+ if ((selector.confidentialCompute === "required" || allocation.execution === "oci-kata-qemu-snp") && provisionedResources.confidential !== true)
934
+ fail(`deployment.spec.targets.${targetName}.provisioning.resources.confidential`, "must be true for confidential execution.");
935
+ if (typeof provisioning.monthlyAmountCents !== "string" || !/^\d{1,18}$/.test(provisioning.monthlyAmountCents))
936
+ fail(`deployment.spec.targets.${targetName}.provisioning.monthlyAmountCents`, "must be a bounded USD-cent amount.");
920
937
  if (typeof provisioning.maxMonthlySpendMinor !== "string" || !/^\d{1,18}$/.test(provisioning.maxMonthlySpendMinor))
921
938
  fail(`deployment.spec.targets.${targetName}.provisioning.maxMonthlySpendMinor`, "must be a bounded decimal minor-unit amount.");
922
939
  }
@@ -910,13 +910,30 @@ function compileDeployment(sourceValue) {
910
910
  fail(`deployment.spec.targets.${targetName}.allocation.execution`, "cannot satisfy required confidential compute.");
911
911
  if (target.provisioning !== undefined) {
912
912
  const provisioning = object(target.provisioning, `deployment.spec.targets.${targetName}.provisioning`);
913
- exact3(provisioning, ["planKey", "regionKey", "imageKey", "environmentKey", "ownership", "metalHostname", "maxMonthlySpendMinor"], `deployment.spec.targets.${targetName}.provisioning`);
914
- for (const key of ["planKey", "regionKey", "imageKey", "environmentKey"])
913
+ exact3(provisioning, ["regionKey", "imageKey", "environmentKey", "ownership", "metalHostname", "resources", "monthlyAmountCents", "maxMonthlySpendMinor"], `deployment.spec.targets.${targetName}.provisioning`);
914
+ for (const key of ["regionKey", "imageKey", "environmentKey"])
915
915
  named(provisioning[key], `deployment.spec.targets.${targetName}.provisioning.${key}`);
916
916
  if (!["platform", "tenant-metal"].includes(String(provisioning.ownership)) || provisioning.ownership === "tenant-metal" !== Boolean(provisioning.metalHostname))
917
917
  fail(`deployment.spec.targets.${targetName}.provisioning.ownership`, "must bind platform capacity or one tenant metal hostname.");
918
918
  if (provisioning.metalHostname !== undefined && !/^(?=.{1,253}$)[A-Za-z0-9](?:[A-Za-z0-9.-]*[A-Za-z0-9])?$/.test(String(provisioning.metalHostname)))
919
919
  fail(`deployment.spec.targets.${targetName}.provisioning.metalHostname`, "is invalid.");
920
+ 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`);
922
+ integer(provisionedResources.physicalCores, `deployment.spec.targets.${targetName}.provisioning.resources.physicalCores`, 1, 1024);
923
+ integer(provisionedResources.vcpu, `deployment.spec.targets.${targetName}.provisioning.resources.vcpu`, 1, 4096);
924
+ integer(provisionedResources.memoryGib, `deployment.spec.targets.${targetName}.provisioning.resources.memoryGib`, 1, 4194304);
925
+ integer(provisionedResources.diskGib, `deployment.spec.targets.${targetName}.provisioning.resources.diskGib`, 1, 1048576);
926
+ integer(provisionedResources.egressGuaranteedMbps, `deployment.spec.targets.${targetName}.provisioning.resources.egressGuaranteedMbps`, 0, 1e7);
927
+ integer(provisionedResources.egressBurstMbps, `deployment.spec.targets.${targetName}.provisioning.resources.egressBurstMbps`, Number(provisionedResources.egressGuaranteedMbps), 1e7);
928
+ if (typeof provisionedResources.confidential !== "boolean")
929
+ fail(`deployment.spec.targets.${targetName}.provisioning.resources.confidential`, "must be boolean.");
930
+ if (typeof capacity.cpuCores === "number" && Number(provisionedResources.vcpu) < capacity.cpuCores || typeof capacity.memoryMiB === "number" && Number(provisionedResources.memoryGib) * 1024 < capacity.memoryMiB || typeof capacity.storageGiB === "number" && Number(provisionedResources.diskGib) < capacity.storageGiB) {
931
+ fail(`deployment.spec.targets.${targetName}.provisioning.resources`, "must satisfy the per-slot allocation minimum.");
932
+ }
933
+ if ((selector.confidentialCompute === "required" || allocation.execution === "oci-kata-qemu-snp") && provisionedResources.confidential !== true)
934
+ fail(`deployment.spec.targets.${targetName}.provisioning.resources.confidential`, "must be true for confidential execution.");
935
+ if (typeof provisioning.monthlyAmountCents !== "string" || !/^\d{1,18}$/.test(provisioning.monthlyAmountCents))
936
+ fail(`deployment.spec.targets.${targetName}.provisioning.monthlyAmountCents`, "must be a bounded USD-cent amount.");
920
937
  if (typeof provisioning.maxMonthlySpendMinor !== "string" || !/^\d{1,18}$/.test(provisioning.maxMonthlySpendMinor))
921
938
  fail(`deployment.spec.targets.${targetName}.provisioning.maxMonthlySpendMinor`, "must be a bounded decimal minor-unit amount.");
922
939
  }
package/dist/deploy.d.ts CHANGED
@@ -185,12 +185,21 @@ export interface TargetDefinition {
185
185
  };
186
186
  /** Required only when the control plane may create capacity after reuse is exhausted. */
187
187
  provisioning?: {
188
- planKey: string;
189
188
  regionKey: string;
190
189
  imageKey: string;
191
190
  environmentKey: string;
192
191
  ownership: 'platform' | 'tenant-metal';
193
192
  metalHostname?: string;
193
+ resources: {
194
+ physicalCores: number;
195
+ vcpu: number;
196
+ memoryGib: number;
197
+ diskGib: number;
198
+ egressGuaranteedMbps: number;
199
+ egressBurstMbps: number;
200
+ confidential: boolean;
201
+ };
202
+ monthlyAmountCents: string;
194
203
  maxMonthlySpendMinor: string;
195
204
  };
196
205
  /** Per-slot connectivity intent. Credential names resolve through the scoped Vault, never to plan values. */
@@ -123,12 +123,21 @@ export interface ResolvedDeploymentTarget {
123
123
  existing: 'prefer' | 'require';
124
124
  };
125
125
  provisioning?: {
126
- planKey: string;
127
126
  regionKey: string;
128
127
  imageKey: string;
129
128
  environmentKey: string;
130
129
  ownership: 'platform' | 'tenant-metal';
131
130
  metalHostname?: string;
131
+ resources: {
132
+ physicalCores: number;
133
+ vcpu: number;
134
+ memoryGib: number;
135
+ diskGib: number;
136
+ egressGuaranteedMbps: number;
137
+ egressBurstMbps: number;
138
+ confidential: boolean;
139
+ };
140
+ monthlyAmountCents: string;
132
141
  maxMonthlySpendMinor: string;
133
142
  };
134
143
  connectivity?: {
package/dist/fz-agent.js CHANGED
@@ -7160,13 +7160,30 @@ function compileDeployment(sourceValue) {
7160
7160
  fail(`deployment.spec.targets.${targetName}.allocation.execution`, "cannot satisfy required confidential compute.");
7161
7161
  if (target.provisioning !== undefined) {
7162
7162
  const provisioning = object(target.provisioning, `deployment.spec.targets.${targetName}.provisioning`);
7163
- exact3(provisioning, ["planKey", "regionKey", "imageKey", "environmentKey", "ownership", "metalHostname", "maxMonthlySpendMinor"], `deployment.spec.targets.${targetName}.provisioning`);
7164
- for (const key of ["planKey", "regionKey", "imageKey", "environmentKey"])
7163
+ exact3(provisioning, ["regionKey", "imageKey", "environmentKey", "ownership", "metalHostname", "resources", "monthlyAmountCents", "maxMonthlySpendMinor"], `deployment.spec.targets.${targetName}.provisioning`);
7164
+ for (const key of ["regionKey", "imageKey", "environmentKey"])
7165
7165
  named(provisioning[key], `deployment.spec.targets.${targetName}.provisioning.${key}`);
7166
7166
  if (!["platform", "tenant-metal"].includes(String(provisioning.ownership)) || provisioning.ownership === "tenant-metal" !== Boolean(provisioning.metalHostname))
7167
7167
  fail(`deployment.spec.targets.${targetName}.provisioning.ownership`, "must bind platform capacity or one tenant metal hostname.");
7168
7168
  if (provisioning.metalHostname !== undefined && !/^(?=.{1,253}$)[A-Za-z0-9](?:[A-Za-z0-9.-]*[A-Za-z0-9])?$/.test(String(provisioning.metalHostname)))
7169
7169
  fail(`deployment.spec.targets.${targetName}.provisioning.metalHostname`, "is invalid.");
7170
+ const provisionedResources = object(provisioning.resources, `deployment.spec.targets.${targetName}.provisioning.resources`);
7171
+ exact3(provisionedResources, ["physicalCores", "vcpu", "memoryGib", "diskGib", "egressGuaranteedMbps", "egressBurstMbps", "confidential"], `deployment.spec.targets.${targetName}.provisioning.resources`);
7172
+ integer(provisionedResources.physicalCores, `deployment.spec.targets.${targetName}.provisioning.resources.physicalCores`, 1, 1024);
7173
+ integer(provisionedResources.vcpu, `deployment.spec.targets.${targetName}.provisioning.resources.vcpu`, 1, 4096);
7174
+ integer(provisionedResources.memoryGib, `deployment.spec.targets.${targetName}.provisioning.resources.memoryGib`, 1, 4194304);
7175
+ integer(provisionedResources.diskGib, `deployment.spec.targets.${targetName}.provisioning.resources.diskGib`, 1, 1048576);
7176
+ integer(provisionedResources.egressGuaranteedMbps, `deployment.spec.targets.${targetName}.provisioning.resources.egressGuaranteedMbps`, 0, 1e7);
7177
+ integer(provisionedResources.egressBurstMbps, `deployment.spec.targets.${targetName}.provisioning.resources.egressBurstMbps`, Number(provisionedResources.egressGuaranteedMbps), 1e7);
7178
+ if (typeof provisionedResources.confidential !== "boolean")
7179
+ fail(`deployment.spec.targets.${targetName}.provisioning.resources.confidential`, "must be boolean.");
7180
+ if (typeof capacity.cpuCores === "number" && Number(provisionedResources.vcpu) < capacity.cpuCores || typeof capacity.memoryMiB === "number" && Number(provisionedResources.memoryGib) * 1024 < capacity.memoryMiB || typeof capacity.storageGiB === "number" && Number(provisionedResources.diskGib) < capacity.storageGiB) {
7181
+ fail(`deployment.spec.targets.${targetName}.provisioning.resources`, "must satisfy the per-slot allocation minimum.");
7182
+ }
7183
+ if ((selector.confidentialCompute === "required" || allocation.execution === "oci-kata-qemu-snp") && provisionedResources.confidential !== true)
7184
+ fail(`deployment.spec.targets.${targetName}.provisioning.resources.confidential`, "must be true for confidential execution.");
7185
+ if (typeof provisioning.monthlyAmountCents !== "string" || !/^\d{1,18}$/.test(provisioning.monthlyAmountCents))
7186
+ fail(`deployment.spec.targets.${targetName}.provisioning.monthlyAmountCents`, "must be a bounded USD-cent amount.");
7170
7187
  if (typeof provisioning.maxMonthlySpendMinor !== "string" || !/^\d{1,18}$/.test(provisioning.maxMonthlySpendMinor))
7171
7188
  fail(`deployment.spec.targets.${targetName}.provisioning.maxMonthlySpendMinor`, "must be a bounded decimal minor-unit amount.");
7172
7189
  }
@@ -9601,7 +9618,7 @@ async function writeAndCloseProcessInput(input, value) {
9601
9618
  }
9602
9619
 
9603
9620
  // src/version.ts
9604
- var VERSION2 = "0.1.116";
9621
+ var VERSION2 = "0.1.118";
9605
9622
 
9606
9623
  // src/ssh-bootstrap.ts
9607
9624
  class SshBootstrapError extends Error {
package/dist/fz.js CHANGED
@@ -4634,7 +4634,7 @@ var VaultError, runtimeEnvironment = () => typeof process !== "undefined" && pro
4634
4634
  } catch {
4635
4635
  return;
4636
4636
  }
4637
- }, VERSION = "0.1.20";
4637
+ }, VERSION = "0.1.21";
4638
4638
  var init_dist = __esm(() => {
4639
4639
  init_identity();
4640
4640
  VaultError = class VaultError extends Error {
@@ -4841,7 +4841,7 @@ var UPDATE_RETRY_BASE_MS = 5 * 60000;
4841
4841
  var UPDATE_RETRY_MAX_MS = 24 * 60 * 60000;
4842
4842
 
4843
4843
  // src/version.ts
4844
- var VERSION2 = "0.1.116";
4844
+ var VERSION2 = "0.1.118";
4845
4845
 
4846
4846
  // src/software.ts
4847
4847
  var PINNED_BUN_VERSION = "1.3.14";
@@ -11349,13 +11349,30 @@ function compileDeployment(sourceValue) {
11349
11349
  fail2(`deployment.spec.targets.${targetName}.allocation.execution`, "cannot satisfy required confidential compute.");
11350
11350
  if (target.provisioning !== undefined) {
11351
11351
  const provisioning = object(target.provisioning, `deployment.spec.targets.${targetName}.provisioning`);
11352
- exact3(provisioning, ["planKey", "regionKey", "imageKey", "environmentKey", "ownership", "metalHostname", "maxMonthlySpendMinor"], `deployment.spec.targets.${targetName}.provisioning`);
11353
- for (const key of ["planKey", "regionKey", "imageKey", "environmentKey"])
11352
+ exact3(provisioning, ["regionKey", "imageKey", "environmentKey", "ownership", "metalHostname", "resources", "monthlyAmountCents", "maxMonthlySpendMinor"], `deployment.spec.targets.${targetName}.provisioning`);
11353
+ for (const key of ["regionKey", "imageKey", "environmentKey"])
11354
11354
  named(provisioning[key], `deployment.spec.targets.${targetName}.provisioning.${key}`);
11355
11355
  if (!["platform", "tenant-metal"].includes(String(provisioning.ownership)) || provisioning.ownership === "tenant-metal" !== Boolean(provisioning.metalHostname))
11356
11356
  fail2(`deployment.spec.targets.${targetName}.provisioning.ownership`, "must bind platform capacity or one tenant metal hostname.");
11357
11357
  if (provisioning.metalHostname !== undefined && !/^(?=.{1,253}$)[A-Za-z0-9](?:[A-Za-z0-9.-]*[A-Za-z0-9])?$/.test(String(provisioning.metalHostname)))
11358
11358
  fail2(`deployment.spec.targets.${targetName}.provisioning.metalHostname`, "is invalid.");
11359
+ const provisionedResources = object(provisioning.resources, `deployment.spec.targets.${targetName}.provisioning.resources`);
11360
+ exact3(provisionedResources, ["physicalCores", "vcpu", "memoryGib", "diskGib", "egressGuaranteedMbps", "egressBurstMbps", "confidential"], `deployment.spec.targets.${targetName}.provisioning.resources`);
11361
+ integer(provisionedResources.physicalCores, `deployment.spec.targets.${targetName}.provisioning.resources.physicalCores`, 1, 1024);
11362
+ integer(provisionedResources.vcpu, `deployment.spec.targets.${targetName}.provisioning.resources.vcpu`, 1, 4096);
11363
+ integer(provisionedResources.memoryGib, `deployment.spec.targets.${targetName}.provisioning.resources.memoryGib`, 1, 4194304);
11364
+ integer(provisionedResources.diskGib, `deployment.spec.targets.${targetName}.provisioning.resources.diskGib`, 1, 1048576);
11365
+ integer(provisionedResources.egressGuaranteedMbps, `deployment.spec.targets.${targetName}.provisioning.resources.egressGuaranteedMbps`, 0, 1e7);
11366
+ integer(provisionedResources.egressBurstMbps, `deployment.spec.targets.${targetName}.provisioning.resources.egressBurstMbps`, Number(provisionedResources.egressGuaranteedMbps), 1e7);
11367
+ if (typeof provisionedResources.confidential !== "boolean")
11368
+ fail2(`deployment.spec.targets.${targetName}.provisioning.resources.confidential`, "must be boolean.");
11369
+ if (typeof capacity.cpuCores === "number" && Number(provisionedResources.vcpu) < capacity.cpuCores || typeof capacity.memoryMiB === "number" && Number(provisionedResources.memoryGib) * 1024 < capacity.memoryMiB || typeof capacity.storageGiB === "number" && Number(provisionedResources.diskGib) < capacity.storageGiB) {
11370
+ fail2(`deployment.spec.targets.${targetName}.provisioning.resources`, "must satisfy the per-slot allocation minimum.");
11371
+ }
11372
+ if ((selector.confidentialCompute === "required" || allocation.execution === "oci-kata-qemu-snp") && provisionedResources.confidential !== true)
11373
+ fail2(`deployment.spec.targets.${targetName}.provisioning.resources.confidential`, "must be true for confidential execution.");
11374
+ if (typeof provisioning.monthlyAmountCents !== "string" || !/^\d{1,18}$/.test(provisioning.monthlyAmountCents))
11375
+ fail2(`deployment.spec.targets.${targetName}.provisioning.monthlyAmountCents`, "must be a bounded USD-cent amount.");
11359
11376
  if (typeof provisioning.maxMonthlySpendMinor !== "string" || !/^\d{1,18}$/.test(provisioning.maxMonthlySpendMinor))
11360
11377
  fail2(`deployment.spec.targets.${targetName}.provisioning.maxMonthlySpendMinor`, "must be a bounded decimal minor-unit amount.");
11361
11378
  }
@@ -11701,13 +11718,24 @@ function initCoordinates(options) {
11701
11718
  throw new Error("reuse require cannot include provisioning coordinates");
11702
11719
  if (options.provisioning !== undefined) {
11703
11720
  for (const [label, value] of Object.entries({
11704
- plan: options.provisioning.planKey,
11705
11721
  region: options.provisioning.regionKey,
11706
11722
  image: options.provisioning.imageKey,
11707
11723
  environment: options.provisioning.environmentKey
11708
11724
  }))
11709
11725
  if (!/^[a-z][a-z0-9-]{0,62}$/.test(value))
11710
11726
  throw new Error(`deployment provisioning ${label} must be a lowercase typed name`);
11727
+ const resources = options.provisioning.resources;
11728
+ for (const [label, value] of Object.entries(resources).filter(([key]) => key !== "confidential")) {
11729
+ if (!Number.isSafeInteger(value) || Number(value) < 0)
11730
+ throw new Error(`deployment provisioning ${label} must be a non-negative integer`);
11731
+ }
11732
+ if (resources.physicalCores < 1 || resources.vcpu < result.cpuCores || resources.memoryGib * 1024 < result.memoryMiB || resources.diskGib < result.storageGiB || resources.egressBurstMbps < resources.egressGuaranteedMbps) {
11733
+ throw new Error("deployment provisioning resources must satisfy the target allocation and bandwidth bounds");
11734
+ }
11735
+ if (result.isolation === "sev-snp" && !resources.confidential)
11736
+ throw new Error("deployment provisioning must provide confidential capacity for sev-snp");
11737
+ if (!/^\d{1,18}$/.test(options.provisioning.monthlyAmountCents))
11738
+ throw new Error("deployment provisioning monthly amount must be a bounded USD-cent amount");
11711
11739
  if (!/^\d{1,18}$/.test(options.provisioning.maxMonthlySpendMinor))
11712
11740
  throw new Error("deployment provisioning monthly spend must be a bounded decimal minor-unit amount");
11713
11741
  if (options.provisioning.ownership === "tenant-metal" && !options.provisioning.metalHostname)
@@ -11724,7 +11752,7 @@ function defaultTypeScriptDeployment(name, options = {}) {
11724
11752
  const execution = selected.runtime === "native" ? "native" : selected.runtime === "containerd" ? "oci-runc" : "oci-kata-qemu-snp";
11725
11753
  const hostPackageVersion = selected.operatingSystem === "ubuntu-24.04" ? "ubuntu-24.04" : "ubuntu-26.04";
11726
11754
  const provisioningBlock = selected.provisioning === undefined ? "" : `,
11727
- provisioning: { planKey: '${selected.provisioning.planKey}', regionKey: '${selected.provisioning.regionKey}', imageKey: '${selected.provisioning.imageKey}', environmentKey: '${selected.provisioning.environmentKey}', ownership: '${selected.provisioning.ownership}',${selected.provisioning.metalHostname ? ` metalHostname: '${selected.provisioning.metalHostname}',` : ""} maxMonthlySpendMinor: '${selected.provisioning.maxMonthlySpendMinor}' }`;
11755
+ provisioning: { regionKey: '${selected.provisioning.regionKey}', imageKey: '${selected.provisioning.imageKey}', environmentKey: '${selected.provisioning.environmentKey}', ownership: '${selected.provisioning.ownership}',${selected.provisioning.metalHostname ? ` metalHostname: '${selected.provisioning.metalHostname}',` : ""} resources: ${JSON.stringify(selected.provisioning.resources)}, monthlyAmountCents: '${selected.provisioning.monthlyAmountCents}', maxMonthlySpendMinor: '${selected.provisioning.maxMonthlySpendMinor}' }`;
11728
11756
  const requirementBlock = selected.runtime === "native" ? `bun: providers.bun.require()` : selected.runtime === "containerd" ? `containerd: providers.containerd.require({ version: '${hostPackageVersion}' }),
11729
11757
  nginx: providers.nginx.require({ version: '${hostPackageVersion}' })` : `containerd: providers.containerd.require(),
11730
11758
  kata: providers.kata.require(),
@@ -12383,9 +12411,6 @@ function validatePlatformSharedEnvironment(input) {
12383
12411
  } else if (input.email !== undefined) {
12384
12412
  throw new Error("Bootstrap email provider must be smtp or jetemail.");
12385
12413
  }
12386
- if (!input.githubOAuth || !/^(?:Iv1\.[A-Fa-f0-9]{16}|Ov23li[A-Za-z0-9]{14,})$/.test(input.githubOAuth.clientId)) {
12387
- throw new Error("GitHub OAuth client id is malformed.");
12388
- }
12389
12414
  boundedInteger("publicApiPort", input.publicApiPort, 1024, 65533);
12390
12415
  if (!Array.isArray(input.seedSyncMembers) || input.seedSyncMembers.length < 3 || input.seedSyncMembers.length > 64 || new Set(input.seedSyncMembers).size !== input.seedSyncMembers.length) {
12391
12416
  throw new Error("seedSyncMembers must contain 3 to 64 unique physical host identities.");
@@ -12516,7 +12541,6 @@ function renderPlatformSharedEnvironment(input) {
12516
12541
  FZ_REALTIME_WORKER_SCRIPT: value.realtime?.workerScriptName ?? "",
12517
12542
  FZ_REALTIME_ENDPOINT: value.realtime?.endpoint ?? "",
12518
12543
  FZ_REALTIME_PRODUCER: value.realtime?.producer ?? "",
12519
- FZ_GITHUB_OAUTH_CLIENT_ID: value.githubOAuth.clientId,
12520
12544
  FZ_PLATFORM_INITIAL_INVENTORY: value.initialInventory ? JSON.stringify(value.initialInventory) : ""
12521
12545
  };
12522
12546
  return `# Generated by fz bootstrap platform. Non-secret coordinates only.
@@ -12528,7 +12552,6 @@ function platformApiCredentialSpecs(options) {
12528
12552
  const optional = [
12529
12553
  ["fz_smtp.password", options.emailProvider === "smtp"],
12530
12554
  ["fz_jetemail.apiKey", options.emailProvider === "jetemail"],
12531
- ["fz_oauth.github.clientSecret", options.githubOAuth],
12532
12555
  ["CF_API_TOKEN", options.cloudflareKv],
12533
12556
  ["CF_TUNNEL_TOKEN", options.cloudflareKv],
12534
12557
  ["REALTIME_PUBLISH_SECRET", options.realtime],
@@ -14201,15 +14224,7 @@ function validatePlatformBootstrapSecrets(config, input) {
14201
14224
  if (!input || typeof input !== "object" || Array.isArray(input))
14202
14225
  throw new Error("bootstrap credential input must be an object");
14203
14226
  const source = input;
14204
- const allowed = [
14205
- "clusterBootstrapCode",
14206
- "emailSecret",
14207
- "enrolmentToken",
14208
- "backupS3Secret",
14209
- "cloudflareTunnelToken",
14210
- "cloudflareApiToken",
14211
- "githubOAuthClientSecret"
14212
- ];
14227
+ const allowed = ["clusterBootstrapCode", "emailSecret", "enrolmentToken", "backupS3Secret", "cloudflareTunnelToken", "cloudflareApiToken"];
14213
14228
  const unknown = Object.keys(source).filter((key) => !allowed.includes(key));
14214
14229
  if (unknown.length)
14215
14230
  throw new Error(`bootstrap credential input contains unsupported field ${unknown[0]}`);
@@ -14219,7 +14234,6 @@ function validatePlatformBootstrapSecrets(config, input) {
14219
14234
  const backupS3Secret = typeof source.backupS3Secret === "string" ? source.backupS3Secret.trim() : undefined;
14220
14235
  const cloudflareTunnelToken = typeof source.cloudflareTunnelToken === "string" ? source.cloudflareTunnelToken.trim() : undefined;
14221
14236
  const cloudflareApiToken = typeof source.cloudflareApiToken === "string" ? source.cloudflareApiToken.trim() : undefined;
14222
- const githubOAuthClientSecret = typeof source.githubOAuthClientSecret === "string" ? source.githubOAuthClientSecret.trim() : "";
14223
14237
  if (!/^[a-f0-9]{64}$/i.test(clusterBootstrapCode))
14224
14238
  throw new Error("cluster bootstrap code must contain exactly 64 hexadecimal characters");
14225
14239
  if (!emailSecret || emailSecret.length > 16384 || /[\r\n\0]/.test(emailSecret))
@@ -14239,16 +14253,12 @@ function validatePlatformBootstrapSecrets(config, input) {
14239
14253
  }
14240
14254
  if (cloudflareTunnelToken)
14241
14255
  validateCloudflareBootstrapSecretPair({ cloudflareTunnelToken, cloudflareApiToken });
14242
- if (githubOAuthClientSecret.length < 20 || githubOAuthClientSecret.length > 512 || /[\r\n\0]/.test(githubOAuthClientSecret)) {
14243
- throw new Error("GitHub OAuth client secret is malformed");
14244
- }
14245
14256
  return {
14246
14257
  clusterBootstrapCode,
14247
14258
  emailSecret,
14248
14259
  ...enrolmentToken ? { enrolmentToken } : {},
14249
14260
  ...backupS3Secret ? { backupS3Secret } : {},
14250
- ...cloudflareTunnelToken ? { cloudflareTunnelToken, cloudflareApiToken } : {},
14251
- githubOAuthClientSecret
14261
+ ...cloudflareTunnelToken ? { cloudflareTunnelToken, cloudflareApiToken } : {}
14252
14262
  };
14253
14263
  }
14254
14264
  var platformBootstrapRunner = (config) => config.kind === "platform" && config.database.role === "master";
@@ -15171,8 +15181,7 @@ async function applyBootstrap(input, host = localBootstrapHost(), secrets, depen
15171
15181
  enrolmentToken: checked4.enrolmentToken,
15172
15182
  backup: checked4.backupS3Secret,
15173
15183
  cloudflareTunnelToken: checked4.cloudflareTunnelToken,
15174
- cloudflareApiToken: checked4.cloudflareApiToken,
15175
- githubOAuthClientSecret: checked4.githubOAuthClientSecret
15184
+ cloudflareApiToken: checked4.cloudflareApiToken
15176
15185
  };
15177
15186
  })() : undefined;
15178
15187
  const enrolledPrivate = config.kind === "enrolled-compute" ? validateEnrolledComputeBootstrapSecrets(config, secrets) : undefined;
@@ -15273,7 +15282,6 @@ async function applyBootstrap(input, host = localBootstrapHost(), secrets, depen
15273
15282
  const emailCredentialName = config.runtime.environment.email?.provider === "smtp" ? "fz_smtp.password" : config.runtime.environment.email?.provider === "jetemail" ? "fz_jetemail.apiKey" : undefined;
15274
15283
  for (const [name, source] of Object.entries({
15275
15284
  ...emailCredentialName ? { [emailCredentialName]: platformPrivate.email } : {},
15276
- "fz_oauth.github.clientSecret": platformPrivate.githubOAuthClientSecret,
15277
15285
  "backup.s3.secretAccessKey": platformPrivate.backup
15278
15286
  })) {
15279
15287
  if (source) {
@@ -15290,7 +15298,6 @@ async function applyBootstrap(input, host = localBootstrapHost(), secrets, depen
15290
15298
  const credentials = platformApiCredentialSpecs({
15291
15299
  emailProvider: runtime.environment.email?.provider,
15292
15300
  cloudflareKv: cloudflareConfigured,
15293
- githubOAuth: true,
15294
15301
  realtime: Boolean(runtime.environment.realtime)
15295
15302
  });
15296
15303
  const units = renderPlatformApiUnits({
@@ -15538,7 +15545,6 @@ function strictBootstrapDocument(value) {
15538
15545
  "agentOtlpEndpoint",
15539
15546
  "custodianEmail",
15540
15547
  "email",
15541
- "githubOAuth",
15542
15548
  "deployProfile",
15543
15549
  "otlpFlushIntervalMs",
15544
15550
  "otlpTraceSampleRatio",
@@ -15549,7 +15555,6 @@ function strictBootstrapDocument(value) {
15549
15555
  "databaseReadPreferredCoordinators"
15550
15556
  ], "runtime environment");
15551
15557
  const environment = runtime.environment;
15552
- exactKeys2(environment.githubOAuth, ["clientId"], "GitHub OAuth config");
15553
15558
  if (environment.initialInventory !== undefined) {
15554
15559
  const inventory = exactKeys2(environment.initialInventory, ["metalHostname", "metalIdentity", "region", "computes", "attestation", "deployment"], "initial inventory");
15555
15560
  if (inventory.metalIdentity !== undefined) {
@@ -18263,7 +18268,6 @@ function forgeZeroLaunchTemplate(profile, guests, bundle, owner) {
18263
18268
  otlpTraceSampleRatio: 0.1,
18264
18269
  custodianEmail: owner.custodianEmail,
18265
18270
  email: owner.email,
18266
- githubOAuth: owner.githubOAuth,
18267
18271
  deployProfile: profile.environment
18268
18272
  },
18269
18273
  serviceUser: "forgezero-api",
@@ -18651,18 +18655,15 @@ function readPlatformLaunchEnvironment(path) {
18651
18655
  throw new Error(`bootstrap secret environment is missing ${name}`);
18652
18656
  return value;
18653
18657
  };
18654
- const githubOAuth = { clientId: requiredValue("FZ_GITHUB_OAUTH_CLIENT_ID") };
18655
18658
  const owner = {
18656
18659
  custodianEmail: "info@axxra.in",
18657
- email: { provider: "jetemail", from: "noreply@forgezero.net", eu: false },
18658
- githubOAuth
18660
+ email: { provider: "jetemail", from: "noreply@forgezero.net", eu: false }
18659
18661
  };
18660
18662
  return {
18661
18663
  owner,
18662
18664
  emailSecret: requiredValue("FZ_JETEMAIL_API_KEY"),
18663
18665
  cloudflareTunnelToken: requiredValue("CF_TUNNEL_TOKEN"),
18664
- cloudflareApiToken: requiredValue("CF_API_TOKEN"),
18665
- githubOAuthClientSecret: requiredValue("FZ_GITHUB_OAUTH_CLIENT_SECRET")
18666
+ cloudflareApiToken: requiredValue("CF_API_TOKEN")
18666
18667
  };
18667
18668
  }
18668
18669
 
@@ -18798,9 +18799,6 @@ function parseOptions(argv2) {
18798
18799
  options.deployReuse = value;
18799
18800
  else
18800
18801
  options.optionError = "--reuse must be require or prefer.";
18801
- } else if (token === "--provision-plan") {
18802
- options.deployProvisionPlan = argv2[++index];
18803
- options.deployInitCustomized = true;
18804
18802
  } else if (token === "--provision-region") {
18805
18803
  options.deployProvisionRegion = argv2[++index];
18806
18804
  options.deployInitCustomized = true;
@@ -18820,6 +18818,26 @@ function parseOptions(argv2) {
18820
18818
  } else if (token === "--provision-metal") {
18821
18819
  options.deployProvisionMetal = argv2[++index];
18822
18820
  options.deployInitCustomized = true;
18821
+ } else if (["--provision-physical-cores", "--provision-vcpu", "--provision-memory-gib", "--provision-disk-gib", "--provision-guaranteed-mbps", "--provision-burst-mbps"].includes(token)) {
18822
+ const value = Number(argv2[++index] ?? "");
18823
+ options.deployInitCustomized = true;
18824
+ if (!Number.isSafeInteger(value) || value < 0)
18825
+ options.optionError = `${token} must be a non-negative integer.`;
18826
+ else if (token === "--provision-physical-cores")
18827
+ options.deployProvisionPhysicalCores = value;
18828
+ else if (token === "--provision-vcpu")
18829
+ options.deployProvisionVcpu = value;
18830
+ else if (token === "--provision-memory-gib")
18831
+ options.deployProvisionMemoryGib = value;
18832
+ else if (token === "--provision-disk-gib")
18833
+ options.deployProvisionDiskGib = value;
18834
+ else if (token === "--provision-guaranteed-mbps")
18835
+ options.deployProvisionGuaranteedMbps = value;
18836
+ else
18837
+ options.deployProvisionBurstMbps = value;
18838
+ } else if (token === "--provision-monthly-amount-cents") {
18839
+ options.deployProvisionMonthlyAmountCents = argv2[++index];
18840
+ options.deployInitCustomized = true;
18823
18841
  } else if (token === "--max-monthly-spend-minor") {
18824
18842
  options.deployMaxMonthlySpendMinor = argv2[++index];
18825
18843
  options.deployInitCustomized = true;
@@ -19488,8 +19506,7 @@ async function promptPlatformBootstrapSecrets(config, generatedClusterBootstrapC
19488
19506
  ...config.cloudflareHandoff || config.runtime.environment.cloudflare ? {
19489
19507
  cloudflareTunnelToken: await bootstrapSecret("CF_TUNNEL_TOKEN"),
19490
19508
  cloudflareApiToken: await bootstrapSecret("CF_API_TOKEN")
19491
- } : {},
19492
- githubOAuthClientSecret: await bootstrapSecret("GitHub OAuth client secret")
19509
+ } : {}
19493
19510
  });
19494
19511
  }
19495
19512
  var bootstrapList = (question, fallback) => bootstrapAnswer(question, fallback).split(",").map((value) => value.trim()).filter(Boolean);
@@ -19787,11 +19804,9 @@ function selectedForgeZeroLaunchEnvironment(value) {
19787
19804
  return value;
19788
19805
  }
19789
19806
  function forgeZeroLaunchOwnerInput() {
19790
- const githubOAuth = { clientId: bootstrapAnswer("GitHub OAuth client ID") };
19791
19807
  return {
19792
19808
  custodianEmail: "info@axxra.in",
19793
- email: { provider: "jetemail", from: "noreply@forgezero.net", eu: false },
19794
- githubOAuth
19809
+ email: { provider: "jetemail", from: "noreply@forgezero.net", eu: false }
19795
19810
  };
19796
19811
  }
19797
19812
  async function prepareForgeZeroPlatformLaunch(environment, outputDirectory, projectRoot, owner) {
@@ -19860,7 +19875,6 @@ function interactiveBootstrap(kind, genesisGuests, genesisCloudflareCheckpoint)
19860
19875
  const backupRegion = backupEndpoint ? bootstrapAnswer("Backup S3 region") : undefined;
19861
19876
  const backupBucket = backupEndpoint ? bootstrapAnswer("Backup S3 bucket") : undefined;
19862
19877
  const backupAccessKeyId = backupEndpoint ? bootstrapAnswer("Backup S3 access-key id") : undefined;
19863
- const githubOAuthClientId = bootstrapAnswer("GitHub OAuth client ID");
19864
19878
  const cloudflareHandoffFile = genesis ? cloudflareHostHandoffPath(genesisCloudflareCheckpoint, computeReference) : bootstrapAnswer("Node-specific Cloudflare host handoff (blank for no public edge)", "");
19865
19879
  const cloudflareNodeName = cloudflareHandoffFile ? genesis ? computeReference : bootstrapAnswer("Cloudflare handoff node name", computeReference) : undefined;
19866
19880
  const databaseNetworkMode = "private-lan";
@@ -19915,7 +19929,6 @@ function interactiveBootstrap(kind, genesisGuests, genesisCloudflareCheckpoint)
19915
19929
  otlpTraceSampleRatio: 0.1,
19916
19930
  custodianEmail: role === "master" ? bootstrapAnswer("First custodian email") : undefined,
19917
19931
  email: emailProvider === "smtp" ? { provider: "smtp", host: smtpHost, port: smtpPort, user: smtpUser, from: emailFrom } : { provider: "jetemail", from: emailFrom, eu: jetemailEu },
19918
- githubOAuth: { clientId: githubOAuthClientId },
19919
19932
  ...backupEndpoint && backupRegion && backupBucket && backupAccessKeyId ? {
19920
19933
  backup: { endpoint: backupEndpoint, region: backupRegion, bucket: backupBucket, accessKeyId: backupAccessKeyId }
19921
19934
  } : {},
@@ -19975,8 +19988,7 @@ async function runAttendedPlatformFleet(fleet, apply, generatedClusterBootstrapC
19975
19988
  clusterBootstrapCode: generatedClusterBootstrapCode,
19976
19989
  emailSecret: environmentInput.emailSecret,
19977
19990
  cloudflareTunnelToken: environmentInput.cloudflareTunnelToken,
19978
- cloudflareApiToken: environmentInput.cloudflareApiToken,
19979
- githubOAuthClientSecret: environmentInput.githubOAuthClientSecret
19991
+ cloudflareApiToken: environmentInput.cloudflareApiToken
19980
19992
  }) : await promptPlatformBootstrapSecrets(firstConfig, generatedClusterBootstrapCode);
19981
19993
  const cloudflare = await resolveCloudflareBootstrapCommandConfig(fleet.cloudflareConfigFile, {
19982
19994
  tunnelToken: secrets.cloudflareTunnelToken,
@@ -20614,20 +20626,35 @@ async function cmdDeploy(options, args) {
20614
20626
  reuse: options.deployReuse,
20615
20627
  profile: options.deployProfile,
20616
20628
  ...[
20617
- options.deployProvisionPlan,
20618
20629
  options.deployProvisionRegion,
20619
20630
  options.deployProvisionImage,
20620
20631
  options.deployProvisionEnvironment,
20621
20632
  options.deployProvisionOwnership,
20633
+ options.deployProvisionPhysicalCores,
20634
+ options.deployProvisionVcpu,
20635
+ options.deployProvisionMemoryGib,
20636
+ options.deployProvisionDiskGib,
20637
+ options.deployProvisionGuaranteedMbps,
20638
+ options.deployProvisionBurstMbps,
20639
+ options.deployProvisionMonthlyAmountCents,
20622
20640
  options.deployMaxMonthlySpendMinor
20623
20641
  ].some((value) => value !== undefined) ? {
20624
20642
  provisioning: {
20625
- planKey: options.deployProvisionPlan ?? "",
20626
20643
  regionKey: options.deployProvisionRegion ?? "",
20627
20644
  imageKey: options.deployProvisionImage ?? "",
20628
20645
  environmentKey: options.deployProvisionEnvironment ?? "",
20629
20646
  ownership: options.deployProvisionOwnership ?? "platform",
20630
20647
  ...options.deployProvisionMetal ? { metalHostname: options.deployProvisionMetal } : {},
20648
+ resources: {
20649
+ physicalCores: options.deployProvisionPhysicalCores ?? 0,
20650
+ vcpu: options.deployProvisionVcpu ?? 0,
20651
+ memoryGib: options.deployProvisionMemoryGib ?? 0,
20652
+ diskGib: options.deployProvisionDiskGib ?? 0,
20653
+ egressGuaranteedMbps: options.deployProvisionGuaranteedMbps ?? 0,
20654
+ egressBurstMbps: options.deployProvisionBurstMbps ?? 0,
20655
+ confidential: options.deployIsolation === "sev-snp"
20656
+ },
20657
+ monthlyAmountCents: options.deployProvisionMonthlyAmountCents ?? "",
20631
20658
  maxMonthlySpendMinor: options.deployMaxMonthlySpendMinor ?? ""
20632
20659
  }
20633
20660
  } : {}
@@ -20966,9 +20993,13 @@ function usage() {
20966
20993
  --storage-gib <n> Reserved storage GiB per compute
20967
20994
  --sharing <mode> exclusive or shared (native requires exclusive)
20968
20995
  --reuse <mode> require existing capacity or prefer reuse then approved provisioning
20969
- --provision-plan <key> --provision-region <key> --provision-image <key>
20996
+ --provision-region <key> --provision-image <key>
20970
20997
  --provision-environment <key> --provision-ownership <platform|tenant-metal>
20971
20998
  --provision-metal <host> Required only for tenant-metal ownership
20999
+ --provision-physical-cores <n> --provision-vcpu <n>
21000
+ --provision-memory-gib <n> --provision-disk-gib <n>
21001
+ --provision-guaranteed-mbps <n> --provision-burst-mbps <n>
21002
+ --provision-monthly-amount-cents <n> Exact approved USD cost per created compute
20972
21003
  --max-monthly-spend-minor <n> Hard approved scale-out spend ceiling
20973
21004
  --force Init may replace an existing generated target
20974
21005
 
@@ -366,7 +366,7 @@ function systemdAgentEgressDirectives(loopbackTcpPorts = []) {
366
366
  }
367
367
 
368
368
  // src/version.ts
369
- var VERSION = "0.1.116";
369
+ var VERSION = "0.1.118";
370
370
 
371
371
  // src/otel-collector.ts
372
372
  var FORGEZERO_OTEL_COLLECTOR_UNIT = "forgezero-otel-collector.service";
@@ -8,7 +8,7 @@ export interface MetalCpuPool {
8
8
  key: string;
9
9
  /** Linux CPU-list syntax, including every SMT sibling in this pool. */
10
10
  cpus: string;
11
- /** Real cores represented by cpus; checked against the commercial promise. */
11
+ /** Real cores represented by cpus; checked against the sellable capacity promise. */
12
12
  physicalCores: number;
13
13
  /** Linux NUMA node-list syntax. Optional on a non-NUMA machine. */
14
14
  memoryNodes?: string;
@@ -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.116";
1463
+ var VERSION = "0.1.118";
1464
1464
 
1465
1465
  // src/software.ts
1466
1466
  var PINNED_BUN_VERSION = "1.3.14";
@@ -3272,9 +3272,6 @@ function validatePlatformSharedEnvironment(input) {
3272
3272
  } else if (input.email !== undefined) {
3273
3273
  throw new Error("Bootstrap email provider must be smtp or jetemail.");
3274
3274
  }
3275
- if (!input.githubOAuth || !/^(?:Iv1\.[A-Fa-f0-9]{16}|Ov23li[A-Za-z0-9]{14,})$/.test(input.githubOAuth.clientId)) {
3276
- throw new Error("GitHub OAuth client id is malformed.");
3277
- }
3278
3275
  boundedInteger("publicApiPort", input.publicApiPort, 1024, 65533);
3279
3276
  if (!Array.isArray(input.seedSyncMembers) || input.seedSyncMembers.length < 3 || input.seedSyncMembers.length > 64 || new Set(input.seedSyncMembers).size !== input.seedSyncMembers.length) {
3280
3277
  throw new Error("seedSyncMembers must contain 3 to 64 unique physical host identities.");
@@ -3405,7 +3402,6 @@ function renderPlatformSharedEnvironment(input) {
3405
3402
  FZ_REALTIME_WORKER_SCRIPT: value.realtime?.workerScriptName ?? "",
3406
3403
  FZ_REALTIME_ENDPOINT: value.realtime?.endpoint ?? "",
3407
3404
  FZ_REALTIME_PRODUCER: value.realtime?.producer ?? "",
3408
- FZ_GITHUB_OAUTH_CLIENT_ID: value.githubOAuth.clientId,
3409
3405
  FZ_PLATFORM_INITIAL_INVENTORY: value.initialInventory ? JSON.stringify(value.initialInventory) : ""
3410
3406
  };
3411
3407
  return `# Generated by fz bootstrap platform. Non-secret coordinates only.
@@ -3417,7 +3413,6 @@ function platformApiCredentialSpecs(options) {
3417
3413
  const optional = [
3418
3414
  ["fz_smtp.password", options.emailProvider === "smtp"],
3419
3415
  ["fz_jetemail.apiKey", options.emailProvider === "jetemail"],
3420
- ["fz_oauth.github.clientSecret", options.githubOAuth],
3421
3416
  ["CF_API_TOKEN", options.cloudflareKv],
3422
3417
  ["CF_TUNNEL_TOKEN", options.cloudflareKv],
3423
3418
  ["REALTIME_PUBLISH_SECRET", options.realtime],
@@ -3814,15 +3809,7 @@ function validatePlatformBootstrapSecrets(config, input) {
3814
3809
  if (!input || typeof input !== "object" || Array.isArray(input))
3815
3810
  throw new Error("bootstrap credential input must be an object");
3816
3811
  const source = input;
3817
- const allowed = [
3818
- "clusterBootstrapCode",
3819
- "emailSecret",
3820
- "enrolmentToken",
3821
- "backupS3Secret",
3822
- "cloudflareTunnelToken",
3823
- "cloudflareApiToken",
3824
- "githubOAuthClientSecret"
3825
- ];
3812
+ const allowed = ["clusterBootstrapCode", "emailSecret", "enrolmentToken", "backupS3Secret", "cloudflareTunnelToken", "cloudflareApiToken"];
3826
3813
  const unknown = Object.keys(source).filter((key) => !allowed.includes(key));
3827
3814
  if (unknown.length)
3828
3815
  throw new Error(`bootstrap credential input contains unsupported field ${unknown[0]}`);
@@ -3832,7 +3819,6 @@ function validatePlatformBootstrapSecrets(config, input) {
3832
3819
  const backupS3Secret = typeof source.backupS3Secret === "string" ? source.backupS3Secret.trim() : undefined;
3833
3820
  const cloudflareTunnelToken = typeof source.cloudflareTunnelToken === "string" ? source.cloudflareTunnelToken.trim() : undefined;
3834
3821
  const cloudflareApiToken = typeof source.cloudflareApiToken === "string" ? source.cloudflareApiToken.trim() : undefined;
3835
- const githubOAuthClientSecret = typeof source.githubOAuthClientSecret === "string" ? source.githubOAuthClientSecret.trim() : "";
3836
3822
  if (!/^[a-f0-9]{64}$/i.test(clusterBootstrapCode))
3837
3823
  throw new Error("cluster bootstrap code must contain exactly 64 hexadecimal characters");
3838
3824
  if (!emailSecret || emailSecret.length > 16384 || /[\r\n\0]/.test(emailSecret))
@@ -3852,16 +3838,12 @@ function validatePlatformBootstrapSecrets(config, input) {
3852
3838
  }
3853
3839
  if (cloudflareTunnelToken)
3854
3840
  validateCloudflareBootstrapSecretPair({ cloudflareTunnelToken, cloudflareApiToken });
3855
- if (githubOAuthClientSecret.length < 20 || githubOAuthClientSecret.length > 512 || /[\r\n\0]/.test(githubOAuthClientSecret)) {
3856
- throw new Error("GitHub OAuth client secret is malformed");
3857
- }
3858
3841
  return {
3859
3842
  clusterBootstrapCode,
3860
3843
  emailSecret,
3861
3844
  ...enrolmentToken ? { enrolmentToken } : {},
3862
3845
  ...backupS3Secret ? { backupS3Secret } : {},
3863
- ...cloudflareTunnelToken ? { cloudflareTunnelToken, cloudflareApiToken } : {},
3864
- githubOAuthClientSecret
3846
+ ...cloudflareTunnelToken ? { cloudflareTunnelToken, cloudflareApiToken } : {}
3865
3847
  };
3866
3848
  }
3867
3849
  var platformBootstrapRunner = (config) => config.kind === "platform" && config.database.role === "master";
@@ -4784,8 +4766,7 @@ async function applyBootstrap(input, host = localBootstrapHost(), secrets, depen
4784
4766
  enrolmentToken: checked4.enrolmentToken,
4785
4767
  backup: checked4.backupS3Secret,
4786
4768
  cloudflareTunnelToken: checked4.cloudflareTunnelToken,
4787
- cloudflareApiToken: checked4.cloudflareApiToken,
4788
- githubOAuthClientSecret: checked4.githubOAuthClientSecret
4769
+ cloudflareApiToken: checked4.cloudflareApiToken
4789
4770
  };
4790
4771
  })() : undefined;
4791
4772
  const enrolledPrivate = config.kind === "enrolled-compute" ? validateEnrolledComputeBootstrapSecrets(config, secrets) : undefined;
@@ -4886,7 +4867,6 @@ async function applyBootstrap(input, host = localBootstrapHost(), secrets, depen
4886
4867
  const emailCredentialName = config.runtime.environment.email?.provider === "smtp" ? "fz_smtp.password" : config.runtime.environment.email?.provider === "jetemail" ? "fz_jetemail.apiKey" : undefined;
4887
4868
  for (const [name, source] of Object.entries({
4888
4869
  ...emailCredentialName ? { [emailCredentialName]: platformPrivate.email } : {},
4889
- "fz_oauth.github.clientSecret": platformPrivate.githubOAuthClientSecret,
4890
4870
  "backup.s3.secretAccessKey": platformPrivate.backup
4891
4871
  })) {
4892
4872
  if (source) {
@@ -4903,7 +4883,6 @@ async function applyBootstrap(input, host = localBootstrapHost(), secrets, depen
4903
4883
  const credentials = platformApiCredentialSpecs({
4904
4884
  emailProvider: runtime.environment.email?.provider,
4905
4885
  cloudflareKv: cloudflareConfigured,
4906
- githubOAuth: true,
4907
4886
  realtime: Boolean(runtime.environment.realtime)
4908
4887
  });
4909
4888
  const units = renderPlatformApiUnits({
@@ -5151,7 +5130,6 @@ function strictBootstrapDocument(value) {
5151
5130
  "agentOtlpEndpoint",
5152
5131
  "custodianEmail",
5153
5132
  "email",
5154
- "githubOAuth",
5155
5133
  "deployProfile",
5156
5134
  "otlpFlushIntervalMs",
5157
5135
  "otlpTraceSampleRatio",
@@ -5162,7 +5140,6 @@ function strictBootstrapDocument(value) {
5162
5140
  "databaseReadPreferredCoordinators"
5163
5141
  ], "runtime environment");
5164
5142
  const environment = runtime.environment;
5165
- exactKeys(environment.githubOAuth, ["clientId"], "GitHub OAuth config");
5166
5143
  if (environment.initialInventory !== undefined) {
5167
5144
  const inventory = exactKeys(environment.initialInventory, ["metalHostname", "metalIdentity", "region", "computes", "attestation", "deployment"], "initial inventory");
5168
5145
  if (inventory.metalIdentity !== undefined) {
@@ -68,14 +68,6 @@ export type PlatformBootstrapEmail = {
68
68
  from: string;
69
69
  eu: boolean;
70
70
  };
71
- /**
72
- * Public coordinates for one GitHub App. Its client secret, RSA private key and
73
- * webhook secret are attended inputs sealed as systemd credentials and later
74
- * imported into the unlocked platform Vault.
75
- */
76
- export interface PlatformBootstrapGitHubOAuth {
77
- clientId: string;
78
- }
79
71
  export interface PlatformSharedEnvironment {
80
72
  softwareProfile: PlatformSoftwareProfile;
81
73
  databaseRole: PlatformDatabaseRole;
@@ -107,7 +99,6 @@ export interface PlatformSharedEnvironment {
107
99
  otlpTraceSampleRatio: number;
108
100
  custodianEmail?: string;
109
101
  email?: PlatformBootstrapEmail;
110
- githubOAuth: PlatformBootstrapGitHubOAuth;
111
102
  backup?: {
112
103
  endpoint: string;
113
104
  region: string;
@@ -135,13 +126,12 @@ export declare function validatePlatformSharedEnvironment(input: PlatformSharedE
135
126
  /** Render only non-secret runtime coordinates. Passwords/tokens have no field in this contract. */
136
127
  export declare function renderPlatformSharedEnvironment(input: PlatformSharedEnvironment): string;
137
128
  export interface SystemdCredentialSpec {
138
- name: 'arangodb-jwt' | 'arangodb-root-password' | 'seed-sync-root' | 'fz_smtp.password' | 'fz_jetemail.apiKey' | 'fz_oauth.github.clientSecret' | 'CF_API_TOKEN' | 'CF_TUNNEL_TOKEN' | 'REALTIME_PUBLISH_SECRET' | 'REALTIME_TICKET_SECRET';
129
+ name: 'arangodb-jwt' | 'arangodb-root-password' | 'seed-sync-root' | 'fz_smtp.password' | 'fz_jetemail.apiKey' | 'CF_API_TOKEN' | 'CF_TUNNEL_TOKEN' | 'REALTIME_PUBLISH_SECRET' | 'REALTIME_TICKET_SECRET';
139
130
  encryptedPath: string;
140
131
  required: boolean;
141
132
  }
142
133
  export declare function platformApiCredentialSpecs(options: {
143
134
  emailProvider?: PlatformBootstrapEmail['provider'];
144
- githubOAuth: boolean;
145
135
  cloudflareKv: boolean;
146
136
  realtime: boolean;
147
137
  }): SystemdCredentialSpec[];
@@ -831,9 +831,6 @@ function validatePlatformSharedEnvironment(input) {
831
831
  } else if (input.email !== undefined) {
832
832
  throw new Error("Bootstrap email provider must be smtp or jetemail.");
833
833
  }
834
- if (!input.githubOAuth || !/^(?:Iv1\.[A-Fa-f0-9]{16}|Ov23li[A-Za-z0-9]{14,})$/.test(input.githubOAuth.clientId)) {
835
- throw new Error("GitHub OAuth client id is malformed.");
836
- }
837
834
  boundedInteger("publicApiPort", input.publicApiPort, 1024, 65533);
838
835
  if (!Array.isArray(input.seedSyncMembers) || input.seedSyncMembers.length < 3 || input.seedSyncMembers.length > 64 || new Set(input.seedSyncMembers).size !== input.seedSyncMembers.length) {
839
836
  throw new Error("seedSyncMembers must contain 3 to 64 unique physical host identities.");
@@ -964,7 +961,6 @@ function renderPlatformSharedEnvironment(input) {
964
961
  FZ_REALTIME_WORKER_SCRIPT: value.realtime?.workerScriptName ?? "",
965
962
  FZ_REALTIME_ENDPOINT: value.realtime?.endpoint ?? "",
966
963
  FZ_REALTIME_PRODUCER: value.realtime?.producer ?? "",
967
- FZ_GITHUB_OAUTH_CLIENT_ID: value.githubOAuth.clientId,
968
964
  FZ_PLATFORM_INITIAL_INVENTORY: value.initialInventory ? JSON.stringify(value.initialInventory) : ""
969
965
  };
970
966
  return `# Generated by fz bootstrap platform. Non-secret coordinates only.
@@ -976,7 +972,6 @@ function platformApiCredentialSpecs(options) {
976
972
  const optional = [
977
973
  ["fz_smtp.password", options.emailProvider === "smtp"],
978
974
  ["fz_jetemail.apiKey", options.emailProvider === "jetemail"],
979
- ["fz_oauth.github.clientSecret", options.githubOAuth],
980
975
  ["CF_API_TOKEN", options.cloudflareKv],
981
976
  ["CF_TUNNEL_TOKEN", options.cloudflareKv],
982
977
  ["REALTIME_PUBLISH_SECRET", options.realtime],
@@ -3009,7 +3009,7 @@ function requestSoftware(requirements, socketPath = DEFAULT_SOFTWARE_HELPER_SOCK
3009
3009
  }
3010
3010
 
3011
3011
  // src/version.ts
3012
- var VERSION3 = "0.1.116";
3012
+ var VERSION3 = "0.1.118";
3013
3013
 
3014
3014
  // src/egress-policy.ts
3015
3015
  import { realpathSync as realpathSync3 } from "node:fs";
@@ -4347,9 +4347,6 @@ function validatePlatformSharedEnvironment(input) {
4347
4347
  } else if (input.email !== undefined) {
4348
4348
  throw new Error("Bootstrap email provider must be smtp or jetemail.");
4349
4349
  }
4350
- if (!input.githubOAuth || !/^(?:Iv1\.[A-Fa-f0-9]{16}|Ov23li[A-Za-z0-9]{14,})$/.test(input.githubOAuth.clientId)) {
4351
- throw new Error("GitHub OAuth client id is malformed.");
4352
- }
4353
4350
  boundedInteger("publicApiPort", input.publicApiPort, 1024, 65533);
4354
4351
  if (!Array.isArray(input.seedSyncMembers) || input.seedSyncMembers.length < 3 || input.seedSyncMembers.length > 64 || new Set(input.seedSyncMembers).size !== input.seedSyncMembers.length) {
4355
4352
  throw new Error("seedSyncMembers must contain 3 to 64 unique physical host identities.");
@@ -4480,7 +4477,6 @@ function renderPlatformSharedEnvironment(input) {
4480
4477
  FZ_REALTIME_WORKER_SCRIPT: value.realtime?.workerScriptName ?? "",
4481
4478
  FZ_REALTIME_ENDPOINT: value.realtime?.endpoint ?? "",
4482
4479
  FZ_REALTIME_PRODUCER: value.realtime?.producer ?? "",
4483
- FZ_GITHUB_OAUTH_CLIENT_ID: value.githubOAuth.clientId,
4484
4480
  FZ_PLATFORM_INITIAL_INVENTORY: value.initialInventory ? JSON.stringify(value.initialInventory) : ""
4485
4481
  };
4486
4482
  return `# Generated by fz bootstrap platform. Non-secret coordinates only.
@@ -4492,7 +4488,6 @@ function platformApiCredentialSpecs(options) {
4492
4488
  const optional = [
4493
4489
  ["fz_smtp.password", options.emailProvider === "smtp"],
4494
4490
  ["fz_jetemail.apiKey", options.emailProvider === "jetemail"],
4495
- ["fz_oauth.github.clientSecret", options.githubOAuth],
4496
4491
  ["CF_API_TOKEN", options.cloudflareKv],
4497
4492
  ["CF_TUNNEL_TOKEN", options.cloudflareKv],
4498
4493
  ["REALTIME_PUBLISH_SECRET", options.realtime],
@@ -4,7 +4,6 @@ export interface PlatformLaunchEnvironmentInput {
4
4
  emailSecret: string;
5
5
  cloudflareTunnelToken: string;
6
6
  cloudflareApiToken: string;
7
- githubOAuthClientSecret: string;
8
7
  }
9
8
  /**
10
9
  * Read the development-only attended-launch adapter.
@@ -45,10 +45,6 @@ export interface ForgeZeroLaunchOwnerInput {
45
45
  from: string;
46
46
  eu: boolean;
47
47
  };
48
- /** Required bootstrap identity provider. Repository automation is configured after genesis. */
49
- githubOAuth: {
50
- clientId: string;
51
- };
52
48
  }
53
49
  /**
54
50
  * ForgeZero's own genesis public coordinates. They are reviewed source data,
package/dist/provision.js CHANGED
@@ -3009,7 +3009,7 @@ function requestSoftware(requirements, socketPath = DEFAULT_SOFTWARE_HELPER_SOCK
3009
3009
  }
3010
3010
 
3011
3011
  // src/version.ts
3012
- var VERSION3 = "0.1.116";
3012
+ var VERSION3 = "0.1.118";
3013
3013
 
3014
3014
  // src/egress-policy.ts
3015
3015
  import { realpathSync as realpathSync3 } from "node:fs";
package/dist/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  /** One package version shared by both public binaries. Pinned to package.json by tests. */
2
- export declare const VERSION = "0.1.116";
2
+ export declare const VERSION = "0.1.118";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forgezero/agent",
3
- "version": "0.1.116",
3
+ "version": "0.1.118",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "check": "tsc --noEmit",
@@ -11,13 +11,13 @@
11
11
  "typescript": "^5.6.0",
12
12
  "@types/bun": "latest",
13
13
  "@types/node": "^22.0.0",
14
- "@forgezero/access": "0.1.9",
14
+ "@forgezero/access": "0.1.11",
15
15
  "@noble/curves": "^2.2.0",
16
16
  "@noble/post-quantum": "^0.6.1"
17
17
  },
18
18
  "dependencies": {
19
- "@forgezero/runtime": "0.1.14",
20
- "@forgezero/vault": "0.1.20",
19
+ "@forgezero/runtime": "0.1.16",
20
+ "@forgezero/vault": "0.1.21",
21
21
  "@noble/curves": "2.2.0",
22
22
  "@noble/hashes": "2.2.0",
23
23
  "@noble/post-quantum": "0.6.1",