diff --git a/github/github.go b/github/github.go index e2ee652..4a9fb14 100644 --- a/github/github.go +++ b/github/github.go @@ -74,6 +74,7 @@ const ( WorkflowJobEvent Event = "workflow_job" WorkflowRunEvent Event = "workflow_run" GitHubAppAuthorizationEvent Event = "github_app_authorization" + CodeScanningAlertEvent Event = "code_scanning_alert" ) // EventSubtype defines a GitHub Hook Event subtype @@ -353,6 +354,10 @@ func (hook Webhook) Parse(r *http.Request, events ...Event) (interface{}, error) var pl GitHubAppAuthorizationPayload err = json.Unmarshal([]byte(payload), &pl) return pl, err + case CodeScanningAlertEvent: + var pl CodeScanningAlertPayload + err = json.Unmarshal([]byte(payload), &pl) + return pl, err default: return nil, fmt.Errorf("unknown event %s", gitHubEvent) } diff --git a/github/github_test.go b/github/github_test.go index 109d694..39a6203 100644 --- a/github/github_test.go +++ b/github/github_test.go @@ -555,6 +555,15 @@ func TestWebhooks(t *testing.T) { "X-Github-Event": []string{"github_app_authorization"}, }, }, + { + name: "CodeScanningAlertEvent", + event: CodeScanningAlertEvent, + typ: CodeScanningAlertPayload{}, + filename: "../testdata/github/code_scanning_alert.json", + headers: http.Header{ + "X-Github-Event": []string{"code_scanning_alert"}, + }, + }, } for _, tt := range tests { diff --git a/github/payload.go b/github/payload.go index d3e343f..4853de1 100644 --- a/github/payload.go +++ b/github/payload.go @@ -7179,3 +7179,205 @@ type GitHubAppAuthorizationPayload struct { SiteAdmin bool `json:"site_admin"` } `json:"sender"` } + +// CodeScanningAlertPayload contains code scanning alert payload +type CodeScanningAlertPayload struct { + Action string `json:"action"` + Alert struct { + Number int `json:"number"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + Url string `json:"url"` + HtmlUrl string `json:"html_url"` + State string `json:"state"` + FixedAt interface{} `json:"fixed_at"` + DismissedBy interface{} `json:"dismissed_by"` + DismissedAt interface{} `json:"dismissed_at"` + DismissedReason interface{} `json:"dismissed_reason"` + DismissedComment interface{} `json:"dismissed_comment"` + Rule struct { + Id string `json:"id"` + Severity string `json:"severity"` + Description string `json:"description"` + Name string `json:"name"` + Tags []string `json:"tags"` + FullDescription string `json:"full_description"` + Help string `json:"help"` + HelpUri string `json:"help_uri"` + SecuritySeverityLevel string `json:"security_severity_level"` + } `json:"rule"` + Tool struct { + Name string `json:"name"` + Guid interface{} `json:"guid"` + Version string `json:"version"` + } `json:"tool"` + MostRecentInstance struct { + Ref string `json:"ref"` + AnalysisKey string `json:"analysis_key"` + Environment string `json:"environment"` + Category string `json:"category"` + State string `json:"state"` + CommitSha string `json:"commit_sha"` + Message struct { + Text string `json:"text"` + } `json:"message"` + Location struct { + Path string `json:"path"` + StartLine int `json:"start_line"` + EndLine int `json:"end_line"` + StartColumn int `json:"start_column"` + EndColumn int `json:"end_column"` + } `json:"location"` + Classifications []interface{} `json:"classifications"` + } `json:"most_recent_instance"` + InstancesUrl string `json:"instances_url"` + } `json:"alert"` + Ref string `json:"ref"` + CommitOid string `json:"commit_oid"` + Repository struct { + Id int `json:"id"` + NodeId string `json:"node_id"` + Name string `json:"name"` + FullName string `json:"full_name"` + Private bool `json:"private"` + Owner struct { + Login string `json:"login"` + Id int `json:"id"` + NodeId string `json:"node_id"` + AvatarUrl string `json:"avatar_url"` + GravatarId string `json:"gravatar_id"` + Url string `json:"url"` + HtmlUrl string `json:"html_url"` + FollowersUrl string `json:"followers_url"` + FollowingUrl string `json:"following_url"` + GistsUrl string `json:"gists_url"` + StarredUrl string `json:"starred_url"` + SubscriptionsUrl string `json:"subscriptions_url"` + OrganizationsUrl string `json:"organizations_url"` + ReposUrl string `json:"repos_url"` + EventsUrl string `json:"events_url"` + ReceivedEventsUrl string `json:"received_events_url"` + Type string `json:"type"` + SiteAdmin bool `json:"site_admin"` + } `json:"owner"` + HtmlUrl string `json:"html_url"` + Description string `json:"description"` + Fork bool `json:"fork"` + Url string `json:"url"` + ForksUrl string `json:"forks_url"` + KeysUrl string `json:"keys_url"` + CollaboratorsUrl string `json:"collaborators_url"` + TeamsUrl string `json:"teams_url"` + HooksUrl string `json:"hooks_url"` + IssueEventsUrl string `json:"issue_events_url"` + EventsUrl string `json:"events_url"` + AssigneesUrl string `json:"assignees_url"` + BranchesUrl string `json:"branches_url"` + TagsUrl string `json:"tags_url"` + BlobsUrl string `json:"blobs_url"` + GitTagsUrl string `json:"git_tags_url"` + GitRefsUrl string `json:"git_refs_url"` + TreesUrl string `json:"trees_url"` + StatusesUrl string `json:"statuses_url"` + LanguagesUrl string `json:"languages_url"` + StargazersUrl string `json:"stargazers_url"` + ContributorsUrl string `json:"contributors_url"` + SubscribersUrl string `json:"subscribers_url"` + SubscriptionUrl string `json:"subscription_url"` + CommitsUrl string `json:"commits_url"` + GitCommitsUrl string `json:"git_commits_url"` + CommentsUrl string `json:"comments_url"` + IssueCommentUrl string `json:"issue_comment_url"` + ContentsUrl string `json:"contents_url"` + CompareUrl string `json:"compare_url"` + MergesUrl string `json:"merges_url"` + ArchiveUrl string `json:"archive_url"` + DownloadsUrl string `json:"downloads_url"` + IssuesUrl string `json:"issues_url"` + PullsUrl string `json:"pulls_url"` + MilestonesUrl string `json:"milestones_url"` + NotificationsUrl string `json:"notifications_url"` + LabelsUrl string `json:"labels_url"` + ReleasesUrl string `json:"releases_url"` + DeploymentsUrl string `json:"deployments_url"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + PushedAt time.Time `json:"pushed_at"` + GitUrl string `json:"git_url"` + SshUrl string `json:"ssh_url"` + CloneUrl string `json:"clone_url"` + SvnUrl string `json:"svn_url"` + Homepage string `json:"homepage"` + Size int `json:"size"` + StargazersCount int `json:"stargazers_count"` + WatchersCount int `json:"watchers_count"` + Language string `json:"language"` + HasIssues bool `json:"has_issues"` + HasProjects bool `json:"has_projects"` + HasDownloads bool `json:"has_downloads"` + HasWiki bool `json:"has_wiki"` + HasPages bool `json:"has_pages"` + HasDiscussions bool `json:"has_discussions"` + ForksCount int `json:"forks_count"` + MirrorUrl interface{} `json:"mirror_url"` + Archived bool `json:"archived"` + Disabled bool `json:"disabled"` + OpenIssuesCount int `json:"open_issues_count"` + License interface{} `json:"license"` + AllowForking bool `json:"allow_forking"` + IsTemplate bool `json:"is_template"` + WebCommitSignoffRequired bool `json:"web_commit_signoff_required"` + Topics []string `json:"topics"` + Visibility string `json:"visibility"` + Forks int `json:"forks"` + OpenIssues int `json:"open_issues"` + Watchers int `json:"watchers"` + DefaultBranch string `json:"default_branch"` + } `json:"repository"` + Organization struct { + Login string `json:"login"` + Id int `json:"id"` + NodeId string `json:"node_id"` + Url string `json:"url"` + ReposUrl string `json:"repos_url"` + EventsUrl string `json:"events_url"` + HooksUrl string `json:"hooks_url"` + IssuesUrl string `json:"issues_url"` + MembersUrl string `json:"members_url"` + PublicMembersUrl string `json:"public_members_url"` + AvatarUrl string `json:"avatar_url"` + Description string `json:"description"` + } `json:"organization"` + Enterprise struct { + Id int `json:"id"` + Slug string `json:"slug"` + Name string `json:"name"` + NodeId string `json:"node_id"` + AvatarUrl string `json:"avatar_url"` + Description string `json:"description"` + WebsiteUrl string `json:"website_url"` + HtmlUrl string `json:"html_url"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + } `json:"enterprise"` + Sender struct { + Login string `json:"login"` + Id int `json:"id"` + NodeId string `json:"node_id"` + AvatarUrl string `json:"avatar_url"` + GravatarId string `json:"gravatar_id"` + Url string `json:"url"` + HtmlUrl string `json:"html_url"` + FollowersUrl string `json:"followers_url"` + FollowingUrl string `json:"following_url"` + GistsUrl string `json:"gists_url"` + StarredUrl string `json:"starred_url"` + SubscriptionsUrl string `json:"subscriptions_url"` + OrganizationsUrl string `json:"organizations_url"` + ReposUrl string `json:"repos_url"` + EventsUrl string `json:"events_url"` + ReceivedEventsUrl string `json:"received_events_url"` + Type string `json:"type"` + SiteAdmin bool `json:"site_admin"` + } `json:"sender"` +} diff --git a/testdata/github/code_scanning_alert.json b/testdata/github/code_scanning_alert.json new file mode 100644 index 0000000..38ff286 --- /dev/null +++ b/testdata/github/code_scanning_alert.json @@ -0,0 +1,208 @@ +{ + "action": "reopened_by_user", + "alert": { + "number": 2996, + "created_at": "2023-12-12T09:04:37Z", + "updated_at": "2023-12-17T13:40:01Z", + "url": "https://github.com/api/v3/repos/dummyrepo/non-existing/code-scanning/alerts/2996", + "html_url": "https://github.com/dummyrepo/non-existing/security/code-scanning/2996", + "state": "open", + "fixed_at": null, + "dismissed_by": null, + "dismissed_at": null, + "dismissed_reason": null, + "dismissed_comment": null, + "rule": { + "id": "CVE-2023-123456", + "severity": "note", + "description": "curl: cookie injection with none file", + "name": "OsPackageVulnerability", + "tags": [ + "LOW", + "security", + "vulnerability" + ], + "full_description": "This flaw allows an attacker to insert cookies at will into a running program.", + "help": "**Vulnerability CVE-2023-123456**\n", + "help_uri": "https://avd.aquasec.com/nvd/cve-2023-123456", + "security_severity_level": "low" + }, + "tool": { + "name": "Trivy", + "guid": null, + "version": "0.47.0" + }, + "most_recent_instance": { + "ref": "refs/heads/main", + "analysis_key": ".github/workflows/image.yml", + "environment": "{}", + "category": ".github/workflows/image.yml", + "state": "open", + "commit_sha": "285b53e372a84db195d9cdaecea544601045c9e0", + "message": { + "text": "Package: libcurl3-gnutls\nInstalled Version: 7.74.0-1.3+deb11u1\nVulnerability CVE-2023-123456\nSeverity: LOW\nFixed Version: 7.74.0-1.3+deb11u10\nLink: [CVE-2023-123456](https://avd.aquasec.com/nvd/cve-2023-123456)" + }, + "location": { + "path": "some-path", + "start_line": 1, + "end_line": 1, + "start_column": 1, + "end_column": 1 + }, + "classifications": [ + + ] + }, + "instances_url": "https://github.com/api/v3/repos/dummyrepo/non-existing/code-scanning/alerts/2996/instances" + }, + "ref": "", + "commit_oid": "", + "repository": { + "id": 89033, + "node_id": "MDEwOlJlcG9zaXRvcnk4OTAzMw==", + "name": "somerepo", + "full_name": "someorg/somerepo", + "private": false, + "owner": { + "login": "someorg", + "id": 33886, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjMzODg2", + "avatar_url": "https://avatars.github.com/u/33886?", + "gravatar_id": "", + "url": "https://github.com/api/v3/users/someorg", + "html_url": "https://github.com/someorg", + "followers_url": "https://github.com/api/v3/users/someorg/followers", + "following_url": "https://github.com/api/v3/users/someorg/following{/other_user}", + "gists_url": "https://github.com/api/v3/users/someorg/gists{/gist_id}", + "starred_url": "https://github.com/api/v3/users/someorg/starred{/owner}{/repo}", + "subscriptions_url": "https://github.com/api/v3/users/someorg/subscriptions", + "organizations_url": "https://github.com/api/v3/users/someorg/orgs", + "repos_url": "https://github.com/api/v3/users/someorg/repos", + "events_url": "https://github.com/api/v3/users/someorg/events{/privacy}", + "received_events_url": "https://github.com/api/v3/users/someorg/received_events", + "type": "Organization", + "site_admin": false + }, + "html_url": "https://github.com/someorg/somerepo", + "description": "Some description", + "fork": false, + "url": "https://github.com/api/v3/repos/someorg/somerepo", + "forks_url": "https://github.com/api/v3/repos/dummyrepo/non-existing/forks", + "keys_url": "https://github.com/api/v3/repos/dummyrepo/non-existing/keys{/key_id}", + "collaborators_url": "https://github.com/api/v3/repos/dummyrepo/non-existing/collaborators{/collaborator}", + "teams_url": "https://github.com/api/v3/repos/dummyrepo/non-existing/teams", + "hooks_url": "https://github.com/api/v3/repos/dummyrepo/non-existing/hooks", + "issue_events_url": "https://github.com/api/v3/repos/dummyrepo/non-existing/issues/events{/number}", + "events_url": "https://github.com/api/v3/repos/dummyrepo/non-existing/events", + "assignees_url": "https://github.com/api/v3/repos/dummyrepo/non-existing/assignees{/user}", + "branches_url": "https://github.com/api/v3/repos/dummyrepo/non-existing/branches{/branch}", + "tags_url": "https://github.com/api/v3/repos/dummyrepo/non-existing/tags", + "blobs_url": "https://github.com/api/v3/repos/dummyrepo/non-existing/git/blobs{/sha}", + "git_tags_url": "https://github.com/api/v3/repos/dummyrepo/non-existing/git/tags{/sha}", + "git_refs_url": "https://github.com/api/v3/repos/dummyrepo/non-existing/git/refs{/sha}", + "trees_url": "https://github.com/api/v3/repos/dummyrepo/non-existing/git/trees{/sha}", + "statuses_url": "https://github.com/api/v3/repos/dummyrepo/non-existing/statuses/{sha}", + "languages_url": "https://github.com/api/v3/repos/dummyrepo/non-existing/languages", + "stargazers_url": "https://github.com/api/v3/repos/dummyrepo/non-existing/stargazers", + "contributors_url": "https://github.com/api/v3/repos/dummyrepo/non-existing/contributors", + "subscribers_url": "https://github.com/api/v3/repos/dummyrepo/non-existing/subscribers", + "subscription_url": "https://github.com/api/v3/repos/dummyrepo/non-existing/subscription", + "commits_url": "https://github.com/api/v3/repos/dummyrepo/non-existing/commits{/sha}", + "git_commits_url": "https://github.com/api/v3/repos/dummyrepo/non-existing/git/commits{/sha}", + "comments_url": "https://github.com/api/v3/repos/dummyrepo/non-existing/comments{/number}", + "issue_comment_url": "https://github.com/api/v3/repos/dummyrepo/non-existing/issues/comments{/number}", + "contents_url": "https://github.com/api/v3/repos/dummyrepo/non-existing/contents/{+path}", + "compare_url": "https://github.com/api/v3/repos/dummyrepo/non-existing/compare/{base}...{head}", + "merges_url": "https://github.com/api/v3/repos/dummyrepo/non-existing/merges", + "archive_url": "https://github.com/api/v3/repos/dummyrepo/non-existing/{archive_format}{/ref}", + "downloads_url": "https://github.com/api/v3/repos/dummyrepo/non-existing/downloads", + "issues_url": "https://github.com/api/v3/repos/dummyrepo/non-existing/issues{/number}", + "pulls_url": "https://github.com/api/v3/repos/dummyrepo/non-existing/pulls{/number}", + "milestones_url": "https://github.com/api/v3/repos/dummyrepo/non-existing/milestones{/number}", + "notifications_url": "https://github.com/api/v3/repos/dummyrepo/non-existing/notifications{?since,all,participating}", + "labels_url": "https://github.com/api/v3/repos/dummyrepo/non-existing/labels{/name}", + "releases_url": "https://github.com/api/v3/repos/dummyrepo/non-existing/releases{/id}", + "deployments_url": "https://github.com/api/v3/repos/dummyrepo/non-existing/deployments", + "created_at": "2022-01-24T06:53:38Z", + "updated_at": "2023-06-15T13:56:45Z", + "pushed_at": "2023-12-15T09:52:10Z", + "git_url": "git://github.com/somerepo/someorg.git", + "ssh_url": "git@github.com:somerepo/someorg.git", + "clone_url": "https://github.com/somerepo/someorg.git", + "svn_url": "https://github.com/somerepo/someorg", + "homepage": "", + "size": 28828, + "stargazers_count": 0, + "watchers_count": 0, + "language": "Shell", + "has_issues": true, + "has_projects": true, + "has_downloads": true, + "has_wiki": false, + "has_pages": false, + "has_discussions": false, + "forks_count": 1, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 10, + "license": null, + "allow_forking": true, + "is_template": false, + "web_commit_signoff_required": false, + "topics": [ + "sometopic" + ], + "visibility": "public", + "forks": 1, + "open_issues": 10, + "watchers": 0, + "default_branch": "main" + }, + "organization": { + "login": "someorg", + "id": 33886, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjMzODg2", + "url": "https://github.com/api/v3/orgs/someorg", + "repos_url": "https://github.com/api/v3/orgs/someorg/repos", + "events_url": "https://github.com/api/v3/orgs/someorg/events", + "hooks_url": "https://github.com/api/v3/orgs/someorg/hooks", + "issues_url": "https://github.com/api/v3/orgs/someorg/issues", + "members_url": "https://github.com/api/v3/orgs/someorg/members{/member}", + "public_members_url": "https://github.com/api/v3/orgs/someorg/public_members{/member}", + "avatar_url": "https://avatars.github.com/u/33886?", + "description": "Some description." + }, + "enterprise": { + "id": 1, + "slug": "some-company", + "name": "Some Company", + "node_id": "MDEwOkVudGVabcJpc2Ux", + "avatar_url": "https://avatars.github.com/b/1?", + "description": "", + "website_url": "https://github.com/", + "html_url": "https://github.com/enterprises/some-company", + "created_at": "2018-11-29T17:39:39Z", + "updated_at": "2023-06-20T14:11:12Z" + }, + "sender": { + "login": "some-user", + "id": 9773, + "node_id": "MDQ6VXabcdk3NzM=", + "avatar_url": "https://avatars.github.com/u/9773?", + "gravatar_id": "", + "url": "https://github.com/api/v3/users/some-user", + "html_url": "https://github.com/some-user", + "followers_url": "https://github.com/api/v3/users/some-user/followers", + "following_url": "https://github.com/api/v3/users/some-user/following{/other_user}", + "gists_url": "https://github.com/api/v3/users/some-user/gists{/gist_id}", + "starred_url": "https://github.com/api/v3/users/some-user/starred{/owner}{/repo}", + "subscriptions_url": "https://github.com/api/v3/users/some-user/subscriptions", + "organizations_url": "https://github.com/api/v3/users/some-user/orgs", + "repos_url": "https://github.com/api/v3/users/some-user/repos", + "events_url": "https://github.com/api/v3/users/some-user/events{/privacy}", + "received_events_url": "https://github.com/api/v3/users/some-user/received_events", + "type": "User", + "site_admin": false + } +} \ No newline at end of file