diff --git a/github/github-accessors.go b/github/github-accessors.go index 96cfbc5924..36d43d1aad 100644 --- a/github/github-accessors.go +++ b/github/github-accessors.go @@ -15940,6 +15940,206 @@ func (s *SecretScanning) GetStatus() string { return *s.Status } +// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. +func (s *SecretScanningAlert) GetCreatedAt() Timestamp { + if s == nil || s.CreatedAt == nil { + return Timestamp{} + } + return *s.CreatedAt +} + +// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. +func (s *SecretScanningAlert) GetHTMLURL() string { + if s == nil || s.HTMLURL == nil { + return "" + } + return *s.HTMLURL +} + +// GetLocationsURL returns the LocationsURL field if it's non-nil, zero value otherwise. +func (s *SecretScanningAlert) GetLocationsURL() string { + if s == nil || s.LocationsURL == nil { + return "" + } + return *s.LocationsURL +} + +// GetNumber returns the Number field if it's non-nil, zero value otherwise. +func (s *SecretScanningAlert) GetNumber() int { + if s == nil || s.Number == nil { + return 0 + } + return *s.Number +} + +// GetResolution returns the Resolution field if it's non-nil, zero value otherwise. +func (s *SecretScanningAlert) GetResolution() string { + if s == nil || s.Resolution == nil { + return "" + } + return *s.Resolution +} + +// GetResolvedAt returns the ResolvedAt field if it's non-nil, zero value otherwise. +func (s *SecretScanningAlert) GetResolvedAt() Timestamp { + if s == nil || s.ResolvedAt == nil { + return Timestamp{} + } + return *s.ResolvedAt +} + +// GetResolvedBy returns the ResolvedBy field. +func (s *SecretScanningAlert) GetResolvedBy() *User { + if s == nil { + return nil + } + return s.ResolvedBy +} + +// GetSecret returns the Secret field if it's non-nil, zero value otherwise. +func (s *SecretScanningAlert) GetSecret() string { + if s == nil || s.Secret == nil { + return "" + } + return *s.Secret +} + +// GetSecretType returns the SecretType field if it's non-nil, zero value otherwise. +func (s *SecretScanningAlert) GetSecretType() string { + if s == nil || s.SecretType == nil { + return "" + } + return *s.SecretType +} + +// GetState returns the State field if it's non-nil, zero value otherwise. +func (s *SecretScanningAlert) GetState() string { + if s == nil || s.State == nil { + return "" + } + return *s.State +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (s *SecretScanningAlert) GetURL() string { + if s == nil || s.URL == nil { + return "" + } + return *s.URL +} + +// GetDetails returns the Details field. +func (s *SecretScanningAlertLocation) GetDetails() *SecretScanningAlertLocationDetails { + if s == nil { + return nil + } + return s.Details +} + +// GetType returns the Type field if it's non-nil, zero value otherwise. +func (s *SecretScanningAlertLocation) GetType() string { + if s == nil || s.Type == nil { + return "" + } + return *s.Type +} + +// GetBlobSHA returns the BlobSHA field if it's non-nil, zero value otherwise. +func (s *SecretScanningAlertLocationDetails) GetBlobSHA() string { + if s == nil || s.BlobSHA == nil { + return "" + } + return *s.BlobSHA +} + +// GetBlobURL returns the BlobURL field if it's non-nil, zero value otherwise. +func (s *SecretScanningAlertLocationDetails) GetBlobURL() string { + if s == nil || s.BlobURL == nil { + return "" + } + return *s.BlobURL +} + +// GetCommitSHA returns the CommitSHA field if it's non-nil, zero value otherwise. +func (s *SecretScanningAlertLocationDetails) GetCommitSHA() string { + if s == nil || s.CommitSHA == nil { + return "" + } + return *s.CommitSHA +} + +// GetCommitURL returns the CommitURL field if it's non-nil, zero value otherwise. +func (s *SecretScanningAlertLocationDetails) GetCommitURL() string { + if s == nil || s.CommitURL == nil { + return "" + } + return *s.CommitURL +} + +// GetEndColumn returns the EndColumn field if it's non-nil, zero value otherwise. +func (s *SecretScanningAlertLocationDetails) GetEndColumn() int { + if s == nil || s.EndColumn == nil { + return 0 + } + return *s.EndColumn +} + +// GetEndLine returns the EndLine field if it's non-nil, zero value otherwise. +func (s *SecretScanningAlertLocationDetails) GetEndLine() int { + if s == nil || s.EndLine == nil { + return 0 + } + return *s.EndLine +} + +// GetPath returns the Path field if it's non-nil, zero value otherwise. +func (s *SecretScanningAlertLocationDetails) GetPath() string { + if s == nil || s.Path == nil { + return "" + } + return *s.Path +} + +// GetStartColumn returns the StartColumn field if it's non-nil, zero value otherwise. +func (s *SecretScanningAlertLocationDetails) GetStartColumn() int { + if s == nil || s.StartColumn == nil { + return 0 + } + return *s.StartColumn +} + +// GetStartline returns the Startline field if it's non-nil, zero value otherwise. +func (s *SecretScanningAlertLocationDetails) GetStartline() int { + if s == nil || s.Startline == nil { + return 0 + } + return *s.Startline +} + +// GetResolution returns the Resolution field if it's non-nil, zero value otherwise. +func (s *SecretScanningAlertUpdateOptions) GetResolution() string { + if s == nil || s.Resolution == nil { + return "" + } + return *s.Resolution +} + +// GetSecretType returns the SecretType field if it's non-nil, zero value otherwise. +func (s *SecretScanningAlertUpdateOptions) GetSecretType() string { + if s == nil || s.SecretType == nil { + return "" + } + return *s.SecretType +} + +// GetState returns the State field if it's non-nil, zero value otherwise. +func (s *SecretScanningAlertUpdateOptions) GetState() string { + if s == nil || s.State == nil { + return "" + } + return *s.State +} + // GetAdvancedSecurity returns the AdvancedSecurity field. func (s *SecurityAndAnalysis) GetAdvancedSecurity() *AdvancedSecurity { if s == nil { diff --git a/github/github-accessors_test.go b/github/github-accessors_test.go index 4aa6d6df9f..4024725605 100644 --- a/github/github-accessors_test.go +++ b/github/github-accessors_test.go @@ -18660,6 +18660,250 @@ func TestSecretScanning_GetStatus(tt *testing.T) { s.GetStatus() } +func TestSecretScanningAlert_GetCreatedAt(tt *testing.T) { + var zeroValue Timestamp + s := &SecretScanningAlert{CreatedAt: &zeroValue} + s.GetCreatedAt() + s = &SecretScanningAlert{} + s.GetCreatedAt() + s = nil + s.GetCreatedAt() +} + +func TestSecretScanningAlert_GetHTMLURL(tt *testing.T) { + var zeroValue string + s := &SecretScanningAlert{HTMLURL: &zeroValue} + s.GetHTMLURL() + s = &SecretScanningAlert{} + s.GetHTMLURL() + s = nil + s.GetHTMLURL() +} + +func TestSecretScanningAlert_GetLocationsURL(tt *testing.T) { + var zeroValue string + s := &SecretScanningAlert{LocationsURL: &zeroValue} + s.GetLocationsURL() + s = &SecretScanningAlert{} + s.GetLocationsURL() + s = nil + s.GetLocationsURL() +} + +func TestSecretScanningAlert_GetNumber(tt *testing.T) { + var zeroValue int + s := &SecretScanningAlert{Number: &zeroValue} + s.GetNumber() + s = &SecretScanningAlert{} + s.GetNumber() + s = nil + s.GetNumber() +} + +func TestSecretScanningAlert_GetResolution(tt *testing.T) { + var zeroValue string + s := &SecretScanningAlert{Resolution: &zeroValue} + s.GetResolution() + s = &SecretScanningAlert{} + s.GetResolution() + s = nil + s.GetResolution() +} + +func TestSecretScanningAlert_GetResolvedAt(tt *testing.T) { + var zeroValue Timestamp + s := &SecretScanningAlert{ResolvedAt: &zeroValue} + s.GetResolvedAt() + s = &SecretScanningAlert{} + s.GetResolvedAt() + s = nil + s.GetResolvedAt() +} + +func TestSecretScanningAlert_GetResolvedBy(tt *testing.T) { + s := &SecretScanningAlert{} + s.GetResolvedBy() + s = nil + s.GetResolvedBy() +} + +func TestSecretScanningAlert_GetSecret(tt *testing.T) { + var zeroValue string + s := &SecretScanningAlert{Secret: &zeroValue} + s.GetSecret() + s = &SecretScanningAlert{} + s.GetSecret() + s = nil + s.GetSecret() +} + +func TestSecretScanningAlert_GetSecretType(tt *testing.T) { + var zeroValue string + s := &SecretScanningAlert{SecretType: &zeroValue} + s.GetSecretType() + s = &SecretScanningAlert{} + s.GetSecretType() + s = nil + s.GetSecretType() +} + +func TestSecretScanningAlert_GetState(tt *testing.T) { + var zeroValue string + s := &SecretScanningAlert{State: &zeroValue} + s.GetState() + s = &SecretScanningAlert{} + s.GetState() + s = nil + s.GetState() +} + +func TestSecretScanningAlert_GetURL(tt *testing.T) { + var zeroValue string + s := &SecretScanningAlert{URL: &zeroValue} + s.GetURL() + s = &SecretScanningAlert{} + s.GetURL() + s = nil + s.GetURL() +} + +func TestSecretScanningAlertLocation_GetDetails(tt *testing.T) { + s := &SecretScanningAlertLocation{} + s.GetDetails() + s = nil + s.GetDetails() +} + +func TestSecretScanningAlertLocation_GetType(tt *testing.T) { + var zeroValue string + s := &SecretScanningAlertLocation{Type: &zeroValue} + s.GetType() + s = &SecretScanningAlertLocation{} + s.GetType() + s = nil + s.GetType() +} + +func TestSecretScanningAlertLocationDetails_GetBlobSHA(tt *testing.T) { + var zeroValue string + s := &SecretScanningAlertLocationDetails{BlobSHA: &zeroValue} + s.GetBlobSHA() + s = &SecretScanningAlertLocationDetails{} + s.GetBlobSHA() + s = nil + s.GetBlobSHA() +} + +func TestSecretScanningAlertLocationDetails_GetBlobURL(tt *testing.T) { + var zeroValue string + s := &SecretScanningAlertLocationDetails{BlobURL: &zeroValue} + s.GetBlobURL() + s = &SecretScanningAlertLocationDetails{} + s.GetBlobURL() + s = nil + s.GetBlobURL() +} + +func TestSecretScanningAlertLocationDetails_GetCommitSHA(tt *testing.T) { + var zeroValue string + s := &SecretScanningAlertLocationDetails{CommitSHA: &zeroValue} + s.GetCommitSHA() + s = &SecretScanningAlertLocationDetails{} + s.GetCommitSHA() + s = nil + s.GetCommitSHA() +} + +func TestSecretScanningAlertLocationDetails_GetCommitURL(tt *testing.T) { + var zeroValue string + s := &SecretScanningAlertLocationDetails{CommitURL: &zeroValue} + s.GetCommitURL() + s = &SecretScanningAlertLocationDetails{} + s.GetCommitURL() + s = nil + s.GetCommitURL() +} + +func TestSecretScanningAlertLocationDetails_GetEndColumn(tt *testing.T) { + var zeroValue int + s := &SecretScanningAlertLocationDetails{EndColumn: &zeroValue} + s.GetEndColumn() + s = &SecretScanningAlertLocationDetails{} + s.GetEndColumn() + s = nil + s.GetEndColumn() +} + +func TestSecretScanningAlertLocationDetails_GetEndLine(tt *testing.T) { + var zeroValue int + s := &SecretScanningAlertLocationDetails{EndLine: &zeroValue} + s.GetEndLine() + s = &SecretScanningAlertLocationDetails{} + s.GetEndLine() + s = nil + s.GetEndLine() +} + +func TestSecretScanningAlertLocationDetails_GetPath(tt *testing.T) { + var zeroValue string + s := &SecretScanningAlertLocationDetails{Path: &zeroValue} + s.GetPath() + s = &SecretScanningAlertLocationDetails{} + s.GetPath() + s = nil + s.GetPath() +} + +func TestSecretScanningAlertLocationDetails_GetStartColumn(tt *testing.T) { + var zeroValue int + s := &SecretScanningAlertLocationDetails{StartColumn: &zeroValue} + s.GetStartColumn() + s = &SecretScanningAlertLocationDetails{} + s.GetStartColumn() + s = nil + s.GetStartColumn() +} + +func TestSecretScanningAlertLocationDetails_GetStartline(tt *testing.T) { + var zeroValue int + s := &SecretScanningAlertLocationDetails{Startline: &zeroValue} + s.GetStartline() + s = &SecretScanningAlertLocationDetails{} + s.GetStartline() + s = nil + s.GetStartline() +} + +func TestSecretScanningAlertUpdateOptions_GetResolution(tt *testing.T) { + var zeroValue string + s := &SecretScanningAlertUpdateOptions{Resolution: &zeroValue} + s.GetResolution() + s = &SecretScanningAlertUpdateOptions{} + s.GetResolution() + s = nil + s.GetResolution() +} + +func TestSecretScanningAlertUpdateOptions_GetSecretType(tt *testing.T) { + var zeroValue string + s := &SecretScanningAlertUpdateOptions{SecretType: &zeroValue} + s.GetSecretType() + s = &SecretScanningAlertUpdateOptions{} + s.GetSecretType() + s = nil + s.GetSecretType() +} + +func TestSecretScanningAlertUpdateOptions_GetState(tt *testing.T) { + var zeroValue string + s := &SecretScanningAlertUpdateOptions{State: &zeroValue} + s.GetState() + s = &SecretScanningAlertUpdateOptions{} + s.GetState() + s = nil + s.GetState() +} + func TestSecurityAndAnalysis_GetAdvancedSecurity(tt *testing.T) { s := &SecurityAndAnalysis{} s.GetAdvancedSecurity() diff --git a/github/github.go b/github/github.go index 4fb466e3a6..e5d5940042 100644 --- a/github/github.go +++ b/github/github.go @@ -196,6 +196,7 @@ type Client struct { Repositories *RepositoriesService SCIM *SCIMService Search *SearchService + SecretScanning *SecretScanningService Teams *TeamsService Users *UsersService } @@ -325,6 +326,7 @@ func NewClient(httpClient *http.Client) *Client { c.Repositories = (*RepositoriesService)(&c.common) c.SCIM = (*SCIMService)(&c.common) c.Search = (*SearchService)(&c.common) + c.SecretScanning = (*SecretScanningService)(&c.common) c.Teams = (*TeamsService)(&c.common) c.Users = (*UsersService)(&c.common) return c diff --git a/github/secret_scanning.go b/github/secret_scanning.go new file mode 100644 index 0000000000..f5061f3b92 --- /dev/null +++ b/github/secret_scanning.go @@ -0,0 +1,234 @@ +// Copyright 2022 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" +) + +// SecretScanningService handles communication with the secret scanning related +// methods of the GitHub API. +// +// GitHub API docs: https://docs.github.com/en/rest/reference/secret-scanning +type SecretScanningService service + +// SecretScanningAlert represents a GitHub secret scanning alert. +type SecretScanningAlert struct { + Number *int `json:"number,omitempty"` + CreatedAt *Timestamp `json:"created_at,omitempty"` + URL *string `json:"url,omitempty"` + HTMLURL *string `json:"html_url,omitempty"` + LocationsURL *string `json:"locations_url,omitempty"` + State *string `json:"state,omitempty"` + Resolution *string `json:"resolution,omitempty"` + ResolvedAt *Timestamp `json:"resolved_at,omitempty"` + ResolvedBy *User `json:"resolved_by,omitempty"` + SecretType *string `json:"secret_type,omitempty"` + Secret *string `json:"secret,omitempty"` +} + +// SecretScanningAlertLocation represents the location for a secret scanning alert. +type SecretScanningAlertLocation struct { + Type *string `json:"type,omitempty"` + Details *SecretScanningAlertLocationDetails `json:"details,omitempty"` +} + +// SecretScanningAlertLocationDetails represents the location details for a secret scanning alert. +type SecretScanningAlertLocationDetails struct { + Path *string `json:"path,omitempty"` + Startline *int `json:"start_line,omitempty"` + EndLine *int `json:"end_line,omitempty"` + StartColumn *int `json:"start_column,omitempty"` + EndColumn *int `json:"end_column,omitempty"` + BlobSHA *string `json:"blob_sha,omitempty"` + BlobURL *string `json:"blob_url,omitempty"` + CommitSHA *string `json:"commit_sha,omitempty"` + CommitURL *string `json:"commit_url,omitempty"` +} + +// SecretScanningAlertListOptions specifies optional parameters to the SecretScanningService.ListAlertsForEnterprise method. +type SecretScanningAlertListOptions struct { + // State of the secret scanning alerts to list. Set to open or resolved to only list secret scanning alerts in a specific state. + State string `url:"state,omitempty"` + + // A comma-separated list of secret types to return. By default all secret types are returned. + SecretType string `url:"secret_type,omitempty"` + + // A comma-separated list of resolutions. Only secret scanning alerts with one of these resolutions are listed. + // Valid resolutions are false_positive, wont_fix, revoked, pattern_edited, pattern_deleted or used_in_tests. + Resolution string `url:"resolution,omitempty"` + + ListCursorOptions +} + +// SecretScanningAlertUpdateOptions specifies optional parameters to the SecretScanningService.UpdateAlert method. +type SecretScanningAlertUpdateOptions struct { + // Required. Sets the state of the secret scanning alert. Can be either open or resolved. + // You must provide resolution when you set the state to resolved. + State *string `url:"state,omitempty"` + + // A comma-separated list of secret types to return. By default all secret types are returned. + SecretType *string `url:"secret_type,omitempty"` + + // Required when the state is resolved. The reason for resolving the alert. Can be one of false_positive, + // wont_fix, revoked, or used_in_tests. + Resolution *string `url:"resolution,omitempty"` +} + +// Lists secret scanning alerts for eligible repositories in an enterprise, from newest to oldest. +// +// To use this endpoint, you must be a member of the enterprise, and you must use an access token with the repo scope or +// security_events scope. Alerts are only returned for organizations in the enterprise for which you are an organization owner or a security manager. +// +// GitHub API docs: https://docs.github.com/en/rest/reference/secret-scanning#list-secret-scanning-alerts-for-an-enterprise +func (s *SecretScanningService) ListAlertsForEnterprise(ctx context.Context, enterprise string, opts *SecretScanningAlertListOptions) ([]*SecretScanningAlert, *Response, error) { + u := fmt.Sprintf("enterprises/%v/secret-scanning/alerts", enterprise) + 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 []*SecretScanningAlert + resp, err := s.client.Do(ctx, req, &alerts) + if err != nil { + return nil, resp, err + } + + return alerts, resp, nil +} + +// Lists secret scanning alerts for eligible repositories in an organization, from newest to oldest. +// +// To use this endpoint, you must be an administrator for the repository or organization, and you must use an access token with +// the repo scope or security_events scope. +// +// GitHub API docs: https://docs.github.com/en/rest/reference/secret-scanning#list-secret-scanning-alerts-for-an-organization +func (s *SecretScanningService) ListAlertsForOrg(ctx context.Context, org string, opts *SecretScanningAlertListOptions) ([]*SecretScanningAlert, *Response, error) { + u := fmt.Sprintf("orgs/%v/secret-scanning/alerts", org) + 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 []*SecretScanningAlert + resp, err := s.client.Do(ctx, req, &alerts) + if err != nil { + return nil, resp, err + } + + return alerts, resp, nil +} + +// Lists secret scanning alerts for a private repository, from newest to oldest. +// +// To use this endpoint, you must be an administrator for the repository or organization, and you must use an access token with +// the repo scope or security_events scope. +// +// GitHub API docs: https://docs.github.com/en/rest/reference/secret-scanning#list-secret-scanning-alerts-for-a-repository +func (s *SecretScanningService) ListAlertsForRepo(ctx context.Context, owner, repo string, opts *SecretScanningAlertListOptions) ([]*SecretScanningAlert, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/secret-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 []*SecretScanningAlert + resp, err := s.client.Do(ctx, req, &alerts) + if err != nil { + return nil, resp, err + } + + return alerts, resp, nil +} + +// Gets a single secret scanning alert detected in a private repository. +// +// To use this endpoint, you must be an administrator for the repository or organization, and you must use an access token with +// the repo scope or security_events scope. +// +// GitHub API docs: https://docs.github.com/en/rest/reference/secret-scanning#get-a-secret-scanning-alert +func (s *SecretScanningService) GetAlert(ctx context.Context, owner, repo string, number int64) (*SecretScanningAlert, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/secret-scanning/alerts/%v", owner, repo, number) + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + var alert *SecretScanningAlert + resp, err := s.client.Do(ctx, req, &alert) + if err != nil { + return nil, resp, err + } + + return alert, resp, nil +} + +// Updates the status of a secret scanning alert in a private repository. +// +// To use this endpoint, you must be an administrator for the repository or organization, and you must use an access token with +// the repo scope or security_events scope. +// +// GitHub API docs: https://docs.github.com/en/rest/reference/secret-scanning#update-a-secret-scanning-alert +func (s *SecretScanningService) UpdateAlert(ctx context.Context, owner, repo string, number int64, opts *SecretScanningAlertUpdateOptions) (*SecretScanningAlert, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/secret-scanning/alerts/%v", owner, repo, number) + + req, err := s.client.NewRequest("PATCH", u, opts) + if err != nil { + return nil, nil, err + } + + var alert *SecretScanningAlert + resp, err := s.client.Do(ctx, req, &alert) + if err != nil { + return nil, resp, err + } + + return alert, resp, nil +} + +// Lists all locations for a given secret scanning alert for a private repository. +// +// To use this endpoint, you must be an administrator for the repository or organization, and you must use an access token with +// the repo scope or security_events scope. +// +// GitHub API docs: https://docs.github.com/en/rest/reference/secret-scanning#list-locations-for-a-secret-scanning-alert +func (s *SecretScanningService) ListLocationsForAlert(ctx context.Context, owner, repo string, number int64, opts *ListOptions) ([]*SecretScanningAlertLocation, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/secret-scanning/alerts/%v/locations", owner, repo, number) + 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 locations []*SecretScanningAlertLocation + resp, err := s.client.Do(ctx, req, &locations) + if err != nil { + return nil, resp, err + } + + return locations, resp, nil +} diff --git a/github/secret_scanning_test.go b/github/secret_scanning_test.go new file mode 100644 index 0000000000..afe6144e7c --- /dev/null +++ b/github/secret_scanning_test.go @@ -0,0 +1,410 @@ +// Copyright 2022 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" + "encoding/json" + "fmt" + "net/http" + "testing" + "time" + + "github.com/google/go-cmp/cmp" +) + +func TestSecretScanningService_ListAlertsForEnterprise(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/enterprises/e/secret-scanning/alerts", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + testFormValues(t, r, values{"state": "open", "secret_type": "mailchimp_api_key"}) + + fmt.Fprint(w, `[{ + "number": 1, + "created_at": "1996-06-20T00:00:00Z", + "url": "https://api.github.com/repos/o/r/secret-scanning/alerts/1", + "html_url": "https://github.com/o/r/security/secret-scanning/1", + "locations_url": "https://api.github.com/repos/o/r/secret-scanning/alerts/1/locations", + "state": "open", + "resolution": null, + "resolved_at": null, + "resolved_by": null, + "secret_type": "mailchimp_api_key", + "secret": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-us2" + }]`) + }) + + ctx := context.Background() + opts := &SecretScanningAlertListOptions{State: "open", SecretType: "mailchimp_api_key"} + + alerts, _, err := client.SecretScanning.ListAlertsForEnterprise(ctx, "e", opts) + if err != nil { + t.Errorf("SecretScanning.ListAlertsForEnterprise returned error: %v", err) + } + + date := Timestamp{time.Date(1996, time.June, 20, 00, 00, 00, 0, time.UTC)} + want := []*SecretScanningAlert{ + { + Number: Int(1), + CreatedAt: &date, + URL: String("https://api.github.com/repos/o/r/secret-scanning/alerts/1"), + HTMLURL: String("https://github.com/o/r/security/secret-scanning/1"), + LocationsURL: String("https://api.github.com/repos/o/r/secret-scanning/alerts/1/locations"), + State: String("open"), + Resolution: nil, + ResolvedAt: nil, + ResolvedBy: nil, + SecretType: String("mailchimp_api_key"), + Secret: String("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-us2"), + }, + } + + if !cmp.Equal(alerts, want) { + t.Errorf("SecretScanning.ListAlertsForEnterprise returned %+v, want %+v", alerts, want) + } + + const methodName = "ListAlertsForEnterprise" + + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.SecretScanning.ListAlertsForEnterprise(ctx, "\n", opts) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + _, resp, err := client.SecretScanning.ListAlertsForEnterprise(ctx, "e", opts) + return resp, err + }) +} + +func TestSecretScanningService_ListAlertsForOrg(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/orgs/o/secret-scanning/alerts", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + testFormValues(t, r, values{"state": "open", "secret_type": "mailchimp_api_key"}) + + fmt.Fprint(w, `[{ + "number": 1, + "created_at": "1996-06-20T00:00:00Z", + "url": "https://api.github.com/repos/o/r/secret-scanning/alerts/1", + "html_url": "https://github.com/o/r/security/secret-scanning/1", + "locations_url": "https://api.github.com/repos/o/r/secret-scanning/alerts/1/locations", + "state": "open", + "resolution": null, + "resolved_at": null, + "resolved_by": null, + "secret_type": "mailchimp_api_key", + "secret": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-us2" + }]`) + }) + + ctx := context.Background() + opts := &SecretScanningAlertListOptions{State: "open", SecretType: "mailchimp_api_key"} + + alerts, _, err := client.SecretScanning.ListAlertsForOrg(ctx, "o", opts) + if err != nil { + t.Errorf("SecretScanning.ListAlertsForOrg returned error: %v", err) + } + + date := Timestamp{time.Date(1996, time.June, 20, 00, 00, 00, 0, time.UTC)} + want := []*SecretScanningAlert{ + { + Number: Int(1), + CreatedAt: &date, + URL: String("https://api.github.com/repos/o/r/secret-scanning/alerts/1"), + HTMLURL: String("https://github.com/o/r/security/secret-scanning/1"), + LocationsURL: String("https://api.github.com/repos/o/r/secret-scanning/alerts/1/locations"), + State: String("open"), + Resolution: nil, + ResolvedAt: nil, + ResolvedBy: nil, + SecretType: String("mailchimp_api_key"), + Secret: String("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-us2"), + }, + } + + if !cmp.Equal(alerts, want) { + t.Errorf("SecretScanning.ListAlertsForOrg returned %+v, want %+v", alerts, want) + } + + const methodName = "ListAlertsForOrg" + + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.SecretScanning.ListAlertsForOrg(ctx, "\n", opts) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + _, resp, err := client.SecretScanning.ListAlertsForOrg(ctx, "o", opts) + return resp, err + }) +} + +func TestSecretScanningService_ListAlertsForRepo(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/repos/o/r/secret-scanning/alerts", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + testFormValues(t, r, values{"state": "open", "secret_type": "mailchimp_api_key"}) + + fmt.Fprint(w, `[{ + "number": 1, + "created_at": "1996-06-20T00:00:00Z", + "url": "https://api.github.com/repos/o/r/secret-scanning/alerts/1", + "html_url": "https://github.com/o/r/security/secret-scanning/1", + "locations_url": "https://api.github.com/repos/o/r/secret-scanning/alerts/1/locations", + "state": "open", + "resolution": null, + "resolved_at": null, + "resolved_by": null, + "secret_type": "mailchimp_api_key", + "secret": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-us2" + }]`) + }) + + ctx := context.Background() + opts := &SecretScanningAlertListOptions{State: "open", SecretType: "mailchimp_api_key"} + + alerts, _, err := client.SecretScanning.ListAlertsForRepo(ctx, "o", "r", opts) + if err != nil { + t.Errorf("SecretScanning.ListAlertsForRepo returned error: %v", err) + } + + date := Timestamp{time.Date(1996, time.June, 20, 00, 00, 00, 0, time.UTC)} + want := []*SecretScanningAlert{ + { + Number: Int(1), + CreatedAt: &date, + URL: String("https://api.github.com/repos/o/r/secret-scanning/alerts/1"), + HTMLURL: String("https://github.com/o/r/security/secret-scanning/1"), + LocationsURL: String("https://api.github.com/repos/o/r/secret-scanning/alerts/1/locations"), + State: String("open"), + Resolution: nil, + ResolvedAt: nil, + ResolvedBy: nil, + SecretType: String("mailchimp_api_key"), + Secret: String("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-us2"), + }, + } + + if !cmp.Equal(alerts, want) { + t.Errorf("SecretScanning.ListAlertsForRepo returned %+v, want %+v", alerts, want) + } + + const methodName = "ListAlertsForRepo" + + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.SecretScanning.ListAlertsForRepo(ctx, "\n", "\n", opts) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + _, resp, err := client.SecretScanning.ListAlertsForRepo(ctx, "o", "r", opts) + return resp, err + }) +} + +func TestSecretScanningService_GetAlert(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/repos/o/r/secret-scanning/alerts/1", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + + fmt.Fprint(w, `{ + "number": 1, + "created_at": "1996-06-20T00:00:00Z", + "url": "https://api.github.com/repos/o/r/secret-scanning/alerts/1", + "html_url": "https://github.com/o/r/security/secret-scanning/1", + "locations_url": "https://api.github.com/repos/o/r/secret-scanning/alerts/1/locations", + "state": "open", + "resolution": null, + "resolved_at": null, + "resolved_by": null, + "secret_type": "mailchimp_api_key", + "secret": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-us2" + }`) + }) + + ctx := context.Background() + + alert, _, err := client.SecretScanning.GetAlert(ctx, "o", "r", 1) + if err != nil { + t.Errorf("SecretScanning.GetAlert returned error: %v", err) + } + + date := Timestamp{time.Date(1996, time.June, 20, 00, 00, 00, 0, time.UTC)} + want := &SecretScanningAlert{ + Number: Int(1), + CreatedAt: &date, + URL: String("https://api.github.com/repos/o/r/secret-scanning/alerts/1"), + HTMLURL: String("https://github.com/o/r/security/secret-scanning/1"), + LocationsURL: String("https://api.github.com/repos/o/r/secret-scanning/alerts/1/locations"), + State: String("open"), + Resolution: nil, + ResolvedAt: nil, + ResolvedBy: nil, + SecretType: String("mailchimp_api_key"), + Secret: String("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-us2"), + } + + if !cmp.Equal(alert, want) { + t.Errorf("SecretScanning.GetAlert returned %+v, want %+v", alert, want) + } + + const methodName = "GetAlert" + + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.SecretScanning.GetAlert(ctx, "\n", "\n", 0) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + _, resp, err := client.SecretScanning.GetAlert(ctx, "o", "r", 1) + return resp, err + }) +} + +func TestSecretScanningService_UpdateAlert(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/repos/o/r/secret-scanning/alerts/1", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "PATCH") + + v := new(SecretScanningAlertUpdateOptions) + json.NewDecoder(r.Body).Decode(v) + + want := &SecretScanningAlertUpdateOptions{State: String("resolved"), Resolution: String("used_in_tests")} + + if !cmp.Equal(v, want) { + t.Errorf("Request body = %+v, want %+v", v, want) + } + + fmt.Fprint(w, `{ + "number": 1, + "created_at": "1996-06-20T00:00:00Z", + "url": "https://api.github.com/repos/o/r/secret-scanning/alerts/1", + "html_url": "https://github.com/o/r/security/secret-scanning/1", + "locations_url": "https://api.github.com/repos/o/r/secret-scanning/alerts/1/locations", + "state": "resolved", + "resolution": "used_in_tests", + "resolved_at": "1996-06-20T00:00:00Z", + "resolved_by": null, + "secret_type": "mailchimp_api_key", + "secret": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-us2" + }`) + }) + + ctx := context.Background() + opts := &SecretScanningAlertUpdateOptions{State: String("resolved"), Resolution: String("used_in_tests")} + + alert, _, err := client.SecretScanning.UpdateAlert(ctx, "o", "r", 1, opts) + if err != nil { + t.Errorf("SecretScanning.UpdateAlert returned error: %v", err) + } + + date := Timestamp{time.Date(1996, time.June, 20, 00, 00, 00, 0, time.UTC)} + want := &SecretScanningAlert{ + Number: Int(1), + CreatedAt: &date, + URL: String("https://api.github.com/repos/o/r/secret-scanning/alerts/1"), + HTMLURL: String("https://github.com/o/r/security/secret-scanning/1"), + LocationsURL: String("https://api.github.com/repos/o/r/secret-scanning/alerts/1/locations"), + State: String("resolved"), + Resolution: String("used_in_tests"), + ResolvedAt: &date, + ResolvedBy: nil, + SecretType: String("mailchimp_api_key"), + Secret: String("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-us2"), + } + + if !cmp.Equal(alert, want) { + t.Errorf("SecretScanning.UpdateAlert returned %+v, want %+v", alert, want) + } + + const methodName = "UpdateAlert" + + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.SecretScanning.UpdateAlert(ctx, "\n", "\n", 1, opts) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + _, resp, err := client.SecretScanning.UpdateAlert(ctx, "o", "r", 1, opts) + return resp, err + }) +} + +func TestSecretScanningService_ListLocationsForAlert(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/repos/o/r/secret-scanning/alerts/1/locations", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + testFormValues(t, r, values{"page": "1", "per_page": "100"}) + + fmt.Fprint(w, `[{ + "type": "commit", + "details": { + "path": "/example/secrets.txt", + "start_line": 1, + "end_line": 1, + "start_column": 1, + "end_column": 64, + "blob_sha": "af5626b4a114abcb82d63db7c8082c3c4756e51b", + "blob_url": "https://api.github.com/repos/o/r/git/blobs/af5626b4a114abcb82d63db7c8082c3c4756e51b", + "commit_sha": "f14d7debf9775f957cf4f1e8176da0786431f72b", + "commit_url": "https://api.github.com/repos/o/r/git/commits/f14d7debf9775f957cf4f1e8176da0786431f72b" + } + }]`) + }) + + ctx := context.Background() + opts := &ListOptions{Page: 1, PerPage: 100} + + locations, _, err := client.SecretScanning.ListLocationsForAlert(ctx, "o", "r", 1, opts) + if err != nil { + t.Errorf("SecretScanning.ListLocationsForAlert returned error: %v", err) + } + + want := []*SecretScanningAlertLocation{ + { + Type: String("commit"), + Details: &SecretScanningAlertLocationDetails{ + Path: String("/example/secrets.txt"), + Startline: Int(1), + EndLine: Int(1), + StartColumn: Int(1), + EndColumn: Int(64), + BlobSHA: String("af5626b4a114abcb82d63db7c8082c3c4756e51b"), + BlobURL: String("https://api.github.com/repos/o/r/git/blobs/af5626b4a114abcb82d63db7c8082c3c4756e51b"), + CommitSHA: String("f14d7debf9775f957cf4f1e8176da0786431f72b"), + CommitURL: String("https://api.github.com/repos/o/r/git/commits/f14d7debf9775f957cf4f1e8176da0786431f72b"), + }, + }, + } + + if !cmp.Equal(locations, want) { + t.Errorf("SecretScanning.ListLocationsForAlert returned %+v, want %+v", locations, want) + } + + const methodName = "ListLocationsForAlert" + + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.SecretScanning.ListLocationsForAlert(ctx, "\n", "\n", 1, opts) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + _, resp, err := client.SecretScanning.ListLocationsForAlert(ctx, "o", "r", 1, opts) + return resp, err + }) +}