+
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
f97ab6d
add PushProtectionBypasses and ScanHistory in secret scanning endpoints
Not-Dhananjay-Mishra Aug 18, 2025
895f152
use timestamp instead of time.Time
Not-Dhananjay-Mishra Aug 18, 2025
3a24cda
change method names
Not-Dhananjay-Mishra Aug 18, 2025
52ce83a
fix comments
Not-Dhananjay-Mishra Aug 18, 2025
9908a2d
add comments to struct and change some name
Not-Dhananjay-Mishra Aug 18, 2025
25437f3
fix comments
Not-Dhananjay-Mishra Aug 18, 2025
317ee25
fix comments
Not-Dhananjay-Mishra Aug 18, 2025
3ba69ca
Merge branch 'master' into feat-3686
Not-Dhananjay-Mishra Aug 18, 2025
4aa75c6
Merge branch 'master' into feat-3686
Not-Dhananjay-Mishra Aug 18, 2025
6f7860e
add omitempty
Not-Dhananjay-Mishra Aug 18, 2025
c7213dc
use omitempty where needed and adjust names
Not-Dhananjay-Mishra Aug 18, 2025
1d091ff
fix responsePushProtectionBypass
Not-Dhananjay-Mishra Aug 18, 2025
6606dd4
Merge branch 'master' into feat-3686
Not-Dhananjay-Mishra Aug 19, 2025
399ec39
Merge branch 'master' into feat-3686
gmlewis Sep 22, 2025
a4badd1
Merge branch 'master' into feat-3686
gmlewis Sep 22, 2025
3ccea73
Merge branch 'master' into feat-3686
gmlewis Sep 22, 2025
d92b8d2
change struct name
Not-Dhananjay-Mishra Sep 30, 2025
7dfdcfd
Merge branch 'master' into feat-3686
Not-Dhananjay-Mishra Sep 30, 2025
82cb264
Merge branch 'master' into feat-3686
Not-Dhananjay-Mishra Oct 1, 2025
cfa6d5e
Merge branch 'master' into feat-3686
Not-Dhananjay-Mishra Oct 7, 2025
71aa241
Merge branch 'google:master' into feat-3686
Not-Dhananjay-Mishra Oct 7, 2025
be5f36d
change context
Not-Dhananjay-Mishra Oct 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions github/github-accessors.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

55 changes: 55 additions & 0 deletions github/github-accessors_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

96 changes: 96 additions & 0 deletions github/secret_scanning.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,53 @@ type SecretScanningAlertUpdateOptions struct {
ResolutionComment *string `json:"resolution_comment,omitempty"`
}

// PushProtectionBypassRequest represents the parameters for CreatePushProtectionBypass.
type PushProtectionBypassRequest struct {
// The reason for bypassing push protection.
// Can be one of: false_positive, used_in_tests, will_fix_later
Reason string `json:"reason"`
// PlaceholderID is an identifier used for the bypass request.
// GitHub Secret Scanning provides you with a unique PlaceholderID associated with that specific blocked push.
PlaceholderID string `json:"placeholder_id"`
}

// PushProtectionBypass represents the response from CreatePushProtectionBypass.
type PushProtectionBypass struct {
// The reason for bypassing push protection.
Reason string `json:"reason"`
// The time that the bypass will expire in ISO 8601 format.
ExpireAt *Timestamp `json:"expire_at"`
// The token type this bypass is for.
TokenType string `json:"token_type"`
}

// SecretsScan represents the common fields for a secret scanning scan.
type SecretsScan struct {
Type string `json:"type"`
Status string `json:"status"`
CompletedAt *Timestamp `json:"completed_at,omitempty"`
StartedAt *Timestamp `json:"started_at,omitempty"`
}

// CustomPatternBackfillScan represents a scan with an associated custom pattern.
type CustomPatternBackfillScan struct {
SecretsScan
PatternSlug *string `json:"pattern_slug,omitempty"`
PatternScope *string `json:"pattern_scope,omitempty"`
}

// SecretScanningScanHistory is the top-level struct for the secret scanning API response.
type SecretScanningScanHistory struct {
// Information on incremental scan performed by secret scanning on the repository.
IncrementalScans []*SecretsScan `json:"incremental_scans,omitempty"`
// Information on backfill scan performed by secret scanning on the repository.
BackfillScans []*SecretsScan `json:"backfill_scans,omitempty"`
// Information on pattern update scan performed by secret scanning on the repository.
PatternUpdateScans []*SecretsScan `json:"pattern_update_scans,omitempty"`
// Information on custom pattern backfill scan performed by secret scanning on the repository.
CustomPatternBackfillScans []*CustomPatternBackfillScan `json:"custom_pattern_backfill_scans,omitempty"`
}

// ListAlertsForEnterprise 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
Expand Down Expand Up @@ -285,3 +332,52 @@ func (s *SecretScanningService) ListLocationsForAlert(ctx context.Context, owner

return locations, resp, nil
}

// CreatePushProtectionBypass creates a push protection bypass for a given 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/rest/secret-scanning/secret-scanning#create-a-push-protection-bypass
//
//meta:operation POST /repos/{owner}/{repo}/secret-scanning/push-protection-bypasses
func (s *SecretScanningService) CreatePushProtectionBypass(ctx context.Context, owner, repo string, request PushProtectionBypassRequest) (*PushProtectionBypass, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/secret-scanning/push-protection-bypasses", owner, repo)

req, err := s.client.NewRequest("POST", u, request)
if err != nil {
return nil, nil, err
}

var pushProtectionBypass *PushProtectionBypass
resp, err := s.client.Do(ctx, req, &pushProtectionBypass)
if err != nil {
return nil, resp, err
}
return pushProtectionBypass, resp, nil
}

// GetScanHistory fetches the secret scanning history for a given 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 and gitHub advanced security or secret scanning must be enabled.
//
// GitHub API docs: https://docs.github.com/rest/secret-scanning/secret-scanning#get-secret-scanning-scan-history-for-a-repository
//
//meta:operation GET /repos/{owner}/{repo}/secret-scanning/scan-history
func (s *SecretScanningService) GetScanHistory(ctx context.Context, owner, repo string) (*SecretScanningScanHistory, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/secret-scanning/scan-history", owner, repo)

req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}

var secretScanningHistory *SecretScanningScanHistory
resp, err := s.client.Do(ctx, req, &secretScanningHistory)
if err != nil {
return nil, resp, err
}

return secretScanningHistory, resp, nil
}
125 changes: 125 additions & 0 deletions github/secret_scanning_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -616,3 +616,128 @@ func TestSecretScanningAlertUpdateOptions_Marshal(t *testing.T) {

testJSONMarshal(t, u, want)
}

func TestSecretScanningService_CreatePushProtectionBypass(t *testing.T) {
t.Parallel()
client, mux, _ := setup(t)

owner := "o"
repo := "r"

mux.HandleFunc(fmt.Sprintf("/repos/%v/%v/secret-scanning/push-protection-bypasses", owner, repo), func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "POST")
var v *PushProtectionBypassRequest
assertNilError(t, json.NewDecoder(r.Body).Decode(&v))
want := &PushProtectionBypassRequest{Reason: "valid reason", PlaceholderID: "bypass-123"}
if !cmp.Equal(v, want) {
t.Errorf("Request body = %+v, want %+v", v, want)
}

fmt.Fprint(w, `{
"reason": "valid reason",
"expire_at": "2018-01-01T00:00:00Z",
"token_type": "github_token"
}`)
})

ctx := t.Context()
opts := PushProtectionBypassRequest{Reason: "valid reason", PlaceholderID: "bypass-123"}

bypass, _, err := client.SecretScanning.CreatePushProtectionBypass(ctx, owner, repo, opts)
if err != nil {
t.Errorf("SecretScanning.CreatePushProtectionBypass returned error: %v", err)
}

expireTime := Timestamp{time.Date(2018, time.January, 1, 0, 0, 0, 0, time.UTC)}
want := &PushProtectionBypass{
Reason: "valid reason",
ExpireAt: &expireTime,
TokenType: "github_token",
}

if !cmp.Equal(bypass, want) {
t.Errorf("SecretScanning.CreatePushProtectionBypass returned %+v, want %+v", bypass, want)
}
const methodName = "CreatePushProtectionBypass"
testBadOptions(t, methodName, func() (err error) {
_, _, err = client.SecretScanning.CreatePushProtectionBypass(ctx, "\n", "\n", opts)
return err
})
testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
_, resp, err := client.SecretScanning.CreatePushProtectionBypass(ctx, "o", "r", opts)
return resp, err
})
}

func TestSecretScanningService_GetScanHistory(t *testing.T) {
t.Parallel()
client, mux, _ := setup(t)

owner := "o"
repo := "r"

mux.HandleFunc(fmt.Sprintf("/repos/%v/%v/secret-scanning/scan-history", owner, repo), func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `{
"incremental_scans": [
{
"type": "incremental",
"status": "success",
"completed_at": "2025-07-29T10:00:00Z",
"started_at": "2025-07-29T09:55:00Z"
}
],
"backfill_scans": [],
"pattern_update_scans": [],
"custom_pattern_backfill_scans": [
{
"type": "custom_backfill",
"status": "in_progress",
"completed_at": null,
"started_at": "2025-07-29T09:00:00Z",
"pattern_slug": "my-custom-pattern",
"pattern_scope": "organization"
}
]
}`)
})

ctx := t.Context()

history, _, err := client.SecretScanning.GetScanHistory(ctx, owner, repo)
if err != nil {
t.Errorf("SecretScanning.GetScanHistory returned error: %v", err)
}

incrementalScanStartAt := Timestamp{time.Date(2025, time.July, 29, 9, 55, 0, 0, time.UTC)}
incrementalScancompleteAt := Timestamp{time.Date(2025, time.July, 29, 10, 0, 0, 0, time.UTC)}
customPatternBackfillScanStartedAt := Timestamp{time.Date(2025, time.July, 29, 9, 0, 0, 0, time.UTC)}

want := &SecretScanningScanHistory{
IncrementalScans: []*SecretsScan{
{Type: "incremental", Status: "success", CompletedAt: &incrementalScancompleteAt, StartedAt: &incrementalScanStartAt},
},
BackfillScans: []*SecretsScan{},
PatternUpdateScans: []*SecretsScan{},
CustomPatternBackfillScans: []*CustomPatternBackfillScan{
{
SecretsScan: SecretsScan{Type: "custom_backfill", Status: "in_progress", CompletedAt: nil, StartedAt: &customPatternBackfillScanStartedAt},
PatternSlug: Ptr("my-custom-pattern"),
PatternScope: Ptr("organization"),
},
},
}

if !cmp.Equal(history, want) {
t.Errorf("SecretScanning.GetScanHistory returned %+v, want %+v", history, want)
}
const methodName = "GetScanHistory"
testBadOptions(t, methodName, func() (err error) {
_, _, err = client.SecretScanning.GetScanHistory(ctx, "\n", "\n")
return err
})
testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
_, resp, err := client.SecretScanning.GetScanHistory(ctx, "o", "r")
return resp, err
})
}
Loading
点击 这是indexloc提供的php浏览器服务,不要输入任何密码和下载