diff --git a/github/github-accessors.go b/github/github-accessors.go index c703fb98d98..71756128d59 100644 --- a/github/github-accessors.go +++ b/github/github-accessors.go @@ -39430,6 +39430,206 @@ func (s *SecretScanningAlertUpdateOptions) GetState() string { return s.State } +// GetPatterns returns the Patterns slice if it's non-nil, nil otherwise. +func (s *SecretScanningCreateCustomPatternsRequest) GetPatterns() []*SecretScanningCustomPatternRequest { + if s == nil || s.Patterns == nil { + return nil + } + return s.Patterns +} + +// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. +func (s *SecretScanningCustomPattern) GetCreatedAt() Timestamp { + if s == nil || s.CreatedAt == nil { + return Timestamp{} + } + return *s.CreatedAt +} + +// GetCustomPatternVersion returns the CustomPatternVersion field if it's non-nil, zero value otherwise. +func (s *SecretScanningCustomPattern) GetCustomPatternVersion() string { + if s == nil || s.CustomPatternVersion == nil { + return "" + } + return *s.CustomPatternVersion +} + +// GetEndDelimiter returns the EndDelimiter field if it's non-nil, zero value otherwise. +func (s *SecretScanningCustomPattern) GetEndDelimiter() string { + if s == nil || s.EndDelimiter == nil { + return "" + } + return *s.EndDelimiter +} + +// GetID returns the ID field. +func (s *SecretScanningCustomPattern) GetID() int64 { + if s == nil { + return 0 + } + return s.ID +} + +// GetMustMatch returns the MustMatch slice if it's non-nil, nil otherwise. +func (s *SecretScanningCustomPattern) GetMustMatch() []string { + if s == nil || s.MustMatch == nil { + return nil + } + return s.MustMatch +} + +// GetMustNotMatch returns the MustNotMatch slice if it's non-nil, nil otherwise. +func (s *SecretScanningCustomPattern) GetMustNotMatch() []string { + if s == nil || s.MustNotMatch == nil { + return nil + } + return s.MustNotMatch +} + +// GetName returns the Name field. +func (s *SecretScanningCustomPattern) GetName() string { + if s == nil { + return "" + } + return s.Name +} + +// GetPattern returns the Pattern field. +func (s *SecretScanningCustomPattern) GetPattern() string { + if s == nil { + return "" + } + return s.Pattern +} + +// GetPushProtectionEnabled returns the PushProtectionEnabled field. +func (s *SecretScanningCustomPattern) GetPushProtectionEnabled() bool { + if s == nil { + return false + } + return s.PushProtectionEnabled +} + +// GetSlug returns the Slug field. +func (s *SecretScanningCustomPattern) GetSlug() string { + if s == nil { + return "" + } + return s.Slug +} + +// GetStartDelimiter returns the StartDelimiter field if it's non-nil, zero value otherwise. +func (s *SecretScanningCustomPattern) GetStartDelimiter() string { + if s == nil || s.StartDelimiter == nil { + return "" + } + return *s.StartDelimiter +} + +// GetState returns the State field if it's non-nil, zero value otherwise. +func (s *SecretScanningCustomPattern) GetState() string { + if s == nil || s.State == nil { + return "" + } + return *s.State +} + +// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. +func (s *SecretScanningCustomPattern) GetUpdatedAt() Timestamp { + if s == nil || s.UpdatedAt == nil { + return Timestamp{} + } + return *s.UpdatedAt +} + +// GetDirection returns the Direction field. +func (s *SecretScanningCustomPatternListOptions) GetDirection() string { + if s == nil { + return "" + } + return s.Direction +} + +// GetPushProtection returns the PushProtection field. +func (s *SecretScanningCustomPatternListOptions) GetPushProtection() string { + if s == nil { + return "" + } + return s.PushProtection +} + +// GetSort returns the Sort field. +func (s *SecretScanningCustomPatternListOptions) GetSort() string { + if s == nil { + return "" + } + return s.Sort +} + +// GetState returns the State field. +func (s *SecretScanningCustomPatternListOptions) GetState() string { + if s == nil { + return "" + } + return s.State +} + +// GetEndDelimiter returns the EndDelimiter field if it's non-nil, zero value otherwise. +func (s *SecretScanningCustomPatternRequest) GetEndDelimiter() string { + if s == nil || s.EndDelimiter == nil { + return "" + } + return *s.EndDelimiter +} + +// GetMustMatch returns the MustMatch slice if it's non-nil, nil otherwise. +func (s *SecretScanningCustomPatternRequest) GetMustMatch() []string { + if s == nil || s.MustMatch == nil { + return nil + } + return s.MustMatch +} + +// GetMustNotMatch returns the MustNotMatch slice if it's non-nil, nil otherwise. +func (s *SecretScanningCustomPatternRequest) GetMustNotMatch() []string { + if s == nil || s.MustNotMatch == nil { + return nil + } + return s.MustNotMatch +} + +// GetName returns the Name field. +func (s *SecretScanningCustomPatternRequest) GetName() string { + if s == nil { + return "" + } + return s.Name +} + +// GetPattern returns the Pattern field. +func (s *SecretScanningCustomPatternRequest) GetPattern() string { + if s == nil { + return "" + } + return s.Pattern +} + +// GetStartDelimiter returns the StartDelimiter field if it's non-nil, zero value otherwise. +func (s *SecretScanningCustomPatternRequest) GetStartDelimiter() string { + if s == nil || s.StartDelimiter == nil { + return "" + } + return *s.StartDelimiter +} + +// GetCreatedPatterns returns the CreatedPatterns slice if it's non-nil, nil otherwise. +func (s *SecretScanningCustomPatternsCreateResponse) GetCreatedPatterns() []*SecretScanningCustomPattern { + if s == nil || s.CreatedPatterns == nil { + return nil + } + return s.CreatedPatterns +} + // GetCustomPatternVersion returns the CustomPatternVersion field if it's non-nil, zero value otherwise. func (s *SecretScanningCustomPatternSetting) GetCustomPatternVersion() string { if s == nil || s.CustomPatternVersion == nil { @@ -39454,6 +39654,22 @@ func (s *SecretScanningCustomPatternSetting) GetTokenType() string { return s.TokenType } +// GetCustomPatternVersion returns the CustomPatternVersion field if it's non-nil, zero value otherwise. +func (s *SecretScanningCustomPatternToDelete) GetCustomPatternVersion() string { + if s == nil || s.CustomPatternVersion == nil { + return "" + } + return *s.CustomPatternVersion +} + +// GetPatternID returns the PatternID field. +func (s *SecretScanningCustomPatternToDelete) GetPatternID() int64 { + if s == nil { + return 0 + } + return s.PatternID +} + // GetReviewers returns the Reviewers slice if it's non-nil, nil otherwise. func (s *SecretScanningDelegatedBypassOptions) GetReviewers() []*BypassReviewer { if s == nil || s.Reviewers == nil { @@ -39462,6 +39678,22 @@ func (s *SecretScanningDelegatedBypassOptions) GetReviewers() []*BypassReviewer return s.Reviewers } +// GetPatterns returns the Patterns slice if it's non-nil, nil otherwise. +func (s *SecretScanningDeleteCustomPatternsRequest) GetPatterns() []*SecretScanningCustomPatternToDelete { + if s == nil || s.Patterns == nil { + return nil + } + return s.Patterns +} + +// GetPostDeleteAction returns the PostDeleteAction field if it's non-nil, zero value otherwise. +func (s *SecretScanningDeleteCustomPatternsRequest) GetPostDeleteAction() string { + if s == nil || s.PostDeleteAction == nil { + return "" + } + return *s.PostDeleteAction +} + // GetCustomPatternOverrides returns the CustomPatternOverrides slice if it's non-nil, nil otherwise. func (s *SecretScanningPatternConfigs) GetCustomPatternOverrides() []*SecretScanningPatternOverride { if s == nil || s.CustomPatternOverrides == nil { @@ -39670,6 +39902,54 @@ func (s *SecretScanningScanHistory) GetPatternUpdateScans() []*SecretsScan { return s.PatternUpdateScans } +// GetCustomPatternVersion returns the CustomPatternVersion field if it's non-nil, zero value otherwise. +func (s *SecretScanningUpdateCustomPatternRequest) GetCustomPatternVersion() string { + if s == nil || s.CustomPatternVersion == nil { + return "" + } + return *s.CustomPatternVersion +} + +// GetEndDelimiter returns the EndDelimiter field if it's non-nil, zero value otherwise. +func (s *SecretScanningUpdateCustomPatternRequest) GetEndDelimiter() string { + if s == nil || s.EndDelimiter == nil { + return "" + } + return *s.EndDelimiter +} + +// GetMustMatch returns the MustMatch slice if it's non-nil, nil otherwise. +func (s *SecretScanningUpdateCustomPatternRequest) GetMustMatch() []string { + if s == nil || s.MustMatch == nil { + return nil + } + return s.MustMatch +} + +// GetMustNotMatch returns the MustNotMatch slice if it's non-nil, nil otherwise. +func (s *SecretScanningUpdateCustomPatternRequest) GetMustNotMatch() []string { + if s == nil || s.MustNotMatch == nil { + return nil + } + return s.MustNotMatch +} + +// GetPattern returns the Pattern field if it's non-nil, zero value otherwise. +func (s *SecretScanningUpdateCustomPatternRequest) GetPattern() string { + if s == nil || s.Pattern == nil { + return "" + } + return *s.Pattern +} + +// GetStartDelimiter returns the StartDelimiter field if it's non-nil, zero value otherwise. +func (s *SecretScanningUpdateCustomPatternRequest) GetStartDelimiter() string { + if s == nil || s.StartDelimiter == nil { + return "" + } + return *s.StartDelimiter +} + // GetStatus returns the Status field if it's non-nil, zero value otherwise. func (s *SecretScanningValidityChecks) GetStatus() string { if s == nil || s.Status == nil { diff --git a/github/github-accessors_test.go b/github/github-accessors_test.go index 38cfcbb866e..ab67c971fe1 100644 --- a/github/github-accessors_test.go +++ b/github/github-accessors_test.go @@ -49388,6 +49388,248 @@ func TestSecretScanningAlertUpdateOptions_GetState(tt *testing.T) { s.GetState() } +func TestSecretScanningCreateCustomPatternsRequest_GetPatterns(tt *testing.T) { + tt.Parallel() + zeroValue := []*SecretScanningCustomPatternRequest{} + s := &SecretScanningCreateCustomPatternsRequest{Patterns: zeroValue} + s.GetPatterns() + s = &SecretScanningCreateCustomPatternsRequest{} + s.GetPatterns() + s = nil + s.GetPatterns() +} + +func TestSecretScanningCustomPattern_GetCreatedAt(tt *testing.T) { + tt.Parallel() + var zeroValue Timestamp + s := &SecretScanningCustomPattern{CreatedAt: &zeroValue} + s.GetCreatedAt() + s = &SecretScanningCustomPattern{} + s.GetCreatedAt() + s = nil + s.GetCreatedAt() +} + +func TestSecretScanningCustomPattern_GetCustomPatternVersion(tt *testing.T) { + tt.Parallel() + var zeroValue string + s := &SecretScanningCustomPattern{CustomPatternVersion: &zeroValue} + s.GetCustomPatternVersion() + s = &SecretScanningCustomPattern{} + s.GetCustomPatternVersion() + s = nil + s.GetCustomPatternVersion() +} + +func TestSecretScanningCustomPattern_GetEndDelimiter(tt *testing.T) { + tt.Parallel() + var zeroValue string + s := &SecretScanningCustomPattern{EndDelimiter: &zeroValue} + s.GetEndDelimiter() + s = &SecretScanningCustomPattern{} + s.GetEndDelimiter() + s = nil + s.GetEndDelimiter() +} + +func TestSecretScanningCustomPattern_GetID(tt *testing.T) { + tt.Parallel() + s := &SecretScanningCustomPattern{} + s.GetID() + s = nil + s.GetID() +} + +func TestSecretScanningCustomPattern_GetMustMatch(tt *testing.T) { + tt.Parallel() + zeroValue := []string{} + s := &SecretScanningCustomPattern{MustMatch: zeroValue} + s.GetMustMatch() + s = &SecretScanningCustomPattern{} + s.GetMustMatch() + s = nil + s.GetMustMatch() +} + +func TestSecretScanningCustomPattern_GetMustNotMatch(tt *testing.T) { + tt.Parallel() + zeroValue := []string{} + s := &SecretScanningCustomPattern{MustNotMatch: zeroValue} + s.GetMustNotMatch() + s = &SecretScanningCustomPattern{} + s.GetMustNotMatch() + s = nil + s.GetMustNotMatch() +} + +func TestSecretScanningCustomPattern_GetName(tt *testing.T) { + tt.Parallel() + s := &SecretScanningCustomPattern{} + s.GetName() + s = nil + s.GetName() +} + +func TestSecretScanningCustomPattern_GetPattern(tt *testing.T) { + tt.Parallel() + s := &SecretScanningCustomPattern{} + s.GetPattern() + s = nil + s.GetPattern() +} + +func TestSecretScanningCustomPattern_GetPushProtectionEnabled(tt *testing.T) { + tt.Parallel() + s := &SecretScanningCustomPattern{} + s.GetPushProtectionEnabled() + s = nil + s.GetPushProtectionEnabled() +} + +func TestSecretScanningCustomPattern_GetSlug(tt *testing.T) { + tt.Parallel() + s := &SecretScanningCustomPattern{} + s.GetSlug() + s = nil + s.GetSlug() +} + +func TestSecretScanningCustomPattern_GetStartDelimiter(tt *testing.T) { + tt.Parallel() + var zeroValue string + s := &SecretScanningCustomPattern{StartDelimiter: &zeroValue} + s.GetStartDelimiter() + s = &SecretScanningCustomPattern{} + s.GetStartDelimiter() + s = nil + s.GetStartDelimiter() +} + +func TestSecretScanningCustomPattern_GetState(tt *testing.T) { + tt.Parallel() + var zeroValue string + s := &SecretScanningCustomPattern{State: &zeroValue} + s.GetState() + s = &SecretScanningCustomPattern{} + s.GetState() + s = nil + s.GetState() +} + +func TestSecretScanningCustomPattern_GetUpdatedAt(tt *testing.T) { + tt.Parallel() + var zeroValue Timestamp + s := &SecretScanningCustomPattern{UpdatedAt: &zeroValue} + s.GetUpdatedAt() + s = &SecretScanningCustomPattern{} + s.GetUpdatedAt() + s = nil + s.GetUpdatedAt() +} + +func TestSecretScanningCustomPatternListOptions_GetDirection(tt *testing.T) { + tt.Parallel() + s := &SecretScanningCustomPatternListOptions{} + s.GetDirection() + s = nil + s.GetDirection() +} + +func TestSecretScanningCustomPatternListOptions_GetPushProtection(tt *testing.T) { + tt.Parallel() + s := &SecretScanningCustomPatternListOptions{} + s.GetPushProtection() + s = nil + s.GetPushProtection() +} + +func TestSecretScanningCustomPatternListOptions_GetSort(tt *testing.T) { + tt.Parallel() + s := &SecretScanningCustomPatternListOptions{} + s.GetSort() + s = nil + s.GetSort() +} + +func TestSecretScanningCustomPatternListOptions_GetState(tt *testing.T) { + tt.Parallel() + s := &SecretScanningCustomPatternListOptions{} + s.GetState() + s = nil + s.GetState() +} + +func TestSecretScanningCustomPatternRequest_GetEndDelimiter(tt *testing.T) { + tt.Parallel() + var zeroValue string + s := &SecretScanningCustomPatternRequest{EndDelimiter: &zeroValue} + s.GetEndDelimiter() + s = &SecretScanningCustomPatternRequest{} + s.GetEndDelimiter() + s = nil + s.GetEndDelimiter() +} + +func TestSecretScanningCustomPatternRequest_GetMustMatch(tt *testing.T) { + tt.Parallel() + zeroValue := []string{} + s := &SecretScanningCustomPatternRequest{MustMatch: zeroValue} + s.GetMustMatch() + s = &SecretScanningCustomPatternRequest{} + s.GetMustMatch() + s = nil + s.GetMustMatch() +} + +func TestSecretScanningCustomPatternRequest_GetMustNotMatch(tt *testing.T) { + tt.Parallel() + zeroValue := []string{} + s := &SecretScanningCustomPatternRequest{MustNotMatch: zeroValue} + s.GetMustNotMatch() + s = &SecretScanningCustomPatternRequest{} + s.GetMustNotMatch() + s = nil + s.GetMustNotMatch() +} + +func TestSecretScanningCustomPatternRequest_GetName(tt *testing.T) { + tt.Parallel() + s := &SecretScanningCustomPatternRequest{} + s.GetName() + s = nil + s.GetName() +} + +func TestSecretScanningCustomPatternRequest_GetPattern(tt *testing.T) { + tt.Parallel() + s := &SecretScanningCustomPatternRequest{} + s.GetPattern() + s = nil + s.GetPattern() +} + +func TestSecretScanningCustomPatternRequest_GetStartDelimiter(tt *testing.T) { + tt.Parallel() + var zeroValue string + s := &SecretScanningCustomPatternRequest{StartDelimiter: &zeroValue} + s.GetStartDelimiter() + s = &SecretScanningCustomPatternRequest{} + s.GetStartDelimiter() + s = nil + s.GetStartDelimiter() +} + +func TestSecretScanningCustomPatternsCreateResponse_GetCreatedPatterns(tt *testing.T) { + tt.Parallel() + zeroValue := []*SecretScanningCustomPattern{} + s := &SecretScanningCustomPatternsCreateResponse{CreatedPatterns: zeroValue} + s.GetCreatedPatterns() + s = &SecretScanningCustomPatternsCreateResponse{} + s.GetCreatedPatterns() + s = nil + s.GetCreatedPatterns() +} + func TestSecretScanningCustomPatternSetting_GetCustomPatternVersion(tt *testing.T) { tt.Parallel() var zeroValue string @@ -49415,6 +49657,25 @@ func TestSecretScanningCustomPatternSetting_GetTokenType(tt *testing.T) { s.GetTokenType() } +func TestSecretScanningCustomPatternToDelete_GetCustomPatternVersion(tt *testing.T) { + tt.Parallel() + var zeroValue string + s := &SecretScanningCustomPatternToDelete{CustomPatternVersion: &zeroValue} + s.GetCustomPatternVersion() + s = &SecretScanningCustomPatternToDelete{} + s.GetCustomPatternVersion() + s = nil + s.GetCustomPatternVersion() +} + +func TestSecretScanningCustomPatternToDelete_GetPatternID(tt *testing.T) { + tt.Parallel() + s := &SecretScanningCustomPatternToDelete{} + s.GetPatternID() + s = nil + s.GetPatternID() +} + func TestSecretScanningDelegatedBypassOptions_GetReviewers(tt *testing.T) { tt.Parallel() zeroValue := []*BypassReviewer{} @@ -49426,6 +49687,28 @@ func TestSecretScanningDelegatedBypassOptions_GetReviewers(tt *testing.T) { s.GetReviewers() } +func TestSecretScanningDeleteCustomPatternsRequest_GetPatterns(tt *testing.T) { + tt.Parallel() + zeroValue := []*SecretScanningCustomPatternToDelete{} + s := &SecretScanningDeleteCustomPatternsRequest{Patterns: zeroValue} + s.GetPatterns() + s = &SecretScanningDeleteCustomPatternsRequest{} + s.GetPatterns() + s = nil + s.GetPatterns() +} + +func TestSecretScanningDeleteCustomPatternsRequest_GetPostDeleteAction(tt *testing.T) { + tt.Parallel() + var zeroValue string + s := &SecretScanningDeleteCustomPatternsRequest{PostDeleteAction: &zeroValue} + s.GetPostDeleteAction() + s = &SecretScanningDeleteCustomPatternsRequest{} + s.GetPostDeleteAction() + s = nil + s.GetPostDeleteAction() +} + func TestSecretScanningPatternConfigs_GetCustomPatternOverrides(tt *testing.T) { tt.Parallel() zeroValue := []*SecretScanningPatternOverride{} @@ -49706,6 +49989,72 @@ func TestSecretScanningScanHistory_GetPatternUpdateScans(tt *testing.T) { s.GetPatternUpdateScans() } +func TestSecretScanningUpdateCustomPatternRequest_GetCustomPatternVersion(tt *testing.T) { + tt.Parallel() + var zeroValue string + s := &SecretScanningUpdateCustomPatternRequest{CustomPatternVersion: &zeroValue} + s.GetCustomPatternVersion() + s = &SecretScanningUpdateCustomPatternRequest{} + s.GetCustomPatternVersion() + s = nil + s.GetCustomPatternVersion() +} + +func TestSecretScanningUpdateCustomPatternRequest_GetEndDelimiter(tt *testing.T) { + tt.Parallel() + var zeroValue string + s := &SecretScanningUpdateCustomPatternRequest{EndDelimiter: &zeroValue} + s.GetEndDelimiter() + s = &SecretScanningUpdateCustomPatternRequest{} + s.GetEndDelimiter() + s = nil + s.GetEndDelimiter() +} + +func TestSecretScanningUpdateCustomPatternRequest_GetMustMatch(tt *testing.T) { + tt.Parallel() + zeroValue := []string{} + s := &SecretScanningUpdateCustomPatternRequest{MustMatch: zeroValue} + s.GetMustMatch() + s = &SecretScanningUpdateCustomPatternRequest{} + s.GetMustMatch() + s = nil + s.GetMustMatch() +} + +func TestSecretScanningUpdateCustomPatternRequest_GetMustNotMatch(tt *testing.T) { + tt.Parallel() + zeroValue := []string{} + s := &SecretScanningUpdateCustomPatternRequest{MustNotMatch: zeroValue} + s.GetMustNotMatch() + s = &SecretScanningUpdateCustomPatternRequest{} + s.GetMustNotMatch() + s = nil + s.GetMustNotMatch() +} + +func TestSecretScanningUpdateCustomPatternRequest_GetPattern(tt *testing.T) { + tt.Parallel() + var zeroValue string + s := &SecretScanningUpdateCustomPatternRequest{Pattern: &zeroValue} + s.GetPattern() + s = &SecretScanningUpdateCustomPatternRequest{} + s.GetPattern() + s = nil + s.GetPattern() +} + +func TestSecretScanningUpdateCustomPatternRequest_GetStartDelimiter(tt *testing.T) { + tt.Parallel() + var zeroValue string + s := &SecretScanningUpdateCustomPatternRequest{StartDelimiter: &zeroValue} + s.GetStartDelimiter() + s = &SecretScanningUpdateCustomPatternRequest{} + s.GetStartDelimiter() + s = nil + s.GetStartDelimiter() +} + func TestSecretScanningValidityChecks_GetStatus(tt *testing.T) { tt.Parallel() var zeroValue string diff --git a/github/github-iterators.go b/github/github-iterators.go index 8248f6b5edb..701004531d7 100644 --- a/github/github-iterators.go +++ b/github/github-iterators.go @@ -6719,6 +6719,37 @@ func (s *SecretScanningService) ListAlertsForRepoIter(ctx context.Context, owner } } +// ListCustomPatternsForRepoIter returns an iterator that paginates through all results of ListCustomPatternsForRepo. +func (s *SecretScanningService) ListCustomPatternsForRepoIter(ctx context.Context, owner string, repo string, opts *SecretScanningCustomPatternListOptions) iter.Seq2[*SecretScanningCustomPattern, error] { + return func(yield func(*SecretScanningCustomPattern, error) bool) { + // Create a copy of opts to avoid mutating the caller's struct + if opts == nil { + opts = &SecretScanningCustomPatternListOptions{} + } else { + opts = Ptr(*opts) + } + + for { + results, resp, err := s.ListCustomPatternsForRepo(ctx, owner, repo, opts) + if err != nil { + yield(nil, err) + return + } + + for _, item := range results { + if !yield(item, nil) { + return + } + } + + if resp.NextPage == 0 { + break + } + opts.ListOptions.Page = resp.NextPage + } + } +} + // ListLocationsForAlertIter returns an iterator that paginates through all results of ListLocationsForAlert. func (s *SecretScanningService) ListLocationsForAlertIter(ctx context.Context, owner string, repo string, number int64, opts *ListOptions) iter.Seq2[*SecretScanningAlertLocation, error] { return func(yield func(*SecretScanningAlertLocation, error) bool) { diff --git a/github/github-iterators_test.go b/github/github-iterators_test.go index 9a3ffc31fd4..ea51452061f 100644 --- a/github/github-iterators_test.go +++ b/github/github-iterators_test.go @@ -14919,6 +14919,78 @@ func TestSecretScanningService_ListAlertsForRepoIter(t *testing.T) { } } +func TestSecretScanningService_ListCustomPatternsForRepoIter(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + var callNum int + mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + callNum++ + switch callNum { + case 1: + w.Header().Set("Link", `; rel="next"`) + fmt.Fprint(w, `[{},{},{}]`) + case 2: + fmt.Fprint(w, `[{},{},{},{}]`) + case 3: + fmt.Fprint(w, `[{},{}]`) + case 4: + w.WriteHeader(http.StatusNotFound) + case 5: + fmt.Fprint(w, `[{},{}]`) + } + }) + + iter := client.SecretScanning.ListCustomPatternsForRepoIter(t.Context(), "", "", nil) + var gotItems int + for _, err := range iter { + gotItems++ + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + } + if want := 7; gotItems != want { + t.Errorf("client.SecretScanning.ListCustomPatternsForRepoIter call 1 got %v items; want %v", gotItems, want) + } + + opts := &SecretScanningCustomPatternListOptions{} + iter = client.SecretScanning.ListCustomPatternsForRepoIter(t.Context(), "", "", opts) + gotItems = 0 + for _, err := range iter { + gotItems++ + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + } + if want := 2; gotItems != want { + t.Errorf("client.SecretScanning.ListCustomPatternsForRepoIter call 2 got %v items; want %v", gotItems, want) + } + + iter = client.SecretScanning.ListCustomPatternsForRepoIter(t.Context(), "", "", nil) + gotItems = 0 + for _, err := range iter { + gotItems++ + if err == nil { + t.Error("expected error; got nil") + } + } + if gotItems != 1 { + t.Errorf("client.SecretScanning.ListCustomPatternsForRepoIter call 3 got %v items; want 1 (an error)", gotItems) + } + + iter = client.SecretScanning.ListCustomPatternsForRepoIter(t.Context(), "", "", nil) + gotItems = 0 + iter(func(item *SecretScanningCustomPattern, err error) bool { + gotItems++ + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + return false + }) + if gotItems != 1 { + t.Errorf("client.SecretScanning.ListCustomPatternsForRepoIter call 4 got %v items; want 1 (an error)", gotItems) + } +} + func TestSecretScanningService_ListLocationsForAlertIter(t *testing.T) { t.Parallel() client, mux, _ := setup(t) diff --git a/github/secret_scanning_custom_patterns.go b/github/secret_scanning_custom_patterns.go new file mode 100644 index 00000000000..f7c9ac46e2f --- /dev/null +++ b/github/secret_scanning_custom_patterns.go @@ -0,0 +1,263 @@ +// Copyright 2026 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" +) + +// SecretScanningCustomPattern represents a custom pattern for secret scanning, +// as returned by the GitHub API. +// +// GitHub API docs: https://docs.github.com/en/rest/secret-scanning/secret-scanning +type SecretScanningCustomPattern struct { + // ID is the unique identifier of the custom pattern. + ID int64 `json:"id"` + + // Name is the name of the custom pattern. + Name string `json:"name"` + + // Pattern is the regular expression that defines the custom pattern. + Pattern string `json:"pattern"` + + // Slug is the URL-friendly identifier derived from the pattern name. + Slug string `json:"slug"` + + // State is the publish state of the pattern. Possible values are: + // "published" or "unpublished". + State *string `json:"state,omitempty"` + + // PushProtectionEnabled reports whether push protection is enabled for + // this custom pattern. + PushProtectionEnabled bool `json:"push_protection_enabled"` + + // StartDelimiter is the start delimiter regex for the custom pattern. + StartDelimiter *string `json:"start_delimiter,omitempty"` + + // EndDelimiter is the end delimiter regex for the custom pattern. + EndDelimiter *string `json:"end_delimiter,omitempty"` + + // MustMatch is the list of regexes that the secret must match. + MustMatch []string `json:"must_match,omitempty"` + + // MustNotMatch is the list of regexes that the secret must not match. + MustNotMatch []string `json:"must_not_match,omitempty"` + + // CustomPatternVersion is used to confirm you're updating the current + // version of the pattern and to avoid unintentionally overriding + // someone else's update. + CustomPatternVersion *string `json:"custom_pattern_version,omitempty"` + + // CreatedAt is the time the custom pattern was created. + CreatedAt *Timestamp `json:"created_at,omitempty"` + + // UpdatedAt is the time the custom pattern was last updated. + UpdatedAt *Timestamp `json:"updated_at,omitempty"` +} + +// SecretScanningCustomPatternRequest represents a single custom pattern to +// be created for secret scanning. +type SecretScanningCustomPatternRequest struct { + // Name is the name of the custom pattern. + Name string `json:"name"` + + // Pattern is the regular expression that defines the custom pattern. + Pattern string `json:"pattern"` + + // StartDelimiter is the start delimiter regex for the custom pattern. + // Defaults to a sensible boundary regex when not specified. + StartDelimiter *string `json:"start_delimiter,omitempty"` + + // EndDelimiter is the end delimiter regex for the custom pattern. + // Defaults to a sensible boundary regex when not specified. + EndDelimiter *string `json:"end_delimiter,omitempty"` + + // MustMatch is the list of regexes that the secret must match. + MustMatch []string `json:"must_match,omitempty"` + + // MustNotMatch is the list of regexes that the secret must not match. + MustNotMatch []string `json:"must_not_match,omitempty"` +} + +// SecretScanningCreateCustomPatternsRequest represents the bulk request body +// used to create one or more custom patterns. +type SecretScanningCreateCustomPatternsRequest struct { + // Patterns is the list of custom patterns to create. + Patterns []*SecretScanningCustomPatternRequest `json:"patterns"` +} + +// SecretScanningCustomPatternsCreateResponse represents the bulk response +// returned after creating one or more custom patterns. +type SecretScanningCustomPatternsCreateResponse struct { + // CreatedPatterns is the list of successfully created custom patterns. + CreatedPatterns []*SecretScanningCustomPattern `json:"created_patterns"` +} + +// SecretScanningCustomPatternToDelete identifies a single custom pattern to +// remove in a bulk delete operation. +type SecretScanningCustomPatternToDelete struct { + // PatternID is the ID of the custom pattern to delete. + PatternID int64 `json:"pattern_id"` + + // CustomPatternVersion is used to confirm you're deleting the current + // version of the pattern. + CustomPatternVersion *string `json:"custom_pattern_version,omitempty"` +} + +// SecretScanningDeleteCustomPatternsRequest represents the bulk request body +// used to delete one or more custom patterns. +type SecretScanningDeleteCustomPatternsRequest struct { + // Patterns is the list of custom patterns to delete. + Patterns []*SecretScanningCustomPatternToDelete `json:"patterns"` + + // PostDeleteAction controls what happens to alerts associated with the + // deleted patterns. Possible values are: "delete_alerts" (default) or + // "resolve_alerts". + PostDeleteAction *string `json:"post_delete_action,omitempty"` +} + +// SecretScanningUpdateCustomPatternRequest represents the fields that can be +// updated on an existing custom pattern. At least one of Pattern, +// StartDelimiter, EndDelimiter, MustMatch, or MustNotMatch must be set. +type SecretScanningUpdateCustomPatternRequest struct { + // Pattern is the updated regular expression of the custom pattern. + Pattern *string `json:"pattern,omitempty"` + + // StartDelimiter is the updated start delimiter regex for the custom + // pattern. + StartDelimiter *string `json:"start_delimiter,omitempty"` + + // EndDelimiter is the updated end delimiter regex for the custom + // pattern. + EndDelimiter *string `json:"end_delimiter,omitempty"` + + // MustMatch is the updated list of regexes that the secret must match. + MustMatch []string `json:"must_match,omitempty"` + + // MustNotMatch is the updated list of regexes that the secret must not + // match. + MustNotMatch []string `json:"must_not_match,omitempty"` + + // CustomPatternVersion is required and is used to confirm you're + // updating the current version of the pattern. + CustomPatternVersion *string `json:"custom_pattern_version"` +} + +// SecretScanningCustomPatternListOptions specifies the optional parameters +// to the SecretScanningService.ListCustomPatternsForRepo method. +type SecretScanningCustomPatternListOptions struct { + // State filters custom patterns by state. Possible values are: + // "published" or "unpublished". When absent, returns patterns in all + // states. + State string `url:"state,omitempty"` + + // PushProtection filters custom patterns by whether push protection is + // enabled. Possible values are: "enabled" or "disabled". When absent, + // returns patterns regardless of push protection status. + PushProtection string `url:"push_protection,omitempty"` + + // Sort is the property to sort the results by. Possible values are: + // "created", "updated", or "name". Default: "created". + Sort string `url:"sort,omitempty"` + + // Direction is the direction to sort the results by. Possible values + // are: "asc" or "desc". Default: "desc". + Direction string `url:"direction,omitempty"` + + // ListOptions controls pagination via Page and PerPage. + ListOptions +} + +// ListCustomPatternsForRepo lists the secret scanning custom patterns +// defined at the repository level. +// +// GitHub API docs: https://docs.github.com/rest/secret-scanning/custom-patterns?apiVersion=2022-11-28#list-repository-custom-patterns +// +//meta:operation GET /repos/{owner}/{repo}/secret-scanning/custom-patterns +func (s *SecretScanningService) ListCustomPatternsForRepo(ctx context.Context, owner, repo string, opts *SecretScanningCustomPatternListOptions) ([]*SecretScanningCustomPattern, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/secret-scanning/custom-patterns", owner, repo) + u, err := addOptions(u, opts) + if err != nil { + return nil, nil, err + } + + req, err := s.client.NewRequest(ctx, "GET", u, nil) + if err != nil { + return nil, nil, err + } + + var patterns []*SecretScanningCustomPattern + resp, err := s.client.Do(req, &patterns) + if err != nil { + return nil, resp, err + } + + return patterns, resp, nil +} + +// CreateCustomPatternsForRepo creates one or more secret scanning custom +// patterns at the repository level. +// +// GitHub API docs: https://docs.github.com/rest/secret-scanning/custom-patterns?apiVersion=2022-11-28#bulk-create-repository-custom-patterns +// +//meta:operation POST /repos/{owner}/{repo}/secret-scanning/custom-patterns +func (s *SecretScanningService) CreateCustomPatternsForRepo(ctx context.Context, owner, repo string, body SecretScanningCreateCustomPatternsRequest) (*SecretScanningCustomPatternsCreateResponse, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/secret-scanning/custom-patterns", owner, repo) + + req, err := s.client.NewRequest(ctx, "POST", u, body) + if err != nil { + return nil, nil, err + } + + var result *SecretScanningCustomPatternsCreateResponse + resp, err := s.client.Do(req, &result) + if err != nil { + return nil, resp, err + } + + return result, resp, nil +} + +// UpdateCustomPatternForRepo updates a single secret scanning custom pattern +// at the repository level. +// +// GitHub API docs: https://docs.github.com/rest/secret-scanning/custom-patterns?apiVersion=2022-11-28#update-a-repository-custom-pattern +// +//meta:operation PATCH /repos/{owner}/{repo}/secret-scanning/custom-patterns/{pattern_id} +func (s *SecretScanningService) UpdateCustomPatternForRepo(ctx context.Context, owner, repo string, patternID int64, body SecretScanningUpdateCustomPatternRequest) (*SecretScanningCustomPattern, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/secret-scanning/custom-patterns/%v", owner, repo, patternID) + + req, err := s.client.NewRequest(ctx, "PATCH", u, body) + if err != nil { + return nil, nil, err + } + + var pattern *SecretScanningCustomPattern + resp, err := s.client.Do(req, &pattern) + if err != nil { + return nil, resp, err + } + + return pattern, resp, nil +} + +// DeleteCustomPatternsForRepo deletes one or more secret scanning custom +// patterns at the repository level. +// +// GitHub API docs: https://docs.github.com/rest/secret-scanning/custom-patterns?apiVersion=2022-11-28#bulk-delete-repository-custom-patterns +// +//meta:operation DELETE /repos/{owner}/{repo}/secret-scanning/custom-patterns +func (s *SecretScanningService) DeleteCustomPatternsForRepo(ctx context.Context, owner, repo string, body SecretScanningDeleteCustomPatternsRequest) (*Response, error) { + u := fmt.Sprintf("repos/%v/%v/secret-scanning/custom-patterns", owner, repo) + + req, err := s.client.NewRequest(ctx, "DELETE", u, body) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} diff --git a/github/secret_scanning_custom_patterns_test.go b/github/secret_scanning_custom_patterns_test.go new file mode 100644 index 00000000000..12bf14178fb --- /dev/null +++ b/github/secret_scanning_custom_patterns_test.go @@ -0,0 +1,246 @@ +// Copyright 2026 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 ( + "fmt" + "net/http" + "testing" + + "github.com/google/go-cmp/cmp" +) + +func TestSecretScanningService_ListCustomPatternsForRepo(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + mux.HandleFunc("/repos/o/r/secret-scanning/custom-patterns", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + testFormValues(t, r, values{ + "state": "published", + "push_protection": "enabled", + "sort": "created", + "direction": "desc", + "page": "2", + }) + fmt.Fprint(w, `[ + { + "id": 1, + "name": "Custom pattern", + "pattern": "[A-Z]{2}-[0-9]{4}", + "slug": "custom-pattern", + "state": "published", + "push_protection_enabled": true, + "start_delimiter": "\\b", + "end_delimiter": "\\b", + "must_match": ["ID-.*"], + "must_not_match": ["TEST-.*"], + "custom_pattern_version": "v1", + "created_at": `+referenceTimeStr+`, + "updated_at": `+referenceTimeStr+` + } + ]`) + }) + + ctx := t.Context() + opts := &SecretScanningCustomPatternListOptions{ + State: "published", + PushProtection: "enabled", + Sort: "created", + Direction: "desc", + ListOptions: ListOptions{Page: 2}, + } + patterns, _, err := client.SecretScanning.ListCustomPatternsForRepo(ctx, "o", "r", opts) + if err != nil { + t.Errorf("SecretScanning.ListCustomPatternsForRepo returned error: %v", err) + } + + want := []*SecretScanningCustomPattern{ + { + ID: 1, + Name: "Custom pattern", + Pattern: "[A-Z]{2}-[0-9]{4}", + Slug: "custom-pattern", + State: Ptr("published"), + PushProtectionEnabled: true, + StartDelimiter: Ptr(`\b`), + EndDelimiter: Ptr(`\b`), + MustMatch: []string{"ID-.*"}, + MustNotMatch: []string{"TEST-.*"}, + CustomPatternVersion: Ptr("v1"), + CreatedAt: &referenceTimestamp, + UpdatedAt: &referenceTimestamp, + }, + } + if !cmp.Equal(patterns, want) { + t.Errorf("SecretScanning.ListCustomPatternsForRepo returned %+v, want %+v", patterns, want) + } + + const methodName = "ListCustomPatternsForRepo" + + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.SecretScanning.ListCustomPatternsForRepo(ctx, "\n", "\n", nil) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + _, resp, err := client.SecretScanning.ListCustomPatternsForRepo(ctx, "o", "r", nil) + return resp, err + }) +} + +func TestSecretScanningService_CreateCustomPatternsForRepo(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + input := SecretScanningCreateCustomPatternsRequest{ + Patterns: []*SecretScanningCustomPatternRequest{ + { + Name: "Custom pattern", + Pattern: "[A-Z]{2}-[0-9]{4}", + }, + }, + } + + mux.HandleFunc("/repos/o/r/secret-scanning/custom-patterns", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "POST") + testJSONBody(t, r, input) + fmt.Fprint(w, `{ + "created_patterns": [ + { + "id": 1, + "name": "Custom pattern", + "pattern": "[A-Z]{2}-[0-9]{4}", + "slug": "custom-pattern", + "state": "published", + "push_protection_enabled": false + } + ] + }`) + }) + + ctx := t.Context() + result, _, err := client.SecretScanning.CreateCustomPatternsForRepo(ctx, "o", "r", input) + if err != nil { + t.Errorf("SecretScanning.CreateCustomPatternsForRepo returned error: %v", err) + } + + want := &SecretScanningCustomPatternsCreateResponse{ + CreatedPatterns: []*SecretScanningCustomPattern{ + { + ID: 1, + Name: "Custom pattern", + Pattern: "[A-Z]{2}-[0-9]{4}", + Slug: "custom-pattern", + State: Ptr("published"), + PushProtectionEnabled: false, + }, + }, + } + if !cmp.Equal(result, want) { + t.Errorf("SecretScanning.CreateCustomPatternsForRepo returned %+v, want %+v", result, want) + } + + const methodName = "CreateCustomPatternsForRepo" + + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.SecretScanning.CreateCustomPatternsForRepo(ctx, "\n", "\n", input) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + _, resp, err := client.SecretScanning.CreateCustomPatternsForRepo(ctx, "o", "r", input) + return resp, err + }) +} + +func TestSecretScanningService_UpdateCustomPatternForRepo(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + input := SecretScanningUpdateCustomPatternRequest{ + Pattern: Ptr("[A-Z]{3}-[0-9]{4}"), + CustomPatternVersion: Ptr("v1"), + } + + mux.HandleFunc("/repos/o/r/secret-scanning/custom-patterns/1", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "PATCH") + testJSONBody(t, r, input) + fmt.Fprint(w, `{ + "id": 1, + "name": "Custom pattern", + "pattern": "[A-Z]{3}-[0-9]{4}", + "slug": "custom-pattern", + "state": "published", + "push_protection_enabled": false, + "custom_pattern_version": "v2" + }`) + }) + + ctx := t.Context() + pattern, _, err := client.SecretScanning.UpdateCustomPatternForRepo(ctx, "o", "r", 1, input) + if err != nil { + t.Errorf("SecretScanning.UpdateCustomPatternForRepo returned error: %v", err) + } + + want := &SecretScanningCustomPattern{ + ID: 1, + Name: "Custom pattern", + Pattern: "[A-Z]{3}-[0-9]{4}", + Slug: "custom-pattern", + State: Ptr("published"), + PushProtectionEnabled: false, + CustomPatternVersion: Ptr("v2"), + } + if !cmp.Equal(pattern, want) { + t.Errorf("SecretScanning.UpdateCustomPatternForRepo returned %+v, want %+v", pattern, want) + } + + const methodName = "UpdateCustomPatternForRepo" + + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.SecretScanning.UpdateCustomPatternForRepo(ctx, "\n", "\n", 1, input) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + _, resp, err := client.SecretScanning.UpdateCustomPatternForRepo(ctx, "o", "r", 1, input) + return resp, err + }) +} + +func TestSecretScanningService_DeleteCustomPatternsForRepo(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + input := SecretScanningDeleteCustomPatternsRequest{ + Patterns: []*SecretScanningCustomPatternToDelete{ + {PatternID: 1}, + }, + } + + mux.HandleFunc("/repos/o/r/secret-scanning/custom-patterns", func(_ http.ResponseWriter, r *http.Request) { + testMethod(t, r, "DELETE") + testJSONBody(t, r, input) + }) + + ctx := t.Context() + _, err := client.SecretScanning.DeleteCustomPatternsForRepo(ctx, "o", "r", input) + if err != nil { + t.Errorf("SecretScanning.DeleteCustomPatternsForRepo returned error: %v", err) + } + + const methodName = "DeleteCustomPatternsForRepo" + + testBadOptions(t, methodName, func() (err error) { + _, err = client.SecretScanning.DeleteCustomPatternsForRepo(ctx, "\n", "\n", input) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + return client.SecretScanning.DeleteCustomPatternsForRepo(ctx, "o", "r", input) + }) +}