chore: all HTTP requests now come with a context, timeout, etc.

This commit is contained in:
jamesread 2026-07-28 23:08:20 +01:00
parent aee6db3263
commit e013ec0f88
8 changed files with 43 additions and 13 deletions

View File

@ -28,7 +28,6 @@ require (
github.com/sirupsen/logrus v1.9.4 github.com/sirupsen/logrus v1.9.4
github.com/stretchr/testify v1.11.1 github.com/stretchr/testify v1.11.1
go.akshayshah.org/connectproto v0.6.0 go.akshayshah.org/connectproto v0.6.0
golang.org/x/exp v0.0.0-20260718201538-764159d718ef
golang.org/x/oauth2 v0.36.0 golang.org/x/oauth2 v0.36.0
golang.org/x/sys v0.47.0 golang.org/x/sys v0.47.0
google.golang.org/protobuf v1.36.11 google.golang.org/protobuf v1.36.11
@ -290,6 +289,7 @@ require (
go.uber.org/zap v1.28.0 // indirect go.uber.org/zap v1.28.0 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/crypto v0.54.0 // indirect golang.org/x/crypto v0.54.0 // indirect
golang.org/x/exp v0.0.0-20260718201538-764159d718ef // indirect
golang.org/x/exp/typeparams v0.0.0-20260718201538-764159d718ef // indirect golang.org/x/exp/typeparams v0.0.0-20260718201538-764159d718ef // indirect
golang.org/x/mod v0.38.0 // indirect golang.org/x/mod v0.38.0 // indirect
golang.org/x/net v0.57.0 // indirect golang.org/x/net v0.57.0 // indirect

View File

@ -21,7 +21,7 @@ func TestCheckUserFromLocalBearerApiKey_Match_LowercaseBearerScheme(t *testing.T
ApiKey: "secret-api-key", ApiKey: "secret-api-key",
}} }}
req := httptest.NewRequest("POST", "/", nil) req := httptest.NewRequestWithContext(t.Context(), "POST", "/", nil)
req.Header.Set("Authorization", "bearer secret-api-key") req.Header.Set("Authorization", "bearer secret-api-key")
ctx := &authpublic.AuthCheckingContext{Request: req, Config: cfg} ctx := &authpublic.AuthCheckingContext{Request: req, Config: cfg}
@ -43,7 +43,7 @@ func TestCheckUserFromLocalBearerApiKey_Match(t *testing.T) {
ApiKey: "secret-api-key", ApiKey: "secret-api-key",
}} }}
req := httptest.NewRequest("POST", "/", nil) req := httptest.NewRequestWithContext(t.Context(), "POST", "/", nil)
req.Header.Set("Authorization", "Bearer secret-api-key") req.Header.Set("Authorization", "Bearer secret-api-key")
ctx := &authpublic.AuthCheckingContext{Request: req, Config: cfg} ctx := &authpublic.AuthCheckingContext{Request: req, Config: cfg}
@ -64,7 +64,7 @@ func TestCheckUserFromLocalBearerApiKey_WrongKey(t *testing.T) {
ApiKey: "secret-api-key", ApiKey: "secret-api-key",
}} }}
req := httptest.NewRequest("POST", "/", nil) req := httptest.NewRequestWithContext(t.Context(), "POST", "/", nil)
req.Header.Set("Authorization", "Bearer wrong") req.Header.Set("Authorization", "Bearer wrong")
ctx := &authpublic.AuthCheckingContext{Request: req, Config: cfg} ctx := &authpublic.AuthCheckingContext{Request: req, Config: cfg}
@ -81,7 +81,7 @@ func TestCheckUserFromLocalBearerApiKey_DisabledLocalUsers(t *testing.T) {
ApiKey: "secret-api-key", ApiKey: "secret-api-key",
}} }}
req := httptest.NewRequest("POST", "/", nil) req := httptest.NewRequestWithContext(t.Context(), "POST", "/", nil)
req.Header.Set("Authorization", "Bearer secret-api-key") req.Header.Set("Authorization", "Bearer secret-api-key")
ctx := &authpublic.AuthCheckingContext{Request: req, Config: cfg} ctx := &authpublic.AuthCheckingContext{Request: req, Config: cfg}
@ -98,7 +98,7 @@ func TestCheckUserFromLocalBearerApiKey_NoBearerPrefix(t *testing.T) {
ApiKey: "secret-api-key", ApiKey: "secret-api-key",
}} }}
req := httptest.NewRequest("POST", "/", nil) req := httptest.NewRequestWithContext(t.Context(), "POST", "/", nil)
req.Header.Set("Authorization", "secret-api-key") req.Header.Set("Authorization", "secret-api-key")
ctx := &authpublic.AuthCheckingContext{Request: req, Config: cfg} ctx := &authpublic.AuthCheckingContext{Request: req, Config: cfg}

View File

@ -132,7 +132,14 @@ func testJwkValidationWithAudience(t *testing.T, expire int64, expectCode int, c
defer srv.Close() defer srv.Close()
res := makeJWTRequest(t, srv, tokenStr) res := makeJWTRequest(t, srv, tokenStr)
verifyJWTResponse(t, res, expectCode) verifyJWTResponse(t, res, expectCode)
err := res.Body.Close()
if err != nil {
t.Error("Could not close response body", err)
}
} }
func TestJWTSignatureVerificationSucceeds(t *testing.T) { func TestJWTSignatureVerificationSucceeds(t *testing.T) {
@ -167,7 +174,7 @@ func createJWTTokenWithGroups(t *testing.T, privateKey *rsa.PrivateKey, groups i
} }
func makeJWTRequest(t *testing.T, srv *httptest.Server, tokenStr string) *http.Response { func makeJWTRequest(t *testing.T, srv *httptest.Server, tokenStr string) *http.Response {
req, err := http.NewRequest("GET", srv.URL, nil) req, err := http.NewRequestWithContext(t.Context(), "GET", srv.URL, nil)
if err != nil { if err != nil {
t.Fatalf("failed to create request: %v", err) t.Fatalf("failed to create request: %v", err)
} }
@ -177,6 +184,7 @@ func makeJWTRequest(t *testing.T, srv *httptest.Server, tokenStr string) *http.R
if err != nil { if err != nil {
t.Fatalf("Client err: %+v", err) t.Fatalf("Client err: %+v", err)
} }
return res return res
} }

View File

@ -342,7 +342,18 @@ type UserInfo struct {
func getUserInfo(cfg *config.Config, client *http.Client, provider *config.OAuth2Provider) *UserInfo { func getUserInfo(cfg *config.Config, client *http.Client, provider *config.OAuth2Provider) *UserInfo {
ret := &UserInfo{} ret := &UserInfo{}
res, err := client.Get(provider.WhoamiUrl) ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
req, err := http.NewRequestWithContext(ctx, "GET", provider.WhoamiUrl, nil)
if err != nil {
log.Error("Could not construct user data request", err)
return ret
}
res, err := http.DefaultClient.Do(req)
if err != nil { if err != nil {
log.Errorf("Failed to get user data: %v", err) log.Errorf("Failed to get user data: %v", err)

View File

@ -56,7 +56,7 @@ func TestHandleOAuthLoginRejectsWhenStateMapFull(t *testing.T) {
} }
} }
req := httptest.NewRequest(http.MethodGet, "/oauth/login?provider=test", nil) req := httptest.NewRequestWithContext(t.Context(), http.MethodGet, "/oauth/login?provider=test", nil)
rec := httptest.NewRecorder() rec := httptest.NewRecorder()
h.HandleOAuthLogin(rec, req) h.HandleOAuthLogin(rec, req)

View File

@ -1,6 +1,7 @@
package updatecheck package updatecheck
import ( import (
"context"
"encoding/json" "encoding/json"
"github.com/Masterminds/semver" "github.com/Masterminds/semver"
config "github.com/OliveTin/OliveTin/internal/config" config "github.com/OliveTin/OliveTin/internal/config"
@ -10,6 +11,7 @@ import (
"io" "io"
"net/http" "net/http"
"os" "os"
"time"
) )
type versionMapType struct { type versionMapType struct {
@ -84,7 +86,11 @@ func parseIfVersionIsLater(currentString string, latestString string) string {
} }
func doRequest() string { func doRequest() string {
req, err := http.NewRequest("GET", "http://update-check.olivetin.app/versions.json", nil) ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
req, err := http.NewRequestWithContext(ctx, "GET", "http://update-check.olivetin.app/versions.json", nil)
if err != nil { if err != nil {
log.Errorf("Update check failed %v", err) log.Errorf("Update check failed %v", err)

View File

@ -12,7 +12,7 @@ import (
func TestExtractJustificationFromWebhookBody(t *testing.T) { func TestExtractJustificationFromWebhookBody(t *testing.T) {
body := []byte(`{"message":"deploy production","repo":"my-app"}`) body := []byte(`{"message":"deploy production","repo":"my-app"}`)
req, err := http.NewRequest(http.MethodPost, "/webhooks/deploy", nil) req, err := http.NewRequestWithContext(t.Context(), http.MethodPost, "/webhooks/deploy", nil)
require.NoError(t, err) require.NoError(t, err)
matcher := NewWebhookMatcher(config.WebhookConfig{ matcher := NewWebhookMatcher(config.WebhookConfig{
@ -25,7 +25,7 @@ func TestExtractJustificationFromWebhookBody(t *testing.T) {
} }
func TestExtractJustificationEmptyWhenNotConfigured(t *testing.T) { func TestExtractJustificationEmptyWhenNotConfigured(t *testing.T) {
req, err := http.NewRequest(http.MethodPost, "/webhooks/deploy", nil) req, err := http.NewRequestWithContext(t.Context(), http.MethodPost, "/webhooks/deploy", nil)
require.NoError(t, err) require.NoError(t, err)
matcher := NewWebhookMatcher(config.WebhookConfig{}, req, []byte(`{}`)) matcher := NewWebhookMatcher(config.WebhookConfig{}, req, []byte(`{}`))

View File

@ -2,6 +2,7 @@ package main
import ( import (
"bufio" "bufio"
"context"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
@ -323,7 +324,11 @@ func finishTestCommand(cmd *exec.Cmd, state *testRunState) (int, runSummary, []t
} }
func runTestsOnce(rootDir string) (int, runSummary, []testFailure, error) { func runTestsOnce(rootDir string) (int, runSummary, []testFailure, error) {
cmd := exec.Command("go", "test", "./...", "-count=1", "-json") ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
cmd := exec.CommandContext(ctx, "go", "test", "./...", "-count=1", "-json")
cmd.Dir = rootDir cmd.Dir = rootDir
stdout, err := cmd.StdoutPipe() stdout, err := cmd.StdoutPipe()