@opengeni/github 0.6.7 → 0.7.1-canary.0

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/dist/index.d.ts CHANGED
@@ -1,7 +1,11 @@
1
1
  import type { Settings } from "@opengeni/config";
2
- import type { GitHubInstallationBindingCandidate, GitHubInstallationBindingProof, GitHubRepository, GitHubUserInstallationAccess } from "@opengeni/contracts";
2
+ import type { GitHubAppRepositoryBranchPage, GitHubInstallationBindingCandidate, GitHubInstallationBindingProof, GitHubRepository, GitHubUserInstallationAccess } from "@opengeni/contracts";
3
+ import type { VerifyPublicGitHubRepositoryRefResponse } from "@opengeni/contracts/github-repository-contracts";
4
+ import { type CanonicalGitHubRepository } from "@opengeni/contracts/github-repository";
3
5
  /** Bound for the server-side repository-id lookup at turn start (mint + read). */
4
6
  export declare const githubRepositoryLookupTimeoutMs = 10000;
7
+ export declare const githubRepositoryBranchesTimeoutMs = 10000;
8
+ export declare const githubPublicRepositoryVerificationTimeoutMs = 10000;
5
9
  export declare const stateMaxAgeSeconds: number;
6
10
  export declare const PERSONAL_GITHUB_GIT_BROKER_TOKEN_TTL_SECONDS: number;
7
11
  export type PersonalGitHubGitBrokerRepositoryClaim = {
@@ -51,6 +55,12 @@ export declare class GitHubAppApiError extends Error {
51
55
  readonly status: number | null;
52
56
  constructor(message: string, status?: number | null);
53
57
  }
58
+ export type GitHubPublicRepositoryVerificationErrorCode = "invalid_input" | "unavailable" | "provider_unavailable";
59
+ export declare class GitHubPublicRepositoryVerificationError extends Error {
60
+ readonly code: GitHubPublicRepositoryVerificationErrorCode;
61
+ readonly status?: number | undefined;
62
+ constructor(code: GitHubPublicRepositoryVerificationErrorCode, message: string, status?: number | undefined);
63
+ }
54
64
  export type GitHubInstallationAuthorityFailure = "authority_denied" | "authority_unavailable" | "installation_missing" | "installation_suspended" | "repository_access_empty";
55
65
  export declare class GitHubInstallationAuthorityError extends GitHubAppApiError {
56
66
  readonly reason: GitHubInstallationAuthorityFailure;
@@ -167,6 +177,26 @@ export declare function getGitHubAppInstallationRepository(settings: Settings, i
167
177
  * URIs from the same installation cost one mint plus one read each.
168
178
  */
169
179
  export declare function createGitHubAppInstallationRepositoryLookup(settings: Settings): GitHubAppInstallationRepositoryLookup;
180
+ /**
181
+ * List one bounded page of branch suggestions with an exact repository-scoped
182
+ * installation token. The token remains local to this server-side helper and
183
+ * is never returned in repository or branch metadata.
184
+ */
185
+ export declare function listGitHubAppRepositoryBranches(settings: Settings, input: {
186
+ installationId: number;
187
+ repositoryId: number;
188
+ page: number;
189
+ limit: number;
190
+ }): Promise<GitHubAppRepositoryBranchPage>;
191
+ /**
192
+ * Verify one exact anonymous github.com repository and ref. The provider URL
193
+ * is derived only from strict canonical coordinates, follows no redirects,
194
+ * sends no credentials, and bounds both request time and response bytes.
195
+ */
196
+ export declare function verifyPublicGitHubRepositoryRef(input: {
197
+ repository: CanonicalGitHubRepository;
198
+ ref: string;
199
+ }, fetchImpl?: typeof fetch): Promise<VerifyPublicGitHubRepositoryRefResponse>;
170
200
  export declare function createGitHubAppInstallationToken(settings: Settings, input: {
171
201
  installationId: number;
172
202
  repositoryIds: number[];
@@ -184,6 +214,7 @@ export declare function createGitHubAppInstallationTokenWithSigningSettings(sett
184
214
  installationId: number;
185
215
  repositoryIds: number[];
186
216
  permissions?: Record<string, "read" | "write">;
217
+ timeoutMs?: number;
187
218
  }): Promise<GitHubAppInstallationToken>;
188
219
  export declare function githubAppBotIdentity(settings: Settings): {
189
220
  name: string;
package/dist/index.js CHANGED
@@ -1,4 +1,8 @@
1
1
  // src/index.ts
2
+ import {
3
+ parseCanonicalGitHubRepositoryUrl
4
+ } from "@opengeni/contracts/github-repository";
5
+ import { readResponseTextBounded } from "@opengeni/network";
2
6
  import {
3
7
  createCipheriv,
4
8
  createDecipheriv,
@@ -13,6 +17,13 @@ var githubApiBase = "https://api.github.com";
13
17
  var githubApiVersion = "2022-11-28";
14
18
  var githubTokenMintTimeoutMs = 6e4;
15
19
  var githubRepositoryLookupTimeoutMs = 1e4;
20
+ var githubRepositoryBranchesTimeoutMs = 1e4;
21
+ var githubRepositoryBranchesResponseMaxBytes = 256 * 1024;
22
+ var githubPublicRepositoryVerificationTimeoutMs = 1e4;
23
+ var githubPublicRepositoryVerificationResponseMaxBytes = 128 * 1024;
24
+ var githubInstallationTokenResponseMaxBytes = 64 * 1024;
25
+ var githubErrorResponseMaxBytes = 64 * 1024;
26
+ var githubErrorMessageMaxLength = 1024;
16
27
  var stateMaxAgeSeconds = 60 * 60;
17
28
  var pkcs8PrivateKeyHeader = `-----BEGIN ${"PRIVATE KEY"}-----`;
18
29
  var rsaPrivateKeyHeader = `-----BEGIN ${"RSA PRIVATE KEY"}-----`;
@@ -155,6 +166,14 @@ var GitHubAppApiError = class extends Error {
155
166
  this.status = status;
156
167
  }
157
168
  };
169
+ var GitHubPublicRepositoryVerificationError = class extends Error {
170
+ constructor(code, message, status) {
171
+ super(message);
172
+ this.code = code;
173
+ this.status = status;
174
+ this.name = "GitHubPublicRepositoryVerificationError";
175
+ }
176
+ };
158
177
  var GitHubInstallationAuthorityError = class extends GitHubAppApiError {
159
178
  constructor(reason, message, status = null) {
160
179
  super(message, status);
@@ -563,6 +582,130 @@ function createGitHubAppInstallationRepositoryLookup(settings) {
563
582
  return repositoryFromPayload(record, input.installationId, account);
564
583
  };
565
584
  }
585
+ async function listGitHubAppRepositoryBranches(settings, input) {
586
+ if (!Number.isSafeInteger(input.installationId) || input.installationId <= 0 || !Number.isSafeInteger(input.repositoryId) || input.repositoryId <= 0 || !Number.isSafeInteger(input.page) || input.page <= 0 || input.page > 1e4 || !Number.isSafeInteger(input.limit) || input.limit <= 0 || input.limit > 100) {
587
+ throw new GitHubAppApiError("GitHub branch lookup requires bounded exact repository input");
588
+ }
589
+ const minted = await createGitHubAppInstallationTokenWithSigningSettings(settings, {
590
+ installationId: input.installationId,
591
+ repositoryIds: [input.repositoryId],
592
+ permissions: { contents: "read", metadata: "read" },
593
+ timeoutMs: githubRepositoryBranchesTimeoutMs
594
+ });
595
+ const repositoryResponse = await githubRepositoryBranchesFetch(
596
+ new URL(`${githubApiBase}/repositories/${input.repositoryId}`),
597
+ minted.token,
598
+ "GitHub repository branch identity"
599
+ );
600
+ const repositoryPayload = await githubResponseJsonBounded(
601
+ repositoryResponse,
602
+ "GitHub repository branch identity response"
603
+ );
604
+ if (!repositoryPayload || typeof repositoryPayload !== "object" || Array.isArray(repositoryPayload)) {
605
+ throw new GitHubAppApiError("GitHub returned an invalid repository branch identity payload");
606
+ }
607
+ const repository = repositoryPayload;
608
+ const repositoryId = asInt(repository.id);
609
+ const fullName = typeof repository.full_name === "string" ? repository.full_name : "";
610
+ const defaultBranch = typeof repository.default_branch === "string" ? repository.default_branch : "";
611
+ const coordinates = fullName.split("/");
612
+ if (repositoryId !== input.repositoryId || coordinates.length !== 2 || !coordinates[0] || !coordinates[1] || defaultBranch.length === 0 || defaultBranch.length > 1024) {
613
+ throw new GitHubAppApiError("GitHub returned an invalid repository branch identity payload");
614
+ }
615
+ const branchUrl = new URL(
616
+ `${githubApiBase}/repos/${encodeURIComponent(coordinates[0])}/${encodeURIComponent(coordinates[1])}/branches`
617
+ );
618
+ branchUrl.searchParams.set("page", String(input.page));
619
+ branchUrl.searchParams.set("per_page", String(input.limit));
620
+ const branchesResponse = await githubRepositoryBranchesFetch(
621
+ branchUrl,
622
+ minted.token,
623
+ "GitHub repository branches"
624
+ );
625
+ const branchPayload = await githubResponseJsonBounded(
626
+ branchesResponse,
627
+ "GitHub repository branches response"
628
+ );
629
+ if (!Array.isArray(branchPayload) || branchPayload.length > input.limit) {
630
+ throw new GitHubAppApiError("GitHub returned an invalid repository branches payload");
631
+ }
632
+ const branches = [];
633
+ const seen = /* @__PURE__ */ new Set();
634
+ for (const value of branchPayload) {
635
+ const name = value && typeof value === "object" && !Array.isArray(value) ? value.name : null;
636
+ if (typeof name !== "string" || name.length === 0 || name.length > 1024 || seen.has(name)) {
637
+ throw new GitHubAppApiError("GitHub returned an invalid repository branches payload");
638
+ }
639
+ seen.add(name);
640
+ branches.push(name);
641
+ }
642
+ return {
643
+ installationId: input.installationId,
644
+ repositoryId: input.repositoryId,
645
+ defaultBranch,
646
+ branches,
647
+ nextPage: branchPayload.length === input.limit && input.page < 1e4 ? input.page + 1 : null
648
+ };
649
+ }
650
+ async function verifyPublicGitHubRepositoryRef(input, fetchImpl = fetch) {
651
+ const ref = input.ref.trim();
652
+ if (!ref || ref.length > 1024 || /[\u0000-\u001f\u007f]/u.test(ref)) {
653
+ throw new GitHubPublicRepositoryVerificationError(
654
+ "invalid_input",
655
+ "Enter a branch, tag, or commit SHA."
656
+ );
657
+ }
658
+ const repositoryUrl = new URL(
659
+ `${githubApiBase}/repos/${encodeURIComponent(input.repository.owner)}/${encodeURIComponent(input.repository.name)}`
660
+ );
661
+ const repositoryPayload = await anonymousGitHubJson(
662
+ fetchImpl,
663
+ repositoryUrl,
664
+ "GitHub repository"
665
+ );
666
+ if (!repositoryPayload || typeof repositoryPayload !== "object" || Array.isArray(repositoryPayload)) {
667
+ throw new GitHubPublicRepositoryVerificationError(
668
+ "provider_unavailable",
669
+ "GitHub returned an invalid repository response."
670
+ );
671
+ }
672
+ const repository = repositoryPayload;
673
+ const fullName = typeof repository.full_name === "string" ? repository.full_name : "";
674
+ const defaultBranch = typeof repository.default_branch === "string" ? repository.default_branch : "";
675
+ const privateRepository = repository.private;
676
+ if (!Number.isSafeInteger(repository.id) || Number(repository.id) <= 0 || privateRepository !== false || !fullName || fullName.toLowerCase() !== input.repository.fullName.toLowerCase() || !defaultBranch || defaultBranch.length > 1024) {
677
+ throw new GitHubPublicRepositoryVerificationError(
678
+ "unavailable",
679
+ "That GitHub repository is private or unavailable."
680
+ );
681
+ }
682
+ let canonical;
683
+ try {
684
+ canonical = parseCanonicalGitHubRepositoryUrl(`https://github.com/${fullName}`);
685
+ } catch {
686
+ throw new GitHubPublicRepositoryVerificationError(
687
+ "provider_unavailable",
688
+ "GitHub returned an invalid repository identity."
689
+ );
690
+ }
691
+ const commitUrl = new URL(
692
+ `${githubApiBase}/repos/${encodeURIComponent(canonical.owner)}/${encodeURIComponent(canonical.name)}/commits/${encodeURIComponent(ref)}`
693
+ );
694
+ const commitPayload = await anonymousGitHubJson(fetchImpl, commitUrl, "GitHub repository ref");
695
+ const commitSha = commitPayload && typeof commitPayload === "object" && !Array.isArray(commitPayload) ? commitPayload.sha : null;
696
+ if (typeof commitSha !== "string" || !/^[0-9a-f]{40}$/u.test(commitSha)) {
697
+ throw new GitHubPublicRepositoryVerificationError(
698
+ "unavailable",
699
+ "That branch, tag, or commit SHA is not available on the public repository."
700
+ );
701
+ }
702
+ return {
703
+ ...canonical,
704
+ defaultBranch,
705
+ ref,
706
+ commitSha
707
+ };
708
+ }
566
709
  async function createGitHubAppInstallationToken(settings, input) {
567
710
  return (await createGitHubAppInstallationTokenWithExpiry(settings, input)).token;
568
711
  }
@@ -593,7 +736,8 @@ async function createGitHubAppInstallationTokenWithSigningSettings(settings, inp
593
736
  return await createInstallationToken(jwt, {
594
737
  installationId: input.installationId,
595
738
  repositoryIds,
596
- ...input.permissions ? { permissions: input.permissions } : {}
739
+ ...input.permissions ? { permissions: input.permissions } : {},
740
+ ...input.timeoutMs !== void 0 ? { timeoutMs: input.timeoutMs } : {}
597
741
  });
598
742
  }
599
743
  function githubAppBotIdentity(settings) {
@@ -794,20 +938,36 @@ async function createInstallationToken(appJwt, input) {
794
938
  ...githubHeaders(appJwt),
795
939
  ...scoped ? { "Content-Type": "application/json" } : {}
796
940
  },
941
+ redirect: "manual",
797
942
  signal: AbortSignal.timeout(input.timeoutMs ?? githubTokenMintTimeoutMs),
798
943
  ...scoped ? { body: JSON.stringify(body) } : {}
799
944
  }
800
945
  );
801
946
  if (!response.ok) {
802
- throw new GitHubAppApiError(await githubErrorMessage(response));
947
+ throw new GitHubAppApiError(await githubErrorMessage(response), response.status);
803
948
  }
804
- const payload = await response.json();
805
- if (!payload || typeof payload !== "object" || typeof payload.token !== "string") {
949
+ let payload;
950
+ try {
951
+ payload = JSON.parse(
952
+ await readResponseTextBounded(
953
+ response,
954
+ githubInstallationTokenResponseMaxBytes,
955
+ "GitHub installation token response"
956
+ )
957
+ );
958
+ } catch {
959
+ throw new GitHubAppApiError("GitHub returned an invalid installation token payload");
960
+ }
961
+ if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
962
+ throw new GitHubAppApiError("GitHub returned an invalid installation token payload");
963
+ }
964
+ const record = payload;
965
+ if (typeof record.token !== "string") {
806
966
  throw new GitHubAppApiError("GitHub returned an invalid installation token payload");
807
967
  }
808
968
  return {
809
- token: payload.token,
810
- expiresAt: typeof payload.expires_at === "string" ? payload.expires_at : null
969
+ token: record.token,
970
+ expiresAt: typeof record.expires_at === "string" ? record.expires_at : null
811
971
  };
812
972
  }
813
973
  async function listInstallationRepositories(token, installationId, account) {
@@ -859,6 +1019,74 @@ async function githubGet(path, token, params = {}) {
859
1019
  }
860
1020
  return await response.json();
861
1021
  }
1022
+ async function githubRepositoryBranchesFetch(url, token, label) {
1023
+ let response;
1024
+ try {
1025
+ response = await fetch(url, {
1026
+ headers: githubHeaders(token),
1027
+ redirect: "manual",
1028
+ signal: AbortSignal.timeout(githubRepositoryBranchesTimeoutMs)
1029
+ });
1030
+ } catch {
1031
+ throw new GitHubAppApiError(`${label} request failed`);
1032
+ }
1033
+ if (!response.ok) {
1034
+ throw new GitHubAppApiError(await githubErrorMessage(response), response.status);
1035
+ }
1036
+ return response;
1037
+ }
1038
+ async function githubResponseJsonBounded(response, label) {
1039
+ try {
1040
+ return JSON.parse(
1041
+ await readResponseTextBounded(response, githubRepositoryBranchesResponseMaxBytes, label)
1042
+ );
1043
+ } catch {
1044
+ throw new GitHubAppApiError(`${label} was invalid or too large`);
1045
+ }
1046
+ }
1047
+ async function anonymousGitHubJson(fetchImpl, url, label) {
1048
+ let response;
1049
+ try {
1050
+ response = await fetchImpl(url, {
1051
+ headers: githubHeaders(),
1052
+ redirect: "manual",
1053
+ signal: AbortSignal.timeout(githubPublicRepositoryVerificationTimeoutMs)
1054
+ });
1055
+ } catch {
1056
+ throw new GitHubPublicRepositoryVerificationError(
1057
+ "provider_unavailable",
1058
+ `${label} verification is temporarily unavailable.`
1059
+ );
1060
+ }
1061
+ if (response.status === 404) {
1062
+ throw new GitHubPublicRepositoryVerificationError(
1063
+ "unavailable",
1064
+ label === "GitHub repository" ? "That GitHub repository is private or unavailable." : "That branch, tag, or commit SHA is not available on the public repository.",
1065
+ response.status
1066
+ );
1067
+ }
1068
+ if (!response.ok) {
1069
+ throw new GitHubPublicRepositoryVerificationError(
1070
+ "provider_unavailable",
1071
+ response.status === 429 ? "GitHub is temporarily rate limited. Try again shortly." : `${label} verification is temporarily unavailable.`,
1072
+ response.status
1073
+ );
1074
+ }
1075
+ try {
1076
+ return JSON.parse(
1077
+ await readResponseTextBounded(
1078
+ response,
1079
+ githubPublicRepositoryVerificationResponseMaxBytes,
1080
+ `${label} verification response`
1081
+ )
1082
+ );
1083
+ } catch {
1084
+ throw new GitHubPublicRepositoryVerificationError(
1085
+ "provider_unavailable",
1086
+ `${label} verification returned an invalid response.`
1087
+ );
1088
+ }
1089
+ }
862
1090
  function repositoryFromPayload(payload, installationId, account) {
863
1091
  const id = asInt(payload.id);
864
1092
  const fullName = String(payload.full_name ?? "");
@@ -896,14 +1124,26 @@ function githubHeaders(token) {
896
1124
  };
897
1125
  }
898
1126
  async function githubErrorMessage(response) {
1127
+ let text;
899
1128
  try {
900
- const payload = await response.json();
1129
+ text = await readResponseTextBounded(
1130
+ response,
1131
+ githubErrorResponseMaxBytes,
1132
+ "GitHub error response"
1133
+ );
1134
+ } catch {
1135
+ return `GitHub API ${response.status}`;
1136
+ }
1137
+ try {
1138
+ const payload = JSON.parse(text);
901
1139
  if (payload && typeof payload === "object" && "message" in payload) {
902
- return `GitHub API ${response.status}: ${String(payload.message)}`;
1140
+ return `GitHub API ${response.status}: ${String(
1141
+ payload.message
1142
+ ).slice(0, githubErrorMessageMaxLength)}`;
903
1143
  }
904
1144
  } catch {
905
1145
  }
906
- return `GitHub API ${response.status}: ${await response.text()}`;
1146
+ return `GitHub API ${response.status}: ${text.slice(0, githubErrorMessageMaxLength)}`;
907
1147
  }
908
1148
  function normalizeGitHubAppPrivateKey(value) {
909
1149
  const privateKey = value.trim().replace(/\\n/g, "\n");
@@ -937,6 +1177,7 @@ export {
937
1177
  GitHubAppApiError,
938
1178
  GitHubAppConfigurationError,
939
1179
  GitHubInstallationAuthorityError,
1180
+ GitHubPublicRepositoryVerificationError,
940
1181
  PERSONAL_GITHUB_GIT_BROKER_TOKEN_TTL_SECONDS,
941
1182
  authorizeGitHubAppUser,
942
1183
  authorizeGitHubInstallationBinding,
@@ -955,10 +1196,13 @@ export {
955
1196
  githubAppBotIdentityWarnings,
956
1197
  githubAppMissingSettings,
957
1198
  githubOAuthAuthorizeUrl,
1199
+ githubPublicRepositoryVerificationTimeoutMs,
1200
+ githubRepositoryBranchesTimeoutMs,
958
1201
  githubRepositoryLookupTimeoutMs,
959
1202
  listGitHubAppInstallationSummaries,
960
1203
  listGitHubAppRepositories,
961
1204
  listGitHubAppRepositoriesWithSigningSettings,
1205
+ listGitHubAppRepositoryBranches,
962
1206
  normalizeGitHubAppPrivateKey,
963
1207
  openPersonalGitHubGitBrokerClaims,
964
1208
  organizationAppManifestUrl,
@@ -970,6 +1214,7 @@ export {
970
1214
  settingsForPrReviewGitHubApp,
971
1215
  stateMaxAgeSeconds,
972
1216
  verifyGitHubInstallationAccessForUser,
1217
+ verifyPublicGitHubRepositoryRef,
973
1218
  verifySignedState
974
1219
  };
975
1220
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { Settings } from \"@opengeni/config\";\nimport type {\n GitHubInstallationBindingCandidate,\n GitHubInstallationBindingProof,\n GitHubRepository,\n GitHubRepositoryPermissions,\n GitHubUserInstallationAccess,\n GitHubUserRepositoryAccess,\n} from \"@opengeni/contracts\";\nimport {\n createCipheriv,\n createDecipheriv,\n createHash,\n createHmac,\n createPrivateKey,\n randomBytes,\n timingSafeEqual,\n} from \"node:crypto\";\nimport { SignJWT, importPKCS8 } from \"jose\";\n\nconst githubApiBase = \"https://api.github.com\";\nconst githubApiVersion = \"2022-11-28\";\nconst githubTokenMintTimeoutMs = 60_000;\n/** Bound for the server-side repository-id lookup at turn start (mint + read). */\nexport const githubRepositoryLookupTimeoutMs = 10_000;\nexport const stateMaxAgeSeconds = 60 * 60;\nconst pkcs8PrivateKeyHeader = `-----BEGIN ${\"PRIVATE KEY\"}-----`;\nconst rsaPrivateKeyHeader = `-----BEGIN ${\"RSA PRIVATE KEY\"}-----`;\n\nconst PERSONAL_GITHUB_GIT_BROKER_TOKEN_PREFIX = \"oggh1\";\nconst PERSONAL_GITHUB_GIT_BROKER_KEY_CONTEXT = \"opengeni:personal-github:git-broker:v1\";\nexport const PERSONAL_GITHUB_GIT_BROKER_TOKEN_TTL_SECONDS = 5 * 60;\n\nexport type PersonalGitHubGitBrokerRepositoryClaim = {\n repositoryId: string;\n fullName: string;\n canonicalUrl: string;\n ref: string;\n access: \"read\" | \"write\";\n selectionGeneration: number;\n routeId: string;\n};\n\nexport type PersonalGitHubGitBrokerClaims = {\n version: 1;\n accountId: string;\n workspaceId: string;\n sessionId: string;\n rootSessionId: string;\n turnId: string;\n attemptId: string;\n executionGeneration: number;\n originWorkspaceId: string;\n connectionId: string;\n connectionAuthorityGeneration: number;\n ownerSubjectId: string;\n credentialBindingId: string;\n selectionGeneration: number;\n nonce: string;\n issuedAt: number;\n expiresAt: number;\n};\n\nexport function personalGitHubGitBrokerRouteId(\n secret: string,\n input: Omit<PersonalGitHubGitBrokerClaims, \"nonce\" | \"issuedAt\" | \"expiresAt\"> & {\n repository: Omit<PersonalGitHubGitBrokerRepositoryClaim, \"routeId\">;\n },\n): string {\n const hmac = createHmac(\"sha256\", personalGitHubGitBrokerKey(secret));\n for (const value of [\n String(input.version),\n input.accountId,\n input.workspaceId,\n input.sessionId,\n input.rootSessionId,\n input.turnId,\n input.attemptId,\n String(input.executionGeneration),\n input.originWorkspaceId,\n input.connectionId,\n String(input.connectionAuthorityGeneration),\n input.ownerSubjectId,\n input.credentialBindingId,\n String(input.selectionGeneration),\n input.repository.repositoryId,\n input.repository.fullName,\n input.repository.canonicalUrl,\n input.repository.ref,\n input.repository.access,\n String(input.repository.selectionGeneration),\n ]) {\n const bytes = Buffer.from(value, \"utf8\");\n hmac.update(Buffer.from(String(bytes.byteLength), \"ascii\"));\n hmac.update(\":\");\n hmac.update(bytes);\n hmac.update(\";\");\n }\n return hmac.digest(\"base64url\");\n}\n\n/**\n * Seal exact Git broker authority into a confidential, authenticated bearer.\n * The payload is encrypted rather than merely signed so tenant, session,\n * connection, and repository identities are not readable from the sandbox's\n * short-lived token file.\n */\nexport function sealPersonalGitHubGitBrokerClaims(\n secret: string,\n claims: PersonalGitHubGitBrokerClaims,\n): string {\n assertPersonalGitHubGitBrokerClaims(claims);\n const iv = randomBytes(12);\n const cipher = createCipheriv(\"aes-256-gcm\", personalGitHubGitBrokerKey(secret), iv);\n cipher.setAAD(Buffer.from(PERSONAL_GITHUB_GIT_BROKER_TOKEN_PREFIX, \"ascii\"));\n const ciphertext = Buffer.concat([cipher.update(JSON.stringify(claims), \"utf8\"), cipher.final()]);\n return [\n PERSONAL_GITHUB_GIT_BROKER_TOKEN_PREFIX,\n iv.toString(\"base64url\"),\n ciphertext.toString(\"base64url\"),\n cipher.getAuthTag().toString(\"base64url\"),\n ].join(\".\");\n}\n\nexport function openPersonalGitHubGitBrokerClaims(\n secret: string,\n token: string,\n nowSeconds = Math.floor(Date.now() / 1_000),\n): PersonalGitHubGitBrokerClaims | null {\n const [prefix, encodedIv, encodedCiphertext, encodedTag, extra] = token.split(\".\");\n if (\n prefix !== PERSONAL_GITHUB_GIT_BROKER_TOKEN_PREFIX ||\n !encodedIv ||\n !encodedCiphertext ||\n !encodedTag ||\n extra !== undefined\n ) {\n return null;\n }\n try {\n const iv = Buffer.from(encodedIv, \"base64url\");\n const ciphertext = Buffer.from(encodedCiphertext, \"base64url\");\n const tag = Buffer.from(encodedTag, \"base64url\");\n if (iv.byteLength !== 12 || tag.byteLength !== 16 || ciphertext.byteLength > 4_096) {\n return null;\n }\n const decipher = createDecipheriv(\"aes-256-gcm\", personalGitHubGitBrokerKey(secret), iv);\n decipher.setAAD(Buffer.from(PERSONAL_GITHUB_GIT_BROKER_TOKEN_PREFIX, \"ascii\"));\n decipher.setAuthTag(tag);\n const payload = JSON.parse(\n Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString(\"utf8\"),\n ) as unknown;\n assertPersonalGitHubGitBrokerClaims(payload);\n if (payload.issuedAt > nowSeconds + 60 || nowSeconds >= payload.expiresAt) return null;\n if (payload.expiresAt - payload.issuedAt > PERSONAL_GITHUB_GIT_BROKER_TOKEN_TTL_SECONDS) {\n return null;\n }\n return payload;\n } catch {\n return null;\n }\n}\n\nfunction personalGitHubGitBrokerKey(secret: string): Buffer {\n const normalized = secret.trim();\n if (!normalized) throw new Error(\"personal GitHub Git broker signing secret is unavailable\");\n return createHash(\"sha256\")\n .update(PERSONAL_GITHUB_GIT_BROKER_KEY_CONTEXT, \"utf8\")\n .update(\"\\0\", \"utf8\")\n .update(normalized, \"utf8\")\n .digest();\n}\n\nfunction assertPersonalGitHubGitBrokerClaims(\n value: unknown,\n): asserts value is PersonalGitHubGitBrokerClaims {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n throw new Error(\"invalid personal GitHub Git broker claims\");\n }\n const claims = value as Record<string, unknown>;\n const expectedKeys = new Set([\n \"version\",\n \"accountId\",\n \"workspaceId\",\n \"sessionId\",\n \"rootSessionId\",\n \"turnId\",\n \"attemptId\",\n \"executionGeneration\",\n \"originWorkspaceId\",\n \"connectionId\",\n \"connectionAuthorityGeneration\",\n \"ownerSubjectId\",\n \"credentialBindingId\",\n \"selectionGeneration\",\n \"nonce\",\n \"issuedAt\",\n \"expiresAt\",\n ]);\n const strings = [\n \"accountId\",\n \"workspaceId\",\n \"sessionId\",\n \"rootSessionId\",\n \"turnId\",\n \"attemptId\",\n \"originWorkspaceId\",\n \"connectionId\",\n \"ownerSubjectId\",\n \"credentialBindingId\",\n \"nonce\",\n ];\n if (\n claims.version !== 1 ||\n strings.some(\n (field) =>\n typeof claims[field] !== \"string\" ||\n claims[field].length === 0 ||\n claims[field].length > (field === \"ownerSubjectId\" ? 512 : 128),\n ) ||\n !positiveIntegerClaim(claims.executionGeneration) ||\n !positiveIntegerClaim(claims.connectionAuthorityGeneration) ||\n !positiveIntegerClaim(claims.selectionGeneration) ||\n !positiveIntegerClaim(claims.issuedAt) ||\n !positiveIntegerClaim(claims.expiresAt) ||\n Object.keys(claims).some((key) => !expectedKeys.has(key))\n ) {\n throw new Error(\"invalid personal GitHub Git broker claims\");\n }\n}\n\nfunction positiveIntegerClaim(value: unknown): value is number {\n return typeof value === \"number\" && Number.isSafeInteger(value) && value > 0;\n}\n\nexport class GitHubAppConfigurationError extends Error {\n constructor(readonly missing: string[]) {\n super(\"GitHub App is not configured\");\n }\n}\n\nexport class GitHubAppApiError extends Error {\n constructor(\n message: string,\n readonly status: number | null = null,\n ) {\n super(message);\n }\n}\n\nexport type GitHubInstallationAuthorityFailure =\n | \"authority_denied\"\n | \"authority_unavailable\"\n | \"installation_missing\"\n | \"installation_suspended\"\n | \"repository_access_empty\";\n\nexport class GitHubInstallationAuthorityError extends GitHubAppApiError {\n constructor(\n readonly reason: GitHubInstallationAuthorityFailure,\n message: string,\n status: number | null = null,\n ) {\n super(message, status);\n }\n}\n\nexport type GitHubAppInstallationSummary = {\n installationId: number;\n accountId: number;\n accountLogin: string | null;\n accountType: string | null;\n suspended: boolean;\n};\n\nexport type GitHubSignedStatePayload = {\n nonce: string;\n iat: number;\n accountId?: string;\n workspaceId?: string;\n [key: string]: unknown;\n};\n\nexport function githubAppMissingSettings(settings: Settings): string[] {\n const required: Record<string, string | undefined> = {\n OPENGENI_GITHUB_APP_ID: settings.githubAppId,\n OPENGENI_GITHUB_CLIENT_ID: settings.githubClientId,\n OPENGENI_GITHUB_CLIENT_SECRET: settings.githubClientSecret,\n OPENGENI_GITHUB_APP_SLUG: settings.githubAppSlug,\n OPENGENI_GITHUB_APP_PRIVATE_KEY: settings.githubAppPrivateKey,\n };\n return Object.entries(required).flatMap(([name, value]) => (value && value.trim() ? [] : [name]));\n}\n\nexport function prReviewGitHubAppMissingSettings(settings: Settings): string[] {\n const required: Record<string, string | undefined> = {\n OPENGENI_GITHUB_APP_MANIFEST_STATE_SECRET: settings.githubAppManifestStateSecret,\n OPENGENI_ENVIRONMENTS_ENCRYPTION_KEY: settings.environmentsEncryptionKey,\n OPENGENI_PR_REVIEW_GITHUB_APP_ID: settings.prReviewGithubAppId,\n OPENGENI_PR_REVIEW_GITHUB_CLIENT_ID: settings.prReviewGithubClientId,\n OPENGENI_PR_REVIEW_GITHUB_CLIENT_SECRET: settings.prReviewGithubClientSecret,\n OPENGENI_PR_REVIEW_GITHUB_APP_SLUG: settings.prReviewGithubAppSlug,\n OPENGENI_PR_REVIEW_GITHUB_WEBHOOK_SECRET: settings.prReviewGithubWebhookSecret,\n OPENGENI_PR_REVIEW_GITHUB_APP_PRIVATE_KEY: settings.prReviewGithubAppPrivateKey,\n };\n return Object.entries(required).flatMap(([name, value]) => (value && value.trim() ? [] : [name]));\n}\n\n/** Project the separately configured review App onto the ordinary GitHub App\n * authority client. This keeps its OAuth, signing, webhook, and installation\n * identity disjoint from the platform GitHub App while reusing the same\n * personal-owner / organization-owner proof implementation. */\nexport function settingsForPrReviewGitHubApp(settings: Settings): Settings {\n return {\n ...settings,\n githubAppId: settings.prReviewGithubAppId,\n githubClientId: settings.prReviewGithubClientId,\n githubClientSecret: settings.prReviewGithubClientSecret,\n githubAppSlug: settings.prReviewGithubAppSlug,\n githubWebhookSecret: settings.prReviewGithubWebhookSecret,\n githubAppPrivateKey: settings.prReviewGithubAppPrivateKey,\n };\n}\n\nexport type GitHubAppSigningSettings = Pick<Settings, \"githubAppId\" | \"githubAppPrivateKey\">;\n\nfunction githubAppTokenMissingSettings(settings: GitHubAppSigningSettings): string[] {\n const required: Record<string, string | undefined> = {\n OPENGENI_GITHUB_APP_ID: settings.githubAppId,\n OPENGENI_GITHUB_APP_PRIVATE_KEY: settings.githubAppPrivateKey,\n };\n return Object.entries(required).flatMap(([name, value]) => (value && value.trim() ? [] : [name]));\n}\n\nexport function buildGitHubAppManifest(input: {\n appName: string;\n baseUrl: string;\n public: boolean;\n includeCiPermissions: boolean;\n setupUrl?: string;\n}): Record<string, unknown> {\n const base = input.baseUrl.replace(/\\/+$/, \"\");\n const permissions: Record<string, string> = {\n metadata: \"read\",\n contents: \"write\",\n pull_requests: \"write\",\n // Required for the authenticated-user membership endpoint that proves an\n // active organization owner. Existing installations must approve this\n // permission before organization-owner self-service can succeed.\n members: \"read\",\n };\n if (input.includeCiPermissions) {\n permissions.actions = \"read\";\n permissions.checks = \"read\";\n permissions.statuses = \"write\";\n }\n const manifest: Record<string, unknown> = {\n name: input.appName,\n url: base,\n redirect_url: `${base}/v1/github/app-manifest/callback`,\n callback_urls: [`${base}/v1/github/oauth/callback`],\n public: input.public,\n // A setup URL and OAuth-on-install are mutually exclusive in GitHub's App\n // contract. OpenGeni needs the setup callback to receive the installation\n // id, then starts its own exact user-authorization flow.\n request_oauth_on_install: !input.setupUrl,\n default_permissions: permissions,\n };\n if (input.setupUrl) {\n manifest.setup_url = input.setupUrl;\n manifest.setup_on_update = true;\n }\n return manifest;\n}\n\nexport function personalAppManifestUrl(state: string): string {\n return `https://github.com/settings/apps/new?state=${state}`;\n}\n\nexport function organizationAppManifestUrl(organization: string, state: string): string {\n return `https://github.com/organizations/${encodeURIComponent(organization)}/settings/apps/new?state=${state}`;\n}\n\nexport function githubOAuthAuthorizeUrl(input: {\n clientId: string;\n state: string;\n redirectUri?: string;\n}): string {\n const url = new URL(\"https://github.com/login/oauth/authorize\");\n url.searchParams.set(\"client_id\", input.clientId);\n url.searchParams.set(\"state\", input.state);\n if (input.redirectUri) {\n url.searchParams.set(\"redirect_uri\", input.redirectUri);\n }\n return url.toString();\n}\n\nexport function createSignedState(\n secret: string,\n payloadOrNow: Record<string, unknown> | number = {},\n nowArg = Math.floor(Date.now() / 1000),\n): string {\n const payloadInput = typeof payloadOrNow === \"number\" ? {} : payloadOrNow;\n const now = typeof payloadOrNow === \"number\" ? payloadOrNow : nowArg;\n const payload = {\n ...payloadInput,\n nonce: randomBytes(16).toString(\"base64url\"),\n iat: now,\n };\n const encoded = Buffer.from(JSON.stringify(payload)).toString(\"base64url\");\n return `${encoded}.${signStatePayload(encoded, secret)}`;\n}\n\nexport function readSignedState(\n state: string,\n secret: string,\n now = Math.floor(Date.now() / 1000),\n): GitHubSignedStatePayload | null {\n const [encoded, signature] = state.split(\".\", 2);\n if (!encoded || !signature) {\n return null;\n }\n const expected = signStatePayload(encoded, secret);\n if (!safeEqual(signature, expected)) {\n return null;\n }\n let payload: unknown;\n try {\n payload = JSON.parse(Buffer.from(encoded, \"base64url\").toString(\"utf8\"));\n } catch {\n return null;\n }\n if (\n !payload ||\n typeof payload !== \"object\" ||\n typeof (payload as { iat?: unknown }).iat !== \"number\" ||\n typeof (payload as { nonce?: unknown }).nonce !== \"string\"\n ) {\n return null;\n }\n const age = now - (payload as { iat: number }).iat;\n return age >= 0 && age <= stateMaxAgeSeconds ? (payload as GitHubSignedStatePayload) : null;\n}\n\nexport function verifySignedState(\n state: string,\n secret: string,\n now = Math.floor(Date.now() / 1000),\n): boolean {\n return readSignedState(state, secret, now) !== null;\n}\n\nexport function envLinesFromGitHubManifestConversion(payload: Record<string, unknown>): string[] {\n const privateKey = String(payload.pem ?? \"\").replace(/\\n/g, \"\\\\n\");\n return [\n `OPENGENI_GITHUB_APP_ID=${payload.id ?? \"\"}`,\n `OPENGENI_GITHUB_CLIENT_ID=${payload.client_id ?? \"\"}`,\n `OPENGENI_GITHUB_CLIENT_SECRET=${payload.client_secret ?? \"\"}`,\n `OPENGENI_GITHUB_APP_SLUG=${payload.slug ?? \"\"}`,\n `OPENGENI_GITHUB_WEBHOOK_SECRET=${payload.webhook_secret ?? \"\"}`,\n `OPENGENI_GITHUB_APP_PRIVATE_KEY=\"${privateKey}\"`,\n ];\n}\n\nexport async function convertGitHubAppManifest(code: string): Promise<Record<string, unknown>> {\n const response = await fetch(`${githubApiBase}/app-manifests/${code}/conversions`, {\n method: \"POST\",\n headers: githubHeaders(undefined),\n });\n if (!response.ok) {\n throw new GitHubAppApiError(await githubErrorMessage(response));\n }\n const payload = await response.json();\n if (!payload || typeof payload !== \"object\" || Array.isArray(payload)) {\n throw new GitHubAppApiError(\"GitHub returned an invalid manifest conversion payload\");\n }\n return payload as Record<string, unknown>;\n}\n\nexport async function listGitHubAppInstallationSummaries(\n settings: Settings,\n): Promise<GitHubAppInstallationSummary[]> {\n const missing = githubAppMissingSettings(settings);\n if (missing.length > 0) {\n throw new GitHubAppConfigurationError(missing);\n }\n const jwt = await createGitHubAppJwt(settings);\n const installations = await listInstallations(jwt);\n return installations.map(installationSummaryFromPayload);\n}\n\nexport async function getGitHubAppInstallationSummary(\n settings: Settings,\n installationId: number,\n): Promise<GitHubAppInstallationSummary | null> {\n const installations = await listGitHubAppInstallationSummaries(settings);\n return (\n installations.find((installation) => installation.installationId === installationId) ?? null\n );\n}\n\nexport async function verifyGitHubInstallationAccessForUser(\n settings: Settings,\n input: {\n code: string;\n installationId: number;\n },\n): Promise<GitHubAppInstallationSummary> {\n const token = await exchangeGitHubOAuthCodeForUserToken(settings, input.code);\n const installations = await listUserAccessibleInstallations(token);\n const installation = installations.find(\n (candidate) => candidate.installationId === input.installationId,\n );\n if (!installation) {\n throw new GitHubAppApiError(\"GitHub installation is not accessible to the installing user\");\n }\n return installation;\n}\n\n/**\n * Exchange a GitHub App user-authorization code and discover the installations\n * and repositories the user can explicitly access. This is compatibility\n * discovery metadata only: visibility and repository permission bits do not\n * prove that the human may install, configure, or bind the App installation.\n * No production binding path may treat this result as authority.\n */\nexport async function authorizeGitHubAppUser(\n settings: Settings,\n input: { code: string },\n): Promise<GitHubUserInstallationAccess[]> {\n const token = await exchangeGitHubOAuthCodeForUserToken(settings, input.code);\n const installations = await listUserAccessibleInstallations(token);\n return await Promise.all(\n installations.map(async (installation) => ({\n ...installation,\n repositories: installation.suspended\n ? []\n : await listUserInstallationRepositories(token, installation),\n })),\n );\n}\n\n/**\n * Prove current GitHub installation authority without treating repository\n * administration or installation visibility as delegation authority.\n *\n * GitHub exposes an exact personal-account owner through the authenticated\n * user's immutable id. For organizations, GitHub's authenticated membership\n * endpoint exposes active owners as role=admin. GitHub does not expose an\n * equivalent current-authority receipt for App Managers, so that case remains\n * unsupported and fails closed.\n */\nexport async function authorizeGitHubInstallationBinding(\n settings: Settings,\n input: { code: string; installationId: number },\n): Promise<GitHubInstallationBindingProof> {\n const userToken = await exchangeGitHubOAuthCodeForUserToken(settings, input.code);\n const actor = await getAuthenticatedGitHubUser(userToken);\n const visibleInstallations = await listUserAccessibleInstallations(userToken);\n const visible = visibleInstallations.find(\n (installation) => installation.installationId === input.installationId,\n );\n if (!visible) {\n throw new GitHubInstallationAuthorityError(\n \"authority_denied\",\n \"GitHub did not associate this installation with the authorized user\",\n );\n }\n\n const jwt = await createGitHubAppJwt(settings);\n const livePayload = (await listInstallations(jwt)).find(\n (installation) => asInt(installation.id) === input.installationId,\n );\n if (!livePayload) {\n throw new GitHubInstallationAuthorityError(\n \"installation_missing\",\n \"GitHub App installation was deleted or is not owned by this App\",\n );\n }\n const installation = installationSummaryFromPayload(livePayload);\n if (\n installation.accountId !== visible.accountId ||\n installation.accountLogin !== visible.accountLogin ||\n installation.accountType !== visible.accountType\n ) {\n throw new GitHubInstallationAuthorityError(\n \"authority_denied\",\n \"GitHub installation identity changed during authorization\",\n );\n }\n if (installation.suspended) {\n throw new GitHubInstallationAuthorityError(\n \"installation_suspended\",\n \"GitHub App installation is suspended\",\n );\n }\n\n let authorityKind: GitHubInstallationBindingProof[\"authorityKind\"];\n if (installation.accountType === \"User\" && actor.id === installation.accountId) {\n authorityKind = \"personal_owner\";\n } else if (installation.accountType === \"Organization\" && installation.accountLogin) {\n await assertActiveOrganizationOwner(\n userToken,\n installation.accountId,\n installation.accountLogin,\n );\n authorityKind = \"organization_owner\";\n } else {\n throw new GitHubInstallationAuthorityError(\n \"authority_denied\",\n \"Only a GitHub personal-account owner or organization owner may bind an installation\",\n );\n }\n\n const installationToken = await createInstallationToken(jwt, {\n installationId: installation.installationId,\n });\n const repositories = await listInstallationRepositories(\n installationToken.token,\n installation.installationId,\n { login: installation.accountLogin, type: installation.accountType },\n );\n if (repositories.length === 0) {\n throw new GitHubInstallationAuthorityError(\n \"repository_access_empty\",\n \"GitHub App installation does not currently grant access to any repositories\",\n );\n }\n if (authorityKind === \"organization_owner\") {\n // Repository enumeration is an async provider boundary. Re-read the live\n // owner tuple after it so a role revoked after the chooser proof cannot be\n // durably bound with a later, misleading authority timestamp.\n await assertActiveOrganizationOwner(\n userToken,\n installation.accountId,\n installation.accountLogin!,\n );\n }\n return {\n actorId: actor.id,\n actorLogin: actor.login,\n authorityKind,\n installation,\n repositories,\n };\n}\n\n/**\n * Discover existing installations that the freshly authorized GitHub human\n * can bind as an exact personal owner or active organization owner.\n *\n * `GET /user/installations` is discovery input only. Every candidate is\n * cross-checked against the App's live installation inventory and an\n * organization candidate requires a live `state=active, role=admin`\n * membership proof. The later exact authorization still re-runs the complete\n * proof immediately before the durable bind.\n */\nexport async function discoverGitHubInstallationBindingCandidates(\n settings: Settings,\n input: { code: string },\n): Promise<GitHubInstallationBindingCandidate[]> {\n const userToken = await exchangeGitHubOAuthCodeForUserToken(settings, input.code);\n const actor = await getAuthenticatedGitHubUser(userToken);\n const visibleInstallations = await listUserAccessibleInstallations(userToken);\n const jwt = await createGitHubAppJwt(settings);\n const liveInstallations = new Map(\n (await listInstallations(jwt)).map((payload) => {\n const installation = installationSummaryFromPayload(payload);\n return [installation.installationId, installation] as const;\n }),\n );\n const candidates: GitHubInstallationBindingCandidate[] = [];\n\n for (const visible of visibleInstallations) {\n const installation = liveInstallations.get(visible.installationId);\n if (\n !installation ||\n installation.suspended ||\n installation.accountId !== visible.accountId ||\n installation.accountLogin !== visible.accountLogin ||\n installation.accountType !== visible.accountType\n ) {\n continue;\n }\n if (installation.accountType === \"User\" && actor.id === installation.accountId) {\n candidates.push({ installation, authorityKind: \"personal_owner\" });\n continue;\n }\n if (installation.accountType !== \"Organization\" || !installation.accountLogin) {\n continue;\n }\n try {\n await assertActiveOrganizationOwner(\n userToken,\n installation.accountId,\n installation.accountLogin,\n );\n candidates.push({ installation, authorityKind: \"organization_owner\" });\n } catch (error) {\n if (\n error instanceof GitHubInstallationAuthorityError &&\n error.reason === \"authority_unavailable\"\n ) {\n continue;\n }\n if (\n error instanceof GitHubInstallationAuthorityError &&\n error.reason === \"authority_denied\"\n ) {\n continue;\n }\n throw error;\n }\n }\n\n return candidates.sort((left, right) =>\n (left.installation.accountLogin ?? \"\").localeCompare(right.installation.accountLogin ?? \"\"),\n );\n}\n\nexport async function listGitHubAppRepositories(\n settings: Settings,\n input: {\n installationIds?: number[];\n } = {},\n): Promise<GitHubRepository[]> {\n const missing = githubAppMissingSettings(settings);\n if (missing.length > 0) {\n throw new GitHubAppConfigurationError(missing);\n }\n return await listGitHubAppRepositoriesWithSigningSettings(settings, input);\n}\n\n/** List repositories for a separately registered App that needs only signing credentials. */\nexport async function listGitHubAppRepositoriesWithSigningSettings(\n settings: GitHubAppSigningSettings,\n input: {\n installationIds?: number[];\n } = {},\n): Promise<GitHubRepository[]> {\n const missing = githubAppTokenMissingSettings(settings);\n if (missing.length > 0) {\n throw new GitHubAppConfigurationError(missing);\n }\n const allowedInstallations = input.installationIds ? new Set(input.installationIds) : null;\n if (allowedInstallations && allowedInstallations.size === 0) {\n return [];\n }\n const jwt = await createGitHubAppJwt(settings);\n const installations = await listInstallations(jwt);\n const repositories: GitHubRepository[] = [];\n for (const installation of installations) {\n if (installation.suspended_at) {\n continue;\n }\n const installationId = asInt(installation.id);\n if (installationId === null) {\n continue;\n }\n if (allowedInstallations && !allowedInstallations.has(installationId)) {\n continue;\n }\n const account =\n typeof installation.account === \"object\" && installation.account\n ? (installation.account as Record<string, unknown>)\n : {};\n const token = await createInstallationToken(jwt, { installationId });\n repositories.push(\n ...(await listInstallationRepositories(token.token, installationId, account)),\n );\n }\n repositories.sort((left, right) => left.fullName.localeCompare(right.fullName));\n return repositories;\n}\n\nexport type GitHubAppInstallationRepositoryLookupInput = {\n installationId: number;\n owner: string;\n name: string;\n};\n\nexport type GitHubAppInstallationRepositoryLookup = (\n input: GitHubAppInstallationRepositoryLookupInput,\n) => Promise<GitHubRepository | null>;\n\n/**\n * Resolve one `owner/name` repository through an exact App installation and\n * return GitHub's stable repository identity, or null when that installation\n * cannot see the repository. The server-side lookup token never leaves the\n * caller and grants nothing by itself: the workspace allowlist decides whether\n * the returned id may mint a sandbox-bound token.\n */\nexport async function getGitHubAppInstallationRepository(\n settings: Settings,\n input: GitHubAppInstallationRepositoryLookupInput,\n): Promise<GitHubRepository | null> {\n return await createGitHubAppInstallationRepositoryLookup(settings)(input);\n}\n\n/**\n * One lookup client that reuses a server-side installation token per\n * installation for its lifetime (one worker turn), so several bare repository\n * URIs from the same installation cost one mint plus one read each.\n */\nexport function createGitHubAppInstallationRepositoryLookup(\n settings: Settings,\n): GitHubAppInstallationRepositoryLookup {\n const missing = githubAppMissingSettings(settings);\n if (missing.length > 0) {\n throw new GitHubAppConfigurationError(missing);\n }\n const tokens = new Map<number, Promise<GitHubAppInstallationToken>>();\n const installationToken = (installationId: number): Promise<GitHubAppInstallationToken> => {\n let pending = tokens.get(installationId);\n if (!pending) {\n // Metadata-read only: the lookup needs the repository id, never contents.\n // Bounded well below the sandbox mint timeout so a slow GitHub cannot\n // hold turn start; the caller proceeds bare on expiry.\n pending = createGitHubAppJwt(settings).then((jwt) =>\n createInstallationToken(jwt, {\n installationId,\n permissions: { metadata: \"read\" },\n timeoutMs: githubRepositoryLookupTimeoutMs,\n }),\n );\n pending.catch(() => tokens.delete(installationId));\n tokens.set(installationId, pending);\n }\n return pending;\n };\n return async (input) => {\n const owner = input.owner.trim();\n const name = input.name.trim();\n if (\n !/^[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?$/u.test(owner) ||\n !/^[A-Za-z0-9._-]+$/u.test(name)\n ) {\n return null;\n }\n const token = await installationToken(input.installationId);\n const response = await fetch(\n `${githubApiBase}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(name)}`,\n {\n headers: githubHeaders(token.token),\n signal: AbortSignal.timeout(githubRepositoryLookupTimeoutMs),\n },\n );\n if (response.status === 404) {\n return null;\n }\n if (!response.ok) {\n throw new GitHubAppApiError(await githubErrorMessage(response), response.status);\n }\n const payload = await response.json();\n if (!payload || typeof payload !== \"object\" || Array.isArray(payload)) {\n throw new GitHubAppApiError(\"GitHub returned an invalid repository payload\");\n }\n const record = payload as Record<string, unknown>;\n const account =\n record.owner && typeof record.owner === \"object\" && !Array.isArray(record.owner)\n ? (record.owner as Record<string, unknown>)\n : {};\n return repositoryFromPayload(record, input.installationId, account);\n };\n}\n\nexport async function createGitHubAppInstallationToken(\n settings: Settings,\n input: {\n installationId: number;\n repositoryIds: number[];\n },\n): Promise<string> {\n return (await createGitHubAppInstallationTokenWithExpiry(settings, input)).token;\n}\n\nexport type GitHubAppInstallationToken = {\n token: string;\n expiresAt: string | null;\n};\n\nexport async function createGitHubAppInstallationTokenWithExpiry(\n settings: Settings,\n input: {\n installationId: number;\n repositoryIds: number[];\n },\n): Promise<GitHubAppInstallationToken> {\n const missing = githubAppMissingSettings(settings);\n if (missing.length > 0) {\n throw new GitHubAppConfigurationError(missing);\n }\n return await createGitHubAppInstallationTokenWithSigningSettings(settings, input);\n}\n\n/** Mint for a separately registered App without requiring unrelated OAuth settings. */\nexport async function createGitHubAppInstallationTokenWithSigningSettings(\n settings: GitHubAppSigningSettings,\n input: {\n installationId: number;\n repositoryIds: number[];\n permissions?: Record<string, \"read\" | \"write\">;\n },\n): Promise<GitHubAppInstallationToken> {\n const missing = githubAppTokenMissingSettings(settings);\n if (missing.length > 0) {\n throw new GitHubAppConfigurationError(missing);\n }\n if (!Array.isArray(input.repositoryIds)) {\n throw new GitHubAppApiError(\n \"GitHub installation token mint requires an explicit, unique repository allowlist\",\n );\n }\n const repositoryIds = [...new Set(input.repositoryIds)];\n if (\n !Number.isSafeInteger(input.installationId) ||\n input.installationId <= 0 ||\n repositoryIds.length === 0 ||\n repositoryIds.length !== input.repositoryIds.length ||\n repositoryIds.some((id) => !Number.isSafeInteger(id) || id <= 0)\n ) {\n throw new GitHubAppApiError(\n \"GitHub installation token mint requires an explicit, unique repository allowlist\",\n );\n }\n const jwt = await createGitHubAppJwt(settings);\n return await createInstallationToken(jwt, {\n installationId: input.installationId,\n repositoryIds,\n ...(input.permissions ? { permissions: input.permissions } : {}),\n });\n}\n\nexport function githubAppBotIdentity(settings: Settings): { name: string; email: string } | null {\n const appId = settings.githubAppId?.trim();\n const slug = settings.githubAppSlug?.trim();\n if (!appId || !slug) {\n return null;\n }\n const login = `${slug}[bot]`;\n return {\n name: login,\n email: `${appId}+${login}@users.noreply.github.com`,\n };\n}\n\nexport const GITHUB_APP_BOT_IDENTITY_UNAVAILABLE_WARNING =\n \"github_app_bot_identity_unavailable\" as const;\n\n/**\n * Non-secret health posture for the stable sandbox Git identity. API-direct\n * attach and worker-turn startup must add the same identity keys. A complete\n * deployment-level author identity is sufficient because committer values\n * default to it; otherwise a partially configured workspace GitHub App must\n * surface that its bot identity cannot be derived.\n */\nexport function githubAppBotIdentityWarnings(\n settings: Settings,\n): Array<typeof GITHUB_APP_BOT_IDENTITY_UNAVAILABLE_WARNING> {\n const workspaceAppConfigured = [\n settings.githubAppId,\n settings.githubClientId,\n settings.githubClientSecret,\n settings.githubAppSlug,\n settings.githubWebhookSecret,\n settings.githubAppPrivateKey,\n ].some((value) => typeof value === \"string\" && value.trim().length > 0);\n const explicitGitIdentityConfigured =\n typeof settings.gitAuthorName === \"string\" &&\n settings.gitAuthorName.trim().length > 0 &&\n typeof settings.gitAuthorEmail === \"string\" &&\n settings.gitAuthorEmail.trim().length > 0;\n if (\n !workspaceAppConfigured ||\n explicitGitIdentityConfigured ||\n githubAppBotIdentity(settings) !== null\n ) {\n return [];\n }\n return [GITHUB_APP_BOT_IDENTITY_UNAVAILABLE_WARNING];\n}\n\nasync function createGitHubAppJwt(settings: GitHubAppSigningSettings): Promise<string> {\n const privateKey = normalizeGitHubAppPrivateKey(settings.githubAppPrivateKey ?? \"\");\n const appId = settings.githubAppId?.trim();\n if (!appId || !privateKey) {\n throw new GitHubAppConfigurationError(githubAppTokenMissingSettings(settings));\n }\n const key = await importPKCS8(privateKey, \"RS256\");\n const now = Math.floor(Date.now() / 1000);\n return await new SignJWT({})\n .setProtectedHeader({ alg: \"RS256\" })\n .setIssuedAt(now - 60)\n .setExpirationTime(now + 9 * 60)\n .setIssuer(appId)\n .sign(key);\n}\n\nasync function listInstallations(token: string): Promise<Array<Record<string, unknown>>> {\n const out: Array<Record<string, unknown>> = [];\n for (let page = 1; ; page += 1) {\n const payload = await githubGet(\"/app/installations\", token, {\n per_page: \"100\",\n page: String(page),\n });\n if (!Array.isArray(payload)) {\n throw new GitHubAppApiError(\"GitHub returned an invalid installations payload\");\n }\n out.push(\n ...payload.filter((item): item is Record<string, unknown> =>\n Boolean(item && typeof item === \"object\" && !Array.isArray(item)),\n ),\n );\n if (payload.length < 100) {\n return out;\n }\n }\n}\n\nasync function exchangeGitHubOAuthCodeForUserToken(\n settings: Settings,\n code: string,\n): Promise<string> {\n if (!settings.githubClientId || !settings.githubClientSecret) {\n throw new GitHubAppConfigurationError(githubAppMissingSettings(settings));\n }\n const response = await fetch(\"https://github.com/login/oauth/access_token\", {\n method: \"POST\",\n headers: {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n client_id: settings.githubClientId,\n client_secret: settings.githubClientSecret,\n code,\n }),\n });\n if (!response.ok) {\n throw new GitHubAppApiError(await githubErrorMessage(response));\n }\n const payload = await response.json();\n if (!payload || typeof payload !== \"object\" || typeof payload.access_token !== \"string\") {\n throw new GitHubAppApiError(\"GitHub returned an invalid OAuth token payload\");\n }\n return payload.access_token;\n}\n\nasync function getAuthenticatedGitHubUser(token: string): Promise<{ id: number; login: string }> {\n const payload = await githubGet(\"/user\", token);\n const id = payload && typeof payload === \"object\" ? asInt(payload.id) : null;\n const login =\n payload && typeof payload === \"object\" && typeof payload.login === \"string\"\n ? payload.login\n : null;\n if (id === null || !login) {\n throw new GitHubAppApiError(\"GitHub returned an invalid authenticated user payload\");\n }\n return { id, login };\n}\n\nasync function getAuthenticatedOrganizationMembership(\n token: string,\n organizationLogin: string,\n): Promise<{ organizationId: number; role: string; state: string }> {\n let payload: any;\n try {\n payload = await githubGet(\n `/user/memberships/orgs/${encodeURIComponent(organizationLogin)}`,\n token,\n );\n } catch (error) {\n if (error instanceof GitHubAppApiError) {\n throw new GitHubInstallationAuthorityError(\n \"authority_unavailable\",\n \"GitHub could not prove current organization-owner membership\",\n error.status,\n );\n }\n throw error;\n }\n const organization =\n payload && typeof payload === \"object\" && payload.organization ? payload.organization : null;\n const organizationId =\n organization && typeof organization === \"object\" ? asInt(organization.id) : null;\n if (\n organizationId === null ||\n typeof payload?.role !== \"string\" ||\n typeof payload?.state !== \"string\"\n ) {\n throw new GitHubInstallationAuthorityError(\n \"authority_unavailable\",\n \"GitHub returned an invalid organization membership proof\",\n );\n }\n return { organizationId, role: payload.role, state: payload.state };\n}\n\nasync function assertActiveOrganizationOwner(\n token: string,\n organizationId: number,\n organizationLogin: string,\n): Promise<void> {\n const membership = await getAuthenticatedOrganizationMembership(token, organizationLogin);\n if (\n membership.organizationId !== organizationId ||\n membership.state !== \"active\" ||\n membership.role !== \"admin\"\n ) {\n throw new GitHubInstallationAuthorityError(\n \"authority_denied\",\n \"Only an active GitHub organization owner may bind this installation\",\n );\n }\n}\n\nasync function listUserAccessibleInstallations(\n token: string,\n): Promise<GitHubAppInstallationSummary[]> {\n const out: GitHubAppInstallationSummary[] = [];\n for (let page = 1; ; page += 1) {\n const payload = await githubGet(\"/user/installations\", token, {\n per_page: \"100\",\n page: String(page),\n });\n const installations: unknown[] | null =\n payload && typeof payload === \"object\" && Array.isArray(payload.installations)\n ? (payload.installations as unknown[])\n : null;\n if (!installations) {\n throw new GitHubAppApiError(\"GitHub returned an invalid user installations payload\");\n }\n out.push(\n ...installations\n .filter((item): item is Record<string, unknown> =>\n Boolean(item && typeof item === \"object\" && !Array.isArray(item)),\n )\n .map(installationSummaryFromPayload),\n );\n if (installations.length < 100) {\n return out;\n }\n }\n}\n\nasync function listUserInstallationRepositories(\n token: string,\n installation: GitHubAppInstallationSummary,\n): Promise<GitHubUserRepositoryAccess[]> {\n const out: GitHubUserRepositoryAccess[] = [];\n const account = {\n ...(installation.accountLogin ? { login: installation.accountLogin } : {}),\n ...(installation.accountType ? { type: installation.accountType } : {}),\n };\n for (let page = 1; ; page += 1) {\n const payload = await githubGet(\n `/user/installations/${installation.installationId}/repositories`,\n token,\n { per_page: \"100\", page: String(page) },\n );\n if (\n !payload ||\n typeof payload !== \"object\" ||\n Array.isArray(payload) ||\n !Array.isArray(payload.repositories)\n ) {\n throw new GitHubAppApiError(\n \"GitHub returned an invalid user installation repositories payload\",\n );\n }\n for (const repository of payload.repositories) {\n if (!repository || typeof repository !== \"object\" || Array.isArray(repository)) {\n continue;\n }\n const record = repository as Record<string, unknown>;\n out.push({\n ...repositoryFromPayload(record, installation.installationId, account),\n permissions: repositoryPermissionsFromPayload(record.permissions),\n });\n }\n if (payload.repositories.length < 100) {\n return out;\n }\n }\n}\n\nasync function createInstallationToken(\n appJwt: string,\n input: {\n installationId: number;\n repositoryIds?: number[];\n /** Narrow the token below the installation's granted permissions. */\n permissions?: Record<string, \"read\" | \"write\">;\n timeoutMs?: number;\n },\n): Promise<GitHubAppInstallationToken> {\n const body: Record<string, unknown> = {};\n if (input.repositoryIds && input.repositoryIds.length > 0) {\n body.repository_ids = input.repositoryIds;\n }\n if (input.permissions && Object.keys(input.permissions).length > 0) {\n body.permissions = input.permissions;\n }\n const scoped = Object.keys(body).length > 0;\n const response = await fetch(\n `${githubApiBase}/app/installations/${input.installationId}/access_tokens`,\n {\n method: \"POST\",\n headers: {\n ...githubHeaders(appJwt),\n ...(scoped ? { \"Content-Type\": \"application/json\" } : {}),\n },\n signal: AbortSignal.timeout(input.timeoutMs ?? githubTokenMintTimeoutMs),\n ...(scoped ? { body: JSON.stringify(body) } : {}),\n },\n );\n if (!response.ok) {\n throw new GitHubAppApiError(await githubErrorMessage(response));\n }\n const payload = await response.json();\n if (!payload || typeof payload !== \"object\" || typeof payload.token !== \"string\") {\n throw new GitHubAppApiError(\"GitHub returned an invalid installation token payload\");\n }\n return {\n token: payload.token,\n expiresAt: typeof payload.expires_at === \"string\" ? payload.expires_at : null,\n };\n}\n\nasync function listInstallationRepositories(\n token: string,\n installationId: number,\n account: Record<string, unknown>,\n): Promise<GitHubRepository[]> {\n const out: GitHubRepository[] = [];\n for (let page = 1; ; page += 1) {\n const payload = await githubGet(\"/installation/repositories\", token, {\n per_page: \"100\",\n page: String(page),\n });\n if (\n !payload ||\n typeof payload !== \"object\" ||\n Array.isArray(payload) ||\n !Array.isArray(payload.repositories)\n ) {\n throw new GitHubAppApiError(\"GitHub returned an invalid repositories payload\");\n }\n for (const repo of payload.repositories) {\n if (repo && typeof repo === \"object\" && !Array.isArray(repo)) {\n out.push(repositoryFromPayload(repo as Record<string, unknown>, installationId, account));\n }\n }\n if (payload.repositories.length < 100) {\n return out;\n }\n }\n}\n\nfunction installationSummaryFromPayload(\n payload: Record<string, unknown>,\n): GitHubAppInstallationSummary {\n const installationId = asInt(payload.id);\n if (installationId === null) {\n throw new GitHubAppApiError(\"GitHub returned an installation without id\");\n }\n const account =\n typeof payload.account === \"object\" && payload.account\n ? (payload.account as Record<string, unknown>)\n : {};\n const accountId = asInt(account.id);\n if (accountId === null) {\n throw new GitHubAppApiError(\"GitHub returned an installation without an account id\");\n }\n return {\n installationId,\n accountId,\n accountLogin: typeof account.login === \"string\" ? account.login : null,\n accountType: typeof account.type === \"string\" ? account.type : null,\n suspended: Boolean(payload.suspended_at),\n };\n}\n\nasync function githubGet(\n path: string,\n token: string,\n params: Record<string, string> = {},\n): Promise<any> {\n const url = new URL(`${githubApiBase}${path}`);\n for (const [key, value] of Object.entries(params)) {\n url.searchParams.set(key, value);\n }\n const response = await fetch(url, { headers: githubHeaders(token) });\n if (!response.ok) {\n throw new GitHubAppApiError(await githubErrorMessage(response), response.status);\n }\n return await response.json();\n}\n\nfunction repositoryFromPayload(\n payload: Record<string, unknown>,\n installationId: number,\n account: Record<string, unknown>,\n): GitHubRepository {\n const id = asInt(payload.id);\n const fullName = String(payload.full_name ?? \"\");\n if (id === null || !fullName) {\n throw new GitHubAppApiError(\"GitHub returned a repository without id/full_name\");\n }\n return {\n id,\n installationId,\n fullName,\n name: String(payload.name ?? fullName.split(\"/\").at(-1) ?? fullName),\n private: Boolean(payload.private),\n htmlUrl: String(payload.html_url ?? `https://github.com/${fullName}`),\n cloneUrl: String(payload.clone_url ?? `https://github.com/${fullName}.git`),\n defaultBranch: String(payload.default_branch ?? \"main\"),\n accountLogin: String(account.login ?? fullName.split(\"/\", 1)[0]),\n accountType: typeof account.type === \"string\" ? account.type : null,\n };\n}\n\nfunction repositoryPermissionsFromPayload(payload: unknown): GitHubRepositoryPermissions {\n const permissions =\n payload && typeof payload === \"object\" && !Array.isArray(payload)\n ? (payload as Record<string, unknown>)\n : {};\n return {\n admin: permissions.admin === true,\n maintain: permissions.maintain === true,\n push: permissions.push === true,\n triage: permissions.triage === true,\n pull: permissions.pull === true,\n };\n}\n\nfunction githubHeaders(token?: string): HeadersInit {\n return {\n Accept: \"application/vnd.github+json\",\n ...(token ? { Authorization: `Bearer ${token}` } : {}),\n \"X-GitHub-Api-Version\": githubApiVersion,\n };\n}\n\nasync function githubErrorMessage(response: Response): Promise<string> {\n try {\n const payload = await response.json();\n if (payload && typeof payload === \"object\" && \"message\" in payload) {\n return `GitHub API ${response.status}: ${String(payload.message)}`;\n }\n } catch {\n // fall through\n }\n return `GitHub API ${response.status}: ${await response.text()}`;\n}\n\nexport function normalizeGitHubAppPrivateKey(value: string): string {\n const privateKey = value.trim().replace(/\\\\n/g, \"\\n\");\n if (!privateKey || privateKey.startsWith(pkcs8PrivateKeyHeader)) {\n return privateKey;\n }\n if (privateKey.startsWith(rsaPrivateKeyHeader)) {\n return createPrivateKey(privateKey).export({ type: \"pkcs8\", format: \"pem\" }).toString();\n }\n return privateKey;\n}\n\nfunction signStatePayload(encoded: string, secret: string): string {\n return createHmac(\"sha256\", secret).update(encoded).digest(\"base64url\");\n}\n\nfunction safeEqual(left: string, right: string): boolean {\n const a = Buffer.from(left);\n const b = Buffer.from(right);\n return a.length === b.length && timingSafeEqual(a, b);\n}\n\nfunction asInt(value: unknown): number | null {\n if (typeof value === \"number\" && Number.isInteger(value)) {\n return value;\n }\n if (typeof value === \"string\" && /^\\d+$/.test(value)) {\n return Number(value);\n }\n return null;\n}\n"],"mappings":"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","names":["installation"]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { Settings } from \"@opengeni/config\";\nimport type {\n GitHubAppRepositoryBranchPage,\n GitHubInstallationBindingCandidate,\n GitHubInstallationBindingProof,\n GitHubRepository,\n GitHubRepositoryPermissions,\n GitHubUserInstallationAccess,\n GitHubUserRepositoryAccess,\n} from \"@opengeni/contracts\";\nimport type { VerifyPublicGitHubRepositoryRefResponse } from \"@opengeni/contracts/github-repository-contracts\";\nimport {\n parseCanonicalGitHubRepositoryUrl,\n type CanonicalGitHubRepository,\n} from \"@opengeni/contracts/github-repository\";\nimport { readResponseTextBounded } from \"@opengeni/network\";\nimport {\n createCipheriv,\n createDecipheriv,\n createHash,\n createHmac,\n createPrivateKey,\n randomBytes,\n timingSafeEqual,\n} from \"node:crypto\";\nimport { SignJWT, importPKCS8 } from \"jose\";\n\nconst githubApiBase = \"https://api.github.com\";\nconst githubApiVersion = \"2022-11-28\";\nconst githubTokenMintTimeoutMs = 60_000;\n/** Bound for the server-side repository-id lookup at turn start (mint + read). */\nexport const githubRepositoryLookupTimeoutMs = 10_000;\nexport const githubRepositoryBranchesTimeoutMs = 10_000;\nconst githubRepositoryBranchesResponseMaxBytes = 256 * 1024;\nexport const githubPublicRepositoryVerificationTimeoutMs = 10_000;\nconst githubPublicRepositoryVerificationResponseMaxBytes = 128 * 1024;\nconst githubInstallationTokenResponseMaxBytes = 64 * 1024;\nconst githubErrorResponseMaxBytes = 64 * 1024;\nconst githubErrorMessageMaxLength = 1024;\nexport const stateMaxAgeSeconds = 60 * 60;\nconst pkcs8PrivateKeyHeader = `-----BEGIN ${\"PRIVATE KEY\"}-----`;\nconst rsaPrivateKeyHeader = `-----BEGIN ${\"RSA PRIVATE KEY\"}-----`;\n\nconst PERSONAL_GITHUB_GIT_BROKER_TOKEN_PREFIX = \"oggh1\";\nconst PERSONAL_GITHUB_GIT_BROKER_KEY_CONTEXT = \"opengeni:personal-github:git-broker:v1\";\nexport const PERSONAL_GITHUB_GIT_BROKER_TOKEN_TTL_SECONDS = 5 * 60;\n\nexport type PersonalGitHubGitBrokerRepositoryClaim = {\n repositoryId: string;\n fullName: string;\n canonicalUrl: string;\n ref: string;\n access: \"read\" | \"write\";\n selectionGeneration: number;\n routeId: string;\n};\n\nexport type PersonalGitHubGitBrokerClaims = {\n version: 1;\n accountId: string;\n workspaceId: string;\n sessionId: string;\n rootSessionId: string;\n turnId: string;\n attemptId: string;\n executionGeneration: number;\n originWorkspaceId: string;\n connectionId: string;\n connectionAuthorityGeneration: number;\n ownerSubjectId: string;\n credentialBindingId: string;\n selectionGeneration: number;\n nonce: string;\n issuedAt: number;\n expiresAt: number;\n};\n\nexport function personalGitHubGitBrokerRouteId(\n secret: string,\n input: Omit<PersonalGitHubGitBrokerClaims, \"nonce\" | \"issuedAt\" | \"expiresAt\"> & {\n repository: Omit<PersonalGitHubGitBrokerRepositoryClaim, \"routeId\">;\n },\n): string {\n const hmac = createHmac(\"sha256\", personalGitHubGitBrokerKey(secret));\n for (const value of [\n String(input.version),\n input.accountId,\n input.workspaceId,\n input.sessionId,\n input.rootSessionId,\n input.turnId,\n input.attemptId,\n String(input.executionGeneration),\n input.originWorkspaceId,\n input.connectionId,\n String(input.connectionAuthorityGeneration),\n input.ownerSubjectId,\n input.credentialBindingId,\n String(input.selectionGeneration),\n input.repository.repositoryId,\n input.repository.fullName,\n input.repository.canonicalUrl,\n input.repository.ref,\n input.repository.access,\n String(input.repository.selectionGeneration),\n ]) {\n const bytes = Buffer.from(value, \"utf8\");\n hmac.update(Buffer.from(String(bytes.byteLength), \"ascii\"));\n hmac.update(\":\");\n hmac.update(bytes);\n hmac.update(\";\");\n }\n return hmac.digest(\"base64url\");\n}\n\n/**\n * Seal exact Git broker authority into a confidential, authenticated bearer.\n * The payload is encrypted rather than merely signed so tenant, session,\n * connection, and repository identities are not readable from the sandbox's\n * short-lived token file.\n */\nexport function sealPersonalGitHubGitBrokerClaims(\n secret: string,\n claims: PersonalGitHubGitBrokerClaims,\n): string {\n assertPersonalGitHubGitBrokerClaims(claims);\n const iv = randomBytes(12);\n const cipher = createCipheriv(\"aes-256-gcm\", personalGitHubGitBrokerKey(secret), iv);\n cipher.setAAD(Buffer.from(PERSONAL_GITHUB_GIT_BROKER_TOKEN_PREFIX, \"ascii\"));\n const ciphertext = Buffer.concat([cipher.update(JSON.stringify(claims), \"utf8\"), cipher.final()]);\n return [\n PERSONAL_GITHUB_GIT_BROKER_TOKEN_PREFIX,\n iv.toString(\"base64url\"),\n ciphertext.toString(\"base64url\"),\n cipher.getAuthTag().toString(\"base64url\"),\n ].join(\".\");\n}\n\nexport function openPersonalGitHubGitBrokerClaims(\n secret: string,\n token: string,\n nowSeconds = Math.floor(Date.now() / 1_000),\n): PersonalGitHubGitBrokerClaims | null {\n const [prefix, encodedIv, encodedCiphertext, encodedTag, extra] = token.split(\".\");\n if (\n prefix !== PERSONAL_GITHUB_GIT_BROKER_TOKEN_PREFIX ||\n !encodedIv ||\n !encodedCiphertext ||\n !encodedTag ||\n extra !== undefined\n ) {\n return null;\n }\n try {\n const iv = Buffer.from(encodedIv, \"base64url\");\n const ciphertext = Buffer.from(encodedCiphertext, \"base64url\");\n const tag = Buffer.from(encodedTag, \"base64url\");\n if (iv.byteLength !== 12 || tag.byteLength !== 16 || ciphertext.byteLength > 4_096) {\n return null;\n }\n const decipher = createDecipheriv(\"aes-256-gcm\", personalGitHubGitBrokerKey(secret), iv);\n decipher.setAAD(Buffer.from(PERSONAL_GITHUB_GIT_BROKER_TOKEN_PREFIX, \"ascii\"));\n decipher.setAuthTag(tag);\n const payload = JSON.parse(\n Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString(\"utf8\"),\n ) as unknown;\n assertPersonalGitHubGitBrokerClaims(payload);\n if (payload.issuedAt > nowSeconds + 60 || nowSeconds >= payload.expiresAt) return null;\n if (payload.expiresAt - payload.issuedAt > PERSONAL_GITHUB_GIT_BROKER_TOKEN_TTL_SECONDS) {\n return null;\n }\n return payload;\n } catch {\n return null;\n }\n}\n\nfunction personalGitHubGitBrokerKey(secret: string): Buffer {\n const normalized = secret.trim();\n if (!normalized) throw new Error(\"personal GitHub Git broker signing secret is unavailable\");\n return createHash(\"sha256\")\n .update(PERSONAL_GITHUB_GIT_BROKER_KEY_CONTEXT, \"utf8\")\n .update(\"\\0\", \"utf8\")\n .update(normalized, \"utf8\")\n .digest();\n}\n\nfunction assertPersonalGitHubGitBrokerClaims(\n value: unknown,\n): asserts value is PersonalGitHubGitBrokerClaims {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n throw new Error(\"invalid personal GitHub Git broker claims\");\n }\n const claims = value as Record<string, unknown>;\n const expectedKeys = new Set([\n \"version\",\n \"accountId\",\n \"workspaceId\",\n \"sessionId\",\n \"rootSessionId\",\n \"turnId\",\n \"attemptId\",\n \"executionGeneration\",\n \"originWorkspaceId\",\n \"connectionId\",\n \"connectionAuthorityGeneration\",\n \"ownerSubjectId\",\n \"credentialBindingId\",\n \"selectionGeneration\",\n \"nonce\",\n \"issuedAt\",\n \"expiresAt\",\n ]);\n const strings = [\n \"accountId\",\n \"workspaceId\",\n \"sessionId\",\n \"rootSessionId\",\n \"turnId\",\n \"attemptId\",\n \"originWorkspaceId\",\n \"connectionId\",\n \"ownerSubjectId\",\n \"credentialBindingId\",\n \"nonce\",\n ];\n if (\n claims.version !== 1 ||\n strings.some(\n (field) =>\n typeof claims[field] !== \"string\" ||\n claims[field].length === 0 ||\n claims[field].length > (field === \"ownerSubjectId\" ? 512 : 128),\n ) ||\n !positiveIntegerClaim(claims.executionGeneration) ||\n !positiveIntegerClaim(claims.connectionAuthorityGeneration) ||\n !positiveIntegerClaim(claims.selectionGeneration) ||\n !positiveIntegerClaim(claims.issuedAt) ||\n !positiveIntegerClaim(claims.expiresAt) ||\n Object.keys(claims).some((key) => !expectedKeys.has(key))\n ) {\n throw new Error(\"invalid personal GitHub Git broker claims\");\n }\n}\n\nfunction positiveIntegerClaim(value: unknown): value is number {\n return typeof value === \"number\" && Number.isSafeInteger(value) && value > 0;\n}\n\nexport class GitHubAppConfigurationError extends Error {\n constructor(readonly missing: string[]) {\n super(\"GitHub App is not configured\");\n }\n}\n\nexport class GitHubAppApiError extends Error {\n constructor(\n message: string,\n readonly status: number | null = null,\n ) {\n super(message);\n }\n}\n\nexport type GitHubPublicRepositoryVerificationErrorCode =\n | \"invalid_input\"\n | \"unavailable\"\n | \"provider_unavailable\";\n\nexport class GitHubPublicRepositoryVerificationError extends Error {\n constructor(\n readonly code: GitHubPublicRepositoryVerificationErrorCode,\n message: string,\n readonly status?: number,\n ) {\n super(message);\n this.name = \"GitHubPublicRepositoryVerificationError\";\n }\n}\n\nexport type GitHubInstallationAuthorityFailure =\n | \"authority_denied\"\n | \"authority_unavailable\"\n | \"installation_missing\"\n | \"installation_suspended\"\n | \"repository_access_empty\";\n\nexport class GitHubInstallationAuthorityError extends GitHubAppApiError {\n constructor(\n readonly reason: GitHubInstallationAuthorityFailure,\n message: string,\n status: number | null = null,\n ) {\n super(message, status);\n }\n}\n\nexport type GitHubAppInstallationSummary = {\n installationId: number;\n accountId: number;\n accountLogin: string | null;\n accountType: string | null;\n suspended: boolean;\n};\n\nexport type GitHubSignedStatePayload = {\n nonce: string;\n iat: number;\n accountId?: string;\n workspaceId?: string;\n [key: string]: unknown;\n};\n\nexport function githubAppMissingSettings(settings: Settings): string[] {\n const required: Record<string, string | undefined> = {\n OPENGENI_GITHUB_APP_ID: settings.githubAppId,\n OPENGENI_GITHUB_CLIENT_ID: settings.githubClientId,\n OPENGENI_GITHUB_CLIENT_SECRET: settings.githubClientSecret,\n OPENGENI_GITHUB_APP_SLUG: settings.githubAppSlug,\n OPENGENI_GITHUB_APP_PRIVATE_KEY: settings.githubAppPrivateKey,\n };\n return Object.entries(required).flatMap(([name, value]) => (value && value.trim() ? [] : [name]));\n}\n\nexport function prReviewGitHubAppMissingSettings(settings: Settings): string[] {\n const required: Record<string, string | undefined> = {\n OPENGENI_GITHUB_APP_MANIFEST_STATE_SECRET: settings.githubAppManifestStateSecret,\n OPENGENI_ENVIRONMENTS_ENCRYPTION_KEY: settings.environmentsEncryptionKey,\n OPENGENI_PR_REVIEW_GITHUB_APP_ID: settings.prReviewGithubAppId,\n OPENGENI_PR_REVIEW_GITHUB_CLIENT_ID: settings.prReviewGithubClientId,\n OPENGENI_PR_REVIEW_GITHUB_CLIENT_SECRET: settings.prReviewGithubClientSecret,\n OPENGENI_PR_REVIEW_GITHUB_APP_SLUG: settings.prReviewGithubAppSlug,\n OPENGENI_PR_REVIEW_GITHUB_WEBHOOK_SECRET: settings.prReviewGithubWebhookSecret,\n OPENGENI_PR_REVIEW_GITHUB_APP_PRIVATE_KEY: settings.prReviewGithubAppPrivateKey,\n };\n return Object.entries(required).flatMap(([name, value]) => (value && value.trim() ? [] : [name]));\n}\n\n/** Project the separately configured review App onto the ordinary GitHub App\n * authority client. This keeps its OAuth, signing, webhook, and installation\n * identity disjoint from the platform GitHub App while reusing the same\n * personal-owner / organization-owner proof implementation. */\nexport function settingsForPrReviewGitHubApp(settings: Settings): Settings {\n return {\n ...settings,\n githubAppId: settings.prReviewGithubAppId,\n githubClientId: settings.prReviewGithubClientId,\n githubClientSecret: settings.prReviewGithubClientSecret,\n githubAppSlug: settings.prReviewGithubAppSlug,\n githubWebhookSecret: settings.prReviewGithubWebhookSecret,\n githubAppPrivateKey: settings.prReviewGithubAppPrivateKey,\n };\n}\n\nexport type GitHubAppSigningSettings = Pick<Settings, \"githubAppId\" | \"githubAppPrivateKey\">;\n\nfunction githubAppTokenMissingSettings(settings: GitHubAppSigningSettings): string[] {\n const required: Record<string, string | undefined> = {\n OPENGENI_GITHUB_APP_ID: settings.githubAppId,\n OPENGENI_GITHUB_APP_PRIVATE_KEY: settings.githubAppPrivateKey,\n };\n return Object.entries(required).flatMap(([name, value]) => (value && value.trim() ? [] : [name]));\n}\n\nexport function buildGitHubAppManifest(input: {\n appName: string;\n baseUrl: string;\n public: boolean;\n includeCiPermissions: boolean;\n setupUrl?: string;\n}): Record<string, unknown> {\n const base = input.baseUrl.replace(/\\/+$/, \"\");\n const permissions: Record<string, string> = {\n metadata: \"read\",\n contents: \"write\",\n pull_requests: \"write\",\n // Required for the authenticated-user membership endpoint that proves an\n // active organization owner. Existing installations must approve this\n // permission before organization-owner self-service can succeed.\n members: \"read\",\n };\n if (input.includeCiPermissions) {\n permissions.actions = \"read\";\n permissions.checks = \"read\";\n permissions.statuses = \"write\";\n }\n const manifest: Record<string, unknown> = {\n name: input.appName,\n url: base,\n redirect_url: `${base}/v1/github/app-manifest/callback`,\n callback_urls: [`${base}/v1/github/oauth/callback`],\n public: input.public,\n // A setup URL and OAuth-on-install are mutually exclusive in GitHub's App\n // contract. OpenGeni needs the setup callback to receive the installation\n // id, then starts its own exact user-authorization flow.\n request_oauth_on_install: !input.setupUrl,\n default_permissions: permissions,\n };\n if (input.setupUrl) {\n manifest.setup_url = input.setupUrl;\n manifest.setup_on_update = true;\n }\n return manifest;\n}\n\nexport function personalAppManifestUrl(state: string): string {\n return `https://github.com/settings/apps/new?state=${state}`;\n}\n\nexport function organizationAppManifestUrl(organization: string, state: string): string {\n return `https://github.com/organizations/${encodeURIComponent(organization)}/settings/apps/new?state=${state}`;\n}\n\nexport function githubOAuthAuthorizeUrl(input: {\n clientId: string;\n state: string;\n redirectUri?: string;\n}): string {\n const url = new URL(\"https://github.com/login/oauth/authorize\");\n url.searchParams.set(\"client_id\", input.clientId);\n url.searchParams.set(\"state\", input.state);\n if (input.redirectUri) {\n url.searchParams.set(\"redirect_uri\", input.redirectUri);\n }\n return url.toString();\n}\n\nexport function createSignedState(\n secret: string,\n payloadOrNow: Record<string, unknown> | number = {},\n nowArg = Math.floor(Date.now() / 1000),\n): string {\n const payloadInput = typeof payloadOrNow === \"number\" ? {} : payloadOrNow;\n const now = typeof payloadOrNow === \"number\" ? payloadOrNow : nowArg;\n const payload = {\n ...payloadInput,\n nonce: randomBytes(16).toString(\"base64url\"),\n iat: now,\n };\n const encoded = Buffer.from(JSON.stringify(payload)).toString(\"base64url\");\n return `${encoded}.${signStatePayload(encoded, secret)}`;\n}\n\nexport function readSignedState(\n state: string,\n secret: string,\n now = Math.floor(Date.now() / 1000),\n): GitHubSignedStatePayload | null {\n const [encoded, signature] = state.split(\".\", 2);\n if (!encoded || !signature) {\n return null;\n }\n const expected = signStatePayload(encoded, secret);\n if (!safeEqual(signature, expected)) {\n return null;\n }\n let payload: unknown;\n try {\n payload = JSON.parse(Buffer.from(encoded, \"base64url\").toString(\"utf8\"));\n } catch {\n return null;\n }\n if (\n !payload ||\n typeof payload !== \"object\" ||\n typeof (payload as { iat?: unknown }).iat !== \"number\" ||\n typeof (payload as { nonce?: unknown }).nonce !== \"string\"\n ) {\n return null;\n }\n const age = now - (payload as { iat: number }).iat;\n return age >= 0 && age <= stateMaxAgeSeconds ? (payload as GitHubSignedStatePayload) : null;\n}\n\nexport function verifySignedState(\n state: string,\n secret: string,\n now = Math.floor(Date.now() / 1000),\n): boolean {\n return readSignedState(state, secret, now) !== null;\n}\n\nexport function envLinesFromGitHubManifestConversion(payload: Record<string, unknown>): string[] {\n const privateKey = String(payload.pem ?? \"\").replace(/\\n/g, \"\\\\n\");\n return [\n `OPENGENI_GITHUB_APP_ID=${payload.id ?? \"\"}`,\n `OPENGENI_GITHUB_CLIENT_ID=${payload.client_id ?? \"\"}`,\n `OPENGENI_GITHUB_CLIENT_SECRET=${payload.client_secret ?? \"\"}`,\n `OPENGENI_GITHUB_APP_SLUG=${payload.slug ?? \"\"}`,\n `OPENGENI_GITHUB_WEBHOOK_SECRET=${payload.webhook_secret ?? \"\"}`,\n `OPENGENI_GITHUB_APP_PRIVATE_KEY=\"${privateKey}\"`,\n ];\n}\n\nexport async function convertGitHubAppManifest(code: string): Promise<Record<string, unknown>> {\n const response = await fetch(`${githubApiBase}/app-manifests/${code}/conversions`, {\n method: \"POST\",\n headers: githubHeaders(undefined),\n });\n if (!response.ok) {\n throw new GitHubAppApiError(await githubErrorMessage(response));\n }\n const payload = await response.json();\n if (!payload || typeof payload !== \"object\" || Array.isArray(payload)) {\n throw new GitHubAppApiError(\"GitHub returned an invalid manifest conversion payload\");\n }\n return payload as Record<string, unknown>;\n}\n\nexport async function listGitHubAppInstallationSummaries(\n settings: Settings,\n): Promise<GitHubAppInstallationSummary[]> {\n const missing = githubAppMissingSettings(settings);\n if (missing.length > 0) {\n throw new GitHubAppConfigurationError(missing);\n }\n const jwt = await createGitHubAppJwt(settings);\n const installations = await listInstallations(jwt);\n return installations.map(installationSummaryFromPayload);\n}\n\nexport async function getGitHubAppInstallationSummary(\n settings: Settings,\n installationId: number,\n): Promise<GitHubAppInstallationSummary | null> {\n const installations = await listGitHubAppInstallationSummaries(settings);\n return (\n installations.find((installation) => installation.installationId === installationId) ?? null\n );\n}\n\nexport async function verifyGitHubInstallationAccessForUser(\n settings: Settings,\n input: {\n code: string;\n installationId: number;\n },\n): Promise<GitHubAppInstallationSummary> {\n const token = await exchangeGitHubOAuthCodeForUserToken(settings, input.code);\n const installations = await listUserAccessibleInstallations(token);\n const installation = installations.find(\n (candidate) => candidate.installationId === input.installationId,\n );\n if (!installation) {\n throw new GitHubAppApiError(\"GitHub installation is not accessible to the installing user\");\n }\n return installation;\n}\n\n/**\n * Exchange a GitHub App user-authorization code and discover the installations\n * and repositories the user can explicitly access. This is compatibility\n * discovery metadata only: visibility and repository permission bits do not\n * prove that the human may install, configure, or bind the App installation.\n * No production binding path may treat this result as authority.\n */\nexport async function authorizeGitHubAppUser(\n settings: Settings,\n input: { code: string },\n): Promise<GitHubUserInstallationAccess[]> {\n const token = await exchangeGitHubOAuthCodeForUserToken(settings, input.code);\n const installations = await listUserAccessibleInstallations(token);\n return await Promise.all(\n installations.map(async (installation) => ({\n ...installation,\n repositories: installation.suspended\n ? []\n : await listUserInstallationRepositories(token, installation),\n })),\n );\n}\n\n/**\n * Prove current GitHub installation authority without treating repository\n * administration or installation visibility as delegation authority.\n *\n * GitHub exposes an exact personal-account owner through the authenticated\n * user's immutable id. For organizations, GitHub's authenticated membership\n * endpoint exposes active owners as role=admin. GitHub does not expose an\n * equivalent current-authority receipt for App Managers, so that case remains\n * unsupported and fails closed.\n */\nexport async function authorizeGitHubInstallationBinding(\n settings: Settings,\n input: { code: string; installationId: number },\n): Promise<GitHubInstallationBindingProof> {\n const userToken = await exchangeGitHubOAuthCodeForUserToken(settings, input.code);\n const actor = await getAuthenticatedGitHubUser(userToken);\n const visibleInstallations = await listUserAccessibleInstallations(userToken);\n const visible = visibleInstallations.find(\n (installation) => installation.installationId === input.installationId,\n );\n if (!visible) {\n throw new GitHubInstallationAuthorityError(\n \"authority_denied\",\n \"GitHub did not associate this installation with the authorized user\",\n );\n }\n\n const jwt = await createGitHubAppJwt(settings);\n const livePayload = (await listInstallations(jwt)).find(\n (installation) => asInt(installation.id) === input.installationId,\n );\n if (!livePayload) {\n throw new GitHubInstallationAuthorityError(\n \"installation_missing\",\n \"GitHub App installation was deleted or is not owned by this App\",\n );\n }\n const installation = installationSummaryFromPayload(livePayload);\n if (\n installation.accountId !== visible.accountId ||\n installation.accountLogin !== visible.accountLogin ||\n installation.accountType !== visible.accountType\n ) {\n throw new GitHubInstallationAuthorityError(\n \"authority_denied\",\n \"GitHub installation identity changed during authorization\",\n );\n }\n if (installation.suspended) {\n throw new GitHubInstallationAuthorityError(\n \"installation_suspended\",\n \"GitHub App installation is suspended\",\n );\n }\n\n let authorityKind: GitHubInstallationBindingProof[\"authorityKind\"];\n if (installation.accountType === \"User\" && actor.id === installation.accountId) {\n authorityKind = \"personal_owner\";\n } else if (installation.accountType === \"Organization\" && installation.accountLogin) {\n await assertActiveOrganizationOwner(\n userToken,\n installation.accountId,\n installation.accountLogin,\n );\n authorityKind = \"organization_owner\";\n } else {\n throw new GitHubInstallationAuthorityError(\n \"authority_denied\",\n \"Only a GitHub personal-account owner or organization owner may bind an installation\",\n );\n }\n\n const installationToken = await createInstallationToken(jwt, {\n installationId: installation.installationId,\n });\n const repositories = await listInstallationRepositories(\n installationToken.token,\n installation.installationId,\n { login: installation.accountLogin, type: installation.accountType },\n );\n if (repositories.length === 0) {\n throw new GitHubInstallationAuthorityError(\n \"repository_access_empty\",\n \"GitHub App installation does not currently grant access to any repositories\",\n );\n }\n if (authorityKind === \"organization_owner\") {\n // Repository enumeration is an async provider boundary. Re-read the live\n // owner tuple after it so a role revoked after the chooser proof cannot be\n // durably bound with a later, misleading authority timestamp.\n await assertActiveOrganizationOwner(\n userToken,\n installation.accountId,\n installation.accountLogin!,\n );\n }\n return {\n actorId: actor.id,\n actorLogin: actor.login,\n authorityKind,\n installation,\n repositories,\n };\n}\n\n/**\n * Discover existing installations that the freshly authorized GitHub human\n * can bind as an exact personal owner or active organization owner.\n *\n * `GET /user/installations` is discovery input only. Every candidate is\n * cross-checked against the App's live installation inventory and an\n * organization candidate requires a live `state=active, role=admin`\n * membership proof. The later exact authorization still re-runs the complete\n * proof immediately before the durable bind.\n */\nexport async function discoverGitHubInstallationBindingCandidates(\n settings: Settings,\n input: { code: string },\n): Promise<GitHubInstallationBindingCandidate[]> {\n const userToken = await exchangeGitHubOAuthCodeForUserToken(settings, input.code);\n const actor = await getAuthenticatedGitHubUser(userToken);\n const visibleInstallations = await listUserAccessibleInstallations(userToken);\n const jwt = await createGitHubAppJwt(settings);\n const liveInstallations = new Map(\n (await listInstallations(jwt)).map((payload) => {\n const installation = installationSummaryFromPayload(payload);\n return [installation.installationId, installation] as const;\n }),\n );\n const candidates: GitHubInstallationBindingCandidate[] = [];\n\n for (const visible of visibleInstallations) {\n const installation = liveInstallations.get(visible.installationId);\n if (\n !installation ||\n installation.suspended ||\n installation.accountId !== visible.accountId ||\n installation.accountLogin !== visible.accountLogin ||\n installation.accountType !== visible.accountType\n ) {\n continue;\n }\n if (installation.accountType === \"User\" && actor.id === installation.accountId) {\n candidates.push({ installation, authorityKind: \"personal_owner\" });\n continue;\n }\n if (installation.accountType !== \"Organization\" || !installation.accountLogin) {\n continue;\n }\n try {\n await assertActiveOrganizationOwner(\n userToken,\n installation.accountId,\n installation.accountLogin,\n );\n candidates.push({ installation, authorityKind: \"organization_owner\" });\n } catch (error) {\n if (\n error instanceof GitHubInstallationAuthorityError &&\n error.reason === \"authority_unavailable\"\n ) {\n continue;\n }\n if (\n error instanceof GitHubInstallationAuthorityError &&\n error.reason === \"authority_denied\"\n ) {\n continue;\n }\n throw error;\n }\n }\n\n return candidates.sort((left, right) =>\n (left.installation.accountLogin ?? \"\").localeCompare(right.installation.accountLogin ?? \"\"),\n );\n}\n\nexport async function listGitHubAppRepositories(\n settings: Settings,\n input: {\n installationIds?: number[];\n } = {},\n): Promise<GitHubRepository[]> {\n const missing = githubAppMissingSettings(settings);\n if (missing.length > 0) {\n throw new GitHubAppConfigurationError(missing);\n }\n return await listGitHubAppRepositoriesWithSigningSettings(settings, input);\n}\n\n/** List repositories for a separately registered App that needs only signing credentials. */\nexport async function listGitHubAppRepositoriesWithSigningSettings(\n settings: GitHubAppSigningSettings,\n input: {\n installationIds?: number[];\n } = {},\n): Promise<GitHubRepository[]> {\n const missing = githubAppTokenMissingSettings(settings);\n if (missing.length > 0) {\n throw new GitHubAppConfigurationError(missing);\n }\n const allowedInstallations = input.installationIds ? new Set(input.installationIds) : null;\n if (allowedInstallations && allowedInstallations.size === 0) {\n return [];\n }\n const jwt = await createGitHubAppJwt(settings);\n const installations = await listInstallations(jwt);\n const repositories: GitHubRepository[] = [];\n for (const installation of installations) {\n if (installation.suspended_at) {\n continue;\n }\n const installationId = asInt(installation.id);\n if (installationId === null) {\n continue;\n }\n if (allowedInstallations && !allowedInstallations.has(installationId)) {\n continue;\n }\n const account =\n typeof installation.account === \"object\" && installation.account\n ? (installation.account as Record<string, unknown>)\n : {};\n const token = await createInstallationToken(jwt, { installationId });\n repositories.push(\n ...(await listInstallationRepositories(token.token, installationId, account)),\n );\n }\n repositories.sort((left, right) => left.fullName.localeCompare(right.fullName));\n return repositories;\n}\n\nexport type GitHubAppInstallationRepositoryLookupInput = {\n installationId: number;\n owner: string;\n name: string;\n};\n\nexport type GitHubAppInstallationRepositoryLookup = (\n input: GitHubAppInstallationRepositoryLookupInput,\n) => Promise<GitHubRepository | null>;\n\n/**\n * Resolve one `owner/name` repository through an exact App installation and\n * return GitHub's stable repository identity, or null when that installation\n * cannot see the repository. The server-side lookup token never leaves the\n * caller and grants nothing by itself: the workspace allowlist decides whether\n * the returned id may mint a sandbox-bound token.\n */\nexport async function getGitHubAppInstallationRepository(\n settings: Settings,\n input: GitHubAppInstallationRepositoryLookupInput,\n): Promise<GitHubRepository | null> {\n return await createGitHubAppInstallationRepositoryLookup(settings)(input);\n}\n\n/**\n * One lookup client that reuses a server-side installation token per\n * installation for its lifetime (one worker turn), so several bare repository\n * URIs from the same installation cost one mint plus one read each.\n */\nexport function createGitHubAppInstallationRepositoryLookup(\n settings: Settings,\n): GitHubAppInstallationRepositoryLookup {\n const missing = githubAppMissingSettings(settings);\n if (missing.length > 0) {\n throw new GitHubAppConfigurationError(missing);\n }\n const tokens = new Map<number, Promise<GitHubAppInstallationToken>>();\n const installationToken = (installationId: number): Promise<GitHubAppInstallationToken> => {\n let pending = tokens.get(installationId);\n if (!pending) {\n // Metadata-read only: the lookup needs the repository id, never contents.\n // Bounded well below the sandbox mint timeout so a slow GitHub cannot\n // hold turn start; the caller proceeds bare on expiry.\n pending = createGitHubAppJwt(settings).then((jwt) =>\n createInstallationToken(jwt, {\n installationId,\n permissions: { metadata: \"read\" },\n timeoutMs: githubRepositoryLookupTimeoutMs,\n }),\n );\n pending.catch(() => tokens.delete(installationId));\n tokens.set(installationId, pending);\n }\n return pending;\n };\n return async (input) => {\n const owner = input.owner.trim();\n const name = input.name.trim();\n if (\n !/^[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?$/u.test(owner) ||\n !/^[A-Za-z0-9._-]+$/u.test(name)\n ) {\n return null;\n }\n const token = await installationToken(input.installationId);\n const response = await fetch(\n `${githubApiBase}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(name)}`,\n {\n headers: githubHeaders(token.token),\n signal: AbortSignal.timeout(githubRepositoryLookupTimeoutMs),\n },\n );\n if (response.status === 404) {\n return null;\n }\n if (!response.ok) {\n throw new GitHubAppApiError(await githubErrorMessage(response), response.status);\n }\n const payload = await response.json();\n if (!payload || typeof payload !== \"object\" || Array.isArray(payload)) {\n throw new GitHubAppApiError(\"GitHub returned an invalid repository payload\");\n }\n const record = payload as Record<string, unknown>;\n const account =\n record.owner && typeof record.owner === \"object\" && !Array.isArray(record.owner)\n ? (record.owner as Record<string, unknown>)\n : {};\n return repositoryFromPayload(record, input.installationId, account);\n };\n}\n\n/**\n * List one bounded page of branch suggestions with an exact repository-scoped\n * installation token. The token remains local to this server-side helper and\n * is never returned in repository or branch metadata.\n */\nexport async function listGitHubAppRepositoryBranches(\n settings: Settings,\n input: {\n installationId: number;\n repositoryId: number;\n page: number;\n limit: number;\n },\n): Promise<GitHubAppRepositoryBranchPage> {\n if (\n !Number.isSafeInteger(input.installationId) ||\n input.installationId <= 0 ||\n !Number.isSafeInteger(input.repositoryId) ||\n input.repositoryId <= 0 ||\n !Number.isSafeInteger(input.page) ||\n input.page <= 0 ||\n input.page > 10_000 ||\n !Number.isSafeInteger(input.limit) ||\n input.limit <= 0 ||\n input.limit > 100\n ) {\n throw new GitHubAppApiError(\"GitHub branch lookup requires bounded exact repository input\");\n }\n const minted = await createGitHubAppInstallationTokenWithSigningSettings(settings, {\n installationId: input.installationId,\n repositoryIds: [input.repositoryId],\n permissions: { contents: \"read\", metadata: \"read\" },\n timeoutMs: githubRepositoryBranchesTimeoutMs,\n });\n const repositoryResponse = await githubRepositoryBranchesFetch(\n new URL(`${githubApiBase}/repositories/${input.repositoryId}`),\n minted.token,\n \"GitHub repository branch identity\",\n );\n const repositoryPayload = await githubResponseJsonBounded(\n repositoryResponse,\n \"GitHub repository branch identity response\",\n );\n if (\n !repositoryPayload ||\n typeof repositoryPayload !== \"object\" ||\n Array.isArray(repositoryPayload)\n ) {\n throw new GitHubAppApiError(\"GitHub returned an invalid repository branch identity payload\");\n }\n const repository = repositoryPayload as Record<string, unknown>;\n const repositoryId = asInt(repository.id);\n const fullName = typeof repository.full_name === \"string\" ? repository.full_name : \"\";\n const defaultBranch =\n typeof repository.default_branch === \"string\" ? repository.default_branch : \"\";\n const coordinates = fullName.split(\"/\");\n if (\n repositoryId !== input.repositoryId ||\n coordinates.length !== 2 ||\n !coordinates[0] ||\n !coordinates[1] ||\n defaultBranch.length === 0 ||\n defaultBranch.length > 1024\n ) {\n throw new GitHubAppApiError(\"GitHub returned an invalid repository branch identity payload\");\n }\n const branchUrl = new URL(\n `${githubApiBase}/repos/${encodeURIComponent(coordinates[0])}/${encodeURIComponent(coordinates[1])}/branches`,\n );\n branchUrl.searchParams.set(\"page\", String(input.page));\n branchUrl.searchParams.set(\"per_page\", String(input.limit));\n const branchesResponse = await githubRepositoryBranchesFetch(\n branchUrl,\n minted.token,\n \"GitHub repository branches\",\n );\n const branchPayload = await githubResponseJsonBounded(\n branchesResponse,\n \"GitHub repository branches response\",\n );\n if (!Array.isArray(branchPayload) || branchPayload.length > input.limit) {\n throw new GitHubAppApiError(\"GitHub returned an invalid repository branches payload\");\n }\n const branches: string[] = [];\n const seen = new Set<string>();\n for (const value of branchPayload) {\n const name =\n value && typeof value === \"object\" && !Array.isArray(value)\n ? (value as Record<string, unknown>).name\n : null;\n if (typeof name !== \"string\" || name.length === 0 || name.length > 1024 || seen.has(name)) {\n throw new GitHubAppApiError(\"GitHub returned an invalid repository branches payload\");\n }\n seen.add(name);\n branches.push(name);\n }\n return {\n installationId: input.installationId,\n repositoryId: input.repositoryId,\n defaultBranch,\n branches,\n nextPage: branchPayload.length === input.limit && input.page < 10_000 ? input.page + 1 : null,\n };\n}\n\n/**\n * Verify one exact anonymous github.com repository and ref. The provider URL\n * is derived only from strict canonical coordinates, follows no redirects,\n * sends no credentials, and bounds both request time and response bytes.\n */\nexport async function verifyPublicGitHubRepositoryRef(\n input: { repository: CanonicalGitHubRepository; ref: string },\n fetchImpl: typeof fetch = fetch,\n): Promise<VerifyPublicGitHubRepositoryRefResponse> {\n const ref = input.ref.trim();\n if (!ref || ref.length > 1024 || /[\\u0000-\\u001f\\u007f]/u.test(ref)) {\n throw new GitHubPublicRepositoryVerificationError(\n \"invalid_input\",\n \"Enter a branch, tag, or commit SHA.\",\n );\n }\n const repositoryUrl = new URL(\n `${githubApiBase}/repos/${encodeURIComponent(input.repository.owner)}/${encodeURIComponent(input.repository.name)}`,\n );\n const repositoryPayload = await anonymousGitHubJson(\n fetchImpl,\n repositoryUrl,\n \"GitHub repository\",\n );\n if (\n !repositoryPayload ||\n typeof repositoryPayload !== \"object\" ||\n Array.isArray(repositoryPayload)\n ) {\n throw new GitHubPublicRepositoryVerificationError(\n \"provider_unavailable\",\n \"GitHub returned an invalid repository response.\",\n );\n }\n const repository = repositoryPayload as Record<string, unknown>;\n const fullName = typeof repository.full_name === \"string\" ? repository.full_name : \"\";\n const defaultBranch =\n typeof repository.default_branch === \"string\" ? repository.default_branch : \"\";\n const privateRepository = repository.private;\n if (\n !Number.isSafeInteger(repository.id) ||\n Number(repository.id) <= 0 ||\n privateRepository !== false ||\n !fullName ||\n fullName.toLowerCase() !== input.repository.fullName.toLowerCase() ||\n !defaultBranch ||\n defaultBranch.length > 1024\n ) {\n throw new GitHubPublicRepositoryVerificationError(\n \"unavailable\",\n \"That GitHub repository is private or unavailable.\",\n );\n }\n let canonical: CanonicalGitHubRepository;\n try {\n canonical = parseCanonicalGitHubRepositoryUrl(`https://github.com/${fullName}`);\n } catch {\n throw new GitHubPublicRepositoryVerificationError(\n \"provider_unavailable\",\n \"GitHub returned an invalid repository identity.\",\n );\n }\n const commitUrl = new URL(\n `${githubApiBase}/repos/${encodeURIComponent(canonical.owner)}/${encodeURIComponent(canonical.name)}/commits/${encodeURIComponent(ref)}`,\n );\n const commitPayload = await anonymousGitHubJson(fetchImpl, commitUrl, \"GitHub repository ref\");\n const commitSha =\n commitPayload && typeof commitPayload === \"object\" && !Array.isArray(commitPayload)\n ? (commitPayload as Record<string, unknown>).sha\n : null;\n if (typeof commitSha !== \"string\" || !/^[0-9a-f]{40}$/u.test(commitSha)) {\n throw new GitHubPublicRepositoryVerificationError(\n \"unavailable\",\n \"That branch, tag, or commit SHA is not available on the public repository.\",\n );\n }\n return {\n ...canonical,\n defaultBranch,\n ref,\n commitSha,\n };\n}\n\nexport async function createGitHubAppInstallationToken(\n settings: Settings,\n input: {\n installationId: number;\n repositoryIds: number[];\n },\n): Promise<string> {\n return (await createGitHubAppInstallationTokenWithExpiry(settings, input)).token;\n}\n\nexport type GitHubAppInstallationToken = {\n token: string;\n expiresAt: string | null;\n};\n\nexport async function createGitHubAppInstallationTokenWithExpiry(\n settings: Settings,\n input: {\n installationId: number;\n repositoryIds: number[];\n },\n): Promise<GitHubAppInstallationToken> {\n const missing = githubAppMissingSettings(settings);\n if (missing.length > 0) {\n throw new GitHubAppConfigurationError(missing);\n }\n return await createGitHubAppInstallationTokenWithSigningSettings(settings, input);\n}\n\n/** Mint for a separately registered App without requiring unrelated OAuth settings. */\nexport async function createGitHubAppInstallationTokenWithSigningSettings(\n settings: GitHubAppSigningSettings,\n input: {\n installationId: number;\n repositoryIds: number[];\n permissions?: Record<string, \"read\" | \"write\">;\n timeoutMs?: number;\n },\n): Promise<GitHubAppInstallationToken> {\n const missing = githubAppTokenMissingSettings(settings);\n if (missing.length > 0) {\n throw new GitHubAppConfigurationError(missing);\n }\n if (!Array.isArray(input.repositoryIds)) {\n throw new GitHubAppApiError(\n \"GitHub installation token mint requires an explicit, unique repository allowlist\",\n );\n }\n const repositoryIds = [...new Set(input.repositoryIds)];\n if (\n !Number.isSafeInteger(input.installationId) ||\n input.installationId <= 0 ||\n repositoryIds.length === 0 ||\n repositoryIds.length !== input.repositoryIds.length ||\n repositoryIds.some((id) => !Number.isSafeInteger(id) || id <= 0)\n ) {\n throw new GitHubAppApiError(\n \"GitHub installation token mint requires an explicit, unique repository allowlist\",\n );\n }\n const jwt = await createGitHubAppJwt(settings);\n return await createInstallationToken(jwt, {\n installationId: input.installationId,\n repositoryIds,\n ...(input.permissions ? { permissions: input.permissions } : {}),\n ...(input.timeoutMs !== undefined ? { timeoutMs: input.timeoutMs } : {}),\n });\n}\n\nexport function githubAppBotIdentity(settings: Settings): { name: string; email: string } | null {\n const appId = settings.githubAppId?.trim();\n const slug = settings.githubAppSlug?.trim();\n if (!appId || !slug) {\n return null;\n }\n const login = `${slug}[bot]`;\n return {\n name: login,\n email: `${appId}+${login}@users.noreply.github.com`,\n };\n}\n\nexport const GITHUB_APP_BOT_IDENTITY_UNAVAILABLE_WARNING =\n \"github_app_bot_identity_unavailable\" as const;\n\n/**\n * Non-secret health posture for the stable sandbox Git identity. API-direct\n * attach and worker-turn startup must add the same identity keys. A complete\n * deployment-level author identity is sufficient because committer values\n * default to it; otherwise a partially configured workspace GitHub App must\n * surface that its bot identity cannot be derived.\n */\nexport function githubAppBotIdentityWarnings(\n settings: Settings,\n): Array<typeof GITHUB_APP_BOT_IDENTITY_UNAVAILABLE_WARNING> {\n const workspaceAppConfigured = [\n settings.githubAppId,\n settings.githubClientId,\n settings.githubClientSecret,\n settings.githubAppSlug,\n settings.githubWebhookSecret,\n settings.githubAppPrivateKey,\n ].some((value) => typeof value === \"string\" && value.trim().length > 0);\n const explicitGitIdentityConfigured =\n typeof settings.gitAuthorName === \"string\" &&\n settings.gitAuthorName.trim().length > 0 &&\n typeof settings.gitAuthorEmail === \"string\" &&\n settings.gitAuthorEmail.trim().length > 0;\n if (\n !workspaceAppConfigured ||\n explicitGitIdentityConfigured ||\n githubAppBotIdentity(settings) !== null\n ) {\n return [];\n }\n return [GITHUB_APP_BOT_IDENTITY_UNAVAILABLE_WARNING];\n}\n\nasync function createGitHubAppJwt(settings: GitHubAppSigningSettings): Promise<string> {\n const privateKey = normalizeGitHubAppPrivateKey(settings.githubAppPrivateKey ?? \"\");\n const appId = settings.githubAppId?.trim();\n if (!appId || !privateKey) {\n throw new GitHubAppConfigurationError(githubAppTokenMissingSettings(settings));\n }\n const key = await importPKCS8(privateKey, \"RS256\");\n const now = Math.floor(Date.now() / 1000);\n return await new SignJWT({})\n .setProtectedHeader({ alg: \"RS256\" })\n .setIssuedAt(now - 60)\n .setExpirationTime(now + 9 * 60)\n .setIssuer(appId)\n .sign(key);\n}\n\nasync function listInstallations(token: string): Promise<Array<Record<string, unknown>>> {\n const out: Array<Record<string, unknown>> = [];\n for (let page = 1; ; page += 1) {\n const payload = await githubGet(\"/app/installations\", token, {\n per_page: \"100\",\n page: String(page),\n });\n if (!Array.isArray(payload)) {\n throw new GitHubAppApiError(\"GitHub returned an invalid installations payload\");\n }\n out.push(\n ...payload.filter((item): item is Record<string, unknown> =>\n Boolean(item && typeof item === \"object\" && !Array.isArray(item)),\n ),\n );\n if (payload.length < 100) {\n return out;\n }\n }\n}\n\nasync function exchangeGitHubOAuthCodeForUserToken(\n settings: Settings,\n code: string,\n): Promise<string> {\n if (!settings.githubClientId || !settings.githubClientSecret) {\n throw new GitHubAppConfigurationError(githubAppMissingSettings(settings));\n }\n const response = await fetch(\"https://github.com/login/oauth/access_token\", {\n method: \"POST\",\n headers: {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n client_id: settings.githubClientId,\n client_secret: settings.githubClientSecret,\n code,\n }),\n });\n if (!response.ok) {\n throw new GitHubAppApiError(await githubErrorMessage(response));\n }\n const payload = await response.json();\n if (!payload || typeof payload !== \"object\" || typeof payload.access_token !== \"string\") {\n throw new GitHubAppApiError(\"GitHub returned an invalid OAuth token payload\");\n }\n return payload.access_token;\n}\n\nasync function getAuthenticatedGitHubUser(token: string): Promise<{ id: number; login: string }> {\n const payload = await githubGet(\"/user\", token);\n const id = payload && typeof payload === \"object\" ? asInt(payload.id) : null;\n const login =\n payload && typeof payload === \"object\" && typeof payload.login === \"string\"\n ? payload.login\n : null;\n if (id === null || !login) {\n throw new GitHubAppApiError(\"GitHub returned an invalid authenticated user payload\");\n }\n return { id, login };\n}\n\nasync function getAuthenticatedOrganizationMembership(\n token: string,\n organizationLogin: string,\n): Promise<{ organizationId: number; role: string; state: string }> {\n let payload: any;\n try {\n payload = await githubGet(\n `/user/memberships/orgs/${encodeURIComponent(organizationLogin)}`,\n token,\n );\n } catch (error) {\n if (error instanceof GitHubAppApiError) {\n throw new GitHubInstallationAuthorityError(\n \"authority_unavailable\",\n \"GitHub could not prove current organization-owner membership\",\n error.status,\n );\n }\n throw error;\n }\n const organization =\n payload && typeof payload === \"object\" && payload.organization ? payload.organization : null;\n const organizationId =\n organization && typeof organization === \"object\" ? asInt(organization.id) : null;\n if (\n organizationId === null ||\n typeof payload?.role !== \"string\" ||\n typeof payload?.state !== \"string\"\n ) {\n throw new GitHubInstallationAuthorityError(\n \"authority_unavailable\",\n \"GitHub returned an invalid organization membership proof\",\n );\n }\n return { organizationId, role: payload.role, state: payload.state };\n}\n\nasync function assertActiveOrganizationOwner(\n token: string,\n organizationId: number,\n organizationLogin: string,\n): Promise<void> {\n const membership = await getAuthenticatedOrganizationMembership(token, organizationLogin);\n if (\n membership.organizationId !== organizationId ||\n membership.state !== \"active\" ||\n membership.role !== \"admin\"\n ) {\n throw new GitHubInstallationAuthorityError(\n \"authority_denied\",\n \"Only an active GitHub organization owner may bind this installation\",\n );\n }\n}\n\nasync function listUserAccessibleInstallations(\n token: string,\n): Promise<GitHubAppInstallationSummary[]> {\n const out: GitHubAppInstallationSummary[] = [];\n for (let page = 1; ; page += 1) {\n const payload = await githubGet(\"/user/installations\", token, {\n per_page: \"100\",\n page: String(page),\n });\n const installations: unknown[] | null =\n payload && typeof payload === \"object\" && Array.isArray(payload.installations)\n ? (payload.installations as unknown[])\n : null;\n if (!installations) {\n throw new GitHubAppApiError(\"GitHub returned an invalid user installations payload\");\n }\n out.push(\n ...installations\n .filter((item): item is Record<string, unknown> =>\n Boolean(item && typeof item === \"object\" && !Array.isArray(item)),\n )\n .map(installationSummaryFromPayload),\n );\n if (installations.length < 100) {\n return out;\n }\n }\n}\n\nasync function listUserInstallationRepositories(\n token: string,\n installation: GitHubAppInstallationSummary,\n): Promise<GitHubUserRepositoryAccess[]> {\n const out: GitHubUserRepositoryAccess[] = [];\n const account = {\n ...(installation.accountLogin ? { login: installation.accountLogin } : {}),\n ...(installation.accountType ? { type: installation.accountType } : {}),\n };\n for (let page = 1; ; page += 1) {\n const payload = await githubGet(\n `/user/installations/${installation.installationId}/repositories`,\n token,\n { per_page: \"100\", page: String(page) },\n );\n if (\n !payload ||\n typeof payload !== \"object\" ||\n Array.isArray(payload) ||\n !Array.isArray(payload.repositories)\n ) {\n throw new GitHubAppApiError(\n \"GitHub returned an invalid user installation repositories payload\",\n );\n }\n for (const repository of payload.repositories) {\n if (!repository || typeof repository !== \"object\" || Array.isArray(repository)) {\n continue;\n }\n const record = repository as Record<string, unknown>;\n out.push({\n ...repositoryFromPayload(record, installation.installationId, account),\n permissions: repositoryPermissionsFromPayload(record.permissions),\n });\n }\n if (payload.repositories.length < 100) {\n return out;\n }\n }\n}\n\nasync function createInstallationToken(\n appJwt: string,\n input: {\n installationId: number;\n repositoryIds?: number[];\n /** Narrow the token below the installation's granted permissions. */\n permissions?: Record<string, \"read\" | \"write\">;\n timeoutMs?: number;\n },\n): Promise<GitHubAppInstallationToken> {\n const body: Record<string, unknown> = {};\n if (input.repositoryIds && input.repositoryIds.length > 0) {\n body.repository_ids = input.repositoryIds;\n }\n if (input.permissions && Object.keys(input.permissions).length > 0) {\n body.permissions = input.permissions;\n }\n const scoped = Object.keys(body).length > 0;\n const response = await fetch(\n `${githubApiBase}/app/installations/${input.installationId}/access_tokens`,\n {\n method: \"POST\",\n headers: {\n ...githubHeaders(appJwt),\n ...(scoped ? { \"Content-Type\": \"application/json\" } : {}),\n },\n redirect: \"manual\",\n signal: AbortSignal.timeout(input.timeoutMs ?? githubTokenMintTimeoutMs),\n ...(scoped ? { body: JSON.stringify(body) } : {}),\n },\n );\n if (!response.ok) {\n throw new GitHubAppApiError(await githubErrorMessage(response), response.status);\n }\n let payload: unknown;\n try {\n payload = JSON.parse(\n await readResponseTextBounded(\n response,\n githubInstallationTokenResponseMaxBytes,\n \"GitHub installation token response\",\n ),\n ) as unknown;\n } catch {\n throw new GitHubAppApiError(\"GitHub returned an invalid installation token payload\");\n }\n if (!payload || typeof payload !== \"object\" || Array.isArray(payload)) {\n throw new GitHubAppApiError(\"GitHub returned an invalid installation token payload\");\n }\n const record = payload as Record<string, unknown>;\n if (typeof record.token !== \"string\") {\n throw new GitHubAppApiError(\"GitHub returned an invalid installation token payload\");\n }\n return {\n token: record.token,\n expiresAt: typeof record.expires_at === \"string\" ? record.expires_at : null,\n };\n}\n\nasync function listInstallationRepositories(\n token: string,\n installationId: number,\n account: Record<string, unknown>,\n): Promise<GitHubRepository[]> {\n const out: GitHubRepository[] = [];\n for (let page = 1; ; page += 1) {\n const payload = await githubGet(\"/installation/repositories\", token, {\n per_page: \"100\",\n page: String(page),\n });\n if (\n !payload ||\n typeof payload !== \"object\" ||\n Array.isArray(payload) ||\n !Array.isArray(payload.repositories)\n ) {\n throw new GitHubAppApiError(\"GitHub returned an invalid repositories payload\");\n }\n for (const repo of payload.repositories) {\n if (repo && typeof repo === \"object\" && !Array.isArray(repo)) {\n out.push(repositoryFromPayload(repo as Record<string, unknown>, installationId, account));\n }\n }\n if (payload.repositories.length < 100) {\n return out;\n }\n }\n}\n\nfunction installationSummaryFromPayload(\n payload: Record<string, unknown>,\n): GitHubAppInstallationSummary {\n const installationId = asInt(payload.id);\n if (installationId === null) {\n throw new GitHubAppApiError(\"GitHub returned an installation without id\");\n }\n const account =\n typeof payload.account === \"object\" && payload.account\n ? (payload.account as Record<string, unknown>)\n : {};\n const accountId = asInt(account.id);\n if (accountId === null) {\n throw new GitHubAppApiError(\"GitHub returned an installation without an account id\");\n }\n return {\n installationId,\n accountId,\n accountLogin: typeof account.login === \"string\" ? account.login : null,\n accountType: typeof account.type === \"string\" ? account.type : null,\n suspended: Boolean(payload.suspended_at),\n };\n}\n\nasync function githubGet(\n path: string,\n token: string,\n params: Record<string, string> = {},\n): Promise<any> {\n const url = new URL(`${githubApiBase}${path}`);\n for (const [key, value] of Object.entries(params)) {\n url.searchParams.set(key, value);\n }\n const response = await fetch(url, { headers: githubHeaders(token) });\n if (!response.ok) {\n throw new GitHubAppApiError(await githubErrorMessage(response), response.status);\n }\n return await response.json();\n}\n\nasync function githubRepositoryBranchesFetch(\n url: URL,\n token: string,\n label: string,\n): Promise<Response> {\n let response: Response;\n try {\n response = await fetch(url, {\n headers: githubHeaders(token),\n redirect: \"manual\",\n signal: AbortSignal.timeout(githubRepositoryBranchesTimeoutMs),\n });\n } catch {\n throw new GitHubAppApiError(`${label} request failed`);\n }\n if (!response.ok) {\n throw new GitHubAppApiError(await githubErrorMessage(response), response.status);\n }\n return response;\n}\n\nasync function githubResponseJsonBounded(response: Response, label: string): Promise<unknown> {\n try {\n return JSON.parse(\n await readResponseTextBounded(response, githubRepositoryBranchesResponseMaxBytes, label),\n ) as unknown;\n } catch {\n throw new GitHubAppApiError(`${label} was invalid or too large`);\n }\n}\n\nasync function anonymousGitHubJson(\n fetchImpl: typeof fetch,\n url: URL,\n label: string,\n): Promise<unknown> {\n let response: Response;\n try {\n response = await fetchImpl(url, {\n headers: githubHeaders(),\n redirect: \"manual\",\n signal: AbortSignal.timeout(githubPublicRepositoryVerificationTimeoutMs),\n });\n } catch {\n throw new GitHubPublicRepositoryVerificationError(\n \"provider_unavailable\",\n `${label} verification is temporarily unavailable.`,\n );\n }\n if (response.status === 404) {\n throw new GitHubPublicRepositoryVerificationError(\n \"unavailable\",\n label === \"GitHub repository\"\n ? \"That GitHub repository is private or unavailable.\"\n : \"That branch, tag, or commit SHA is not available on the public repository.\",\n response.status,\n );\n }\n if (!response.ok) {\n throw new GitHubPublicRepositoryVerificationError(\n \"provider_unavailable\",\n response.status === 429\n ? \"GitHub is temporarily rate limited. Try again shortly.\"\n : `${label} verification is temporarily unavailable.`,\n response.status,\n );\n }\n try {\n return JSON.parse(\n await readResponseTextBounded(\n response,\n githubPublicRepositoryVerificationResponseMaxBytes,\n `${label} verification response`,\n ),\n ) as unknown;\n } catch {\n throw new GitHubPublicRepositoryVerificationError(\n \"provider_unavailable\",\n `${label} verification returned an invalid response.`,\n );\n }\n}\n\nfunction repositoryFromPayload(\n payload: Record<string, unknown>,\n installationId: number,\n account: Record<string, unknown>,\n): GitHubRepository {\n const id = asInt(payload.id);\n const fullName = String(payload.full_name ?? \"\");\n if (id === null || !fullName) {\n throw new GitHubAppApiError(\"GitHub returned a repository without id/full_name\");\n }\n return {\n id,\n installationId,\n fullName,\n name: String(payload.name ?? fullName.split(\"/\").at(-1) ?? fullName),\n private: Boolean(payload.private),\n htmlUrl: String(payload.html_url ?? `https://github.com/${fullName}`),\n cloneUrl: String(payload.clone_url ?? `https://github.com/${fullName}.git`),\n defaultBranch: String(payload.default_branch ?? \"main\"),\n accountLogin: String(account.login ?? fullName.split(\"/\", 1)[0]),\n accountType: typeof account.type === \"string\" ? account.type : null,\n };\n}\n\nfunction repositoryPermissionsFromPayload(payload: unknown): GitHubRepositoryPermissions {\n const permissions =\n payload && typeof payload === \"object\" && !Array.isArray(payload)\n ? (payload as Record<string, unknown>)\n : {};\n return {\n admin: permissions.admin === true,\n maintain: permissions.maintain === true,\n push: permissions.push === true,\n triage: permissions.triage === true,\n pull: permissions.pull === true,\n };\n}\n\nfunction githubHeaders(token?: string): HeadersInit {\n return {\n Accept: \"application/vnd.github+json\",\n ...(token ? { Authorization: `Bearer ${token}` } : {}),\n \"X-GitHub-Api-Version\": githubApiVersion,\n };\n}\n\nasync function githubErrorMessage(response: Response): Promise<string> {\n let text: string;\n try {\n text = await readResponseTextBounded(\n response,\n githubErrorResponseMaxBytes,\n \"GitHub error response\",\n );\n } catch {\n return `GitHub API ${response.status}`;\n }\n try {\n const payload = JSON.parse(text) as unknown;\n if (payload && typeof payload === \"object\" && \"message\" in payload) {\n return `GitHub API ${response.status}: ${String(\n (payload as Record<string, unknown>).message,\n ).slice(0, githubErrorMessageMaxLength)}`;\n }\n } catch {\n // Fall through to the bounded text body.\n }\n return `GitHub API ${response.status}: ${text.slice(0, githubErrorMessageMaxLength)}`;\n}\n\nexport function normalizeGitHubAppPrivateKey(value: string): string {\n const privateKey = value.trim().replace(/\\\\n/g, \"\\n\");\n if (!privateKey || privateKey.startsWith(pkcs8PrivateKeyHeader)) {\n return privateKey;\n }\n if (privateKey.startsWith(rsaPrivateKeyHeader)) {\n return createPrivateKey(privateKey).export({ type: \"pkcs8\", format: \"pem\" }).toString();\n }\n return privateKey;\n}\n\nfunction signStatePayload(encoded: string, secret: string): string {\n return createHmac(\"sha256\", secret).update(encoded).digest(\"base64url\");\n}\n\nfunction safeEqual(left: string, right: string): boolean {\n const a = Buffer.from(left);\n const b = Buffer.from(right);\n return a.length === b.length && timingSafeEqual(a, b);\n}\n\nfunction asInt(value: unknown): number | null {\n if (typeof value === \"number\" && Number.isInteger(value)) {\n return value;\n }\n if (typeof value === \"string\" && /^\\d+$/.test(value)) {\n return Number(value);\n }\n return null;\n}\n"],"mappings":"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","names":["installation"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengeni/github",
3
- "version": "0.6.7",
3
+ "version": "0.7.1-canary.0",
4
4
  "license": "Apache-2.0",
5
5
  "repository": {
6
6
  "type": "git",
@@ -31,8 +31,9 @@
31
31
  "prepublishOnly": "bash ../../scripts/prepublish-guard"
32
32
  },
33
33
  "dependencies": {
34
- "@opengeni/config": "^0.22.5",
35
- "@opengeni/contracts": "^2.9.2",
34
+ "@opengeni/config": "^0.23.2-canary.0",
35
+ "@opengeni/contracts": "^2.11.1-canary.0",
36
+ "@opengeni/network": "^0.2.3-canary.7",
36
37
  "jose": "^6.1.3"
37
38
  }
38
39
  }
package/src/index.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type { Settings } from "@opengeni/config";
2
2
  import type {
3
+ GitHubAppRepositoryBranchPage,
3
4
  GitHubInstallationBindingCandidate,
4
5
  GitHubInstallationBindingProof,
5
6
  GitHubRepository,
@@ -7,6 +8,12 @@ import type {
7
8
  GitHubUserInstallationAccess,
8
9
  GitHubUserRepositoryAccess,
9
10
  } from "@opengeni/contracts";
11
+ import type { VerifyPublicGitHubRepositoryRefResponse } from "@opengeni/contracts/github-repository-contracts";
12
+ import {
13
+ parseCanonicalGitHubRepositoryUrl,
14
+ type CanonicalGitHubRepository,
15
+ } from "@opengeni/contracts/github-repository";
16
+ import { readResponseTextBounded } from "@opengeni/network";
10
17
  import {
11
18
  createCipheriv,
12
19
  createDecipheriv,
@@ -23,6 +30,13 @@ const githubApiVersion = "2022-11-28";
23
30
  const githubTokenMintTimeoutMs = 60_000;
24
31
  /** Bound for the server-side repository-id lookup at turn start (mint + read). */
25
32
  export const githubRepositoryLookupTimeoutMs = 10_000;
33
+ export const githubRepositoryBranchesTimeoutMs = 10_000;
34
+ const githubRepositoryBranchesResponseMaxBytes = 256 * 1024;
35
+ export const githubPublicRepositoryVerificationTimeoutMs = 10_000;
36
+ const githubPublicRepositoryVerificationResponseMaxBytes = 128 * 1024;
37
+ const githubInstallationTokenResponseMaxBytes = 64 * 1024;
38
+ const githubErrorResponseMaxBytes = 64 * 1024;
39
+ const githubErrorMessageMaxLength = 1024;
26
40
  export const stateMaxAgeSeconds = 60 * 60;
27
41
  const pkcs8PrivateKeyHeader = `-----BEGIN ${"PRIVATE KEY"}-----`;
28
42
  const rsaPrivateKeyHeader = `-----BEGIN ${"RSA PRIVATE KEY"}-----`;
@@ -248,6 +262,22 @@ export class GitHubAppApiError extends Error {
248
262
  }
249
263
  }
250
264
 
265
+ export type GitHubPublicRepositoryVerificationErrorCode =
266
+ | "invalid_input"
267
+ | "unavailable"
268
+ | "provider_unavailable";
269
+
270
+ export class GitHubPublicRepositoryVerificationError extends Error {
271
+ constructor(
272
+ readonly code: GitHubPublicRepositoryVerificationErrorCode,
273
+ message: string,
274
+ readonly status?: number,
275
+ ) {
276
+ super(message);
277
+ this.name = "GitHubPublicRepositoryVerificationError";
278
+ }
279
+ }
280
+
251
281
  export type GitHubInstallationAuthorityFailure =
252
282
  | "authority_denied"
253
283
  | "authority_unavailable"
@@ -864,6 +894,195 @@ export function createGitHubAppInstallationRepositoryLookup(
864
894
  };
865
895
  }
866
896
 
897
+ /**
898
+ * List one bounded page of branch suggestions with an exact repository-scoped
899
+ * installation token. The token remains local to this server-side helper and
900
+ * is never returned in repository or branch metadata.
901
+ */
902
+ export async function listGitHubAppRepositoryBranches(
903
+ settings: Settings,
904
+ input: {
905
+ installationId: number;
906
+ repositoryId: number;
907
+ page: number;
908
+ limit: number;
909
+ },
910
+ ): Promise<GitHubAppRepositoryBranchPage> {
911
+ if (
912
+ !Number.isSafeInteger(input.installationId) ||
913
+ input.installationId <= 0 ||
914
+ !Number.isSafeInteger(input.repositoryId) ||
915
+ input.repositoryId <= 0 ||
916
+ !Number.isSafeInteger(input.page) ||
917
+ input.page <= 0 ||
918
+ input.page > 10_000 ||
919
+ !Number.isSafeInteger(input.limit) ||
920
+ input.limit <= 0 ||
921
+ input.limit > 100
922
+ ) {
923
+ throw new GitHubAppApiError("GitHub branch lookup requires bounded exact repository input");
924
+ }
925
+ const minted = await createGitHubAppInstallationTokenWithSigningSettings(settings, {
926
+ installationId: input.installationId,
927
+ repositoryIds: [input.repositoryId],
928
+ permissions: { contents: "read", metadata: "read" },
929
+ timeoutMs: githubRepositoryBranchesTimeoutMs,
930
+ });
931
+ const repositoryResponse = await githubRepositoryBranchesFetch(
932
+ new URL(`${githubApiBase}/repositories/${input.repositoryId}`),
933
+ minted.token,
934
+ "GitHub repository branch identity",
935
+ );
936
+ const repositoryPayload = await githubResponseJsonBounded(
937
+ repositoryResponse,
938
+ "GitHub repository branch identity response",
939
+ );
940
+ if (
941
+ !repositoryPayload ||
942
+ typeof repositoryPayload !== "object" ||
943
+ Array.isArray(repositoryPayload)
944
+ ) {
945
+ throw new GitHubAppApiError("GitHub returned an invalid repository branch identity payload");
946
+ }
947
+ const repository = repositoryPayload as Record<string, unknown>;
948
+ const repositoryId = asInt(repository.id);
949
+ const fullName = typeof repository.full_name === "string" ? repository.full_name : "";
950
+ const defaultBranch =
951
+ typeof repository.default_branch === "string" ? repository.default_branch : "";
952
+ const coordinates = fullName.split("/");
953
+ if (
954
+ repositoryId !== input.repositoryId ||
955
+ coordinates.length !== 2 ||
956
+ !coordinates[0] ||
957
+ !coordinates[1] ||
958
+ defaultBranch.length === 0 ||
959
+ defaultBranch.length > 1024
960
+ ) {
961
+ throw new GitHubAppApiError("GitHub returned an invalid repository branch identity payload");
962
+ }
963
+ const branchUrl = new URL(
964
+ `${githubApiBase}/repos/${encodeURIComponent(coordinates[0])}/${encodeURIComponent(coordinates[1])}/branches`,
965
+ );
966
+ branchUrl.searchParams.set("page", String(input.page));
967
+ branchUrl.searchParams.set("per_page", String(input.limit));
968
+ const branchesResponse = await githubRepositoryBranchesFetch(
969
+ branchUrl,
970
+ minted.token,
971
+ "GitHub repository branches",
972
+ );
973
+ const branchPayload = await githubResponseJsonBounded(
974
+ branchesResponse,
975
+ "GitHub repository branches response",
976
+ );
977
+ if (!Array.isArray(branchPayload) || branchPayload.length > input.limit) {
978
+ throw new GitHubAppApiError("GitHub returned an invalid repository branches payload");
979
+ }
980
+ const branches: string[] = [];
981
+ const seen = new Set<string>();
982
+ for (const value of branchPayload) {
983
+ const name =
984
+ value && typeof value === "object" && !Array.isArray(value)
985
+ ? (value as Record<string, unknown>).name
986
+ : null;
987
+ if (typeof name !== "string" || name.length === 0 || name.length > 1024 || seen.has(name)) {
988
+ throw new GitHubAppApiError("GitHub returned an invalid repository branches payload");
989
+ }
990
+ seen.add(name);
991
+ branches.push(name);
992
+ }
993
+ return {
994
+ installationId: input.installationId,
995
+ repositoryId: input.repositoryId,
996
+ defaultBranch,
997
+ branches,
998
+ nextPage: branchPayload.length === input.limit && input.page < 10_000 ? input.page + 1 : null,
999
+ };
1000
+ }
1001
+
1002
+ /**
1003
+ * Verify one exact anonymous github.com repository and ref. The provider URL
1004
+ * is derived only from strict canonical coordinates, follows no redirects,
1005
+ * sends no credentials, and bounds both request time and response bytes.
1006
+ */
1007
+ export async function verifyPublicGitHubRepositoryRef(
1008
+ input: { repository: CanonicalGitHubRepository; ref: string },
1009
+ fetchImpl: typeof fetch = fetch,
1010
+ ): Promise<VerifyPublicGitHubRepositoryRefResponse> {
1011
+ const ref = input.ref.trim();
1012
+ if (!ref || ref.length > 1024 || /[\u0000-\u001f\u007f]/u.test(ref)) {
1013
+ throw new GitHubPublicRepositoryVerificationError(
1014
+ "invalid_input",
1015
+ "Enter a branch, tag, or commit SHA.",
1016
+ );
1017
+ }
1018
+ const repositoryUrl = new URL(
1019
+ `${githubApiBase}/repos/${encodeURIComponent(input.repository.owner)}/${encodeURIComponent(input.repository.name)}`,
1020
+ );
1021
+ const repositoryPayload = await anonymousGitHubJson(
1022
+ fetchImpl,
1023
+ repositoryUrl,
1024
+ "GitHub repository",
1025
+ );
1026
+ if (
1027
+ !repositoryPayload ||
1028
+ typeof repositoryPayload !== "object" ||
1029
+ Array.isArray(repositoryPayload)
1030
+ ) {
1031
+ throw new GitHubPublicRepositoryVerificationError(
1032
+ "provider_unavailable",
1033
+ "GitHub returned an invalid repository response.",
1034
+ );
1035
+ }
1036
+ const repository = repositoryPayload as Record<string, unknown>;
1037
+ const fullName = typeof repository.full_name === "string" ? repository.full_name : "";
1038
+ const defaultBranch =
1039
+ typeof repository.default_branch === "string" ? repository.default_branch : "";
1040
+ const privateRepository = repository.private;
1041
+ if (
1042
+ !Number.isSafeInteger(repository.id) ||
1043
+ Number(repository.id) <= 0 ||
1044
+ privateRepository !== false ||
1045
+ !fullName ||
1046
+ fullName.toLowerCase() !== input.repository.fullName.toLowerCase() ||
1047
+ !defaultBranch ||
1048
+ defaultBranch.length > 1024
1049
+ ) {
1050
+ throw new GitHubPublicRepositoryVerificationError(
1051
+ "unavailable",
1052
+ "That GitHub repository is private or unavailable.",
1053
+ );
1054
+ }
1055
+ let canonical: CanonicalGitHubRepository;
1056
+ try {
1057
+ canonical = parseCanonicalGitHubRepositoryUrl(`https://github.com/${fullName}`);
1058
+ } catch {
1059
+ throw new GitHubPublicRepositoryVerificationError(
1060
+ "provider_unavailable",
1061
+ "GitHub returned an invalid repository identity.",
1062
+ );
1063
+ }
1064
+ const commitUrl = new URL(
1065
+ `${githubApiBase}/repos/${encodeURIComponent(canonical.owner)}/${encodeURIComponent(canonical.name)}/commits/${encodeURIComponent(ref)}`,
1066
+ );
1067
+ const commitPayload = await anonymousGitHubJson(fetchImpl, commitUrl, "GitHub repository ref");
1068
+ const commitSha =
1069
+ commitPayload && typeof commitPayload === "object" && !Array.isArray(commitPayload)
1070
+ ? (commitPayload as Record<string, unknown>).sha
1071
+ : null;
1072
+ if (typeof commitSha !== "string" || !/^[0-9a-f]{40}$/u.test(commitSha)) {
1073
+ throw new GitHubPublicRepositoryVerificationError(
1074
+ "unavailable",
1075
+ "That branch, tag, or commit SHA is not available on the public repository.",
1076
+ );
1077
+ }
1078
+ return {
1079
+ ...canonical,
1080
+ defaultBranch,
1081
+ ref,
1082
+ commitSha,
1083
+ };
1084
+ }
1085
+
867
1086
  export async function createGitHubAppInstallationToken(
868
1087
  settings: Settings,
869
1088
  input: {
@@ -900,6 +1119,7 @@ export async function createGitHubAppInstallationTokenWithSigningSettings(
900
1119
  installationId: number;
901
1120
  repositoryIds: number[];
902
1121
  permissions?: Record<string, "read" | "write">;
1122
+ timeoutMs?: number;
903
1123
  },
904
1124
  ): Promise<GitHubAppInstallationToken> {
905
1125
  const missing = githubAppTokenMissingSettings(settings);
@@ -928,6 +1148,7 @@ export async function createGitHubAppInstallationTokenWithSigningSettings(
928
1148
  installationId: input.installationId,
929
1149
  repositoryIds,
930
1150
  ...(input.permissions ? { permissions: input.permissions } : {}),
1151
+ ...(input.timeoutMs !== undefined ? { timeoutMs: input.timeoutMs } : {}),
931
1152
  });
932
1153
  }
933
1154
 
@@ -1210,20 +1431,36 @@ async function createInstallationToken(
1210
1431
  ...githubHeaders(appJwt),
1211
1432
  ...(scoped ? { "Content-Type": "application/json" } : {}),
1212
1433
  },
1434
+ redirect: "manual",
1213
1435
  signal: AbortSignal.timeout(input.timeoutMs ?? githubTokenMintTimeoutMs),
1214
1436
  ...(scoped ? { body: JSON.stringify(body) } : {}),
1215
1437
  },
1216
1438
  );
1217
1439
  if (!response.ok) {
1218
- throw new GitHubAppApiError(await githubErrorMessage(response));
1440
+ throw new GitHubAppApiError(await githubErrorMessage(response), response.status);
1219
1441
  }
1220
- const payload = await response.json();
1221
- if (!payload || typeof payload !== "object" || typeof payload.token !== "string") {
1442
+ let payload: unknown;
1443
+ try {
1444
+ payload = JSON.parse(
1445
+ await readResponseTextBounded(
1446
+ response,
1447
+ githubInstallationTokenResponseMaxBytes,
1448
+ "GitHub installation token response",
1449
+ ),
1450
+ ) as unknown;
1451
+ } catch {
1452
+ throw new GitHubAppApiError("GitHub returned an invalid installation token payload");
1453
+ }
1454
+ if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
1455
+ throw new GitHubAppApiError("GitHub returned an invalid installation token payload");
1456
+ }
1457
+ const record = payload as Record<string, unknown>;
1458
+ if (typeof record.token !== "string") {
1222
1459
  throw new GitHubAppApiError("GitHub returned an invalid installation token payload");
1223
1460
  }
1224
1461
  return {
1225
- token: payload.token,
1226
- expiresAt: typeof payload.expires_at === "string" ? payload.expires_at : null,
1462
+ token: record.token,
1463
+ expiresAt: typeof record.expires_at === "string" ? record.expires_at : null,
1227
1464
  };
1228
1465
  }
1229
1466
 
@@ -1297,6 +1534,89 @@ async function githubGet(
1297
1534
  return await response.json();
1298
1535
  }
1299
1536
 
1537
+ async function githubRepositoryBranchesFetch(
1538
+ url: URL,
1539
+ token: string,
1540
+ label: string,
1541
+ ): Promise<Response> {
1542
+ let response: Response;
1543
+ try {
1544
+ response = await fetch(url, {
1545
+ headers: githubHeaders(token),
1546
+ redirect: "manual",
1547
+ signal: AbortSignal.timeout(githubRepositoryBranchesTimeoutMs),
1548
+ });
1549
+ } catch {
1550
+ throw new GitHubAppApiError(`${label} request failed`);
1551
+ }
1552
+ if (!response.ok) {
1553
+ throw new GitHubAppApiError(await githubErrorMessage(response), response.status);
1554
+ }
1555
+ return response;
1556
+ }
1557
+
1558
+ async function githubResponseJsonBounded(response: Response, label: string): Promise<unknown> {
1559
+ try {
1560
+ return JSON.parse(
1561
+ await readResponseTextBounded(response, githubRepositoryBranchesResponseMaxBytes, label),
1562
+ ) as unknown;
1563
+ } catch {
1564
+ throw new GitHubAppApiError(`${label} was invalid or too large`);
1565
+ }
1566
+ }
1567
+
1568
+ async function anonymousGitHubJson(
1569
+ fetchImpl: typeof fetch,
1570
+ url: URL,
1571
+ label: string,
1572
+ ): Promise<unknown> {
1573
+ let response: Response;
1574
+ try {
1575
+ response = await fetchImpl(url, {
1576
+ headers: githubHeaders(),
1577
+ redirect: "manual",
1578
+ signal: AbortSignal.timeout(githubPublicRepositoryVerificationTimeoutMs),
1579
+ });
1580
+ } catch {
1581
+ throw new GitHubPublicRepositoryVerificationError(
1582
+ "provider_unavailable",
1583
+ `${label} verification is temporarily unavailable.`,
1584
+ );
1585
+ }
1586
+ if (response.status === 404) {
1587
+ throw new GitHubPublicRepositoryVerificationError(
1588
+ "unavailable",
1589
+ label === "GitHub repository"
1590
+ ? "That GitHub repository is private or unavailable."
1591
+ : "That branch, tag, or commit SHA is not available on the public repository.",
1592
+ response.status,
1593
+ );
1594
+ }
1595
+ if (!response.ok) {
1596
+ throw new GitHubPublicRepositoryVerificationError(
1597
+ "provider_unavailable",
1598
+ response.status === 429
1599
+ ? "GitHub is temporarily rate limited. Try again shortly."
1600
+ : `${label} verification is temporarily unavailable.`,
1601
+ response.status,
1602
+ );
1603
+ }
1604
+ try {
1605
+ return JSON.parse(
1606
+ await readResponseTextBounded(
1607
+ response,
1608
+ githubPublicRepositoryVerificationResponseMaxBytes,
1609
+ `${label} verification response`,
1610
+ ),
1611
+ ) as unknown;
1612
+ } catch {
1613
+ throw new GitHubPublicRepositoryVerificationError(
1614
+ "provider_unavailable",
1615
+ `${label} verification returned an invalid response.`,
1616
+ );
1617
+ }
1618
+ }
1619
+
1300
1620
  function repositoryFromPayload(
1301
1621
  payload: Record<string, unknown>,
1302
1622
  installationId: number,
@@ -1344,15 +1664,27 @@ function githubHeaders(token?: string): HeadersInit {
1344
1664
  }
1345
1665
 
1346
1666
  async function githubErrorMessage(response: Response): Promise<string> {
1667
+ let text: string;
1347
1668
  try {
1348
- const payload = await response.json();
1669
+ text = await readResponseTextBounded(
1670
+ response,
1671
+ githubErrorResponseMaxBytes,
1672
+ "GitHub error response",
1673
+ );
1674
+ } catch {
1675
+ return `GitHub API ${response.status}`;
1676
+ }
1677
+ try {
1678
+ const payload = JSON.parse(text) as unknown;
1349
1679
  if (payload && typeof payload === "object" && "message" in payload) {
1350
- return `GitHub API ${response.status}: ${String(payload.message)}`;
1680
+ return `GitHub API ${response.status}: ${String(
1681
+ (payload as Record<string, unknown>).message,
1682
+ ).slice(0, githubErrorMessageMaxLength)}`;
1351
1683
  }
1352
1684
  } catch {
1353
- // fall through
1685
+ // Fall through to the bounded text body.
1354
1686
  }
1355
- return `GitHub API ${response.status}: ${await response.text()}`;
1687
+ return `GitHub API ${response.status}: ${text.slice(0, githubErrorMessageMaxLength)}`;
1356
1688
  }
1357
1689
 
1358
1690
  export function normalizeGitHubAppPrivateKey(value: string): string {