-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for Code Scanning API (#1545)
- Loading branch information
Showing
5 changed files
with
365 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
// Copyright 2020 The go-github AUTHORS. All rights reserved. | ||
// | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
package github | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"strconv" | ||
"strings" | ||
) | ||
|
||
// CodeScanningService handles communication with the code scanning related | ||
// methods of the GitHub API. | ||
// | ||
// GitHub API docs: https://developer.github.com/v3/code-scanning/ | ||
type CodeScanningService service | ||
|
||
type Alert struct { | ||
RuleID *string `json:"rule_id,omitempty"` | ||
RuleSeverity *string `json:"rule_severity,omitempty"` | ||
RuleDescription *string `json:"rule_description,omitempty"` | ||
Tool *string `json:"tool,omitempty"` | ||
CreatedAt *Timestamp `json:"created_at,omitempty"` | ||
Open *bool `json:"open,omitempty"` | ||
ClosedBy *User `json:"closed_by,omitempty"` | ||
ClosedAt *Timestamp `json:"closed_at,omitempty"` | ||
URL *string `json:"url,omitempty"` | ||
HTMLURL *string `json:"html_url,omitempty"` | ||
} | ||
|
||
// ID returns the ID associated with an alert. It is the number at the end of the security alert's URL. | ||
func (a *Alert) ID() int64 { | ||
if a == nil { | ||
return 0 | ||
} | ||
|
||
s := a.GetHTMLURL() | ||
|
||
// Check for an ID to parse at the end of the url | ||
if i := strings.LastIndex(s, "/"); i >= 0 { | ||
s = s[i+1:] | ||
} | ||
|
||
// Return the alert ID as a 64-bit integer. Unable to convert or out of range returns 0. | ||
id, err := strconv.ParseInt(s, 10, 64) | ||
if err != nil { | ||
return 0 | ||
} | ||
|
||
return id | ||
} | ||
|
||
// AlertListOptions specifies optional parameters to the CodeScanningService.ListAlerts | ||
// method. | ||
type AlertListOptions struct { | ||
// State of the code scanning alerts to list. Set to closed to list only closed code scanning alerts. Default: open | ||
State string `url:"state,omitempty"` | ||
|
||
// Return code scanning alerts for a specific branch reference. The ref must be formatted as heads/<branch name>. | ||
Ref string `url:"ref,omitempty"` | ||
} | ||
|
||
// ListAlertsForRepo lists code scanning alerts for a repository. | ||
// | ||
// Lists all open code scanning alerts for the default branch (usually master) and protected branches in a repository. | ||
// You must use an access token with the security_events scope to use this endpoint. GitHub Apps must have the security_events | ||
// read permission to use this endpoint. | ||
// | ||
// GitHub API docs: https://developer.github.com/v3/code-scanning/#list-code-scanning-alerts-for-a-repository | ||
func (s *CodeScanningService) ListAlertsForRepo(ctx context.Context, owner, repo string, opts *AlertListOptions) ([]*Alert, *Response, error) { | ||
u := fmt.Sprintf("repos/%v/%v/code-scanning/alerts", owner, repo) | ||
u, err := addOptions(u, opts) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
|
||
req, err := s.client.NewRequest("GET", u, nil) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
|
||
var alerts []*Alert | ||
resp, err := s.client.Do(ctx, req, &alerts) | ||
if err != nil { | ||
return nil, resp, err | ||
} | ||
|
||
return alerts, resp, nil | ||
} | ||
|
||
// GetAlert gets a single code scanning alert for a repository. | ||
// | ||
// You must use an access token with the security_events scope to use this endpoint. | ||
// GitHub Apps must have the security_events read permission to use this endpoint. | ||
// | ||
// The security alert_id is the number at the end of the security alert's URL. | ||
// | ||
// GitHub API docs: https://developer.github.com/v3/code-scanning/#get-a-code-scanning-alert | ||
func (s *CodeScanningService) GetAlert(ctx context.Context, owner, repo string, id int64) (*Alert, *Response, error) { | ||
u := fmt.Sprintf("repos/%v/%v/code-scanning/alerts/%v", owner, repo, id) | ||
|
||
req, err := s.client.NewRequest("GET", u, nil) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
|
||
a := new(Alert) | ||
resp, err := s.client.Do(ctx, req, a) | ||
if err != nil { | ||
return nil, resp, err | ||
} | ||
|
||
return a, resp, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
// Copyright 2020 The go-github AUTHORS. All rights reserved. | ||
// | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
package github | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"net/http" | ||
"reflect" | ||
"testing" | ||
"time" | ||
) | ||
|
||
func TestActionsService_Alert_ID(t *testing.T) { | ||
// Test: nil Alert ID == 0 | ||
var a *Alert | ||
id := a.ID() | ||
var want int64 | ||
if id != want { | ||
t.Errorf("Alert.ID error returned %+v, want %+v", id, want) | ||
} | ||
|
||
// Test: Valid HTMLURL | ||
a = &Alert{ | ||
HTMLURL: String("https://github.com/o/r/security/code-scanning/88"), | ||
} | ||
id = a.ID() | ||
want = 88 | ||
if !reflect.DeepEqual(id, want) { | ||
t.Errorf("Alert.ID error returned %+v, want %+v", id, want) | ||
} | ||
|
||
// Test: HTMLURL is nil | ||
a = &Alert{} | ||
id = a.ID() | ||
want = 0 | ||
if !reflect.DeepEqual(id, want) { | ||
t.Errorf("Alert.ID error returned %+v, want %+v", id, want) | ||
} | ||
|
||
// Test: ID can't be parsed as an int | ||
a = &Alert{ | ||
HTMLURL: String("https://github.com/o/r/security/code-scanning/bad88"), | ||
} | ||
id = a.ID() | ||
want = 0 | ||
if !reflect.DeepEqual(id, want) { | ||
t.Errorf("Alert.ID error returned %+v, want %+v", id, want) | ||
} | ||
} | ||
|
||
func TestActionsService_ListAlertsForRepo(t *testing.T) { | ||
client, mux, _, teardown := setup() | ||
defer teardown() | ||
|
||
mux.HandleFunc("/repos/o/r/code-scanning/alerts", func(w http.ResponseWriter, r *http.Request) { | ||
testMethod(t, r, "GET") | ||
testFormValues(t, r, values{"state": "open", "ref": "heads/master"}) | ||
fmt.Fprint(w, `[{ | ||
"rule_id":"js/trivial-conditional", | ||
"rule_severity":"warning", | ||
"rule_description":"Useless conditional", | ||
"tool":"CodeQL", | ||
"created_at":"2020-05-06T12:00:00Z", | ||
"open":true, | ||
"closed_by":null, | ||
"closed_at":null, | ||
"url":"https://api.github.com/repos/o/r/code-scanning/alerts/25", | ||
"html_url":"https://github.com/o/r/security/code-scanning/25" | ||
}, | ||
{ | ||
"rule_id":"js/useless-expression", | ||
"rule_severity":"warning", | ||
"rule_description":"Expression has no effect", | ||
"tool":"CodeQL", | ||
"created_at":"2020-05-06T12:00:00Z", | ||
"open":true, | ||
"closed_by":null, | ||
"closed_at":null, | ||
"url":"https://api.github.com/repos/o/r/code-scanning/alerts/88", | ||
"html_url":"https://github.com/o/r/security/code-scanning/88" | ||
}]`) | ||
}) | ||
|
||
opts := &AlertListOptions{State: "open", Ref: "heads/master"} | ||
alerts, _, err := client.CodeScanning.ListAlertsForRepo(context.Background(), "o", "r", opts) | ||
if err != nil { | ||
t.Errorf("CodeScanning.ListAlertsForRepo returned error: %v", err) | ||
} | ||
|
||
date := Timestamp{time.Date(2020, time.May, 06, 12, 00, 00, 0, time.UTC)} | ||
want := []*Alert{ | ||
{ | ||
RuleID: String("js/trivial-conditional"), | ||
RuleSeverity: String("warning"), | ||
RuleDescription: String("Useless conditional"), | ||
Tool: String("CodeQL"), | ||
CreatedAt: &date, | ||
Open: Bool(true), | ||
ClosedBy: nil, | ||
ClosedAt: nil, | ||
URL: String("https://api.github.com/repos/o/r/code-scanning/alerts/25"), | ||
HTMLURL: String("https://github.com/o/r/security/code-scanning/25"), | ||
}, | ||
{ | ||
RuleID: String("js/useless-expression"), | ||
RuleSeverity: String("warning"), | ||
RuleDescription: String("Expression has no effect"), | ||
Tool: String("CodeQL"), | ||
CreatedAt: &date, | ||
Open: Bool(true), | ||
ClosedBy: nil, | ||
ClosedAt: nil, | ||
URL: String("https://api.github.com/repos/o/r/code-scanning/alerts/88"), | ||
HTMLURL: String("https://github.com/o/r/security/code-scanning/88"), | ||
}, | ||
} | ||
if !reflect.DeepEqual(alerts, want) { | ||
t.Errorf("CodeScanning.ListAlertsForRepo returned %+v, want %+v", alerts, want) | ||
} | ||
} | ||
|
||
func TestActionsService_GetAlert(t *testing.T) { | ||
client, mux, _, teardown := setup() | ||
defer teardown() | ||
|
||
mux.HandleFunc("/repos/o/r/code-scanning/alerts/88", func(w http.ResponseWriter, r *http.Request) { | ||
testMethod(t, r, "GET") | ||
fmt.Fprint(w, `{"rule_id":"js/useless-expression", | ||
"rule_severity":"warning", | ||
"rule_description":"Expression has no effect", | ||
"tool":"CodeQL", | ||
"created_at":"2019-01-02T15:04:05Z", | ||
"open":true, | ||
"closed_by":null, | ||
"closed_at":null, | ||
"url":"https://api.github.com/repos/o/r/code-scanning/alerts/88", | ||
"html_url":"https://github.com/o/r/security/code-scanning/88"}`) | ||
}) | ||
|
||
alert, _, err := client.CodeScanning.GetAlert(context.Background(), "o", "r", 88) | ||
if err != nil { | ||
t.Errorf("CodeScanning.GetAlert returned error: %v", err) | ||
} | ||
|
||
date := Timestamp{time.Date(2019, time.January, 02, 15, 04, 05, 0, time.UTC)} | ||
want := &Alert{ | ||
RuleID: String("js/useless-expression"), | ||
RuleSeverity: String("warning"), | ||
RuleDescription: String("Expression has no effect"), | ||
Tool: String("CodeQL"), | ||
CreatedAt: &date, | ||
Open: Bool(true), | ||
ClosedBy: nil, | ||
ClosedAt: nil, | ||
URL: String("https://api.github.com/repos/o/r/code-scanning/alerts/88"), | ||
HTMLURL: String("https://github.com/o/r/security/code-scanning/88"), | ||
} | ||
if !reflect.DeepEqual(alert, want) { | ||
t.Errorf("CodeScanning.GetAlert returned %+v, want %+v", alert, want) | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters