@forgezero/agent 0.1.107 → 0.1.108

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.
@@ -917,7 +917,7 @@ async function postSignedNode(options, path, body) {
917
917
  }
918
918
 
919
919
  // src/version.ts
920
- var VERSION3 = "0.1.107";
920
+ var VERSION3 = "0.1.108";
921
921
 
922
922
  // src/agent-heartbeat.ts
923
923
  function readAgentHostMetrics() {
@@ -115,10 +115,7 @@ export interface PlatformBootstrapSecrets {
115
115
  backupS3Secret?: string;
116
116
  cloudflareTunnelToken?: string;
117
117
  cloudflareApiToken?: string;
118
- githubClientSecret?: string;
119
- /** One-line base64 form accepted by prompts/env; decoded before systemd sealing. */
120
- githubPrivateKeyBase64?: string;
121
- githubWebhookSecret?: string;
118
+ githubOAuthClientSecret: string;
122
119
  }
123
120
  export interface EnrolledComputeBootstrapSecrets {
124
121
  enrolmentToken: string;
package/dist/bootstrap.js CHANGED
@@ -1426,7 +1426,7 @@ async function refreshBootstrapBundle(input, exec = run) {
1426
1426
  }
1427
1427
 
1428
1428
  // src/bootstrap.ts
1429
- import { createHash as createHash2, createHmac as createHmac2, createPrivateKey, randomBytes as randomBytes3 } from "crypto";
1429
+ import { createHash as createHash2, createHmac as createHmac2, randomBytes as randomBytes3 } from "crypto";
1430
1430
  import {
1431
1431
  chmodSync as chmodSync3,
1432
1432
  existsSync as existsSync5,
@@ -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.107";
1463
+ var VERSION = "0.1.108";
1464
1464
 
1465
1465
  // src/software.ts
1466
1466
  var PINNED_BUN_VERSION = "1.3.14";
@@ -3228,10 +3228,8 @@ function validatePlatformSharedEnvironment(input) {
3228
3228
  } else if (input.email !== undefined) {
3229
3229
  throw new Error("Bootstrap email provider must be smtp or jetemail.");
3230
3230
  }
3231
- if (input.githubApp) {
3232
- if (!/^(?:Iv1\.[A-Fa-f0-9]{16}|Ov23li[A-Za-z0-9]{14,})$/.test(input.githubApp.clientId) || !/^[1-9][0-9]{0,19}$/.test(input.githubApp.appId) || !/^[a-z0-9][a-z0-9-]{0,99}$/.test(input.githubApp.slug)) {
3233
- throw new Error("GitHub App client id, app id or slug is malformed.");
3234
- }
3231
+ if (!input.githubOAuth || !/^(?:Iv1\.[A-Fa-f0-9]{16}|Ov23li[A-Za-z0-9]{14,})$/.test(input.githubOAuth.clientId)) {
3232
+ throw new Error("GitHub OAuth client id is malformed.");
3235
3233
  }
3236
3234
  boundedInteger("publicApiPort", input.publicApiPort, 1024, 65533);
3237
3235
  if (!Array.isArray(input.seedSyncMembers) || input.seedSyncMembers.length < 3 || input.seedSyncMembers.length > 64 || new Set(input.seedSyncMembers).size !== input.seedSyncMembers.length) {
@@ -3363,9 +3361,7 @@ function renderPlatformSharedEnvironment(input) {
3363
3361
  FZ_REALTIME_WORKER_SCRIPT: value.realtime?.workerScriptName ?? "",
3364
3362
  FZ_REALTIME_ENDPOINT: value.realtime?.endpoint ?? "",
3365
3363
  FZ_REALTIME_PRODUCER: value.realtime?.producer ?? "",
3366
- FZ_GITHUB_CLIENT_ID: value.githubApp?.clientId ?? "",
3367
- FZ_GITHUB_APP_ID: value.githubApp?.appId ?? "",
3368
- FZ_GITHUB_APP_SLUG: value.githubApp?.slug ?? "",
3364
+ FZ_GITHUB_OAUTH_CLIENT_ID: value.githubOAuth.clientId,
3369
3365
  FZ_PLATFORM_INITIAL_INVENTORY: value.initialInventory ? JSON.stringify(value.initialInventory) : ""
3370
3366
  };
3371
3367
  return `# Generated by fz bootstrap platform. Non-secret coordinates only.
@@ -3377,9 +3373,7 @@ function platformApiCredentialSpecs(options) {
3377
3373
  const optional = [
3378
3374
  ["fz_smtp.password", options.emailProvider === "smtp"],
3379
3375
  ["fz_jetemail.apiKey", options.emailProvider === "jetemail"],
3380
- ["fz_github.clientSecret", options.githubApp],
3381
- ["fz_github.privateKey", options.githubApp],
3382
- ["fz_github.webhookSecret", options.githubApp],
3376
+ ["fz_oauth.github.clientSecret", options.githubOAuth],
3383
3377
  ["CF_API_TOKEN", options.cloudflareKv],
3384
3378
  ["CF_TUNNEL_TOKEN", options.cloudflareKv],
3385
3379
  ["REALTIME_PUBLISH_SECRET", options.realtime],
@@ -3783,9 +3777,7 @@ function validatePlatformBootstrapSecrets(config, input) {
3783
3777
  "backupS3Secret",
3784
3778
  "cloudflareTunnelToken",
3785
3779
  "cloudflareApiToken",
3786
- "githubClientSecret",
3787
- "githubPrivateKeyBase64",
3788
- "githubWebhookSecret"
3780
+ "githubOAuthClientSecret"
3789
3781
  ];
3790
3782
  const unknown = Object.keys(source).filter((key) => !allowed.includes(key));
3791
3783
  if (unknown.length)
@@ -3796,9 +3788,7 @@ function validatePlatformBootstrapSecrets(config, input) {
3796
3788
  const backupS3Secret = typeof source.backupS3Secret === "string" ? source.backupS3Secret.trim() : undefined;
3797
3789
  const cloudflareTunnelToken = typeof source.cloudflareTunnelToken === "string" ? source.cloudflareTunnelToken.trim() : undefined;
3798
3790
  const cloudflareApiToken = typeof source.cloudflareApiToken === "string" ? source.cloudflareApiToken.trim() : undefined;
3799
- const githubClientSecret = typeof source.githubClientSecret === "string" ? source.githubClientSecret.trim() : undefined;
3800
- const githubPrivateKeyBase64 = typeof source.githubPrivateKeyBase64 === "string" ? source.githubPrivateKeyBase64.trim() : undefined;
3801
- const githubWebhookSecret = typeof source.githubWebhookSecret === "string" ? source.githubWebhookSecret.trim() : undefined;
3791
+ const githubOAuthClientSecret = typeof source.githubOAuthClientSecret === "string" ? source.githubOAuthClientSecret.trim() : "";
3802
3792
  if (!/^[a-f0-9]{64}$/i.test(clusterBootstrapCode))
3803
3793
  throw new Error("cluster bootstrap code must contain exactly 64 hexadecimal characters");
3804
3794
  if (!emailSecret || emailSecret.length > 16384 || /[\r\n\0]/.test(emailSecret))
@@ -3818,21 +3808,8 @@ function validatePlatformBootstrapSecrets(config, input) {
3818
3808
  }
3819
3809
  if (cloudflareTunnelToken)
3820
3810
  validateCloudflareBootstrapSecretPair({ cloudflareTunnelToken, cloudflareApiToken });
3821
- const githubConfigured = Boolean(config.runtime.environment.githubApp);
3822
- if (githubConfigured !== Boolean(githubClientSecret && githubPrivateKeyBase64 && githubWebhookSecret)) {
3823
- throw new Error("GitHub App coordinates require client secret, private key and webhook secret together");
3824
- }
3825
- if (githubConfigured) {
3826
- if (githubClientSecret.length < 20 || githubClientSecret.length > 512 || /[\r\n\0]/.test(githubClientSecret) || githubWebhookSecret.length < 32 || githubWebhookSecret.length > 512 || /[\r\n\0]/.test(githubWebhookSecret)) {
3827
- throw new Error("GitHub App client or webhook secret is malformed");
3828
- }
3829
- try {
3830
- const pem = Buffer.from(githubPrivateKeyBase64, "base64").toString("utf8");
3831
- if (createPrivateKey(pem).asymmetricKeyType !== "rsa")
3832
- throw new Error("not RSA");
3833
- } catch {
3834
- throw new Error("GitHub App private key must be a base64-encoded RSA private key");
3835
- }
3811
+ if (githubOAuthClientSecret.length < 20 || githubOAuthClientSecret.length > 512 || /[\r\n\0]/.test(githubOAuthClientSecret)) {
3812
+ throw new Error("GitHub OAuth client secret is malformed");
3836
3813
  }
3837
3814
  return {
3838
3815
  clusterBootstrapCode,
@@ -3840,7 +3817,7 @@ function validatePlatformBootstrapSecrets(config, input) {
3840
3817
  ...enrolmentToken ? { enrolmentToken } : {},
3841
3818
  ...backupS3Secret ? { backupS3Secret } : {},
3842
3819
  ...cloudflareTunnelToken ? { cloudflareTunnelToken, cloudflareApiToken } : {},
3843
- ...githubConfigured ? { githubClientSecret, githubPrivateKeyBase64, githubWebhookSecret } : {}
3820
+ githubOAuthClientSecret
3844
3821
  };
3845
3822
  }
3846
3823
  var platformBootstrapRunner = (config) => config.kind === "platform" && config.database.role === "master";
@@ -4764,9 +4741,7 @@ async function applyBootstrap(input, host = localBootstrapHost(), secrets, depen
4764
4741
  backup: checked4.backupS3Secret,
4765
4742
  cloudflareTunnelToken: checked4.cloudflareTunnelToken,
4766
4743
  cloudflareApiToken: checked4.cloudflareApiToken,
4767
- githubClientSecret: checked4.githubClientSecret,
4768
- githubPrivateKey: checked4.githubPrivateKeyBase64 ? Buffer.from(checked4.githubPrivateKeyBase64, "base64").toString("utf8") : undefined,
4769
- githubWebhookSecret: checked4.githubWebhookSecret
4744
+ githubOAuthClientSecret: checked4.githubOAuthClientSecret
4770
4745
  };
4771
4746
  })() : undefined;
4772
4747
  const enrolledPrivate = config.kind === "enrolled-compute" ? validateEnrolledComputeBootstrapSecrets(config, secrets) : undefined;
@@ -4867,9 +4842,7 @@ async function applyBootstrap(input, host = localBootstrapHost(), secrets, depen
4867
4842
  const emailCredentialName = config.runtime.environment.email?.provider === "smtp" ? "fz_smtp.password" : config.runtime.environment.email?.provider === "jetemail" ? "fz_jetemail.apiKey" : undefined;
4868
4843
  for (const [name, source] of Object.entries({
4869
4844
  ...emailCredentialName ? { [emailCredentialName]: platformPrivate.email } : {},
4870
- "fz_github.clientSecret": platformPrivate.githubClientSecret,
4871
- "fz_github.privateKey": platformPrivate.githubPrivateKey,
4872
- "fz_github.webhookSecret": platformPrivate.githubWebhookSecret,
4845
+ "fz_oauth.github.clientSecret": platformPrivate.githubOAuthClientSecret,
4873
4846
  "backup.s3.secretAccessKey": platformPrivate.backup
4874
4847
  })) {
4875
4848
  if (source) {
@@ -4886,7 +4859,7 @@ async function applyBootstrap(input, host = localBootstrapHost(), secrets, depen
4886
4859
  const credentials = platformApiCredentialSpecs({
4887
4860
  emailProvider: runtime.environment.email?.provider,
4888
4861
  cloudflareKv: cloudflareConfigured,
4889
- githubApp: Boolean(runtime.environment.githubApp),
4862
+ githubOAuth: true,
4890
4863
  realtime: Boolean(runtime.environment.realtime)
4891
4864
  });
4892
4865
  const units = renderPlatformApiUnits({
@@ -5134,6 +5107,7 @@ function strictBootstrapDocument(value) {
5134
5107
  "agentOtlpEndpoint",
5135
5108
  "custodianEmail",
5136
5109
  "email",
5110
+ "githubOAuth",
5137
5111
  "deployProfile",
5138
5112
  "otlpFlushIntervalMs",
5139
5113
  "otlpTraceSampleRatio",
@@ -5144,6 +5118,7 @@ function strictBootstrapDocument(value) {
5144
5118
  "databaseReadPreferredCoordinators"
5145
5119
  ], "runtime environment");
5146
5120
  const environment = runtime.environment;
5121
+ exactKeys(environment.githubOAuth, ["clientId"], "GitHub OAuth config");
5147
5122
  if (environment.initialInventory !== undefined) {
5148
5123
  const inventory = exactKeys(environment.initialInventory, ["metalHostname", "metalIdentity", "region", "computes", "attestation", "deployment"], "initial inventory");
5149
5124
  if (inventory.metalIdentity !== undefined) {
package/dist/fz-agent.js CHANGED
@@ -9528,7 +9528,7 @@ async function writeAndCloseProcessInput(input, value) {
9528
9528
  }
9529
9529
 
9530
9530
  // src/version.ts
9531
- var VERSION2 = "0.1.107";
9531
+ var VERSION2 = "0.1.108";
9532
9532
 
9533
9533
  // src/ssh-bootstrap.ts
9534
9534
  class SshBootstrapError extends Error {
package/dist/fz.js CHANGED
@@ -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.107";
4844
+ var VERSION2 = "0.1.108";
4845
4845
 
4846
4846
  // src/software.ts
4847
4847
  var PINNED_BUN_VERSION = "1.3.14";
@@ -12058,7 +12058,7 @@ function removeSession(api, realm, path = defaultSessionPath()) {
12058
12058
  }
12059
12059
 
12060
12060
  // src/bootstrap.ts
12061
- import { createHash as createHash4, createHmac as createHmac2, createPrivateKey, randomBytes as randomBytes7 } from "crypto";
12061
+ import { createHash as createHash4, createHmac as createHmac2, randomBytes as randomBytes7 } from "crypto";
12062
12062
  import {
12063
12063
  chmodSync as chmodSync4,
12064
12064
  existsSync as existsSync9,
@@ -12337,10 +12337,8 @@ function validatePlatformSharedEnvironment(input) {
12337
12337
  } else if (input.email !== undefined) {
12338
12338
  throw new Error("Bootstrap email provider must be smtp or jetemail.");
12339
12339
  }
12340
- if (input.githubApp) {
12341
- if (!/^(?:Iv1\.[A-Fa-f0-9]{16}|Ov23li[A-Za-z0-9]{14,})$/.test(input.githubApp.clientId) || !/^[1-9][0-9]{0,19}$/.test(input.githubApp.appId) || !/^[a-z0-9][a-z0-9-]{0,99}$/.test(input.githubApp.slug)) {
12342
- throw new Error("GitHub App client id, app id or slug is malformed.");
12343
- }
12340
+ if (!input.githubOAuth || !/^(?:Iv1\.[A-Fa-f0-9]{16}|Ov23li[A-Za-z0-9]{14,})$/.test(input.githubOAuth.clientId)) {
12341
+ throw new Error("GitHub OAuth client id is malformed.");
12344
12342
  }
12345
12343
  boundedInteger("publicApiPort", input.publicApiPort, 1024, 65533);
12346
12344
  if (!Array.isArray(input.seedSyncMembers) || input.seedSyncMembers.length < 3 || input.seedSyncMembers.length > 64 || new Set(input.seedSyncMembers).size !== input.seedSyncMembers.length) {
@@ -12472,9 +12470,7 @@ function renderPlatformSharedEnvironment(input) {
12472
12470
  FZ_REALTIME_WORKER_SCRIPT: value.realtime?.workerScriptName ?? "",
12473
12471
  FZ_REALTIME_ENDPOINT: value.realtime?.endpoint ?? "",
12474
12472
  FZ_REALTIME_PRODUCER: value.realtime?.producer ?? "",
12475
- FZ_GITHUB_CLIENT_ID: value.githubApp?.clientId ?? "",
12476
- FZ_GITHUB_APP_ID: value.githubApp?.appId ?? "",
12477
- FZ_GITHUB_APP_SLUG: value.githubApp?.slug ?? "",
12473
+ FZ_GITHUB_OAUTH_CLIENT_ID: value.githubOAuth.clientId,
12478
12474
  FZ_PLATFORM_INITIAL_INVENTORY: value.initialInventory ? JSON.stringify(value.initialInventory) : ""
12479
12475
  };
12480
12476
  return `# Generated by fz bootstrap platform. Non-secret coordinates only.
@@ -12486,9 +12482,7 @@ function platformApiCredentialSpecs(options) {
12486
12482
  const optional = [
12487
12483
  ["fz_smtp.password", options.emailProvider === "smtp"],
12488
12484
  ["fz_jetemail.apiKey", options.emailProvider === "jetemail"],
12489
- ["fz_github.clientSecret", options.githubApp],
12490
- ["fz_github.privateKey", options.githubApp],
12491
- ["fz_github.webhookSecret", options.githubApp],
12485
+ ["fz_oauth.github.clientSecret", options.githubOAuth],
12492
12486
  ["CF_API_TOKEN", options.cloudflareKv],
12493
12487
  ["CF_TUNNEL_TOKEN", options.cloudflareKv],
12494
12488
  ["REALTIME_PUBLISH_SECRET", options.realtime],
@@ -14168,9 +14162,7 @@ function validatePlatformBootstrapSecrets(config, input) {
14168
14162
  "backupS3Secret",
14169
14163
  "cloudflareTunnelToken",
14170
14164
  "cloudflareApiToken",
14171
- "githubClientSecret",
14172
- "githubPrivateKeyBase64",
14173
- "githubWebhookSecret"
14165
+ "githubOAuthClientSecret"
14174
14166
  ];
14175
14167
  const unknown = Object.keys(source).filter((key) => !allowed.includes(key));
14176
14168
  if (unknown.length)
@@ -14181,9 +14173,7 @@ function validatePlatformBootstrapSecrets(config, input) {
14181
14173
  const backupS3Secret = typeof source.backupS3Secret === "string" ? source.backupS3Secret.trim() : undefined;
14182
14174
  const cloudflareTunnelToken = typeof source.cloudflareTunnelToken === "string" ? source.cloudflareTunnelToken.trim() : undefined;
14183
14175
  const cloudflareApiToken = typeof source.cloudflareApiToken === "string" ? source.cloudflareApiToken.trim() : undefined;
14184
- const githubClientSecret = typeof source.githubClientSecret === "string" ? source.githubClientSecret.trim() : undefined;
14185
- const githubPrivateKeyBase64 = typeof source.githubPrivateKeyBase64 === "string" ? source.githubPrivateKeyBase64.trim() : undefined;
14186
- const githubWebhookSecret = typeof source.githubWebhookSecret === "string" ? source.githubWebhookSecret.trim() : undefined;
14176
+ const githubOAuthClientSecret = typeof source.githubOAuthClientSecret === "string" ? source.githubOAuthClientSecret.trim() : "";
14187
14177
  if (!/^[a-f0-9]{64}$/i.test(clusterBootstrapCode))
14188
14178
  throw new Error("cluster bootstrap code must contain exactly 64 hexadecimal characters");
14189
14179
  if (!emailSecret || emailSecret.length > 16384 || /[\r\n\0]/.test(emailSecret))
@@ -14203,21 +14193,8 @@ function validatePlatformBootstrapSecrets(config, input) {
14203
14193
  }
14204
14194
  if (cloudflareTunnelToken)
14205
14195
  validateCloudflareBootstrapSecretPair({ cloudflareTunnelToken, cloudflareApiToken });
14206
- const githubConfigured = Boolean(config.runtime.environment.githubApp);
14207
- if (githubConfigured !== Boolean(githubClientSecret && githubPrivateKeyBase64 && githubWebhookSecret)) {
14208
- throw new Error("GitHub App coordinates require client secret, private key and webhook secret together");
14209
- }
14210
- if (githubConfigured) {
14211
- if (githubClientSecret.length < 20 || githubClientSecret.length > 512 || /[\r\n\0]/.test(githubClientSecret) || githubWebhookSecret.length < 32 || githubWebhookSecret.length > 512 || /[\r\n\0]/.test(githubWebhookSecret)) {
14212
- throw new Error("GitHub App client or webhook secret is malformed");
14213
- }
14214
- try {
14215
- const pem = Buffer.from(githubPrivateKeyBase64, "base64").toString("utf8");
14216
- if (createPrivateKey(pem).asymmetricKeyType !== "rsa")
14217
- throw new Error("not RSA");
14218
- } catch {
14219
- throw new Error("GitHub App private key must be a base64-encoded RSA private key");
14220
- }
14196
+ if (githubOAuthClientSecret.length < 20 || githubOAuthClientSecret.length > 512 || /[\r\n\0]/.test(githubOAuthClientSecret)) {
14197
+ throw new Error("GitHub OAuth client secret is malformed");
14221
14198
  }
14222
14199
  return {
14223
14200
  clusterBootstrapCode,
@@ -14225,7 +14202,7 @@ function validatePlatformBootstrapSecrets(config, input) {
14225
14202
  ...enrolmentToken ? { enrolmentToken } : {},
14226
14203
  ...backupS3Secret ? { backupS3Secret } : {},
14227
14204
  ...cloudflareTunnelToken ? { cloudflareTunnelToken, cloudflareApiToken } : {},
14228
- ...githubConfigured ? { githubClientSecret, githubPrivateKeyBase64, githubWebhookSecret } : {}
14205
+ githubOAuthClientSecret
14229
14206
  };
14230
14207
  }
14231
14208
  var platformBootstrapRunner = (config) => config.kind === "platform" && config.database.role === "master";
@@ -15149,9 +15126,7 @@ async function applyBootstrap(input, host = localBootstrapHost(), secrets, depen
15149
15126
  backup: checked4.backupS3Secret,
15150
15127
  cloudflareTunnelToken: checked4.cloudflareTunnelToken,
15151
15128
  cloudflareApiToken: checked4.cloudflareApiToken,
15152
- githubClientSecret: checked4.githubClientSecret,
15153
- githubPrivateKey: checked4.githubPrivateKeyBase64 ? Buffer.from(checked4.githubPrivateKeyBase64, "base64").toString("utf8") : undefined,
15154
- githubWebhookSecret: checked4.githubWebhookSecret
15129
+ githubOAuthClientSecret: checked4.githubOAuthClientSecret
15155
15130
  };
15156
15131
  })() : undefined;
15157
15132
  const enrolledPrivate = config.kind === "enrolled-compute" ? validateEnrolledComputeBootstrapSecrets(config, secrets) : undefined;
@@ -15252,9 +15227,7 @@ async function applyBootstrap(input, host = localBootstrapHost(), secrets, depen
15252
15227
  const emailCredentialName = config.runtime.environment.email?.provider === "smtp" ? "fz_smtp.password" : config.runtime.environment.email?.provider === "jetemail" ? "fz_jetemail.apiKey" : undefined;
15253
15228
  for (const [name, source] of Object.entries({
15254
15229
  ...emailCredentialName ? { [emailCredentialName]: platformPrivate.email } : {},
15255
- "fz_github.clientSecret": platformPrivate.githubClientSecret,
15256
- "fz_github.privateKey": platformPrivate.githubPrivateKey,
15257
- "fz_github.webhookSecret": platformPrivate.githubWebhookSecret,
15230
+ "fz_oauth.github.clientSecret": platformPrivate.githubOAuthClientSecret,
15258
15231
  "backup.s3.secretAccessKey": platformPrivate.backup
15259
15232
  })) {
15260
15233
  if (source) {
@@ -15271,7 +15244,7 @@ async function applyBootstrap(input, host = localBootstrapHost(), secrets, depen
15271
15244
  const credentials = platformApiCredentialSpecs({
15272
15245
  emailProvider: runtime.environment.email?.provider,
15273
15246
  cloudflareKv: cloudflareConfigured,
15274
- githubApp: Boolean(runtime.environment.githubApp),
15247
+ githubOAuth: true,
15275
15248
  realtime: Boolean(runtime.environment.realtime)
15276
15249
  });
15277
15250
  const units = renderPlatformApiUnits({
@@ -15519,6 +15492,7 @@ function strictBootstrapDocument(value) {
15519
15492
  "agentOtlpEndpoint",
15520
15493
  "custodianEmail",
15521
15494
  "email",
15495
+ "githubOAuth",
15522
15496
  "deployProfile",
15523
15497
  "otlpFlushIntervalMs",
15524
15498
  "otlpTraceSampleRatio",
@@ -15529,6 +15503,7 @@ function strictBootstrapDocument(value) {
15529
15503
  "databaseReadPreferredCoordinators"
15530
15504
  ], "runtime environment");
15531
15505
  const environment = runtime.environment;
15506
+ exactKeys2(environment.githubOAuth, ["clientId"], "GitHub OAuth config");
15532
15507
  if (environment.initialInventory !== undefined) {
15533
15508
  const inventory = exactKeys2(environment.initialInventory, ["metalHostname", "metalIdentity", "region", "computes", "attestation", "deployment"], "initial inventory");
15534
15509
  if (inventory.metalIdentity !== undefined) {
@@ -18234,7 +18209,7 @@ function forgeZeroLaunchTemplate(profile, guests, bundle, owner) {
18234
18209
  otlpTraceSampleRatio: 0.1,
18235
18210
  custodianEmail: owner.custodianEmail,
18236
18211
  email: owner.email,
18237
- ...owner.githubApp ? { githubApp: owner.githubApp } : {},
18212
+ githubOAuth: owner.githubOAuth,
18238
18213
  deployProfile: profile.environment
18239
18214
  },
18240
18215
  serviceUser: "forgezero-api",
@@ -18594,16 +18569,6 @@ function planAppBuild(input) {
18594
18569
  // src/platform-launch-env.ts
18595
18570
  import { lstatSync as lstatSync10, readFileSync as readFileSync16 } from "fs";
18596
18571
  import { resolve as resolve12 } from "path";
18597
- var booleanValue = (values, name, fallback) => {
18598
- const raw = values.get(name)?.trim().toLowerCase();
18599
- if (raw === undefined || raw === "")
18600
- return fallback;
18601
- if (raw === "true")
18602
- return true;
18603
- if (raw === "false")
18604
- return false;
18605
- throw new Error(`${name} must be true or false`);
18606
- };
18607
18572
  function readPlatformLaunchEnvironment(path) {
18608
18573
  const absolute2 = resolve12(path);
18609
18574
  const stat2 = lstatSync10(absolute2);
@@ -18632,48 +18597,18 @@ function readPlatformLaunchEnvironment(path) {
18632
18597
  throw new Error(`bootstrap secret environment is missing ${name}`);
18633
18598
  return value;
18634
18599
  };
18635
- const provider = requiredValue("FZ_EMAIL_PROVIDER");
18636
- if (provider !== "smtp" && provider !== "jetemail")
18637
- throw new Error("FZ_EMAIL_PROVIDER must be smtp or jetemail");
18638
- const smtpPort = provider === "smtp" ? Number(requiredValue("FZ_SMTP_PORT")) : undefined;
18639
- if (smtpPort !== undefined && (!Number.isInteger(smtpPort) || smtpPort < 1 || smtpPort > 65535)) {
18640
- throw new Error("FZ_SMTP_PORT must be an integer from 1 through 65535");
18641
- }
18642
- const githubEnabled = booleanValue(values, "FZ_GITHUB_ENABLED", false);
18643
- const githubApp = githubEnabled ? {
18644
- clientId: requiredValue("FZ_GITHUB_CLIENT_ID"),
18645
- appId: requiredValue("FZ_GITHUB_APP_ID"),
18646
- slug: requiredValue("FZ_GITHUB_APP_SLUG")
18647
- } : undefined;
18648
- const owner = provider === "jetemail" ? {
18649
- custodianEmail: requiredValue("FZ_BOOTSTRAP_CUSTODIAN_EMAIL"),
18650
- email: {
18651
- provider,
18652
- from: requiredValue("FZ_EMAIL_FROM"),
18653
- eu: booleanValue(values, "FZ_JETEMAIL_EU", false)
18654
- },
18655
- ...githubApp ? { githubApp } : {}
18656
- } : {
18657
- custodianEmail: requiredValue("FZ_BOOTSTRAP_CUSTODIAN_EMAIL"),
18658
- email: {
18659
- provider,
18660
- from: requiredValue("FZ_EMAIL_FROM"),
18661
- host: requiredValue("FZ_SMTP_HOST"),
18662
- port: smtpPort,
18663
- user: requiredValue("FZ_SMTP_USER")
18664
- },
18665
- ...githubApp ? { githubApp } : {}
18600
+ const githubOAuth = { clientId: requiredValue("FZ_GITHUB_OAUTH_CLIENT_ID") };
18601
+ const owner = {
18602
+ custodianEmail: "info@axxra.in",
18603
+ email: { provider: "jetemail", from: "noreply@forgezero.net", eu: false },
18604
+ githubOAuth
18666
18605
  };
18667
18606
  return {
18668
18607
  owner,
18669
- emailSecret: requiredValue(provider === "jetemail" ? "FZ_JETEMAIL_API_KEY" : "FZ_SMTP_PASSWORD"),
18608
+ emailSecret: requiredValue("FZ_JETEMAIL_API_KEY"),
18670
18609
  cloudflareTunnelToken: requiredValue("CF_TUNNEL_TOKEN"),
18671
18610
  cloudflareApiToken: requiredValue("CF_API_TOKEN"),
18672
- ...githubEnabled ? {
18673
- githubClientSecret: requiredValue("FZ_GITHUB_CLIENT_SECRET"),
18674
- githubPrivateKeyBase64: requiredValue("FZ_GITHUB_PRIVATE_KEY_BASE64"),
18675
- githubWebhookSecret: requiredValue("FZ_GITHUB_WEBHOOK_SECRET")
18676
- } : {}
18611
+ githubOAuthClientSecret: requiredValue("FZ_GITHUB_OAUTH_CLIENT_SECRET")
18677
18612
  };
18678
18613
  }
18679
18614
 
@@ -19498,11 +19433,7 @@ async function promptPlatformBootstrapSecrets(config, generatedClusterBootstrapC
19498
19433
  cloudflareTunnelToken: await bootstrapSecret("CF_TUNNEL_TOKEN"),
19499
19434
  cloudflareApiToken: await bootstrapSecret("CF_API_TOKEN")
19500
19435
  } : {},
19501
- ...config.runtime.environment.githubApp ? {
19502
- githubClientSecret: await bootstrapSecret("GitHub App client secret"),
19503
- githubPrivateKeyBase64: await bootstrapSecret("GitHub App RSA private key (base64)"),
19504
- githubWebhookSecret: await bootstrapSecret("GitHub App webhook secret")
19505
- } : {}
19436
+ githubOAuthClientSecret: await bootstrapSecret("GitHub OAuth client secret")
19506
19437
  });
19507
19438
  }
19508
19439
  var bootstrapList = (question, fallback) => bootstrapAnswer(question, fallback).split(",").map((value) => value.trim()).filter(Boolean);
@@ -19800,34 +19731,11 @@ function selectedForgeZeroLaunchEnvironment(value) {
19800
19731
  return value;
19801
19732
  }
19802
19733
  function forgeZeroLaunchOwnerInput() {
19803
- const custodianEmail = bootstrapAnswer("First custodian email");
19804
- const provider = bootstrapAnswer("Bootstrap email provider (smtp/jetemail)", "jetemail");
19805
- if (provider !== "smtp" && provider !== "jetemail") {
19806
- throw new Error("Bootstrap email provider must be smtp or jetemail");
19807
- }
19808
- const from = bootstrapAnswer("Bootstrap email From address");
19809
- const githubApp = bootstrapBoolean("Configure the platform GitHub App now?", "no") ? {
19810
- clientId: bootstrapAnswer("GitHub App client ID"),
19811
- appId: bootstrapAnswer("GitHub App ID"),
19812
- slug: bootstrapAnswer("GitHub App slug")
19813
- } : undefined;
19814
- if (provider === "jetemail") {
19815
- return {
19816
- custodianEmail,
19817
- email: { provider, from, eu: bootstrapBoolean("Use JetEmail EU processing?", "no") },
19818
- ...githubApp ? { githubApp } : {}
19819
- };
19820
- }
19734
+ const githubOAuth = { clientId: bootstrapAnswer("GitHub OAuth client ID") };
19821
19735
  return {
19822
- custodianEmail,
19823
- email: {
19824
- provider,
19825
- from,
19826
- host: bootstrapAnswer("SMTP host"),
19827
- port: bootstrapNumber("SMTP port", "587"),
19828
- user: bootstrapAnswer("SMTP user")
19829
- },
19830
- ...githubApp ? { githubApp } : {}
19736
+ custodianEmail: "info@axxra.in",
19737
+ email: { provider: "jetemail", from: "noreply@forgezero.net", eu: false },
19738
+ githubOAuth
19831
19739
  };
19832
19740
  }
19833
19741
  async function prepareForgeZeroPlatformLaunch(environment, outputDirectory, projectRoot, owner) {
@@ -19896,6 +19804,7 @@ function interactiveBootstrap(kind, genesisGuests, genesisCloudflareCheckpoint)
19896
19804
  const backupRegion = backupEndpoint ? bootstrapAnswer("Backup S3 region") : undefined;
19897
19805
  const backupBucket = backupEndpoint ? bootstrapAnswer("Backup S3 bucket") : undefined;
19898
19806
  const backupAccessKeyId = backupEndpoint ? bootstrapAnswer("Backup S3 access-key id") : undefined;
19807
+ const githubOAuthClientId = bootstrapAnswer("GitHub OAuth client ID");
19899
19808
  const cloudflareHandoffFile = genesis ? cloudflareHostHandoffPath(genesisCloudflareCheckpoint, computeReference) : bootstrapAnswer("Node-specific Cloudflare host handoff (blank for no public edge)", "");
19900
19809
  const cloudflareNodeName = cloudflareHandoffFile ? genesis ? computeReference : bootstrapAnswer("Cloudflare handoff node name", computeReference) : undefined;
19901
19810
  const databaseNetworkMode = "private-lan";
@@ -19950,6 +19859,7 @@ function interactiveBootstrap(kind, genesisGuests, genesisCloudflareCheckpoint)
19950
19859
  otlpTraceSampleRatio: 0.1,
19951
19860
  custodianEmail: role === "master" ? bootstrapAnswer("First custodian email") : undefined,
19952
19861
  email: emailProvider === "smtp" ? { provider: "smtp", host: smtpHost, port: smtpPort, user: smtpUser, from: emailFrom } : { provider: "jetemail", from: emailFrom, eu: jetemailEu },
19862
+ githubOAuth: { clientId: githubOAuthClientId },
19953
19863
  ...backupEndpoint && backupRegion && backupBucket && backupAccessKeyId ? {
19954
19864
  backup: { endpoint: backupEndpoint, region: backupRegion, bucket: backupBucket, accessKeyId: backupAccessKeyId }
19955
19865
  } : {},
@@ -20010,11 +19920,7 @@ async function runAttendedPlatformFleet(fleet, apply, generatedClusterBootstrapC
20010
19920
  emailSecret: environmentInput.emailSecret,
20011
19921
  cloudflareTunnelToken: environmentInput.cloudflareTunnelToken,
20012
19922
  cloudflareApiToken: environmentInput.cloudflareApiToken,
20013
- ...environmentInput.githubClientSecret ? {
20014
- githubClientSecret: environmentInput.githubClientSecret,
20015
- githubPrivateKeyBase64: environmentInput.githubPrivateKeyBase64,
20016
- githubWebhookSecret: environmentInput.githubWebhookSecret
20017
- } : {}
19923
+ githubOAuthClientSecret: environmentInput.githubOAuthClientSecret
20018
19924
  }) : await promptPlatformBootstrapSecrets(firstConfig, generatedClusterBootstrapCode);
20019
19925
  const cloudflare = await resolveCloudflareBootstrapCommandConfig(fleet.cloudflareConfigFile, {
20020
19926
  tunnelToken: secrets.cloudflareTunnelToken,
@@ -366,7 +366,7 @@ function systemdAgentEgressDirectives(loopbackTcpPorts = []) {
366
366
  }
367
367
 
368
368
  // src/version.ts
369
- var VERSION = "0.1.107";
369
+ var VERSION = "0.1.108";
370
370
 
371
371
  // src/otel-collector.ts
372
372
  var FORGEZERO_OTEL_COLLECTOR_UNIT = "forgezero-otel-collector.service";
@@ -1426,7 +1426,7 @@ async function refreshBootstrapBundle(input, exec = run) {
1426
1426
  }
1427
1427
 
1428
1428
  // src/bootstrap.ts
1429
- import { createHash as createHash2, createHmac as createHmac2, createPrivateKey, randomBytes as randomBytes3 } from "crypto";
1429
+ import { createHash as createHash2, createHmac as createHmac2, randomBytes as randomBytes3 } from "crypto";
1430
1430
  import {
1431
1431
  chmodSync as chmodSync3,
1432
1432
  existsSync as existsSync5,
@@ -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.107";
1463
+ var VERSION = "0.1.108";
1464
1464
 
1465
1465
  // src/software.ts
1466
1466
  var PINNED_BUN_VERSION = "1.3.14";
@@ -3228,10 +3228,8 @@ function validatePlatformSharedEnvironment(input) {
3228
3228
  } else if (input.email !== undefined) {
3229
3229
  throw new Error("Bootstrap email provider must be smtp or jetemail.");
3230
3230
  }
3231
- if (input.githubApp) {
3232
- if (!/^(?:Iv1\.[A-Fa-f0-9]{16}|Ov23li[A-Za-z0-9]{14,})$/.test(input.githubApp.clientId) || !/^[1-9][0-9]{0,19}$/.test(input.githubApp.appId) || !/^[a-z0-9][a-z0-9-]{0,99}$/.test(input.githubApp.slug)) {
3233
- throw new Error("GitHub App client id, app id or slug is malformed.");
3234
- }
3231
+ if (!input.githubOAuth || !/^(?:Iv1\.[A-Fa-f0-9]{16}|Ov23li[A-Za-z0-9]{14,})$/.test(input.githubOAuth.clientId)) {
3232
+ throw new Error("GitHub OAuth client id is malformed.");
3235
3233
  }
3236
3234
  boundedInteger("publicApiPort", input.publicApiPort, 1024, 65533);
3237
3235
  if (!Array.isArray(input.seedSyncMembers) || input.seedSyncMembers.length < 3 || input.seedSyncMembers.length > 64 || new Set(input.seedSyncMembers).size !== input.seedSyncMembers.length) {
@@ -3363,9 +3361,7 @@ function renderPlatformSharedEnvironment(input) {
3363
3361
  FZ_REALTIME_WORKER_SCRIPT: value.realtime?.workerScriptName ?? "",
3364
3362
  FZ_REALTIME_ENDPOINT: value.realtime?.endpoint ?? "",
3365
3363
  FZ_REALTIME_PRODUCER: value.realtime?.producer ?? "",
3366
- FZ_GITHUB_CLIENT_ID: value.githubApp?.clientId ?? "",
3367
- FZ_GITHUB_APP_ID: value.githubApp?.appId ?? "",
3368
- FZ_GITHUB_APP_SLUG: value.githubApp?.slug ?? "",
3364
+ FZ_GITHUB_OAUTH_CLIENT_ID: value.githubOAuth.clientId,
3369
3365
  FZ_PLATFORM_INITIAL_INVENTORY: value.initialInventory ? JSON.stringify(value.initialInventory) : ""
3370
3366
  };
3371
3367
  return `# Generated by fz bootstrap platform. Non-secret coordinates only.
@@ -3377,9 +3373,7 @@ function platformApiCredentialSpecs(options) {
3377
3373
  const optional = [
3378
3374
  ["fz_smtp.password", options.emailProvider === "smtp"],
3379
3375
  ["fz_jetemail.apiKey", options.emailProvider === "jetemail"],
3380
- ["fz_github.clientSecret", options.githubApp],
3381
- ["fz_github.privateKey", options.githubApp],
3382
- ["fz_github.webhookSecret", options.githubApp],
3376
+ ["fz_oauth.github.clientSecret", options.githubOAuth],
3383
3377
  ["CF_API_TOKEN", options.cloudflareKv],
3384
3378
  ["CF_TUNNEL_TOKEN", options.cloudflareKv],
3385
3379
  ["REALTIME_PUBLISH_SECRET", options.realtime],
@@ -3783,9 +3777,7 @@ function validatePlatformBootstrapSecrets(config, input) {
3783
3777
  "backupS3Secret",
3784
3778
  "cloudflareTunnelToken",
3785
3779
  "cloudflareApiToken",
3786
- "githubClientSecret",
3787
- "githubPrivateKeyBase64",
3788
- "githubWebhookSecret"
3780
+ "githubOAuthClientSecret"
3789
3781
  ];
3790
3782
  const unknown = Object.keys(source).filter((key) => !allowed.includes(key));
3791
3783
  if (unknown.length)
@@ -3796,9 +3788,7 @@ function validatePlatformBootstrapSecrets(config, input) {
3796
3788
  const backupS3Secret = typeof source.backupS3Secret === "string" ? source.backupS3Secret.trim() : undefined;
3797
3789
  const cloudflareTunnelToken = typeof source.cloudflareTunnelToken === "string" ? source.cloudflareTunnelToken.trim() : undefined;
3798
3790
  const cloudflareApiToken = typeof source.cloudflareApiToken === "string" ? source.cloudflareApiToken.trim() : undefined;
3799
- const githubClientSecret = typeof source.githubClientSecret === "string" ? source.githubClientSecret.trim() : undefined;
3800
- const githubPrivateKeyBase64 = typeof source.githubPrivateKeyBase64 === "string" ? source.githubPrivateKeyBase64.trim() : undefined;
3801
- const githubWebhookSecret = typeof source.githubWebhookSecret === "string" ? source.githubWebhookSecret.trim() : undefined;
3791
+ const githubOAuthClientSecret = typeof source.githubOAuthClientSecret === "string" ? source.githubOAuthClientSecret.trim() : "";
3802
3792
  if (!/^[a-f0-9]{64}$/i.test(clusterBootstrapCode))
3803
3793
  throw new Error("cluster bootstrap code must contain exactly 64 hexadecimal characters");
3804
3794
  if (!emailSecret || emailSecret.length > 16384 || /[\r\n\0]/.test(emailSecret))
@@ -3818,21 +3808,8 @@ function validatePlatformBootstrapSecrets(config, input) {
3818
3808
  }
3819
3809
  if (cloudflareTunnelToken)
3820
3810
  validateCloudflareBootstrapSecretPair({ cloudflareTunnelToken, cloudflareApiToken });
3821
- const githubConfigured = Boolean(config.runtime.environment.githubApp);
3822
- if (githubConfigured !== Boolean(githubClientSecret && githubPrivateKeyBase64 && githubWebhookSecret)) {
3823
- throw new Error("GitHub App coordinates require client secret, private key and webhook secret together");
3824
- }
3825
- if (githubConfigured) {
3826
- if (githubClientSecret.length < 20 || githubClientSecret.length > 512 || /[\r\n\0]/.test(githubClientSecret) || githubWebhookSecret.length < 32 || githubWebhookSecret.length > 512 || /[\r\n\0]/.test(githubWebhookSecret)) {
3827
- throw new Error("GitHub App client or webhook secret is malformed");
3828
- }
3829
- try {
3830
- const pem = Buffer.from(githubPrivateKeyBase64, "base64").toString("utf8");
3831
- if (createPrivateKey(pem).asymmetricKeyType !== "rsa")
3832
- throw new Error("not RSA");
3833
- } catch {
3834
- throw new Error("GitHub App private key must be a base64-encoded RSA private key");
3835
- }
3811
+ if (githubOAuthClientSecret.length < 20 || githubOAuthClientSecret.length > 512 || /[\r\n\0]/.test(githubOAuthClientSecret)) {
3812
+ throw new Error("GitHub OAuth client secret is malformed");
3836
3813
  }
3837
3814
  return {
3838
3815
  clusterBootstrapCode,
@@ -3840,7 +3817,7 @@ function validatePlatformBootstrapSecrets(config, input) {
3840
3817
  ...enrolmentToken ? { enrolmentToken } : {},
3841
3818
  ...backupS3Secret ? { backupS3Secret } : {},
3842
3819
  ...cloudflareTunnelToken ? { cloudflareTunnelToken, cloudflareApiToken } : {},
3843
- ...githubConfigured ? { githubClientSecret, githubPrivateKeyBase64, githubWebhookSecret } : {}
3820
+ githubOAuthClientSecret
3844
3821
  };
3845
3822
  }
3846
3823
  var platformBootstrapRunner = (config) => config.kind === "platform" && config.database.role === "master";
@@ -4764,9 +4741,7 @@ async function applyBootstrap(input, host = localBootstrapHost(), secrets, depen
4764
4741
  backup: checked4.backupS3Secret,
4765
4742
  cloudflareTunnelToken: checked4.cloudflareTunnelToken,
4766
4743
  cloudflareApiToken: checked4.cloudflareApiToken,
4767
- githubClientSecret: checked4.githubClientSecret,
4768
- githubPrivateKey: checked4.githubPrivateKeyBase64 ? Buffer.from(checked4.githubPrivateKeyBase64, "base64").toString("utf8") : undefined,
4769
- githubWebhookSecret: checked4.githubWebhookSecret
4744
+ githubOAuthClientSecret: checked4.githubOAuthClientSecret
4770
4745
  };
4771
4746
  })() : undefined;
4772
4747
  const enrolledPrivate = config.kind === "enrolled-compute" ? validateEnrolledComputeBootstrapSecrets(config, secrets) : undefined;
@@ -4867,9 +4842,7 @@ async function applyBootstrap(input, host = localBootstrapHost(), secrets, depen
4867
4842
  const emailCredentialName = config.runtime.environment.email?.provider === "smtp" ? "fz_smtp.password" : config.runtime.environment.email?.provider === "jetemail" ? "fz_jetemail.apiKey" : undefined;
4868
4843
  for (const [name, source] of Object.entries({
4869
4844
  ...emailCredentialName ? { [emailCredentialName]: platformPrivate.email } : {},
4870
- "fz_github.clientSecret": platformPrivate.githubClientSecret,
4871
- "fz_github.privateKey": platformPrivate.githubPrivateKey,
4872
- "fz_github.webhookSecret": platformPrivate.githubWebhookSecret,
4845
+ "fz_oauth.github.clientSecret": platformPrivate.githubOAuthClientSecret,
4873
4846
  "backup.s3.secretAccessKey": platformPrivate.backup
4874
4847
  })) {
4875
4848
  if (source) {
@@ -4886,7 +4859,7 @@ async function applyBootstrap(input, host = localBootstrapHost(), secrets, depen
4886
4859
  const credentials = platformApiCredentialSpecs({
4887
4860
  emailProvider: runtime.environment.email?.provider,
4888
4861
  cloudflareKv: cloudflareConfigured,
4889
- githubApp: Boolean(runtime.environment.githubApp),
4862
+ githubOAuth: true,
4890
4863
  realtime: Boolean(runtime.environment.realtime)
4891
4864
  });
4892
4865
  const units = renderPlatformApiUnits({
@@ -5134,6 +5107,7 @@ function strictBootstrapDocument(value) {
5134
5107
  "agentOtlpEndpoint",
5135
5108
  "custodianEmail",
5136
5109
  "email",
5110
+ "githubOAuth",
5137
5111
  "deployProfile",
5138
5112
  "otlpFlushIntervalMs",
5139
5113
  "otlpTraceSampleRatio",
@@ -5144,6 +5118,7 @@ function strictBootstrapDocument(value) {
5144
5118
  "databaseReadPreferredCoordinators"
5145
5119
  ], "runtime environment");
5146
5120
  const environment = runtime.environment;
5121
+ exactKeys(environment.githubOAuth, ["clientId"], "GitHub OAuth config");
5147
5122
  if (environment.initialInventory !== undefined) {
5148
5123
  const inventory = exactKeys(environment.initialInventory, ["metalHostname", "metalIdentity", "region", "computes", "attestation", "deployment"], "initial inventory");
5149
5124
  if (inventory.metalIdentity !== undefined) {
@@ -73,10 +73,8 @@ export type PlatformBootstrapEmail = {
73
73
  * webhook secret are attended inputs sealed as systemd credentials and later
74
74
  * imported into the unlocked platform Vault.
75
75
  */
76
- export interface PlatformBootstrapGitHubApp {
76
+ export interface PlatformBootstrapGitHubOAuth {
77
77
  clientId: string;
78
- appId: string;
79
- slug: string;
80
78
  }
81
79
  export interface PlatformSharedEnvironment {
82
80
  softwareProfile: PlatformSoftwareProfile;
@@ -109,7 +107,7 @@ export interface PlatformSharedEnvironment {
109
107
  otlpTraceSampleRatio: number;
110
108
  custodianEmail?: string;
111
109
  email?: PlatformBootstrapEmail;
112
- githubApp?: PlatformBootstrapGitHubApp;
110
+ githubOAuth: PlatformBootstrapGitHubOAuth;
113
111
  backup?: {
114
112
  endpoint: string;
115
113
  region: string;
@@ -137,13 +135,13 @@ export declare function validatePlatformSharedEnvironment(input: PlatformSharedE
137
135
  /** Render only non-secret runtime coordinates. Passwords/tokens have no field in this contract. */
138
136
  export declare function renderPlatformSharedEnvironment(input: PlatformSharedEnvironment): string;
139
137
  export interface SystemdCredentialSpec {
140
- name: 'arangodb-jwt' | 'arangodb-root-password' | 'seed-sync-root' | 'fz_smtp.password' | 'fz_jetemail.apiKey' | 'fz_github.clientSecret' | 'fz_github.privateKey' | 'fz_github.webhookSecret' | 'CF_API_TOKEN' | 'CF_TUNNEL_TOKEN' | 'REALTIME_PUBLISH_SECRET' | 'REALTIME_TICKET_SECRET';
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';
141
139
  encryptedPath: string;
142
140
  required: boolean;
143
141
  }
144
142
  export declare function platformApiCredentialSpecs(options: {
145
143
  emailProvider?: PlatformBootstrapEmail['provider'];
146
- githubApp: boolean;
144
+ githubOAuth: boolean;
147
145
  cloudflareKv: boolean;
148
146
  realtime: boolean;
149
147
  }): SystemdCredentialSpec[];
@@ -828,10 +828,8 @@ function validatePlatformSharedEnvironment(input) {
828
828
  } else if (input.email !== undefined) {
829
829
  throw new Error("Bootstrap email provider must be smtp or jetemail.");
830
830
  }
831
- if (input.githubApp) {
832
- if (!/^(?:Iv1\.[A-Fa-f0-9]{16}|Ov23li[A-Za-z0-9]{14,})$/.test(input.githubApp.clientId) || !/^[1-9][0-9]{0,19}$/.test(input.githubApp.appId) || !/^[a-z0-9][a-z0-9-]{0,99}$/.test(input.githubApp.slug)) {
833
- throw new Error("GitHub App client id, app id or slug is malformed.");
834
- }
831
+ if (!input.githubOAuth || !/^(?:Iv1\.[A-Fa-f0-9]{16}|Ov23li[A-Za-z0-9]{14,})$/.test(input.githubOAuth.clientId)) {
832
+ throw new Error("GitHub OAuth client id is malformed.");
835
833
  }
836
834
  boundedInteger("publicApiPort", input.publicApiPort, 1024, 65533);
837
835
  if (!Array.isArray(input.seedSyncMembers) || input.seedSyncMembers.length < 3 || input.seedSyncMembers.length > 64 || new Set(input.seedSyncMembers).size !== input.seedSyncMembers.length) {
@@ -963,9 +961,7 @@ function renderPlatformSharedEnvironment(input) {
963
961
  FZ_REALTIME_WORKER_SCRIPT: value.realtime?.workerScriptName ?? "",
964
962
  FZ_REALTIME_ENDPOINT: value.realtime?.endpoint ?? "",
965
963
  FZ_REALTIME_PRODUCER: value.realtime?.producer ?? "",
966
- FZ_GITHUB_CLIENT_ID: value.githubApp?.clientId ?? "",
967
- FZ_GITHUB_APP_ID: value.githubApp?.appId ?? "",
968
- FZ_GITHUB_APP_SLUG: value.githubApp?.slug ?? "",
964
+ FZ_GITHUB_OAUTH_CLIENT_ID: value.githubOAuth.clientId,
969
965
  FZ_PLATFORM_INITIAL_INVENTORY: value.initialInventory ? JSON.stringify(value.initialInventory) : ""
970
966
  };
971
967
  return `# Generated by fz bootstrap platform. Non-secret coordinates only.
@@ -977,9 +973,7 @@ function platformApiCredentialSpecs(options) {
977
973
  const optional = [
978
974
  ["fz_smtp.password", options.emailProvider === "smtp"],
979
975
  ["fz_jetemail.apiKey", options.emailProvider === "jetemail"],
980
- ["fz_github.clientSecret", options.githubApp],
981
- ["fz_github.privateKey", options.githubApp],
982
- ["fz_github.webhookSecret", options.githubApp],
976
+ ["fz_oauth.github.clientSecret", options.githubOAuth],
983
977
  ["CF_API_TOKEN", options.cloudflareKv],
984
978
  ["CF_TUNNEL_TOKEN", options.cloudflareKv],
985
979
  ["REALTIME_PUBLISH_SECRET", options.realtime],
@@ -3004,7 +3004,7 @@ function requestSoftware(requirements, socketPath = DEFAULT_SOFTWARE_HELPER_SOCK
3004
3004
  }
3005
3005
 
3006
3006
  // src/version.ts
3007
- var VERSION3 = "0.1.107";
3007
+ var VERSION3 = "0.1.108";
3008
3008
 
3009
3009
  // src/egress-policy.ts
3010
3010
  import { realpathSync as realpathSync3 } from "node:fs";
@@ -4336,10 +4336,8 @@ function validatePlatformSharedEnvironment(input) {
4336
4336
  } else if (input.email !== undefined) {
4337
4337
  throw new Error("Bootstrap email provider must be smtp or jetemail.");
4338
4338
  }
4339
- if (input.githubApp) {
4340
- if (!/^(?:Iv1\.[A-Fa-f0-9]{16}|Ov23li[A-Za-z0-9]{14,})$/.test(input.githubApp.clientId) || !/^[1-9][0-9]{0,19}$/.test(input.githubApp.appId) || !/^[a-z0-9][a-z0-9-]{0,99}$/.test(input.githubApp.slug)) {
4341
- throw new Error("GitHub App client id, app id or slug is malformed.");
4342
- }
4339
+ if (!input.githubOAuth || !/^(?:Iv1\.[A-Fa-f0-9]{16}|Ov23li[A-Za-z0-9]{14,})$/.test(input.githubOAuth.clientId)) {
4340
+ throw new Error("GitHub OAuth client id is malformed.");
4343
4341
  }
4344
4342
  boundedInteger("publicApiPort", input.publicApiPort, 1024, 65533);
4345
4343
  if (!Array.isArray(input.seedSyncMembers) || input.seedSyncMembers.length < 3 || input.seedSyncMembers.length > 64 || new Set(input.seedSyncMembers).size !== input.seedSyncMembers.length) {
@@ -4471,9 +4469,7 @@ function renderPlatformSharedEnvironment(input) {
4471
4469
  FZ_REALTIME_WORKER_SCRIPT: value.realtime?.workerScriptName ?? "",
4472
4470
  FZ_REALTIME_ENDPOINT: value.realtime?.endpoint ?? "",
4473
4471
  FZ_REALTIME_PRODUCER: value.realtime?.producer ?? "",
4474
- FZ_GITHUB_CLIENT_ID: value.githubApp?.clientId ?? "",
4475
- FZ_GITHUB_APP_ID: value.githubApp?.appId ?? "",
4476
- FZ_GITHUB_APP_SLUG: value.githubApp?.slug ?? "",
4472
+ FZ_GITHUB_OAUTH_CLIENT_ID: value.githubOAuth.clientId,
4477
4473
  FZ_PLATFORM_INITIAL_INVENTORY: value.initialInventory ? JSON.stringify(value.initialInventory) : ""
4478
4474
  };
4479
4475
  return `# Generated by fz bootstrap platform. Non-secret coordinates only.
@@ -4485,9 +4481,7 @@ function platformApiCredentialSpecs(options) {
4485
4481
  const optional = [
4486
4482
  ["fz_smtp.password", options.emailProvider === "smtp"],
4487
4483
  ["fz_jetemail.apiKey", options.emailProvider === "jetemail"],
4488
- ["fz_github.clientSecret", options.githubApp],
4489
- ["fz_github.privateKey", options.githubApp],
4490
- ["fz_github.webhookSecret", options.githubApp],
4484
+ ["fz_oauth.github.clientSecret", options.githubOAuth],
4491
4485
  ["CF_API_TOKEN", options.cloudflareKv],
4492
4486
  ["CF_TUNNEL_TOKEN", options.cloudflareKv],
4493
4487
  ["REALTIME_PUBLISH_SECRET", options.realtime],
@@ -4842,7 +4836,7 @@ function planLocalOtlpProof(endpoint, collectorUnit) {
4842
4836
  import { lstatSync as lstatSync5 } from "node:fs";
4843
4837
 
4844
4838
  // src/bootstrap.ts
4845
- import { createHash as createHash7, createHmac as createHmac2, createPrivateKey, randomBytes as randomBytes3 } from "node:crypto";
4839
+ import { createHash as createHash7, createHmac as createHmac2, randomBytes as randomBytes3 } from "node:crypto";
4846
4840
  import {
4847
4841
  chmodSync as chmodSync9,
4848
4842
  existsSync as existsSync11,
@@ -4,9 +4,7 @@ export interface PlatformLaunchEnvironmentInput {
4
4
  emailSecret: string;
5
5
  cloudflareTunnelToken: string;
6
6
  cloudflareApiToken: string;
7
- githubClientSecret?: string;
8
- githubPrivateKeyBase64?: string;
9
- githubWebhookSecret?: string;
7
+ githubOAuthClientSecret: string;
10
8
  }
11
9
  /**
12
10
  * Read the development-only attended-launch adapter.
@@ -45,10 +45,9 @@ export interface ForgeZeroLaunchOwnerInput {
45
45
  from: string;
46
46
  eu: boolean;
47
47
  };
48
- githubApp?: {
48
+ /** Required bootstrap identity provider. Repository automation is configured after genesis. */
49
+ githubOAuth: {
49
50
  clientId: string;
50
- appId: string;
51
- slug: string;
52
51
  };
53
52
  }
54
53
  /**
package/dist/provision.js CHANGED
@@ -3004,7 +3004,7 @@ function requestSoftware(requirements, socketPath = DEFAULT_SOFTWARE_HELPER_SOCK
3004
3004
  }
3005
3005
 
3006
3006
  // src/version.ts
3007
- var VERSION3 = "0.1.107";
3007
+ var VERSION3 = "0.1.108";
3008
3008
 
3009
3009
  // src/egress-policy.ts
3010
3010
  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.107";
2
+ export declare const VERSION = "0.1.108";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forgezero/agent",
3
- "version": "0.1.107",
3
+ "version": "0.1.108",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "check": "tsc --noEmit",