mirror of
https://github.com/tdurieux/anonymous_github.git
synced 2026-11-14 00:07:00 +01:00
92 lines
3.1 KiB
Go
92 lines
3.1 KiB
Go
package server
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"io"
|
|
"net/http"
|
|
"strconv"
|
|
"strings"
|
|
"sync/atomic"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestGitHubQuotaSuppressesRequests(t *testing.T) {
|
|
var calls atomic.Int64
|
|
reset := time.Now().Add(time.Hour).Truncate(time.Second)
|
|
s := &Server{HTTP: &http.Client{Transport: roundTrip(func(r *http.Request) (*http.Response, error) {
|
|
calls.Add(1)
|
|
h := http.Header{}
|
|
h.Set("X-RateLimit-Reset", strconv.FormatInt(reset.Unix(), 10))
|
|
return &http.Response{StatusCode: 429, Header: h, Body: io.NopCloser(strings.NewReader("private upstream text"))}, nil
|
|
})}}
|
|
ctx := context.Background()
|
|
for i := 0; i < 3; i++ {
|
|
_, err := s.github(ctx, "GET", "/repos/team/project", "synthetic-secret", nil)
|
|
var api *APIError
|
|
if !errors.As(err, &api) || api.Code != "github_rate_limit_exceeded" || api.ResetAt != reset.UnixMilli() {
|
|
t.Fatalf("unexpected error: %+v", err)
|
|
}
|
|
}
|
|
if calls.Load() != 1 {
|
|
t.Fatalf("gate allowed %d requests", calls.Load())
|
|
}
|
|
_, _ = s.github(ctx, "GET", "/repos/team/other", "different-secret", nil)
|
|
if calls.Load() != 2 {
|
|
t.Fatal("independent credential blocked")
|
|
}
|
|
canceled, cancel := context.WithCancel(ctx)
|
|
cancel()
|
|
_, err := s.github(canceled, "GET", "/repos/team/project", "unused-secret", nil)
|
|
if !errors.Is(err, context.Canceled) || calls.Load() != 2 {
|
|
t.Fatal("canceled request dispatched", err)
|
|
}
|
|
}
|
|
|
|
func TestGitHubQuotaSurvivesTokenRotation(t *testing.T) {
|
|
s := &Server{}
|
|
s.registerGitHubQuota("old-secret", "installation:app:42")
|
|
s.registerGitHubQuota("new-secret", "installation:app:42")
|
|
h := http.Header{}
|
|
h.Set("Retry-After", "60")
|
|
limited := s.recordGitHubQuota(context.Background(), "old-secret", h).(*APIError)
|
|
var api *APIError
|
|
if !errors.As(s.checkGitHubQuota(context.Background(), "new-secret"), &api) || api.ResetAt != limited.ResetAt {
|
|
t.Fatal("renewal bypassed quota")
|
|
}
|
|
s.registerGitHubQuota("other-secret", "installation:app:43")
|
|
if err := s.checkGitHubQuota(context.Background(), "other-secret"); err != nil {
|
|
t.Fatal("different installation blocked", err)
|
|
}
|
|
for digest := range s.quotaScopes {
|
|
if strings.Contains(digest, "secret") {
|
|
t.Fatal("plaintext token retained")
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestRawBlobQuotaClosesBodyAndSuppressesRetry(t *testing.T) {
|
|
var calls atomic.Int64
|
|
closed := false
|
|
s := &Server{HTTP: &http.Client{Transport: roundTrip(func(r *http.Request) (*http.Response, error) {
|
|
calls.Add(1)
|
|
h := http.Header{}
|
|
h.Set("X-RateLimit-Remaining", "0")
|
|
h.Set("Retry-After", "60")
|
|
return &http.Response{StatusCode: 403, Header: h, Body: &revocationBody{Reader: strings.NewReader("private upstream body"), closed: &closed}}, nil
|
|
})}}
|
|
record := M{"source": M{"repositoryName": "team/project", "commit": strings.Repeat("a", 40)}}
|
|
row := M{"name": "file.txt"}
|
|
for i := 0; i < 2; i++ {
|
|
body, err := s.rawBlob(context.Background(), record, row, "synthetic-raw-token")
|
|
var api *APIError
|
|
if body != nil || !errors.As(err, &api) || api.Status != 429 {
|
|
t.Fatal("raw quota not normalized", err)
|
|
}
|
|
}
|
|
if !closed || calls.Load() != 1 {
|
|
t.Fatal("raw response leaked or retry dispatched", closed, calls.Load())
|
|
}
|
|
}
|