From 4abbc00aaa1f954413f0033e7bf432f681504191 Mon Sep 17 00:00:00 2001 From: Henry Fontanier Date: Tue, 23 Jul 2024 19:02:40 +0200 Subject: [PATCH] fix: don't assume organization in GH webhook (#6422) Co-authored-by: Henry Fontanier --- connectors/src/api/webhooks/webhook_github.ts | 36 ++++-- .../connectors/github/lib/github_webhooks.ts | 113 ++++++++++++------ 2 files changed, 105 insertions(+), 44 deletions(-) diff --git a/connectors/src/api/webhooks/webhook_github.ts b/connectors/src/api/webhooks/webhook_github.ts index f9f24b478b1f..836e3f52d2bc 100644 --- a/connectors/src/api/webhooks/webhook_github.ts +++ b/connectors/src/api/webhooks/webhook_github.ts @@ -195,10 +195,14 @@ const _webhookGithubAPIHandler = async ( return rejectEvent(); case "issues": if (isIssuePayload(jsonBody)) { + const login = + "organization" in jsonBody + ? jsonBody.organization.login + : jsonBody.user.login; if (jsonBody.action === "opened" || jsonBody.action === "edited") { return syncIssue( enabledConnectors, - jsonBody.organization.login, + login, jsonBody.repository.name, jsonBody.repository.id, jsonBody.issue.number, @@ -207,7 +211,7 @@ const _webhookGithubAPIHandler = async ( } else if (jsonBody.action === "deleted") { return garbageCollectIssue( enabledConnectors, - jsonBody.organization.login, + login, jsonBody.repository.name, jsonBody.repository.id, jsonBody.issue.number, @@ -222,6 +226,10 @@ const _webhookGithubAPIHandler = async ( case "issue_comment": if (isCommentPayload(jsonBody)) { + const login = + "organization" in jsonBody + ? jsonBody.organization.login + : jsonBody.user.login; if ( jsonBody.action === "created" || jsonBody.action === "edited" || @@ -229,7 +237,7 @@ const _webhookGithubAPIHandler = async ( ) { return syncIssue( enabledConnectors, - jsonBody.organization.login, + login, jsonBody.repository.name, jsonBody.repository.id, jsonBody.issue.number, @@ -243,10 +251,14 @@ const _webhookGithubAPIHandler = async ( case "pull_request": if (isPullRequestPayload(jsonBody)) { + const login = + "organization" in jsonBody + ? jsonBody.organization.login + : jsonBody.user.login; if (jsonBody.action === "opened" || jsonBody.action === "edited") { return syncIssue( enabledConnectors, - jsonBody.organization.login, + login, jsonBody.repository.name, jsonBody.repository.id, jsonBody.pull_request.number, @@ -256,7 +268,7 @@ const _webhookGithubAPIHandler = async ( if (jsonBody.pull_request.merged) { return syncCode( enabledConnectors, - jsonBody.organization.login, + login, jsonBody.repository.name, jsonBody.repository.id, res @@ -272,10 +284,14 @@ const _webhookGithubAPIHandler = async ( case "discussion": if (isDiscussionPayload(jsonBody)) { + const login = + "organization" in jsonBody + ? jsonBody.organization.login + : jsonBody.user.login; if (jsonBody.action === "created" || jsonBody.action === "edited") { return syncDiscussion( enabledConnectors, - jsonBody.organization.login, + login, jsonBody.repository.name, jsonBody.repository.id, jsonBody.discussion.number, @@ -284,7 +300,7 @@ const _webhookGithubAPIHandler = async ( } else if (jsonBody.action === "deleted") { return garbageCollectDiscussion( enabledConnectors, - jsonBody.organization.login, + login, jsonBody.repository.name, jsonBody.repository.id, jsonBody.discussion.number, @@ -298,6 +314,10 @@ const _webhookGithubAPIHandler = async ( case "discussion_comment": if (isDiscussionPayload(jsonBody)) { + const login = + "organization" in jsonBody + ? jsonBody.organization.login + : jsonBody.user.login; if ( jsonBody.action === "created" || jsonBody.action === "edited" || @@ -305,7 +325,7 @@ const _webhookGithubAPIHandler = async ( ) { return syncDiscussion( enabledConnectors, - jsonBody.organization.login, + login, jsonBody.repository.name, jsonBody.repository.id, jsonBody.discussion.number, diff --git a/connectors/src/connectors/github/lib/github_webhooks.ts b/connectors/src/connectors/github/lib/github_webhooks.ts index 0f961ddabe66..4c304db938f5 100644 --- a/connectors/src/connectors/github/lib/github_webhooks.ts +++ b/connectors/src/connectors/github/lib/github_webhooks.ts @@ -57,32 +57,54 @@ const OrganizationSchema = t.type({ login: t.string, }); -const IssuePayloadSchema = t.type({ - action: t.union([ - t.literal("opened"), - t.literal("edited"), - t.literal("deleted"), - ]), - issue: IssueSchema, - organization: OrganizationSchema, - repository: RepositorySchema, +const UserSchema = t.type({ + login: t.string, }); + +const IssuePayloadSchema = t.intersection([ + t.type({ + action: t.union([ + t.literal("opened"), + t.literal("edited"), + t.literal("deleted"), + ]), + issue: IssueSchema, + repository: RepositorySchema, + }), + t.union([ + t.type({ + organization: OrganizationSchema, + }), + t.type({ + user: UserSchema, + }), + ]), +]); type IssuePayload = t.TypeOf; export function isIssuePayload(payload: unknown): payload is IssuePayload { const validation = IssuePayloadSchema.decode(payload); return isRight(validation); } -const CommentPayloadSchema = t.type({ - action: t.union([ - t.literal("created"), - t.literal("edited"), - t.literal("deleted"), +const CommentPayloadSchema = t.intersection([ + t.type({ + action: t.union([ + t.literal("created"), + t.literal("edited"), + t.literal("deleted"), + ]), + issue: IssueSchema, + repository: RepositorySchema, + }), + t.union([ + t.type({ + organization: OrganizationSchema, + }), + t.type({ + user: UserSchema, + }), ]), - issue: IssueSchema, - organization: OrganizationSchema, - repository: RepositorySchema, -}); +]); type CommentPayload = t.TypeOf; export function isCommentPayload(payload: unknown): payload is CommentPayload { const validation = CommentPayloadSchema.decode(payload); @@ -95,16 +117,26 @@ const PullRequestSchema = t.type({ merged: t.boolean, }); -const PullRequestPayloadSchema = t.type({ - action: t.union([ - t.literal("opened"), - t.literal("edited"), - t.literal("closed"), +const PullRequestPayloadSchema = t.intersection([ + t.type({ + action: t.union([ + t.literal("opened"), + t.literal("edited"), + t.literal("closed"), + ]), + pull_request: PullRequestSchema, + repository: RepositorySchema, + }), + t.union([ + t.type({ + organization: OrganizationSchema, + }), + t.type({ + user: UserSchema, + }), ]), - pull_request: PullRequestSchema, - organization: OrganizationSchema, - repository: RepositorySchema, -}); +]); + type PullRequestPayload = t.TypeOf; export function isPullRequestPayload( payload: unknown @@ -117,16 +149,25 @@ const DiscussionSchema = t.type({ number: t.number, }); -const DiscussionPayloadSchema = t.type({ - action: t.union([ - t.literal("created"), - t.literal("edited"), - t.literal("deleted"), +const DiscussionPayloadSchema = t.intersection([ + t.type({ + action: t.union([ + t.literal("created"), + t.literal("edited"), + t.literal("deleted"), + ]), + discussion: DiscussionSchema, + repository: RepositorySchema, + }), + t.union([ + t.type({ + organization: OrganizationSchema, + }), + t.type({ + user: UserSchema, + }), ]), - discussion: DiscussionSchema, - organization: OrganizationSchema, - repository: RepositorySchema, -}); +]); type DiscussionPayload = t.TypeOf; export function isDiscussionPayload( payload: unknown