From fdb62f65c778bfc324c34a33672433af3e38a0ba Mon Sep 17 00:00:00 2001 From: ganeshkumarsv <53483484+ganeshkumarsv@users.noreply.github.com> Date: Mon, 8 Nov 2021 07:22:54 -0500 Subject: [PATCH] Add method to upload Code Scanning Sarif Analysis results to GitHub (#2165) --- github/code-scanning.go | 44 ++++++++++++++++++ github/code-scanning_test.go | 36 +++++++++++++++ github/github-accessors.go | 64 ++++++++++++++++++++++++++ github/github-accessors_test.go | 80 +++++++++++++++++++++++++++++++++ 4 files changed, 224 insertions(+) diff --git a/github/code-scanning.go b/github/code-scanning.go index 50264a0c3b..4508c3390d 100644 --- a/github/code-scanning.go +++ b/github/code-scanning.go @@ -119,6 +119,26 @@ type AlertListOptions struct { ListOptions } +// SarifAnalysis specifies the results of a code scanning job. +// +// GitHub API docs: https://docs.github.com/en/rest/reference/code-scanning#upload-an-analysis-as-sarif-data +type SarifAnalysis struct { + CommitSHA *string `json:"commit_sha,omitempty"` + Ref *string `json:"ref,omitempty"` + Sarif *string `json:"sarif,omitempty"` + CheckoutURI *string `json:"checkout_uri,omitempty"` + StartedAt *Timestamp `json:"started_at,omitempty"` + ToolName *string `json:"tool_name,omitempty"` +} + +// SarifID identifies a sarif analysis upload. +// +// GitHub API docs: https://docs.github.com/en/rest/reference/code-scanning#upload-an-analysis-as-sarif-data +type SarifID struct { + ID *string `json:"id,omitempty"` + URL *string `json:"url,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. @@ -171,3 +191,27 @@ func (s *CodeScanningService) GetAlert(ctx context.Context, owner, repo string, return a, resp, nil } + +// UploadSarif uploads the result of code scanning job to GitHub. +// +// For the parameter sarif, you must first compress your SARIF file using gzip and then translate the contents of the file into a Base64 encoding string. +// You must use an access token with the security_events scope to use this endpoint. GitHub Apps must have the security_events +// write permission to use this endpoint. +// +// GitHub API docs: https://docs.github.com/en/rest/reference/code-scanning#upload-an-analysis-as-sarif-data +func (s *CodeScanningService) UploadSarif(ctx context.Context, owner, repo string, sarif *SarifAnalysis) (*SarifID, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/code-scanning/sarifs", owner, repo) + + req, err := s.client.NewRequest("POST", u, sarif) + if err != nil { + return nil, nil, err + } + + sarifID := new(SarifID) + resp, err := s.client.Do(ctx, req, sarifID) + if err != nil { + return nil, resp, err + } + + return sarifID, resp, nil +} diff --git a/github/code-scanning_test.go b/github/code-scanning_test.go index 1b1033ee1f..e96d0a0d14 100644 --- a/github/code-scanning_test.go +++ b/github/code-scanning_test.go @@ -7,6 +7,7 @@ package github import ( "context" + "encoding/json" "fmt" "net/http" "testing" @@ -53,6 +54,41 @@ func TestActionsService_Alert_ID(t *testing.T) { } } +func TestActionsService_UploadSarif(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/repos/o/r/code-scanning/sarifs", func(w http.ResponseWriter, r *http.Request) { + v := new(SarifAnalysis) + json.NewDecoder(r.Body).Decode(v) + testMethod(t, r, "POST") + want := &SarifAnalysis{CommitSHA: String("abc"), Ref: String("ref/head/main"), Sarif: String("abc"), CheckoutURI: String("uri"), StartedAt: &Timestamp{time.Date(2006, time.January, 02, 15, 04, 05, 0, time.UTC)}, ToolName: String("codeql-cli")} + if !cmp.Equal(v, want) { + t.Errorf("Request body = %+v, want %+v", v, want) + } + + fmt.Fprint(w, `{"commit_sha":"abc","ref":"ref/head/main","sarif":"abc"}`) + }) + + ctx := context.Background() + sarifAnalysis := &SarifAnalysis{CommitSHA: String("abc"), Ref: String("ref/head/main"), Sarif: String("abc"), CheckoutURI: String("uri"), StartedAt: &Timestamp{time.Date(2006, time.January, 02, 15, 04, 05, 0, time.UTC)}, ToolName: String("codeql-cli")} + _, _, err := client.CodeScanning.UploadSarif(ctx, "o", "r", sarifAnalysis) + if err != nil { + t.Errorf("CodeScanning.UploadSarif returned error: %v", err) + } + + const methodName = "UploadSarif" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.CodeScanning.UploadSarif(ctx, "\n", "\n", sarifAnalysis) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + _, resp, err := client.CodeScanning.UploadSarif(ctx, "o", "r", sarifAnalysis) + return resp, err + }) +} + func TestActionsService_ListAlertsForRepo(t *testing.T) { client, mux, _, teardown := setup() defer teardown() diff --git a/github/github-accessors.go b/github/github-accessors.go index e69d5e84ac..b2c53f36de 100644 --- a/github/github-accessors.go +++ b/github/github-accessors.go @@ -15148,6 +15148,70 @@ func (r *RunnerLabels) GetType() string { return *r.Type } +// GetCheckoutURI returns the CheckoutURI field if it's non-nil, zero value otherwise. +func (s *SarifAnalysis) GetCheckoutURI() string { + if s == nil || s.CheckoutURI == nil { + return "" + } + return *s.CheckoutURI +} + +// GetCommitSHA returns the CommitSHA field if it's non-nil, zero value otherwise. +func (s *SarifAnalysis) GetCommitSHA() string { + if s == nil || s.CommitSHA == nil { + return "" + } + return *s.CommitSHA +} + +// GetRef returns the Ref field if it's non-nil, zero value otherwise. +func (s *SarifAnalysis) GetRef() string { + if s == nil || s.Ref == nil { + return "" + } + return *s.Ref +} + +// GetSarif returns the Sarif field if it's non-nil, zero value otherwise. +func (s *SarifAnalysis) GetSarif() string { + if s == nil || s.Sarif == nil { + return "" + } + return *s.Sarif +} + +// GetStartedAt returns the StartedAt field if it's non-nil, zero value otherwise. +func (s *SarifAnalysis) GetStartedAt() Timestamp { + if s == nil || s.StartedAt == nil { + return Timestamp{} + } + return *s.StartedAt +} + +// GetToolName returns the ToolName field if it's non-nil, zero value otherwise. +func (s *SarifAnalysis) GetToolName() string { + if s == nil || s.ToolName == nil { + return "" + } + return *s.ToolName +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (s *SarifID) GetID() string { + if s == nil || s.ID == nil { + return "" + } + return *s.ID +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (s *SarifID) GetURL() string { + if s == nil || s.URL == nil { + return "" + } + return *s.URL +} + // GetActive returns the Active field if it's non-nil, zero value otherwise. func (s *SCIMUserAttributes) GetActive() bool { if s == nil || s.Active == nil { diff --git a/github/github-accessors_test.go b/github/github-accessors_test.go index 8fb7dc03a9..61b3245191 100644 --- a/github/github-accessors_test.go +++ b/github/github-accessors_test.go @@ -17709,6 +17709,86 @@ func TestRunnerLabels_GetType(tt *testing.T) { r.GetType() } +func TestSarifAnalysis_GetCheckoutURI(tt *testing.T) { + var zeroValue string + s := &SarifAnalysis{CheckoutURI: &zeroValue} + s.GetCheckoutURI() + s = &SarifAnalysis{} + s.GetCheckoutURI() + s = nil + s.GetCheckoutURI() +} + +func TestSarifAnalysis_GetCommitSHA(tt *testing.T) { + var zeroValue string + s := &SarifAnalysis{CommitSHA: &zeroValue} + s.GetCommitSHA() + s = &SarifAnalysis{} + s.GetCommitSHA() + s = nil + s.GetCommitSHA() +} + +func TestSarifAnalysis_GetRef(tt *testing.T) { + var zeroValue string + s := &SarifAnalysis{Ref: &zeroValue} + s.GetRef() + s = &SarifAnalysis{} + s.GetRef() + s = nil + s.GetRef() +} + +func TestSarifAnalysis_GetSarif(tt *testing.T) { + var zeroValue string + s := &SarifAnalysis{Sarif: &zeroValue} + s.GetSarif() + s = &SarifAnalysis{} + s.GetSarif() + s = nil + s.GetSarif() +} + +func TestSarifAnalysis_GetStartedAt(tt *testing.T) { + var zeroValue Timestamp + s := &SarifAnalysis{StartedAt: &zeroValue} + s.GetStartedAt() + s = &SarifAnalysis{} + s.GetStartedAt() + s = nil + s.GetStartedAt() +} + +func TestSarifAnalysis_GetToolName(tt *testing.T) { + var zeroValue string + s := &SarifAnalysis{ToolName: &zeroValue} + s.GetToolName() + s = &SarifAnalysis{} + s.GetToolName() + s = nil + s.GetToolName() +} + +func TestSarifID_GetID(tt *testing.T) { + var zeroValue string + s := &SarifID{ID: &zeroValue} + s.GetID() + s = &SarifID{} + s.GetID() + s = nil + s.GetID() +} + +func TestSarifID_GetURL(tt *testing.T) { + var zeroValue string + s := &SarifID{URL: &zeroValue} + s.GetURL() + s = &SarifID{} + s.GetURL() + s = nil + s.GetURL() +} + func TestSCIMUserAttributes_GetActive(tt *testing.T) { var zeroValue bool s := &SCIMUserAttributes{Active: &zeroValue}