Skip to content

Commit b366d97

Browse files
fix(backend): fall back when GitHub App installation is missing (#1523)
* fix(backend): fall back when GitHub App installation is missing * chore: update changelog for #1523
1 parent 0a019d4 commit b366d97

4 files changed

Lines changed: 28 additions & 23 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1010
### Fixed
1111
- Upgraded `seroval` to `^1.5.6`. [#1508](https://github.com/sourcebot-dev/sourcebot/pull/1508)
1212
- Fixed vulnerability triage for reusable-workflow callers, repositories without CodeQL, and transient non-JSON Linear query responses. [#1515](https://github.com/sourcebot-dev/sourcebot/pull/1515)
13+
- [EE] Fixed GitHub connection syncs failing when a configured organization does not have the GitHub App installed by falling back to legacy authentication for that organization. [#1523](https://github.com/sourcebot-dev/sourcebot/pull/1523)
1314

1415
## [5.1.4] - 2026-07-24
1516

packages/backend/src/ee/githubAppManager.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,13 +106,13 @@ export class GithubAppManager {
106106
this.initialized = true;
107107
}
108108

109-
public async getInstallationToken(owner: string, deploymentHostname: string = GITHUB_DEFAULT_DEPLOYMENT_HOSTNAME): Promise<string> {
109+
public async getInstallationToken(owner: string, deploymentHostname: string = GITHUB_DEFAULT_DEPLOYMENT_HOSTNAME): Promise<string | undefined> {
110110
this.assertInitialized();
111111

112112
const key = this.generateMapKey(owner, deploymentHostname);
113113
const installation = this.installationMap.get(key) as Installation | undefined;
114114
if (!installation) {
115-
throw new Error(`GitHub App Installation not found for ${key}`);
115+
return undefined;
116116
}
117117

118118
const octokitApp = this.octokitApps.get(installation.appId) as App;

packages/backend/src/github.ts

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -136,18 +136,20 @@ export const getOctokitWithGithubApp = async (
136136
throw new Error(`GitHub App authentication is not currently licensed for ${context}.`);
137137
}
138138

139-
try {
140-
const hostname = url ? new URL(url).hostname : GITHUB_CLOUD_HOSTNAME;
141-
const token = await githubAppManager.getInstallationToken(owner, hostname);
142-
const { octokit: octokitFromToken } = await createOctokitFromToken({
143-
token,
144-
url,
145-
});
146-
return octokitFromToken;
147-
} catch (error) {
148-
logger.error(`Error getting GitHub App token for ${context}.`, error);
149-
throw error;
139+
const hostname = url ? new URL(url).hostname : GITHUB_CLOUD_HOSTNAME;
140+
const token = await githubAppManager.getInstallationToken(owner, hostname);
141+
if (!token) {
142+
logger.warn(
143+
`No matching GitHub App installation found for ${context} on ${hostname}; falling back to legacy GitHub authentication.`
144+
);
145+
return octokit;
150146
}
147+
148+
const { octokit: octokitFromToken } = await createOctokitFromToken({
149+
token,
150+
url,
151+
});
152+
return octokitFromToken;
151153
}
152154

153155
export const getGitHubReposFromConfig = async (config: GithubConnectionConfig, signal: AbortSignal): Promise<{ repos: OctokitRepository[], warnings: string[] }> => {

packages/backend/src/utils.ts

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -150,16 +150,18 @@ export const getAuthCredentialsForRepo = async (repo: RepoWithConnections, logge
150150
}
151151

152152
const token = await githubAppManager.getInstallationToken(owner, deploymentHostname);
153-
return {
154-
hostUrl: repo.external_codeHostUrl,
155-
token,
156-
cloneUrlWithToken: createGitCloneUrlWithToken(
157-
repo.cloneUrl,
158-
{
159-
username: 'x-access-token',
160-
password: token
161-
}
162-
),
153+
if (token) {
154+
return {
155+
hostUrl: repo.external_codeHostUrl,
156+
token,
157+
cloneUrlWithToken: createGitCloneUrlWithToken(
158+
repo.cloneUrl,
159+
{
160+
username: 'x-access-token',
161+
password: token
162+
}
163+
),
164+
}
163165
}
164166
}
165167
}

0 commit comments

Comments
 (0)