diff --git a/src/handlers/payout/action.ts b/src/handlers/payout/action.ts index 3d92bee7e..3220f5773 100644 --- a/src/handlers/payout/action.ts +++ b/src/handlers/payout/action.ts @@ -3,6 +3,7 @@ import { getPenalty, getWalletAddress, getWalletMultiplier, removePenalty } from import { getBotConfig, getBotContext, getLogger } from "../../bindings"; import { addLabelToIssue, + checkUserPermissionForRepoAndOrg, clearAllPriceLabelsOnIssue, deleteLabel, generatePermit2Signature, @@ -34,6 +35,10 @@ export const handleIssueClosed = async () => { if (!issue) return; + const userHasPermission = await checkUserPermissionForRepoAndOrg(payload.sender.login, context); + + if (!userHasPermission) return "Permit generation skipped because this issue has been closed by an external contributor."; + const comments = await getAllIssueComments(issue.number); const wasReopened = await wasIssueReopened(issue.number); diff --git a/src/helpers/issue.ts b/src/helpers/issue.ts index 82e11a8d7..5127c1c6c 100644 --- a/src/helpers/issue.ts +++ b/src/helpers/issue.ts @@ -330,6 +330,49 @@ export const removeAssignees = async (issue_number: number, assignees: string[]) } }; +export const checkUserPermissionForRepoAndOrg = async (username: string, context: Context): Promise => { + const permissionForRepo = await checkUserPermissionForRepo(username, context); + const permissionForOrg = await checkUserPermissionForOrg(username, context); + + return permissionForOrg || permissionForRepo; +}; + +export const checkUserPermissionForRepo = async (username: string, context: Context): Promise => { + const logger = getLogger(); + const payload = context.payload as Payload; + + try { + const res = await context.octokit.rest.repos.checkCollaborator({ + owner: payload.repository.owner.login, + repo: payload.repository.name, + username, + }); + + return res.status === 204; + } catch (e: unknown) { + logger.error(`Checking if user permisson for repo failed!, reason: ${e}`); + return false; + } +}; + +export const checkUserPermissionForOrg = async (username: string, context: Context): Promise => { + const logger = getLogger(); + const payload = context.payload as Payload; + if (!payload.organization) return false; + + try { + const res = await context.octokit.rest.orgs.checkMembershipForUser({ + org: payload.organization.login, + username, + }); + // @ts-expect-error This looks like a bug in octokit. (https://github.com/octokit/rest.js/issues/188) + return res.status === 204; + } catch (e: unknown) { + logger.error(`Checking if user permisson for org failed!, reason: ${e}`); + return false; + } +}; + export const getUserPermission = async (username: string, context: Context): Promise => { const logger = getLogger(); const payload = context.payload as Payload;