address review feedback: export_test.go for AllowInsecureHTTPForTest, avoid url.Parse in doRequest
PR Ready Gate / clear-labels (pull_request) Successful in 2s
CI / test (pull_request) Successful in 24s
CI / review (anthropic--claude-4.6-sonnet, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 34s
CI / review (gpt-5, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 1m43s
CI / review (gpt-5, security, ., rodin/security-patterns, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (pull_request) Successful in 1m49s

MINOR #1: Move AllowInsecureHTTPForTest to export_test.go so it is only
available in test binaries and does not pollute the production API surface.

MINOR #2: Replace url.Parse with a strings.EqualFold prefix check in
doRequest's HTTPS enforcement, avoiding a per-request allocation.

NIT #3: Push back — slog.Warn on ignored AllowInsecureHTTP is a deliberate
design choice that helps operators debug 'refusing to send credentials'
errors when the env gate is not set.
This commit is contained in:
claw
2026-05-13 10:48:16 -07:00
parent ce48dc0ec6
commit 91f31ff2d7
2 changed files with 24 additions and 17 deletions
+10 -17
View File
@@ -10,7 +10,6 @@ import (
"io"
"log/slog"
"net/http"
"net/url"
"os"
"strconv"
"strings"
@@ -108,16 +107,6 @@ func AllowInsecureHTTP() ClientOption {
}
}
// AllowInsecureHTTPForTest permits the client to send credentials over HTTP
// without requiring the REVIEW_BOT_ALLOW_INSECURE environment variable.
// This is intended exclusively for tests using httptest.Server.
func AllowInsecureHTTPForTest() ClientOption {
return func(c *clientConfig) {
c.allowInsecureHTTP = true
c.testBypass = true
}
}
// Client interacts with the GitHub API.
// A Client is safe for concurrent use by multiple goroutines.
// SetHTTPClient and SetRetryBackoff are intended for test setup only and must
@@ -173,7 +162,7 @@ func defaultCheckRedirect(req *http.Request, via []*http.Request) error {
// NewClient creates a new GitHub API client.
// If baseURL is empty, it defaults to https://api.github.com.
// For GitHub Enterprise, pass the API base URL (e.g. https://github.concur.com/api/v3).
// The baseURL must use HTTPS unless AllowInsecureHTTP() or AllowInsecureHTTPForTest()
// The baseURL must use HTTPS unless AllowInsecureHTTP() or AllowInsecureHTTPForTest() (test-only)
// is passed as an option.
func NewClient(token, baseURL string, opts ...ClientOption) *Client {
if baseURL == "" {
@@ -273,17 +262,21 @@ func (c *Client) parseRetryAfter(value string) (time.Duration, bool) {
return 0, false
}
// hasHTTPSScheme reports whether rawURL starts with "https://" (case-insensitive).
// It avoids the allocation of url.Parse for a simple scheme check.
func hasHTTPSScheme(rawURL string) bool {
const prefix = "https://"
return len(rawURL) >= len(prefix) && strings.EqualFold(rawURL[:len(prefix)], prefix)
}
// doRequest performs an HTTP request with retry on 429 rate limit responses.
// It respects the Retry-After header when present, supporting both integer
// seconds and HTTP-date formats (capped at maxRetryAfter).
func (c *Client) doRequest(ctx context.Context, method, reqURL string, accept string) ([]byte, error) {
// Reject non-HTTPS URLs when credentials are present and insecure mode is not enabled.
// Uses a string prefix check instead of url.Parse to avoid per-request allocations.
if c.token != "" && !c.allowInsecureHTTP {
parsed, err := url.Parse(reqURL)
if err != nil {
return nil, fmt.Errorf("parse request URL: %w", err)
}
if !strings.EqualFold(parsed.Scheme, "https") {
if !hasHTTPSScheme(reqURL) {
return nil, fmt.Errorf("refusing to send credentials over non-HTTPS URL %q (use AllowInsecureHTTP option for trusted networks)", reqURL)
}
}
+14
View File
@@ -0,0 +1,14 @@
package github
// AllowInsecureHTTPForTest permits the client to send credentials over HTTP
// without requiring the REVIEW_BOT_ALLOW_INSECURE environment variable.
// This is intended exclusively for tests using httptest.Server.
//
// This function lives in export_test.go so it is only available to test
// binaries and does not appear in the production API surface.
func AllowInsecureHTTPForTest() ClientOption {
return func(c *clientConfig) {
c.allowInsecureHTTP = true
c.testBypass = true
}
}