From 3a6b2084bc51802630746a66ef101bf8ce257542 Mon Sep 17 00:00:00 2001 From: Tuan Dang Date: Wed, 18 Jan 2023 16:33:24 +0700 Subject: [PATCH] Patch GitHub integration for organization repos by including correct owner --- .../src/controllers/v1/integrationController.ts | 6 ++++-- backend/src/integrations/apps.ts | 7 +++++-- backend/src/integrations/sync.ts | 13 ++++++------- backend/src/models/integration.ts | 6 ++++++ backend/src/routes/v1/integration.ts | 1 + .../src/components/integrations/Integration.tsx | 16 +++++++--------- .../pages/api/integrations/updateIntegration.ts | 8 ++++++-- 7 files changed, 35 insertions(+), 22 deletions(-) diff --git a/backend/src/controllers/v1/integrationController.ts b/backend/src/controllers/v1/integrationController.ts index c057949591..4f02836a1d 100644 --- a/backend/src/controllers/v1/integrationController.ts +++ b/backend/src/controllers/v1/integrationController.ts @@ -41,7 +41,8 @@ export const updateIntegration = async (req: Request, res: Response) => { isActive, target, // vercel-specific integration param context, // netlify-specific integration param - siteId // netlify-specific integration param + siteId, // netlify-specific integration param + owner // github-specific integration param } = req.body; integration = await Integration.findOneAndUpdate( @@ -54,7 +55,8 @@ export const updateIntegration = async (req: Request, res: Response) => { app, target, context, - siteId + siteId, + owner }, { new: true diff --git a/backend/src/integrations/apps.ts b/backend/src/integrations/apps.ts index 02a1904c70..79187c6926 100644 --- a/backend/src/integrations/apps.ts +++ b/backend/src/integrations/apps.ts @@ -199,13 +199,16 @@ const getAppsGithub = async ({ const repos = (await octokit.request( 'GET /user/repos{?visibility,affiliation,type,sort,direction,per_page,page,since,before}', - {} + { + per_page: 100 + } )).data; apps = repos .filter((a:any) => a.permissions.admin === true) .map((a: any) => ({ - name: a.name + name: a.name, + owner: a.owner.login }) ); } catch (err) { diff --git a/backend/src/integrations/sync.ts b/backend/src/integrations/sync.ts index 0ae57dc594..bfe2887c61 100644 --- a/backend/src/integrations/sync.ts +++ b/backend/src/integrations/sync.ts @@ -530,21 +530,20 @@ const syncSecretsGitHub = async ({ auth: accessToken }); - const user = (await octokit.request('GET /user', {})).data; - + // const user = (await octokit.request('GET /user', {})).data; const repoPublicKey: GitHubRepoKey = (await octokit.request( 'GET /repos/{owner}/{repo}/actions/secrets/public-key', { - owner: user.login, + owner: integration.owner, repo: integration.app } )).data; - // // Get local copy of decrypted secrets. We cannot decrypt them as we dont have access to GH private key + // Get local copy of decrypted secrets. We cannot decrypt them as we dont have access to GH private key const encryptedSecrets: GitHubSecretRes = (await octokit.request( 'GET /repos/{owner}/{repo}/actions/secrets', { - owner: user.login, + owner: integration.owner, repo: integration.app } )) @@ -560,7 +559,7 @@ const syncSecretsGitHub = async ({ await octokit.request( 'DELETE /repos/{owner}/{repo}/actions/secrets/{secret_name}', { - owner: user.login, + owner: integration.owner, repo: integration.app, secret_name: key } @@ -590,7 +589,7 @@ const syncSecretsGitHub = async ({ await octokit.request( 'PUT /repos/{owner}/{repo}/actions/secrets/{secret_name}', { - owner: user.login, + owner: integration.owner, repo: integration.app, secret_name: key, encrypted_value: encryptedSecret, diff --git a/backend/src/models/integration.ts b/backend/src/models/integration.ts index 98e4934d90..397fb48b31 100644 --- a/backend/src/models/integration.ts +++ b/backend/src/models/integration.ts @@ -15,6 +15,7 @@ export interface IIntegration { target: string; context: string; siteId: string; + owner: string; integration: 'heroku' | 'vercel' | 'netlify' | 'github'; integrationAuth: Types.ObjectId; } @@ -54,6 +55,11 @@ const integrationSchema = new Schema( type: String, default: null }, + owner: { + // github-specific repo owner-login + type: String, + default: null + }, integration: { type: String, enum: [ diff --git a/backend/src/routes/v1/integration.ts b/backend/src/routes/v1/integration.ts index ea589162a5..b8604fc610 100644 --- a/backend/src/routes/v1/integration.ts +++ b/backend/src/routes/v1/integration.ts @@ -24,6 +24,7 @@ router.patch( body('target').exists(), body('context').exists(), body('siteId').exists(), + body('owner').exists(), validateRequest, integrationController.updateIntegration ); diff --git a/frontend/src/components/integrations/Integration.tsx b/frontend/src/components/integrations/Integration.tsx index 38b005844a..fc034637cb 100644 --- a/frontend/src/components/integrations/Integration.tsx +++ b/frontend/src/components/integrations/Integration.tsx @@ -26,7 +26,8 @@ interface TIntegration { interface IntegrationApp { name: string; - siteId: string; + siteId?: string; + owner?: string; } type Props = { @@ -42,7 +43,6 @@ const Integration = ({ integration, environments = [] }: Props) => { slug: '' } ); - const [fileState, setFileState] = useState([]); const router = useRouter(); const [apps, setApps] = useState([]); // integration app objects const [integrationApp, setIntegrationApp] = useState(''); // integration app name @@ -51,10 +51,6 @@ const Integration = ({ integration, environments = [] }: Props) => { useEffect(() => { const loadIntegration = async () => { - interface App { - name: string; - siteId?: string; - } const tempApps: [IntegrationApp] = await getIntegrationApps({ integrationAuthId: integration.integrationAuth @@ -178,7 +174,8 @@ const Integration = ({ integration, environments = [] }: Props) => { text="Start Integration" onButtonPressed={async () => { const siteApp = apps.find((app) => app.name === integrationApp); // obj or undefined - const siteId = siteApp?.siteId ? siteApp.siteId : null; + const siteId = siteApp?.siteId ?? null; + const owner = siteApp?.owner ?? null; await updateIntegration({ integrationId: integration._id, @@ -189,9 +186,10 @@ const Integration = ({ integration, environments = [] }: Props) => { context: integrationContext ? reverseContextNetlifyMapping[integrationContext] : null, - siteId + siteId, + owner }); - + router.reload(); }} color="mineshaft" diff --git a/frontend/src/pages/api/integrations/updateIntegration.ts b/frontend/src/pages/api/integrations/updateIntegration.ts index 27047aa7cc..9b9cd02e02 100644 --- a/frontend/src/pages/api/integrations/updateIntegration.ts +++ b/frontend/src/pages/api/integrations/updateIntegration.ts @@ -12,6 +12,7 @@ import SecurityClient from '@app/components/utilities/SecurityClient'; * @param {String} obj.target - (optional) target (environment) for Vercel integration * @param {String} obj.context - (optional) context (environment) for Netlify integration * @param {String} obj.siteId - (optional) app (site_id) for Netlify integration + * @param {String} obj.owner - (optional) owner login of repo for GitHub integration * @returns */ const updateIntegration = ({ @@ -21,7 +22,8 @@ const updateIntegration = ({ isActive, target, context, - siteId + siteId, + owner }: { integrationId: string; app: string; @@ -30,6 +32,7 @@ const updateIntegration = ({ target: string | null; context: string | null; siteId: string | null; + owner: string | null; }) => SecurityClient.fetchCall(`/api/v1/integration/${integrationId}`, { method: 'PATCH', @@ -42,7 +45,8 @@ const updateIntegration = ({ isActive, target, context, - siteId + siteId, + owner }) }).then(async (res) => { if (res && res.status === 200) {