Patch GitHub integration for organization repos by including correct owner

This commit is contained in:
Tuan Dang
2023-01-18 16:33:24 +07:00
parent 2235069e78
commit 3a6b2084bc
7 changed files with 35 additions and 22 deletions
@@ -41,7 +41,8 @@ export const updateIntegration = async (req: Request, res: Response) => {
isActive, isActive,
target, // vercel-specific integration param target, // vercel-specific integration param
context, // netlify-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; } = req.body;
integration = await Integration.findOneAndUpdate( integration = await Integration.findOneAndUpdate(
@@ -54,7 +55,8 @@ export const updateIntegration = async (req: Request, res: Response) => {
app, app,
target, target,
context, context,
siteId siteId,
owner
}, },
{ {
new: true new: true
+5 -2
View File
@@ -199,13 +199,16 @@ const getAppsGithub = async ({
const repos = (await octokit.request( const repos = (await octokit.request(
'GET /user/repos{?visibility,affiliation,type,sort,direction,per_page,page,since,before}', 'GET /user/repos{?visibility,affiliation,type,sort,direction,per_page,page,since,before}',
{} {
per_page: 100
}
)).data; )).data;
apps = repos apps = repos
.filter((a:any) => a.permissions.admin === true) .filter((a:any) => a.permissions.admin === true)
.map((a: any) => ({ .map((a: any) => ({
name: a.name name: a.name,
owner: a.owner.login
}) })
); );
} catch (err) { } catch (err) {
+6 -7
View File
@@ -530,21 +530,20 @@ const syncSecretsGitHub = async ({
auth: accessToken auth: accessToken
}); });
const user = (await octokit.request('GET /user', {})).data; // const user = (await octokit.request('GET /user', {})).data;
const repoPublicKey: GitHubRepoKey = (await octokit.request( const repoPublicKey: GitHubRepoKey = (await octokit.request(
'GET /repos/{owner}/{repo}/actions/secrets/public-key', 'GET /repos/{owner}/{repo}/actions/secrets/public-key',
{ {
owner: user.login, owner: integration.owner,
repo: integration.app repo: integration.app
} }
)).data; )).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( const encryptedSecrets: GitHubSecretRes = (await octokit.request(
'GET /repos/{owner}/{repo}/actions/secrets', 'GET /repos/{owner}/{repo}/actions/secrets',
{ {
owner: user.login, owner: integration.owner,
repo: integration.app repo: integration.app
} }
)) ))
@@ -560,7 +559,7 @@ const syncSecretsGitHub = async ({
await octokit.request( await octokit.request(
'DELETE /repos/{owner}/{repo}/actions/secrets/{secret_name}', 'DELETE /repos/{owner}/{repo}/actions/secrets/{secret_name}',
{ {
owner: user.login, owner: integration.owner,
repo: integration.app, repo: integration.app,
secret_name: key secret_name: key
} }
@@ -590,7 +589,7 @@ const syncSecretsGitHub = async ({
await octokit.request( await octokit.request(
'PUT /repos/{owner}/{repo}/actions/secrets/{secret_name}', 'PUT /repos/{owner}/{repo}/actions/secrets/{secret_name}',
{ {
owner: user.login, owner: integration.owner,
repo: integration.app, repo: integration.app,
secret_name: key, secret_name: key,
encrypted_value: encryptedSecret, encrypted_value: encryptedSecret,
+6
View File
@@ -15,6 +15,7 @@ export interface IIntegration {
target: string; target: string;
context: string; context: string;
siteId: string; siteId: string;
owner: string;
integration: 'heroku' | 'vercel' | 'netlify' | 'github'; integration: 'heroku' | 'vercel' | 'netlify' | 'github';
integrationAuth: Types.ObjectId; integrationAuth: Types.ObjectId;
} }
@@ -54,6 +55,11 @@ const integrationSchema = new Schema<IIntegration>(
type: String, type: String,
default: null default: null
}, },
owner: {
// github-specific repo owner-login
type: String,
default: null
},
integration: { integration: {
type: String, type: String,
enum: [ enum: [
+1
View File
@@ -24,6 +24,7 @@ router.patch(
body('target').exists(), body('target').exists(),
body('context').exists(), body('context').exists(),
body('siteId').exists(), body('siteId').exists(),
body('owner').exists(),
validateRequest, validateRequest,
integrationController.updateIntegration integrationController.updateIntegration
); );
@@ -26,7 +26,8 @@ interface TIntegration {
interface IntegrationApp { interface IntegrationApp {
name: string; name: string;
siteId: string; siteId?: string;
owner?: string;
} }
type Props = { type Props = {
@@ -42,7 +43,6 @@ const Integration = ({ integration, environments = [] }: Props) => {
slug: '' slug: ''
} }
); );
const [fileState, setFileState] = useState([]);
const router = useRouter(); const router = useRouter();
const [apps, setApps] = useState<IntegrationApp[]>([]); // integration app objects const [apps, setApps] = useState<IntegrationApp[]>([]); // integration app objects
const [integrationApp, setIntegrationApp] = useState(''); // integration app name const [integrationApp, setIntegrationApp] = useState(''); // integration app name
@@ -51,10 +51,6 @@ const Integration = ({ integration, environments = [] }: Props) => {
useEffect(() => { useEffect(() => {
const loadIntegration = async () => { const loadIntegration = async () => {
interface App {
name: string;
siteId?: string;
}
const tempApps: [IntegrationApp] = await getIntegrationApps({ const tempApps: [IntegrationApp] = await getIntegrationApps({
integrationAuthId: integration.integrationAuth integrationAuthId: integration.integrationAuth
@@ -178,7 +174,8 @@ const Integration = ({ integration, environments = [] }: Props) => {
text="Start Integration" text="Start Integration"
onButtonPressed={async () => { onButtonPressed={async () => {
const siteApp = apps.find((app) => app.name === integrationApp); // obj or undefined 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({ await updateIntegration({
integrationId: integration._id, integrationId: integration._id,
@@ -189,9 +186,10 @@ const Integration = ({ integration, environments = [] }: Props) => {
context: integrationContext context: integrationContext
? reverseContextNetlifyMapping[integrationContext] ? reverseContextNetlifyMapping[integrationContext]
: null, : null,
siteId siteId,
owner
}); });
router.reload(); router.reload();
}} }}
color="mineshaft" color="mineshaft"
@@ -12,6 +12,7 @@ import SecurityClient from '@app/components/utilities/SecurityClient';
* @param {String} obj.target - (optional) target (environment) for Vercel integration * @param {String} obj.target - (optional) target (environment) for Vercel integration
* @param {String} obj.context - (optional) context (environment) for Netlify 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.siteId - (optional) app (site_id) for Netlify integration
* @param {String} obj.owner - (optional) owner login of repo for GitHub integration
* @returns * @returns
*/ */
const updateIntegration = ({ const updateIntegration = ({
@@ -21,7 +22,8 @@ const updateIntegration = ({
isActive, isActive,
target, target,
context, context,
siteId siteId,
owner
}: { }: {
integrationId: string; integrationId: string;
app: string; app: string;
@@ -30,6 +32,7 @@ const updateIntegration = ({
target: string | null; target: string | null;
context: string | null; context: string | null;
siteId: string | null; siteId: string | null;
owner: string | null;
}) => }) =>
SecurityClient.fetchCall(`/api/v1/integration/${integrationId}`, { SecurityClient.fetchCall(`/api/v1/integration/${integrationId}`, {
method: 'PATCH', method: 'PATCH',
@@ -42,7 +45,8 @@ const updateIntegration = ({
isActive, isActive,
target, target,
context, context,
siteId siteId,
owner
}) })
}).then(async (res) => { }).then(async (res) => {
if (res && res.status === 200) { if (res && res.status === 200) {