From 5df7539f6526c981aefa88bf71c1320f6f6848ec Mon Sep 17 00:00:00 2001 From: x032205 Date: Thu, 24 Jul 2025 21:43:18 -0400 Subject: [PATCH] Swap away from using octokit due to gateway compatibility issues --- .../github/github-connection-fns.ts | 381 ++++++++---------- .../secret-sync/github/github-sync-fns.ts | 258 ++++++------ 2 files changed, 296 insertions(+), 343 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 2607d8e9e..5f4057bd2 100644 --- a/backend/src/services/app-connection/github/github-connection-fns.ts +++ b/backend/src/services/app-connection/github/github-connection-fns.ts @@ -1,7 +1,7 @@ import { createAppAuth } from "@octokit/auth-app"; -import { Octokit } from "@octokit/rest"; import { AxiosError, AxiosRequestConfig, AxiosResponse } from "axios"; import https from "https"; +import RE2 from "re2"; import { verifyHostInputValidity } from "@app/ee/services/dynamic-secret/dynamic-secret-fns"; import { TGatewayServiceFactory } from "@app/ee/services/gateway/gateway-service"; @@ -29,251 +29,196 @@ export const getGitHubConnectionListItem = () => { }; }; -export const getGitHubClient = ( - appConnection: TGitHubConnection, - octokitOptions: Partial<{ baseUrl: string; request: { agent?: https.Agent } }> -) => { - const appCfg = getConfig(); - - const { method, credentials } = appConnection; - const { baseUrl, request } = octokitOptions; - - let client: Octokit; - - const appId = appCfg.INF_APP_CONNECTION_GITHUB_APP_ID; - const appPrivateKey = appCfg.INF_APP_CONNECTION_GITHUB_APP_PRIVATE_KEY; - - switch (method) { - case GitHubConnectionMethod.App: - if (!appId || !appPrivateKey) { - throw new InternalServerError({ - message: `GitHub ${getAppConnectionMethodName(method).replace("GitHub", "")} has not been configured` - }); - } - - client = new Octokit({ - authStrategy: createAppAuth, - auth: { - appId, - privateKey: appPrivateKey, - installationId: credentials.installationId - }, - baseUrl, - request - }); - break; - case GitHubConnectionMethod.OAuth: - client = new Octokit({ - auth: credentials.accessToken, - baseUrl, - request - }); - break; - default: - throw new InternalServerError({ - message: `Unhandled GitHub connection method: ${method as GitHubConnectionMethod}` - }); - } - - return client; -}; - -export const executeWithGitHubGateway = async ( - appConnection: TGitHubConnection, - gatewayService: Pick, - operation: (client: Octokit) => Promise -): Promise => { - const { - gatewayId, - credentials: { host: hostParam } - } = appConnection; - - const host = hostParam || "api.github.com"; - - if (gatewayId && gatewayService) { - const [targetHost] = await verifyHostInputValidity(host, true); - const relayDetails = await gatewayService.fnGetGatewayClientTlsByGatewayId(gatewayId); - const [relayHost, relayPort] = relayDetails.relayAddress.split(":"); - - return withGatewayProxy( - async (proxyPort) => { - const agent = new https.Agent({ - servername: targetHost, - rejectUnauthorized: true - }); - - const client = getGitHubClient(appConnection, { - baseUrl: `https://localhost:${proxyPort}`, - request: { agent } - }); - - return operation(client); - }, - { - protocol: GatewayProxyProtocol.Tcp, - targetHost, - targetPort: 443, - relayHost, - relayPort: Number(relayPort), - identityId: relayDetails.identityId, - orgId: relayDetails.orgId, - tlsOptions: { - ca: relayDetails.certChain, - cert: relayDetails.certificate, - key: relayDetails.privateKey.toString() - } - } - ); - } - - // Non-gateway path - const client = getGitHubClient(appConnection, { - baseUrl: `https://${host}` - }); - - return operation(client); -}; - -// For non-octokit requests export const requestWithGitHubGateway = async ( - appConnection: TGitHubConnectionConfig, + appConnection: { gatewayId?: string | null; credentials: { host?: string } }, gatewayService: Pick, requestConfig: AxiosRequestConfig ): Promise> => { - const { - gatewayId, - credentials: { host: hostParam } - } = appConnection; + const { gatewayId } = appConnection; + + // If gateway isn't set up, don't proxy request + if (!gatewayId) { + return httpRequest.request(requestConfig); + } const url = new URL(requestConfig.url as string); - const host = hostParam || url.host || "github.com"; - if (gatewayId && gatewayService) { - const [targetHost] = await verifyHostInputValidity(host, true); - const relayDetails = await gatewayService.fnGetGatewayClientTlsByGatewayId(gatewayId); - const [relayHost, relayPort] = relayDetails.relayAddress.split(":"); + const [targetHost] = await verifyHostInputValidity(url.host, true); + const relayDetails = await gatewayService.fnGetGatewayClientTlsByGatewayId(gatewayId); + const [relayHost, relayPort] = relayDetails.relayAddress.split(":"); - return withGatewayProxy( - async (proxyPort) => { - const proxyAgent = new https.Agent({ - servername: targetHost, - rejectUnauthorized: true - }); + return withGatewayProxy( + async (proxyPort) => { + const httpsAgent = new https.Agent({ + servername: targetHost + }); - url.protocol = "https:"; - url.host = `localhost:${proxyPort}`; + url.protocol = "https:"; + url.host = `localhost:${proxyPort}`; - const finalRequestConfig: AxiosRequestConfig = { - ...requestConfig, - url: url.toString(), - httpsAgent: proxyAgent, - headers: { - ...requestConfig.headers, - Host: targetHost - } - }; - - try { - return await httpRequest.request(finalRequestConfig); - } catch (error) { - const axiosError = error as AxiosError; - logger.error("Error during GitHub gateway request:", axiosError.message, axiosError.response?.data); - throw error; - } - }, - { - protocol: GatewayProxyProtocol.Tcp, - targetHost, - targetPort: 443, - relayHost, - relayPort: Number(relayPort), - identityId: relayDetails.identityId, - orgId: relayDetails.orgId, - tlsOptions: { - ca: relayDetails.certChain, - cert: relayDetails.certificate, - key: relayDetails.privateKey.toString() + const finalRequestConfig: AxiosRequestConfig = { + ...requestConfig, + url: url.toString(), + httpsAgent, + headers: { + ...requestConfig.headers, + Host: targetHost } + }; + + try { + return await httpRequest.request(finalRequestConfig); + } catch (error) { + const axiosError = error as AxiosError; + logger.error("Error during GitHub gateway request:", axiosError.message, axiosError.response?.data); + throw error; } - ); + }, + { + protocol: GatewayProxyProtocol.Tcp, + targetHost, + targetPort: 443, + relayHost, + relayPort: Number(relayPort), + identityId: relayDetails.identityId, + orgId: relayDetails.orgId, + tlsOptions: { + ca: relayDetails.certChain, + cert: relayDetails.certificate, + key: relayDetails.privateKey.toString() + } + } + ); +}; + +export const getGitHubAppAuthToken = async (appConnection: TGitHubConnection) => { + const appCfg = getConfig(); + const appId = appCfg.INF_APP_CONNECTION_GITHUB_APP_ID; + const appPrivateKey = appCfg.INF_APP_CONNECTION_GITHUB_APP_PRIVATE_KEY; + + if (!appId || !appPrivateKey) { + throw new InternalServerError({ + message: `GitHub App keys are not configured.` + }); } - if (!url.host) { - url.protocol = "https:"; - url.host = host; + if (appConnection.method !== GitHubConnectionMethod.App) { + throw new InternalServerError({ message: "Cannot generate GitHub App token for non-app connection" }); } - const finalRequestConfig: AxiosRequestConfig = { - ...requestConfig, - url: url.toString() - }; + const appAuth = createAppAuth({ + appId, + privateKey: appPrivateKey, + installationId: appConnection.credentials.installationId + }); - return httpRequest.request(finalRequestConfig); + const { token } = await appAuth({ type: "installation" }); + return token; +}; + +export const makePaginatedGitHubRequest = async ( + appConnection: TGitHubConnection, + gatewayService: Pick, + path: string, + dataMapper?: (data: R) => T[] +): Promise => { + const { credentials, method } = appConnection; + + const token = + method === GitHubConnectionMethod.OAuth ? credentials.accessToken : await getGitHubAppAuthToken(appConnection); + let url: string | null = `https://api.${credentials.host || "github.com"}${path}`; + let results: T[] = []; + + while (url) { + // eslint-disable-next-line no-await-in-loop + const response: AxiosResponse = await requestWithGitHubGateway(appConnection, gatewayService, { + url, + method: "GET", + headers: { + Accept: "application/vnd.github+json", + Authorization: `Bearer ${token}`, + "X-GitHub-Api-Version": "2022-11-28" + } + }); + + const items = dataMapper ? dataMapper(response.data) : (response.data as unknown as T[]); + results = results.concat(items); + + const linkHeader = response.headers.link as string | undefined; + const nextLink = + typeof linkHeader === "string" ? linkHeader.split(",").find((s) => s.includes('rel="next"')) : undefined; + if (nextLink) { + url = new RE2(/<(.+)>/).exec(nextLink)?.[1] || null; + } else { + url = null; + } + } + + return results; }; type GitHubOrganization = { login: string; id: number; + type: string; }; type GitHubRepository = { id: number; name: string; owner: GitHubOrganization; + permissions?: { + admin: boolean; + maintain: boolean; + push: boolean; + triage: boolean; + pull: boolean; + }; +}; + +type GitHubEnvironment = { + id: number; + name: string; }; export const getGitHubRepositories = async ( appConnection: TGitHubConnection, gatewayService: Pick ) => { - return executeWithGitHubGateway(appConnection, gatewayService, async (client) => { - let repositories: GitHubRepository[]; + if (appConnection.method === GitHubConnectionMethod.App) { + return makePaginatedGitHubRequest( + appConnection, + gatewayService, + "/installation/repositories", + (data) => data.repositories + ); + } - switch (appConnection.method) { - case GitHubConnectionMethod.App: - repositories = await client.paginate("GET /installation/repositories"); - break; - case GitHubConnectionMethod.OAuth: - default: - repositories = (await client.paginate("GET /user/repos")).filter((repo) => repo.permissions?.admin); - break; - } - - return repositories; - }); + const repos = await makePaginatedGitHubRequest(appConnection, gatewayService, "/user/repos"); + return repos.filter((repo) => repo.permissions?.admin); }; export const getGitHubOrganizations = async ( appConnection: TGitHubConnection, gatewayService: Pick ) => { - return executeWithGitHubGateway(appConnection, gatewayService, async (client) => { - let organizations: GitHubOrganization[]; + if (appConnection.method === GitHubConnectionMethod.App) { + const installationRepositories = await makePaginatedGitHubRequest< + GitHubRepository, + { repositories: GitHubRepository[] } + >(appConnection, gatewayService, "/installation/repositories", (data) => data.repositories); - switch (appConnection.method) { - case GitHubConnectionMethod.App: { - const installationRepositories = await client.paginate("GET /installation/repositories"); - - const organizationMap: Record = {}; - - installationRepositories.forEach((repo) => { - if (repo.owner.type === "Organization") { - organizationMap[repo.owner.id] = repo.owner; - } - }); - - organizations = Object.values(organizationMap); - - break; + const organizationMap: Record = {}; + installationRepositories.forEach((repo) => { + if (repo.owner.type === "Organization") { + organizationMap[repo.owner.id] = repo.owner; } - case GitHubConnectionMethod.OAuth: - default: - organizations = await client.paginate("GET /user/orgs"); - break; - } + }); - return organizations; - }); + return Object.values(organizationMap); + } + + return makePaginatedGitHubRequest(appConnection, gatewayService, "/user/orgs"); }; export const getGitHubEnvironments = async ( @@ -282,23 +227,18 @@ export const getGitHubEnvironments = async ( owner: string, repo: string ) => { - return executeWithGitHubGateway(appConnection, gatewayService, async (client) => { - try { - const environments = await client.paginate("GET /repos/{owner}/{repo}/environments", { - owner, - repo - }); - - return environments; - } catch (e) { - // repo doesn't have envs - if ((e as { status: number }).status === 404) { - return []; - } - - throw e; - } - }); + try { + return await makePaginatedGitHubRequest( + appConnection, + gatewayService, + `/repos/${owner}/${repo}/environments`, + (data) => data.environments + ); + } catch (error) { + const axiosError = error as AxiosError; + if (axiosError.response?.status === 404) return []; + throw error; + } }; export type GithubTokenRespData = { @@ -352,7 +292,6 @@ export const validateGitHubConnectionCredentials = async ( let tokenResp: AxiosResponse; const host = credentials.host || "github.com"; - const apiHost = credentials.host ? `api.${credentials.host}` : "api.github.com"; try { tokenResp = await requestWithGitHubGateway(config, gatewayService, { @@ -406,7 +345,7 @@ export const validateGitHubConnectionCredentials = async ( }; }[]; }>(config, gatewayService, { - url: IntegrationUrls.GITHUB_USER_INSTALLATIONS.replace("api.github.com", apiHost), + url: IntegrationUrls.GITHUB_USER_INSTALLATIONS.replace("api.github.com", `api.${host}`), headers: { Accept: "application/json", Authorization: `Bearer ${tokenResp.data.access_token}`, 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 59affa2b7..580d77bca 100644 --- a/backend/src/services/secret-sync/github/github-sync-fns.ts +++ b/backend/src/services/secret-sync/github/github-sync-fns.ts @@ -1,8 +1,12 @@ -import { Octokit } from "@octokit/rest"; import sodium from "libsodium-wrappers"; import { TGatewayServiceFactory } from "@app/ee/services/gateway/gateway-service"; -import { executeWithGitHubGateway } from "@app/services/app-connection/github"; +import { + getGitHubAppAuthToken, + GitHubConnectionMethod, + makePaginatedGitHubRequest, + requestWithGitHubGateway +} from "@app/services/app-connection/github"; import { GitHubSyncScope, GitHubSyncVisibility } from "@app/services/secret-sync/github/github-sync-enums"; import { SecretSyncError } from "@app/services/secret-sync/secret-sync-errors"; import { matchesSchema } from "@app/services/secret-sync/secret-sync-fns"; @@ -13,151 +17,155 @@ import { TGitHubPublicKey, TGitHubSecret, TGitHubSecretPayload, TGitHubSyncWithC // TODO: rate limit handling -const getEncryptedSecrets = async (client: Octokit, secretSync: TGitHubSyncWithCredentials) => { - let encryptedSecrets: TGitHubSecret[]; - - const { destinationConfig } = secretSync; +const getEncryptedSecrets = async ( + secretSync: TGitHubSyncWithCredentials, + gatewayService: Pick +) => { + const { destinationConfig, connection } = secretSync; + let path: string; switch (destinationConfig.scope) { case GitHubSyncScope.Organization: { - encryptedSecrets = await client.paginate("GET /orgs/{org}/actions/secrets", { - org: destinationConfig.org - }); + path = `/orgs/${destinationConfig.org}/actions/secrets`; break; } case GitHubSyncScope.Repository: { - encryptedSecrets = await client.paginate("GET /repos/{owner}/{repo}/actions/secrets", { - owner: destinationConfig.owner, - repo: destinationConfig.repo - }); - + path = `/repos/${destinationConfig.owner}/${destinationConfig.repo}/actions/secrets`; break; } case GitHubSyncScope.RepositoryEnvironment: default: { - encryptedSecrets = await client.paginate("GET /repos/{owner}/{repo}/environments/{environment_name}/secrets", { - owner: destinationConfig.owner, - repo: destinationConfig.repo, - environment_name: destinationConfig.env - }); + path = `/repos/${destinationConfig.owner}/${destinationConfig.repo}/environments/${destinationConfig.env}/secrets`; break; } } - return encryptedSecrets; + return makePaginatedGitHubRequest( + connection, + gatewayService, + path, + (data) => data.secrets + ); }; -const getPublicKey = async (client: Octokit, secretSync: TGitHubSyncWithCredentials) => { - let publicKey: TGitHubPublicKey; - - const { destinationConfig } = secretSync; +const getPublicKey = async ( + secretSync: TGitHubSyncWithCredentials, + gatewayService: Pick, + token: string +) => { + const { destinationConfig, connection } = secretSync; + let path: string; switch (destinationConfig.scope) { case GitHubSyncScope.Organization: { - publicKey = ( - await client.request("GET /orgs/{org}/actions/secrets/public-key", { - org: destinationConfig.org - }) - ).data; + path = `/orgs/${destinationConfig.org}/actions/secrets/public-key`; break; } case GitHubSyncScope.Repository: { - publicKey = ( - await client.request("GET /repos/{owner}/{repo}/actions/secrets/public-key", { - owner: destinationConfig.owner, - repo: destinationConfig.repo - }) - ).data; + path = `/repos/${destinationConfig.owner}/${destinationConfig.repo}/actions/secrets/public-key`; break; } case GitHubSyncScope.RepositoryEnvironment: default: { - publicKey = ( - await client.request("GET /repos/{owner}/{repo}/environments/{environment_name}/secrets/public-key", { - owner: destinationConfig.owner, - repo: destinationConfig.repo, - environment_name: destinationConfig.env - }) - ).data; + path = `/repos/${destinationConfig.owner}/${destinationConfig.repo}/environments/${destinationConfig.env}/secrets/public-key`; break; } } - return publicKey; + const response = await requestWithGitHubGateway(connection, gatewayService, { + url: `https://api.${connection.credentials.host || "github.com"}${path}`, + method: "GET", + headers: { + Accept: "application/vnd.github+json", + Authorization: `Bearer ${token}`, + "X-GitHub-Api-Version": "2022-11-28" + } + }); + + return response.data; }; const deleteSecret = async ( - client: Octokit, secretSync: TGitHubSyncWithCredentials, + gatewayService: Pick, + token: string, encryptedSecret: TGitHubSecret ) => { - const { destinationConfig } = secretSync; + const { destinationConfig, connection } = secretSync; + let path: string; switch (destinationConfig.scope) { case GitHubSyncScope.Organization: { - await client.request(`DELETE /orgs/{org}/actions/secrets/{secret_name}`, { - org: destinationConfig.org, - secret_name: encryptedSecret.name - }); + path = `/orgs/${destinationConfig.org}/actions/secrets/${encryptedSecret.name}`; break; } case GitHubSyncScope.Repository: { - await client.request("DELETE /repos/{owner}/{repo}/actions/secrets/{secret_name}", { - owner: destinationConfig.owner, - repo: destinationConfig.repo, - secret_name: encryptedSecret.name - }); + path = `/repos/${destinationConfig.owner}/${destinationConfig.repo}/actions/secrets/${encryptedSecret.name}`; break; } case GitHubSyncScope.RepositoryEnvironment: default: { - await client.request("DELETE /repos/{owner}/{repo}/environments/{environment_name}/secrets/{secret_name}", { - owner: destinationConfig.owner, - repo: destinationConfig.repo, - environment_name: destinationConfig.env, - secret_name: encryptedSecret.name - }); + path = `/repos/${destinationConfig.owner}/${destinationConfig.repo}/environments/${destinationConfig.env}/secrets/${encryptedSecret.name}`; break; } } + + await requestWithGitHubGateway(connection, gatewayService, { + url: `https://api.${connection.credentials.host || "github.com"}${path}`, + method: "DELETE", + headers: { + Accept: "application/vnd.github+json", + Authorization: `Bearer ${token}`, + "X-GitHub-Api-Version": "2022-11-28" + } + }); }; -const putSecret = async (client: Octokit, secretSync: TGitHubSyncWithCredentials, payload: TGitHubSecretPayload) => { - const { destinationConfig } = secretSync; +const putSecret = async ( + secretSync: TGitHubSyncWithCredentials, + gatewayService: Pick, + token: string, + payload: TGitHubSecretPayload +) => { + const { destinationConfig, connection } = secretSync; + + let path: string; + let body: Record = payload; switch (destinationConfig.scope) { case GitHubSyncScope.Organization: { const { visibility, selectedRepositoryIds } = destinationConfig; - - await client.request(`PUT /orgs/{org}/actions/secrets/{secret_name}`, { - org: destinationConfig.org, + path = `/orgs/${destinationConfig.org}/actions/secrets/${payload.secret_name}`; + body = { ...payload, visibility, ...(visibility === GitHubSyncVisibility.Selected && { selected_repository_ids: selectedRepositoryIds }) - }); + }; break; } case GitHubSyncScope.Repository: { - await client.request("PUT /repos/{owner}/{repo}/actions/secrets/{secret_name}", { - owner: destinationConfig.owner, - repo: destinationConfig.repo, - ...payload - }); + path = `/repos/${destinationConfig.owner}/${destinationConfig.repo}/actions/secrets/${payload.secret_name}`; break; } case GitHubSyncScope.RepositoryEnvironment: default: { - await client.request("PUT /repos/{owner}/{repo}/environments/{environment_name}/secrets/{secret_name}", { - owner: destinationConfig.owner, - repo: destinationConfig.repo, - environment_name: destinationConfig.env, - ...payload - }); + path = `/repos/${destinationConfig.owner}/${destinationConfig.repo}/environments/${destinationConfig.env}/secrets/${payload.secret_name}`; break; } } + + await requestWithGitHubGateway(connection, gatewayService, { + url: `https://api.${connection.credentials.host || "github.com"}${path}`, + method: "PUT", + headers: { + Accept: "application/vnd.github+json", + Authorization: `Bearer ${token}`, + "X-GitHub-Api-Version": "2022-11-28" + }, + data: body + }); }; export const GithubSyncFns = { @@ -192,50 +200,52 @@ export const GithubSyncFns = { ); } - await executeWithGitHubGateway(secretSync.connection, gatewayService, async (client) => { - const encryptedSecrets = await getEncryptedSecrets(client, secretSync); + const { connection } = secretSync; + const token = + connection.method === GitHubConnectionMethod.OAuth + ? connection.credentials.accessToken + : await getGitHubAppAuthToken(connection); - const publicKey = await getPublicKey(client, secretSync); + const encryptedSecrets = await getEncryptedSecrets(secretSync, gatewayService); + const publicKey = await getPublicKey(secretSync, gatewayService, token); - await sodium.ready.then(async () => { - for await (const key of Object.keys(secretMap)) { - // convert secret & base64 key to Uint8Array. - const binaryKey = sodium.from_base64(publicKey.key, sodium.base64_variants.ORIGINAL); - const binarySecretValue = sodium.from_string(secretMap[key].value); + await sodium.ready; + for await (const key of Object.keys(secretMap)) { + // convert secret & base64 key to Uint8Array. + const binaryKey = sodium.from_base64(publicKey.key, sodium.base64_variants.ORIGINAL); + const binarySecretValue = sodium.from_string(secretMap[key].value); - // encrypt secret using libsodium - const encryptedBytes = sodium.crypto_box_seal(binarySecretValue, binaryKey); + // encrypt secret using libsodium + const encryptedBytes = sodium.crypto_box_seal(binarySecretValue, binaryKey); - // convert encrypted Uint8Array to base64 - const encryptedSecretValue = sodium.to_base64(encryptedBytes, sodium.base64_variants.ORIGINAL); + // convert encrypted Uint8Array to base64 + const encryptedSecretValue = sodium.to_base64(encryptedBytes, sodium.base64_variants.ORIGINAL); - try { - await putSecret(client, secretSync, { - secret_name: key, - encrypted_value: encryptedSecretValue, - key_id: publicKey.key_id - }); - } catch (error) { - throw new SecretSyncError({ - error, - secretKey: key - }); - } - } - }); - - if (secretSync.syncOptions.disableSecretDeletion) return; - - for await (const encryptedSecret of encryptedSecrets) { - if (!matchesSchema(encryptedSecret.name, secretSync.environment?.slug || "", secretSync.syncOptions.keySchema)) - // eslint-disable-next-line no-continue - continue; - - if (!(encryptedSecret.name in secretMap)) { - await deleteSecret(client, secretSync, encryptedSecret); - } + try { + await putSecret(secretSync, gatewayService, token, { + secret_name: key, + encrypted_value: encryptedSecretValue, + key_id: publicKey.key_id + }); + } catch (error) { + throw new SecretSyncError({ + error, + secretKey: key + }); } - }); + } + + if (secretSync.syncOptions.disableSecretDeletion) return; + + for await (const encryptedSecret of encryptedSecrets) { + if (!matchesSchema(encryptedSecret.name, secretSync.environment?.slug || "", secretSync.syncOptions.keySchema)) + // eslint-disable-next-line no-continue + continue; + + if (!(encryptedSecret.name in secretMap)) { + await deleteSecret(secretSync, gatewayService, token, encryptedSecret); + } + } }, getSecrets: async (secretSync: TGitHubSyncWithCredentials) => { throw new Error(`${SECRET_SYNC_NAME_MAP[secretSync.destination]} does not support importing secrets.`); @@ -245,14 +255,18 @@ export const GithubSyncFns = { secretMap: TSecretMap, gatewayService: Pick ) => { - await executeWithGitHubGateway(secretSync.connection, gatewayService, async (client) => { - const encryptedSecrets = await getEncryptedSecrets(client, secretSync); + const { connection } = secretSync; + const token = + connection.method === GitHubConnectionMethod.OAuth + ? connection.credentials.accessToken + : await getGitHubAppAuthToken(connection); - for await (const encryptedSecret of encryptedSecrets) { - if (encryptedSecret.name in secretMap) { - await deleteSecret(client, secretSync, encryptedSecret); - } + const encryptedSecrets = await getEncryptedSecrets(secretSync, gatewayService); + + for await (const encryptedSecret of encryptedSecrets) { + if (encryptedSecret.name in secretMap) { + await deleteSecret(secretSync, gatewayService, token, encryptedSecret); } - }); + } } };