Skip to content

Commit ac3b1e2

Browse files
authored
Add support for list Code Scan Alerts by Org (#2346)
1 parent 8992d1e commit ac3b1e2

File tree

4 files changed

+248
-1
lines changed

4 files changed

+248
-1
lines changed

github/code-scanning.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ type Tool struct {
6868
// GitHub API docs: https://docs.github.com/en/rest/reference/code-scanning#list-code-scanning-alerts-for-a-repository
6969
type Alert struct {
7070
Number *int `json:"number,omitempty"`
71+
Repository *Repository `json:"repository,omitempty"`
7172
RuleID *string `json:"rule_id,omitempty"`
7273
RuleSeverity *string `json:"rule_severity,omitempty"`
7374
RuleDescription *string `json:"rule_description,omitempty"`
@@ -175,6 +176,33 @@ type SarifID struct {
175176
URL *string `json:"url,omitempty"`
176177
}
177178

179+
// ListAlertsForOrg lists code scanning alerts for an org.
180+
//
181+
// You must use an access token with the security_events scope to use this endpoint. GitHub Apps must have the security_events
182+
// read permission to use this endpoint.
183+
//
184+
// GitHub API docs: https://docs.github.com/en/rest/code-scanning#list-code-scanning-alerts-for-an-organization
185+
func (s *CodeScanningService) ListAlertsForOrg(ctx context.Context, org string, opts *AlertListOptions) ([]*Alert, *Response, error) {
186+
u := fmt.Sprintf("orgs/%v/code-scanning/alerts", org)
187+
u, err := addOptions(u, opts)
188+
if err != nil {
189+
return nil, nil, err
190+
}
191+
192+
req, err := s.client.NewRequest("GET", u, nil)
193+
if err != nil {
194+
return nil, nil, err
195+
}
196+
197+
var alerts []*Alert
198+
resp, err := s.client.Do(ctx, req, &alerts)
199+
if err != nil {
200+
return nil, resp, err
201+
}
202+
203+
return alerts, resp, nil
204+
}
205+
178206
// ListAlertsForRepo lists code scanning alerts for a repository.
179207
//
180208
// Lists all open code scanning alerts for the default branch (usually master) and protected branches in a repository.

github/code-scanning_test.go

Lines changed: 205 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,210 @@ func TestCodeScanningService_UploadSarif(t *testing.T) {
8989
})
9090
}
9191

92+
func TestCodeScanningService_ListAlertsForOrg(t *testing.T) {
93+
client, mux, _, teardown := setup()
94+
defer teardown()
95+
96+
mux.HandleFunc("/orgs/o/code-scanning/alerts", func(w http.ResponseWriter, r *http.Request) {
97+
testMethod(t, r, "GET")
98+
testFormValues(t, r, values{"state": "open", "ref": "heads/master"})
99+
fmt.Fprint(w, `[{
100+
"repository": {
101+
"id": 1,
102+
"name": "n",
103+
"url": "url"
104+
},
105+
"rule_id":"js/trivial-conditional",
106+
"rule_severity":"warning",
107+
"rule_description":"Useless conditional",
108+
"tool": {
109+
"name": "CodeQL",
110+
"guid": null,
111+
"version": "1.4.0"
112+
},
113+
"rule": {
114+
"id": "js/trivial-conditional",
115+
"severity": "warning",
116+
"description": "Useless conditional",
117+
"name": "js/trivial-conditional",
118+
"full_description": "Expression has no effect",
119+
"help": "Expression has no effect"
120+
},
121+
"most_recent_instance": {
122+
"ref": "refs/heads/main",
123+
"state": "open",
124+
"commit_sha": "abcdefg12345",
125+
"message": {
126+
"text": "This path depends on a user-provided value."
127+
},
128+
"location": {
129+
"path": "spec-main/api-session-spec.ts",
130+
"start_line": 917,
131+
"end_line": 917,
132+
"start_column": 7,
133+
"end_column": 18
134+
},
135+
"classifications": [
136+
"test"
137+
]
138+
},
139+
"created_at":"2020-05-06T12:00:00Z",
140+
"state":"open",
141+
"closed_by":null,
142+
"closed_at":null,
143+
"url":"https://api.github.com/repos/o/r/code-scanning/alerts/25",
144+
"html_url":"https://github.com/o/r/security/code-scanning/25"
145+
},
146+
{
147+
"rule_id":"js/useless-expression",
148+
"rule_severity":"warning",
149+
"rule_description":"Expression has no effect",
150+
"tool": {
151+
"name": "CodeQL",
152+
"guid": null,
153+
"version": "1.4.0"
154+
},
155+
"rule": {
156+
"id": "js/useless-expression",
157+
"severity": "warning",
158+
"description": "Expression has no effect",
159+
"name": "js/useless-expression",
160+
"full_description": "Expression has no effect",
161+
"help": "Expression has no effect"
162+
},
163+
"most_recent_instance": {
164+
"ref": "refs/heads/main",
165+
"state": "open",
166+
"commit_sha": "abcdefg12345",
167+
"message": {
168+
"text": "This path depends on a user-provided value."
169+
},
170+
"location": {
171+
"path": "spec-main/api-session-spec.ts",
172+
"start_line": 917,
173+
"end_line": 917,
174+
"start_column": 7,
175+
"end_column": 18
176+
},
177+
"classifications": [
178+
"test"
179+
]
180+
},
181+
"created_at":"2020-05-06T12:00:00Z",
182+
"state":"open",
183+
"closed_by":null,
184+
"closed_at":null,
185+
"url":"https://api.github.com/repos/o/r/code-scanning/alerts/88",
186+
"html_url":"https://github.com/o/r/security/code-scanning/88"
187+
}]`)
188+
})
189+
190+
opts := &AlertListOptions{State: "open", Ref: "heads/master"}
191+
ctx := context.Background()
192+
alerts, _, err := client.CodeScanning.ListAlertsForOrg(ctx, "o", opts)
193+
if err != nil {
194+
t.Errorf("CodeScanning.ListAlertsForOrg returned error: %v", err)
195+
}
196+
197+
date := Timestamp{time.Date(2020, time.May, 06, 12, 00, 00, 0, time.UTC)}
198+
want := []*Alert{
199+
{
200+
Repository: &Repository{
201+
ID: Int64(1),
202+
URL: String("url"),
203+
Name: String("n"),
204+
},
205+
RuleID: String("js/trivial-conditional"),
206+
RuleSeverity: String("warning"),
207+
RuleDescription: String("Useless conditional"),
208+
Tool: &Tool{Name: String("CodeQL"), GUID: nil, Version: String("1.4.0")},
209+
Rule: &Rule{
210+
ID: String("js/trivial-conditional"),
211+
Severity: String("warning"),
212+
Description: String("Useless conditional"),
213+
Name: String("js/trivial-conditional"),
214+
FullDescription: String("Expression has no effect"),
215+
Help: String("Expression has no effect"),
216+
},
217+
CreatedAt: &date,
218+
State: String("open"),
219+
ClosedBy: nil,
220+
ClosedAt: nil,
221+
URL: String("https://api.github.com/repos/o/r/code-scanning/alerts/25"),
222+
HTMLURL: String("https://github.com/o/r/security/code-scanning/25"),
223+
MostRecentInstance: &MostRecentInstance{
224+
Ref: String("refs/heads/main"),
225+
State: String("open"),
226+
CommitSHA: String("abcdefg12345"),
227+
Message: &Message{
228+
Text: String("This path depends on a user-provided value."),
229+
},
230+
Location: &Location{
231+
Path: String("spec-main/api-session-spec.ts"),
232+
StartLine: Int(917),
233+
EndLine: Int(917),
234+
StartColumn: Int(7),
235+
EndColumn: Int(18),
236+
},
237+
Classifications: []string{"test"},
238+
},
239+
},
240+
{
241+
RuleID: String("js/useless-expression"),
242+
RuleSeverity: String("warning"),
243+
RuleDescription: String("Expression has no effect"),
244+
Tool: &Tool{Name: String("CodeQL"), GUID: nil, Version: String("1.4.0")},
245+
Rule: &Rule{
246+
ID: String("js/useless-expression"),
247+
Severity: String("warning"),
248+
Description: String("Expression has no effect"),
249+
Name: String("js/useless-expression"),
250+
FullDescription: String("Expression has no effect"),
251+
Help: String("Expression has no effect"),
252+
},
253+
CreatedAt: &date,
254+
State: String("open"),
255+
ClosedBy: nil,
256+
ClosedAt: nil,
257+
URL: String("https://api.github.com/repos/o/r/code-scanning/alerts/88"),
258+
HTMLURL: String("https://github.com/o/r/security/code-scanning/88"),
259+
MostRecentInstance: &MostRecentInstance{
260+
Ref: String("refs/heads/main"),
261+
State: String("open"),
262+
CommitSHA: String("abcdefg12345"),
263+
Message: &Message{
264+
Text: String("This path depends on a user-provided value."),
265+
},
266+
Location: &Location{
267+
Path: String("spec-main/api-session-spec.ts"),
268+
StartLine: Int(917),
269+
EndLine: Int(917),
270+
StartColumn: Int(7),
271+
EndColumn: Int(18),
272+
},
273+
Classifications: []string{"test"},
274+
},
275+
},
276+
}
277+
if !cmp.Equal(alerts, want) {
278+
t.Errorf("CodeScanning.ListAlertsForOrg returned %+v, want %+v", *&alerts, *&want)
279+
}
280+
281+
const methodName = "ListAlertsForOrg"
282+
testBadOptions(t, methodName, func() (err error) {
283+
_, _, err = client.CodeScanning.ListAlertsForOrg(ctx, "\n", opts)
284+
return err
285+
})
286+
287+
testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
288+
got, resp, err := client.CodeScanning.ListAlertsForOrg(ctx, "o", opts)
289+
if got != nil {
290+
t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
291+
}
292+
return resp, err
293+
})
294+
}
295+
92296
func TestCodeScanningService_ListAlertsForRepo(t *testing.T) {
93297
client, mux, _, teardown := setup()
94298
defer teardown()
@@ -322,7 +526,7 @@ func TestCodeScanningService_GetAlert(t *testing.T) {
322526
"classifications": [
323527
"test"
324528
]
325-
},
529+
},
326530
"created_at":"2019-01-02T15:04:05Z",
327531
"state":"open",
328532
"closed_by":null,

github/github-accessors.go

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

github/github-accessors_test.go

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)