From f63ee39f3da1e6608b23c4afb066afc3676eb960 Mon Sep 17 00:00:00 2001 From: x032205 Date: Mon, 25 Aug 2025 17:28:48 -0400 Subject: [PATCH 1/2] Swap away from octokit for GitHub app auth and use gateway --- .../github/github-connection-fns.ts | 48 +++++++++++++------ .../secret-sync/github/github-sync-fns.ts | 4 +- 2 files changed, 36 insertions(+), 16 deletions(-) diff --git a/backend/src/services/app-connection/github/github-connection-fns.ts b/backend/src/services/app-connection/github/github-connection-fns.ts index a71036d82..2d4e70e3a 100644 --- a/backend/src/services/app-connection/github/github-connection-fns.ts +++ b/backend/src/services/app-connection/github/github-connection-fns.ts @@ -1,5 +1,3 @@ -import { createAppAuth } from "@octokit/auth-app"; -import { request } from "@octokit/request"; import { AxiosError, AxiosRequestConfig, AxiosResponse } from "axios"; import https from "https"; import RE2 from "re2"; @@ -8,6 +6,7 @@ import { verifyHostInputValidity } from "@app/ee/services/dynamic-secret/dynamic import { TGatewayServiceFactory } from "@app/ee/services/gateway/gateway-service"; import { getConfig } from "@app/lib/config/env"; import { request as httpRequest } from "@app/lib/config/request"; +import { crypto } from "@app/lib/crypto"; import { BadRequestError, ForbiddenRequestError, InternalServerError } from "@app/lib/errors"; import { GatewayProxyProtocol, withGatewayProxy } from "@app/lib/gateway"; import { logger } from "@app/lib/logger"; @@ -114,7 +113,10 @@ export const requestWithGitHubGateway = async ( ); }; -export const getGitHubAppAuthToken = async (appConnection: TGitHubConnection) => { +export const getGitHubAppAuthToken = async ( + appConnection: TGitHubConnection, + gatewayService: Pick +) => { const appCfg = getConfig(); const appId = appCfg.INF_APP_CONNECTION_GITHUB_APP_ID; const appPrivateKey = appCfg.INF_APP_CONNECTION_GITHUB_APP_PRIVATE_KEY; @@ -129,17 +131,33 @@ export const getGitHubAppAuthToken = async (appConnection: TGitHubConnection) => throw new InternalServerError({ message: "Cannot generate GitHub App token for non-app connection" }); } - const appAuth = createAppAuth({ - appId, - privateKey: appPrivateKey, - installationId: appConnection.credentials.installationId, - request: request.defaults({ - baseUrl: `https://${await getGitHubInstanceApiUrl(appConnection)}` - }) - }); + const now = Math.floor(Date.now() / 1000); + const payload = { + iat: now, + exp: now + 5 * 60, + iss: appId + }; - const { token } = await appAuth({ type: "installation" }); - return token; + const appJwt = crypto.jwt().sign(payload, appPrivateKey, { algorithm: "RS256" }); + + const apiBaseUrl = await getGitHubInstanceApiUrl(appConnection); + const { installationId } = appConnection.credentials; + + const response = await requestWithGitHubGateway<{ token: string; expires_at: string }>( + appConnection, + gatewayService, + { + url: `https://${apiBaseUrl}/app/installations/${installationId}/access_tokens`, + method: "POST", + headers: { + Accept: "application/vnd.github+json", + Authorization: `Bearer ${appJwt}`, + "X-GitHub-Api-Version": "2022-11-28" + } + } + ); + + return response.data.token; }; const parseGitHubLinkHeader = (linkHeader: string | undefined): Record => { @@ -174,7 +192,9 @@ export const makePaginatedGitHubRequest = async ( const { credentials, method } = appConnection; const token = - method === GitHubConnectionMethod.OAuth ? credentials.accessToken : await getGitHubAppAuthToken(appConnection); + method === GitHubConnectionMethod.OAuth + ? credentials.accessToken + : await getGitHubAppAuthToken(appConnection, gatewayService); const baseUrl = `https://${await getGitHubInstanceApiUrl(appConnection)}${path}`; const initialUrlObj = new URL(baseUrl); diff --git a/backend/src/services/secret-sync/github/github-sync-fns.ts b/backend/src/services/secret-sync/github/github-sync-fns.ts index e2cf8f6e8..2cae048aa 100644 --- a/backend/src/services/secret-sync/github/github-sync-fns.ts +++ b/backend/src/services/secret-sync/github/github-sync-fns.ts @@ -207,7 +207,7 @@ export const GithubSyncFns = { const token = connection.method === GitHubConnectionMethod.OAuth ? connection.credentials.accessToken - : await getGitHubAppAuthToken(connection); + : await getGitHubAppAuthToken(connection, gatewayService); const encryptedSecrets = await getEncryptedSecrets(secretSync, gatewayService); const publicKey = await getPublicKey(secretSync, gatewayService, token); @@ -264,7 +264,7 @@ export const GithubSyncFns = { const token = connection.method === GitHubConnectionMethod.OAuth ? connection.credentials.accessToken - : await getGitHubAppAuthToken(connection); + : await getGitHubAppAuthToken(connection, gatewayService); const encryptedSecrets = await getEncryptedSecrets(secretSync, gatewayService); From a349dda4bccd8d1d1dd6ef58c3073aa49f5d30a5 Mon Sep 17 00:00:00 2001 From: x032205 Date: Mon, 25 Aug 2025 18:26:34 -0400 Subject: [PATCH 2/2] Foramt privatekey --- .../app-connection/github/github-connection-fns.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/backend/src/services/app-connection/github/github-connection-fns.ts b/backend/src/services/app-connection/github/github-connection-fns.ts index 2d4e70e3a..164aa31d9 100644 --- a/backend/src/services/app-connection/github/github-connection-fns.ts +++ b/backend/src/services/app-connection/github/github-connection-fns.ts @@ -119,7 +119,7 @@ export const getGitHubAppAuthToken = async ( ) => { const appCfg = getConfig(); const appId = appCfg.INF_APP_CONNECTION_GITHUB_APP_ID; - const appPrivateKey = appCfg.INF_APP_CONNECTION_GITHUB_APP_PRIVATE_KEY; + let appPrivateKey = appCfg.INF_APP_CONNECTION_GITHUB_APP_PRIVATE_KEY; if (!appId || !appPrivateKey) { throw new InternalServerError({ @@ -127,6 +127,11 @@ export const getGitHubAppAuthToken = async ( }); } + appPrivateKey = appPrivateKey + .split("\n") + .map((line) => line.trim()) + .join("\n"); + if (appConnection.method !== GitHubConnectionMethod.App) { throw new InternalServerError({ message: "Cannot generate GitHub App token for non-app connection" }); }