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..164aa31d9 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,10 +113,13 @@ 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; + let appPrivateKey = appCfg.INF_APP_CONNECTION_GITHUB_APP_PRIVATE_KEY; if (!appId || !appPrivateKey) { throw new InternalServerError({ @@ -125,21 +127,42 @@ export const getGitHubAppAuthToken = async (appConnection: TGitHubConnection) => }); } + 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" }); } - 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 +197,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);