Author SHA1 Message Date
sneak 0371d43223 Refresh vendored REPO_POLICIES.md from prompts@origin/main
Check / check (pull_request) Successful in 3m8s
2026-07-07 01:57:04 +02:00
sneak eaa164e83d Adopt scripts-to-rule-them-all: script/ entrypoints, Makefile shims 2026-07-07 01:56:42 +02:00
7 changed files with 64 additions and 120 deletions
+10 -18
View File
@@ -10,23 +10,18 @@
# Status # Status
1.0+. Tagged 1.0.0 on 2026-02-26. Policy violation: main currently 1.0+. Tagged 1.0.0 on 2026-02-26; 8 commits on main since. Policy
fails make check under golangci-lint >= 2.12 (47 lint issues remaining: violation: main currently fails make check (91 lint issues), so the tree
23 gosec, 24 goconst), so the tree is out of compliance until fixed. CI is out of compliance until fixed.
(Dockerfile lint stage, pinned golangci-lint v2.10.1) is green; the pin
bump is tracked in issue #179. The road to release 1.1.0 is tracked in
Gitea issues #175-#182 (milestone 1.1.0).
# Next Step # Next Step
Fix the 22 gosec G710 open-redirect findings in Fix the 47 noctx lint findings (HTTP requests without context) in one
internal/handlers/app.go (issue #176) by validating app IDs in a commit and confirm the count drops under make check. This is the largest
shared redirect helper. of the three lint classes blocking a green main.
# Completed Steps # Completed Steps
- 2026-08-07: Fixed all 47 noctx lint findings: tests now use
httptest.NewRequestWithContext with t.Context() (#175).
- 2026-07-07 Adopted scripts-to-rule-them-all: `script/` entrypoints, - 2026-07-07 Adopted scripts-to-rule-them-all: `script/` entrypoints,
Makefile shims, README Entrypoints section Makefile shims, README Entrypoints section
- 2026-03-11: Monolithic env var editing with bulk save (#158). - 2026-03-11: Monolithic env var editing with bulk save (#158).
@@ -50,14 +45,11 @@ shared redirect helper.
# Future Steps # Future Steps
- Get main green (compliance, ordered): - Get main green (compliance, ordered):
- Fix 22 gosec G710 findings (Next Step, #176). - Fix 47 noctx findings (Next Step).
- Fix 1 gosec G703 finding (#177). - Fix 23 gosec findings.
- Fix 24 goconst findings (#178). - Fix 21 goconst findings.
- Bump Dockerfile golangci-lint pin to v2.12.x (#179).
- Run make check clean on main and keep it green; main must always - Run make check clean on main and keep it green; main must always
pass. pass.
- Confirm .gitea/workflows/check.yml gates merges on make check so main - Confirm .gitea/workflows/check.yml gates merges on make check so main
cannot regress (#180). cannot regress.
- Deploy to fsn1app1 and verify end-to-end (#181), then tag 1.1.0
(#182).
- Resume feature work only after main is green. - Resume feature work only after main is green.
+6 -28
View File
@@ -47,12 +47,7 @@ func setupAPITest(t *testing.T) (*testContext, []*http.Cookie) {
r := apiRouter(tc) r := apiRouter(tc)
loginBody := `{"username":"admin","password":"password123"}` loginBody := `{"username":"admin","password":"password123"}`
req := httptest.NewRequestWithContext( req := httptest.NewRequest(http.MethodPost, "/api/v1/login", strings.NewReader(loginBody))
t.Context(),
http.MethodPost,
"/api/v1/login",
strings.NewReader(loginBody),
)
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
rr := httptest.NewRecorder() rr := httptest.NewRecorder()
@@ -75,7 +70,7 @@ func apiGet(
) *httptest.ResponseRecorder { ) *httptest.ResponseRecorder {
t.Helper() t.Helper()
req := httptest.NewRequestWithContext(t.Context(), http.MethodGet, path, nil) req := httptest.NewRequest(http.MethodGet, path, nil)
for _, c := range cookies { for _, c := range cookies {
req.AddCookie(c) req.AddCookie(c)
@@ -100,12 +95,7 @@ func TestAPILoginSuccess(t *testing.T) {
r := apiRouter(tc) r := apiRouter(tc)
body := `{"username":"admin","password":"password123"}` body := `{"username":"admin","password":"password123"}`
req := httptest.NewRequestWithContext( req := httptest.NewRequest(http.MethodPost, "/api/v1/login", strings.NewReader(body))
t.Context(),
http.MethodPost,
"/api/v1/login",
strings.NewReader(body),
)
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
rr := httptest.NewRecorder() rr := httptest.NewRecorder()
@@ -132,12 +122,7 @@ func TestAPILoginInvalidCredentials(t *testing.T) {
r := apiRouter(tc) r := apiRouter(tc)
body := `{"username":"admin","password":"wrong"}` body := `{"username":"admin","password":"wrong"}`
req := httptest.NewRequestWithContext( req := httptest.NewRequest(http.MethodPost, "/api/v1/login", strings.NewReader(body))
t.Context(),
http.MethodPost,
"/api/v1/login",
strings.NewReader(body),
)
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
rr := httptest.NewRecorder() rr := httptest.NewRecorder()
@@ -154,12 +139,7 @@ func TestAPILoginMissingFields(t *testing.T) {
r := apiRouter(tc) r := apiRouter(tc)
body := `{"username":"","password":""}` body := `{"username":"","password":""}`
req := httptest.NewRequestWithContext( req := httptest.NewRequest(http.MethodPost, "/api/v1/login", strings.NewReader(body))
t.Context(),
http.MethodPost,
"/api/v1/login",
strings.NewReader(body),
)
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
rr := httptest.NewRecorder() rr := httptest.NewRecorder()
@@ -175,9 +155,7 @@ func TestAPIRejectsUnauthenticated(t *testing.T) {
r := apiRouter(tc) r := apiRouter(tc)
req := httptest.NewRequestWithContext( req := httptest.NewRequest(http.MethodGet, "/api/v1/apps", nil)
t.Context(), http.MethodGet, "/api/v1/apps", nil,
)
rr := httptest.NewRecorder() rr := httptest.NewRecorder()
r.ServeHTTP(rr, req) r.ServeHTTP(rr, req)
+33 -59
View File
@@ -193,8 +193,7 @@ func TestHandleHealthCheck(t *testing.T) {
testCtx := setupTestHandlers(t) testCtx := setupTestHandlers(t)
request := httptest.NewRequestWithContext( request := httptest.NewRequest(
t.Context(),
http.MethodGet, http.MethodGet,
"/.well-known/healthcheck.json", "/.well-known/healthcheck.json",
nil, nil,
@@ -219,7 +218,7 @@ func TestHandleSetupGET(t *testing.T) {
testCtx := setupTestHandlers(t) testCtx := setupTestHandlers(t)
request := httptest.NewRequestWithContext(t.Context(), http.MethodGet, "/setup", nil) request := httptest.NewRequest(http.MethodGet, "/setup", nil)
recorder := httptest.NewRecorder() recorder := httptest.NewRecorder()
handler := testCtx.handlers.HandleSetupGET() handler := testCtx.handlers.HandleSetupGET()
@@ -231,18 +230,14 @@ func TestHandleSetupGET(t *testing.T) {
} }
func createSetupFormRequest( func createSetupFormRequest(
t *testing.T,
username, password, confirm string, username, password, confirm string,
) *http.Request { ) *http.Request {
t.Helper()
form := url.Values{} form := url.Values{}
form.Set("username", username) form.Set("username", username)
form.Set("password", password) form.Set("password", password)
form.Set("password_confirm", confirm) form.Set("password_confirm", confirm)
request := httptest.NewRequestWithContext( request := httptest.NewRequest(
t.Context(),
http.MethodPost, http.MethodPost,
"/setup", "/setup",
strings.NewReader(form.Encode()), strings.NewReader(form.Encode()),
@@ -257,7 +252,7 @@ func TestHandleSetupPOSTCreatesUserAndRedirects(t *testing.T) {
testCtx := setupTestHandlers(t) testCtx := setupTestHandlers(t)
request := createSetupFormRequest(t, "admin", "password123", "password123") request := createSetupFormRequest("admin", "password123", "password123")
recorder := httptest.NewRecorder() recorder := httptest.NewRecorder()
handler := testCtx.handlers.HandleSetupPOST() handler := testCtx.handlers.HandleSetupPOST()
@@ -272,7 +267,7 @@ func TestHandleSetupPOSTRejectsEmptyUsername(t *testing.T) {
testCtx := setupTestHandlers(t) testCtx := setupTestHandlers(t)
request := createSetupFormRequest(t, "", "password123", "password123") request := createSetupFormRequest("", "password123", "password123")
recorder := httptest.NewRecorder() recorder := httptest.NewRecorder()
handler := testCtx.handlers.HandleSetupPOST() handler := testCtx.handlers.HandleSetupPOST()
@@ -287,7 +282,7 @@ func TestHandleSetupPOSTRejectsShortPassword(t *testing.T) {
testCtx := setupTestHandlers(t) testCtx := setupTestHandlers(t)
request := createSetupFormRequest(t, "admin", "short", "short") request := createSetupFormRequest("admin", "short", "short")
recorder := httptest.NewRecorder() recorder := httptest.NewRecorder()
handler := testCtx.handlers.HandleSetupPOST() handler := testCtx.handlers.HandleSetupPOST()
@@ -302,7 +297,7 @@ func TestHandleSetupPOSTRejectsMismatchedPasswords(t *testing.T) {
testCtx := setupTestHandlers(t) testCtx := setupTestHandlers(t)
request := createSetupFormRequest(t, "admin", "password123", "different123") request := createSetupFormRequest("admin", "password123", "different123")
recorder := httptest.NewRecorder() recorder := httptest.NewRecorder()
handler := testCtx.handlers.HandleSetupPOST() handler := testCtx.handlers.HandleSetupPOST()
@@ -320,7 +315,7 @@ func TestHandleLoginGET(t *testing.T) {
testCtx := setupTestHandlers(t) testCtx := setupTestHandlers(t)
request := httptest.NewRequestWithContext(t.Context(), http.MethodGet, "/login", nil) request := httptest.NewRequest(http.MethodGet, "/login", nil)
recorder := httptest.NewRecorder() recorder := httptest.NewRecorder()
handler := testCtx.handlers.HandleLoginGET() handler := testCtx.handlers.HandleLoginGET()
@@ -331,15 +326,12 @@ func TestHandleLoginGET(t *testing.T) {
}) })
} }
func createLoginFormRequest(t *testing.T, username, password string) *http.Request { func createLoginFormRequest(username, password string) *http.Request {
t.Helper()
form := url.Values{} form := url.Values{}
form.Set("username", username) form.Set("username", username)
form.Set("password", password) form.Set("password", password)
request := httptest.NewRequestWithContext( request := httptest.NewRequest(
t.Context(),
http.MethodPost, http.MethodPost,
"/login", "/login",
strings.NewReader(form.Encode()), strings.NewReader(form.Encode()),
@@ -362,7 +354,7 @@ func TestHandleLoginPOSTAuthenticatesValidCredentials(t *testing.T) {
) )
require.NoError(t, createErr) require.NoError(t, createErr)
request := createLoginFormRequest(t, "testuser", "testpass123") request := createLoginFormRequest("testuser", "testpass123")
recorder := httptest.NewRecorder() recorder := httptest.NewRecorder()
handler := testCtx.handlers.HandleLoginPOST() handler := testCtx.handlers.HandleLoginPOST()
@@ -385,7 +377,7 @@ func TestHandleLoginPOSTRejectsInvalidCredentials(t *testing.T) {
) )
require.NoError(t, createErr) require.NoError(t, createErr)
request := createLoginFormRequest(t, "testuser", "wrongpassword") request := createLoginFormRequest("testuser", "wrongpassword")
recorder := httptest.NewRecorder() recorder := httptest.NewRecorder()
handler := testCtx.handlers.HandleLoginPOST() handler := testCtx.handlers.HandleLoginPOST()
@@ -403,7 +395,7 @@ func TestHandleDashboard(t *testing.T) {
testCtx := setupTestHandlers(t) testCtx := setupTestHandlers(t)
request := httptest.NewRequestWithContext(t.Context(), http.MethodGet, "/", nil) request := httptest.NewRequest(http.MethodGet, "/", nil)
recorder := httptest.NewRecorder() recorder := httptest.NewRecorder()
handler := testCtx.handlers.HandleDashboard() handler := testCtx.handlers.HandleDashboard()
@@ -421,7 +413,7 @@ func TestHandleDashboard(t *testing.T) {
// Create an app so the template iterates over AppStats and hits .CSRFField // Create an app so the template iterates over AppStats and hits .CSRFField
createTestApp(t, testCtx, "csrf-test-app") createTestApp(t, testCtx, "csrf-test-app")
request := httptest.NewRequestWithContext(t.Context(), http.MethodGet, "/", nil) request := httptest.NewRequest(http.MethodGet, "/", nil)
recorder := httptest.NewRecorder() recorder := httptest.NewRecorder()
handler := testCtx.handlers.HandleDashboard() handler := testCtx.handlers.HandleDashboard()
@@ -441,9 +433,7 @@ func TestHandleAppNew(t *testing.T) {
testCtx := setupTestHandlers(t) testCtx := setupTestHandlers(t)
request := httptest.NewRequestWithContext( request := httptest.NewRequest(http.MethodGet, "/apps/new", nil)
t.Context(), http.MethodGet, "/apps/new", nil,
)
recorder := httptest.NewRecorder() recorder := httptest.NewRecorder()
handler := testCtx.handlers.HandleAppNew() handler := testCtx.handlers.HandleAppNew()
@@ -511,8 +501,7 @@ func TestHandleWebhookRejectsOversizedBody(t *testing.T) {
// Create a body larger than 1MB - it should be silently truncated // Create a body larger than 1MB - it should be silently truncated
// and the webhook should still process (or fail gracefully on parse) // and the webhook should still process (or fail gracefully on parse)
largePayload := strings.Repeat("x", 2*1024*1024) // 2MB largePayload := strings.Repeat("x", 2*1024*1024) // 2MB
request := httptest.NewRequestWithContext( request := httptest.NewRequest(
t.Context(),
http.MethodPost, http.MethodPost,
"/webhook/"+createdApp.WebhookSecret, "/webhook/"+createdApp.WebhookSecret,
strings.NewReader(largePayload), strings.NewReader(largePayload),
@@ -555,8 +544,7 @@ func testOwnershipVerification(t *testing.T, cfg ownedResourceTestConfig) {
resourceID := cfg.createFn(t, testCtx, app1) resourceID := cfg.createFn(t, testCtx, app1)
request := httptest.NewRequestWithContext( request := httptest.NewRequest(
t.Context(),
http.MethodPost, http.MethodPost,
cfg.deletePath(app2.ID, resourceID), cfg.deletePath(app2.ID, resourceID),
nil, nil,
@@ -595,8 +583,7 @@ func TestHandleEnvVarSaveBulk(t *testing.T) {
r := chi.NewRouter() r := chi.NewRouter()
r.Post("/apps/{id}/env", testCtx.handlers.HandleEnvVarSave()) r.Post("/apps/{id}/env", testCtx.handlers.HandleEnvVarSave())
request := httptest.NewRequestWithContext( request := httptest.NewRequest(
t.Context(),
http.MethodPost, http.MethodPost,
"/apps/"+createdApp.ID+"/env", "/apps/"+createdApp.ID+"/env",
strings.NewReader(body), strings.NewReader(body),
@@ -638,8 +625,7 @@ func TestHandleEnvVarSaveAppNotFound(t *testing.T) {
r := chi.NewRouter() r := chi.NewRouter()
r.Post("/apps/{id}/env", testCtx.handlers.HandleEnvVarSave()) r.Post("/apps/{id}/env", testCtx.handlers.HandleEnvVarSave())
request := httptest.NewRequestWithContext( request := httptest.NewRequest(
t.Context(),
http.MethodPost, http.MethodPost,
"/apps/nonexistent-id/env", "/apps/nonexistent-id/env",
strings.NewReader(body), strings.NewReader(body),
@@ -665,8 +651,7 @@ func TestHandleEnvVarSaveEmptyKeyRejected(t *testing.T) {
r := chi.NewRouter() r := chi.NewRouter()
r.Post("/apps/{id}/env", testCtx.handlers.HandleEnvVarSave()) r.Post("/apps/{id}/env", testCtx.handlers.HandleEnvVarSave())
request := httptest.NewRequestWithContext( request := httptest.NewRequest(
t.Context(),
http.MethodPost, http.MethodPost,
"/apps/"+createdApp.ID+"/env", "/apps/"+createdApp.ID+"/env",
strings.NewReader(body), strings.NewReader(body),
@@ -693,8 +678,7 @@ func TestHandleEnvVarSaveDuplicateKeyRejected(t *testing.T) {
r := chi.NewRouter() r := chi.NewRouter()
r.Post("/apps/{id}/env", testCtx.handlers.HandleEnvVarSave()) r.Post("/apps/{id}/env", testCtx.handlers.HandleEnvVarSave())
request := httptest.NewRequestWithContext( request := httptest.NewRequest(
t.Context(),
http.MethodPost, http.MethodPost,
"/apps/"+createdApp.ID+"/env", "/apps/"+createdApp.ID+"/env",
strings.NewReader(body), strings.NewReader(body),
@@ -732,8 +716,7 @@ func TestHandleEnvVarSaveCrossAppIsolation(t *testing.T) {
r := chi.NewRouter() r := chi.NewRouter()
r.Post("/apps/{id}/env", testCtx.handlers.HandleEnvVarSave()) r.Post("/apps/{id}/env", testCtx.handlers.HandleEnvVarSave())
request := httptest.NewRequestWithContext( request := httptest.NewRequest(
t.Context(),
http.MethodPost, http.MethodPost,
"/apps/"+appA.ID+"/env", "/apps/"+appA.ID+"/env",
strings.NewReader(body), strings.NewReader(body),
@@ -796,8 +779,7 @@ func TestHandleEnvVarSaveBodySizeLimit(t *testing.T) {
r := chi.NewRouter() r := chi.NewRouter()
r.Post("/apps/{id}/env", testCtx.handlers.HandleEnvVarSave()) r.Post("/apps/{id}/env", testCtx.handlers.HandleEnvVarSave())
request := httptest.NewRequestWithContext( request := httptest.NewRequest(
t.Context(),
http.MethodPost, http.MethodPost,
"/apps/"+createdApp.ID+"/env", "/apps/"+createdApp.ID+"/env",
strings.NewReader(sb.String()), strings.NewReader(sb.String()),
@@ -866,8 +848,7 @@ func TestDeleteVolumeOwnershipVerification(t *testing.T) {
require.NoError(t, volume.Save(context.Background())) require.NoError(t, volume.Save(context.Background()))
// Try to delete app1's volume using app2's URL path // Try to delete app1's volume using app2's URL path
request := httptest.NewRequestWithContext( request := httptest.NewRequest(
t.Context(),
http.MethodPost, http.MethodPost,
"/apps/"+app2.ID+"/volumes/"+strconv.FormatInt(volume.ID, 10)+"/delete", "/apps/"+app2.ID+"/volumes/"+strconv.FormatInt(volume.ID, 10)+"/delete",
nil, nil,
@@ -908,8 +889,7 @@ func TestDeletePortOwnershipVerification(t *testing.T) {
require.NoError(t, port.Save(context.Background())) require.NoError(t, port.Save(context.Background()))
// Try to delete app1's port using app2's URL path // Try to delete app1's port using app2's URL path
request := httptest.NewRequestWithContext( request := httptest.NewRequest(
t.Context(),
http.MethodPost, http.MethodPost,
"/apps/"+app2.ID+"/ports/"+strconv.FormatInt(port.ID, 10)+"/delete", "/apps/"+app2.ID+"/ports/"+strconv.FormatInt(port.ID, 10)+"/delete",
nil, nil,
@@ -950,8 +930,7 @@ func TestHandleEnvVarSaveEmptyClears(t *testing.T) {
r := chi.NewRouter() r := chi.NewRouter()
r.Post("/apps/{id}/env", testCtx.handlers.HandleEnvVarSave()) r.Post("/apps/{id}/env", testCtx.handlers.HandleEnvVarSave())
request := httptest.NewRequestWithContext( request := httptest.NewRequest(
t.Context(),
http.MethodPost, http.MethodPost,
"/apps/"+createdApp.ID+"/env", "/apps/"+createdApp.ID+"/env",
strings.NewReader("[]"), strings.NewReader("[]"),
@@ -1000,8 +979,7 @@ func TestHandleVolumeAddValidatesPaths(t *testing.T) {
form.Set("host_path", tt.hostPath) form.Set("host_path", tt.hostPath)
form.Set("container_path", tt.containerPath) form.Set("container_path", tt.containerPath)
request := httptest.NewRequestWithContext( request := httptest.NewRequest(
t.Context(),
http.MethodPost, http.MethodPost,
"/apps/"+createdApp.ID+"/volumes", "/apps/"+createdApp.ID+"/volumes",
strings.NewReader(form.Encode()), strings.NewReader(form.Encode()),
@@ -1060,7 +1038,7 @@ func TestSetupRequiredExemptsHealthAndStaticAndAPI(t *testing.T) {
t.Run(path, func(t *testing.T) { t.Run(path, func(t *testing.T) {
t.Parallel() t.Parallel()
req := httptest.NewRequestWithContext(t.Context(), http.MethodGet, path, nil) req := httptest.NewRequest(http.MethodGet, path, nil)
rr := httptest.NewRecorder() rr := httptest.NewRecorder()
wrapped.ServeHTTP(rr, req) wrapped.ServeHTTP(rr, req)
@@ -1073,7 +1051,7 @@ func TestSetupRequiredExemptsHealthAndStaticAndAPI(t *testing.T) {
t.Run("non-exempt redirects", func(t *testing.T) { t.Run("non-exempt redirects", func(t *testing.T) {
t.Parallel() t.Parallel()
req := httptest.NewRequestWithContext(t.Context(), http.MethodGet, "/", nil) req := httptest.NewRequest(http.MethodGet, "/", nil)
rr := httptest.NewRecorder() rr := httptest.NewRecorder()
wrapped.ServeHTTP(rr, req) wrapped.ServeHTTP(rr, req)
@@ -1089,8 +1067,7 @@ func TestHandleCancelDeployRedirects(t *testing.T) {
createdApp := createTestApp(t, testCtx, "cancel-deploy-app") createdApp := createTestApp(t, testCtx, "cancel-deploy-app")
request := httptest.NewRequestWithContext( request := httptest.NewRequest(
t.Context(),
http.MethodPost, http.MethodPost,
"/apps/"+createdApp.ID+"/deployments/cancel", "/apps/"+createdApp.ID+"/deployments/cancel",
nil, nil,
@@ -1110,8 +1087,7 @@ func TestHandleCancelDeployReturns404ForUnknownApp(t *testing.T) {
testCtx := setupTestHandlers(t) testCtx := setupTestHandlers(t)
request := httptest.NewRequestWithContext( request := httptest.NewRequest(
t.Context(),
http.MethodPost, http.MethodPost,
"/apps/nonexistent/deployments/cancel", "/apps/nonexistent/deployments/cancel",
nil, nil,
@@ -1132,8 +1108,7 @@ func TestHandleWebhookReturns404ForUnknownSecret(t *testing.T) {
webhookURL := "/webhook/unknown-secret" webhookURL := "/webhook/unknown-secret"
payload := `{"ref": "refs/heads/main"}` payload := `{"ref": "refs/heads/main"}`
request := httptest.NewRequestWithContext( request := httptest.NewRequest(
t.Context(),
http.MethodPost, http.MethodPost,
webhookURL, webhookURL,
strings.NewReader(payload), strings.NewReader(payload),
@@ -1168,8 +1143,7 @@ func TestHandleWebhookProcessesValidWebhook(t *testing.T) {
payload := `{"ref": "refs/heads/main", "after": "abc123"}` payload := `{"ref": "refs/heads/main", "after": "abc123"}`
webhookURL := "/webhook/" + createdApp.WebhookSecret webhookURL := "/webhook/" + createdApp.WebhookSecret
request := httptest.NewRequestWithContext( request := httptest.NewRequest(
t.Context(),
http.MethodPost, http.MethodPost,
webhookURL, webhookURL,
strings.NewReader(payload), strings.NewReader(payload),
+3 -3
View File
@@ -16,7 +16,7 @@ func TestRenderTemplateBuffersOutput(t *testing.T) {
testCtx := setupTestHandlers(t) testCtx := setupTestHandlers(t)
// The setup page is simple and has no DB dependencies // The setup page is simple and has no DB dependencies
request := httptest.NewRequestWithContext(t.Context(), http.MethodGet, "/setup", nil) request := httptest.NewRequest(http.MethodGet, "/setup", nil)
recorder := httptest.NewRecorder() recorder := httptest.NewRecorder()
handler := testCtx.handlers.HandleSetupGET() handler := testCtx.handlers.HandleSetupGET()
@@ -39,7 +39,7 @@ func TestDashboardRenderTemplateBuffersOutput(t *testing.T) {
testCtx := setupTestHandlers(t) testCtx := setupTestHandlers(t)
request := httptest.NewRequestWithContext(t.Context(), http.MethodGet, "/", nil) request := httptest.NewRequest(http.MethodGet, "/", nil)
recorder := httptest.NewRecorder() recorder := httptest.NewRecorder()
handler := testCtx.handlers.HandleDashboard() handler := testCtx.handlers.HandleDashboard()
@@ -59,7 +59,7 @@ func TestLoginRenderTemplateBuffersOutput(t *testing.T) {
testCtx := setupTestHandlers(t) testCtx := setupTestHandlers(t)
request := httptest.NewRequestWithContext(t.Context(), http.MethodGet, "/login", nil) request := httptest.NewRequest(http.MethodGet, "/login", nil)
recorder := httptest.NewRecorder() recorder := httptest.NewRecorder()
handler := testCtx.handlers.HandleLoginGET() handler := testCtx.handlers.HandleLoginGET()
+3 -3
View File
@@ -32,7 +32,7 @@ func TestCORS_NoOriginsConfigured_NoCORSHeaders(t *testing.T) {
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
})) }))
req := httptest.NewRequestWithContext(t.Context(), http.MethodGet, "/", nil) req := httptest.NewRequest(http.MethodGet, "/", nil)
req.Header.Set("Origin", "https://evil.com") req.Header.Set("Origin", "https://evil.com")
rec := httptest.NewRecorder() rec := httptest.NewRecorder()
@@ -50,7 +50,7 @@ func TestCORS_OriginsConfigured_AllowsMatchingOrigin(t *testing.T) {
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
})) }))
req := httptest.NewRequestWithContext(t.Context(), http.MethodGet, "/", nil) req := httptest.NewRequest(http.MethodGet, "/", nil)
req.Header.Set("Origin", "https://app.example.com") req.Header.Set("Origin", "https://app.example.com")
rec := httptest.NewRecorder() rec := httptest.NewRecorder()
@@ -70,7 +70,7 @@ func TestCORS_OriginsConfigured_RejectsNonMatchingOrigin(t *testing.T) {
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
})) }))
req := httptest.NewRequestWithContext(t.Context(), http.MethodGet, "/", nil) req := httptest.NewRequest(http.MethodGet, "/", nil)
req.Header.Set("Origin", "https://evil.com") req.Header.Set("Origin", "https://evil.com")
rec := httptest.NewRecorder() rec := httptest.NewRecorder()
+7 -7
View File
@@ -36,7 +36,7 @@ func TestLoginRateLimitAllowsUpToBurst(t *testing.T) {
// First 5 requests should succeed (burst) // First 5 requests should succeed (burst)
for i := range 5 { for i := range 5 {
req := httptest.NewRequestWithContext(t.Context(), http.MethodPost, "/login", nil) req := httptest.NewRequest(http.MethodPost, "/login", nil)
req.RemoteAddr = "192.168.1.1:12345" req.RemoteAddr = "192.168.1.1:12345"
rec := httptest.NewRecorder() rec := httptest.NewRecorder()
handler.ServeHTTP(rec, req) handler.ServeHTTP(rec, req)
@@ -44,7 +44,7 @@ func TestLoginRateLimitAllowsUpToBurst(t *testing.T) {
} }
// 6th request should be rate limited // 6th request should be rate limited
req := httptest.NewRequestWithContext(t.Context(), http.MethodPost, "/login", nil) req := httptest.NewRequest(http.MethodPost, "/login", nil)
req.RemoteAddr = "192.168.1.1:12345" req.RemoteAddr = "192.168.1.1:12345"
rec := httptest.NewRecorder() rec := httptest.NewRecorder()
handler.ServeHTTP(rec, req) handler.ServeHTTP(rec, req)
@@ -63,21 +63,21 @@ func TestLoginRateLimitIsolatesIPs(t *testing.T) {
// Exhaust IP1's budget // Exhaust IP1's budget
for range 5 { for range 5 {
req := httptest.NewRequestWithContext(t.Context(), http.MethodPost, "/login", nil) req := httptest.NewRequest(http.MethodPost, "/login", nil)
req.RemoteAddr = "10.0.0.1:1234" req.RemoteAddr = "10.0.0.1:1234"
rec := httptest.NewRecorder() rec := httptest.NewRecorder()
handler.ServeHTTP(rec, req) handler.ServeHTTP(rec, req)
} }
// IP1 should be blocked // IP1 should be blocked
req := httptest.NewRequestWithContext(t.Context(), http.MethodPost, "/login", nil) req := httptest.NewRequest(http.MethodPost, "/login", nil)
req.RemoteAddr = "10.0.0.1:1234" req.RemoteAddr = "10.0.0.1:1234"
rec := httptest.NewRecorder() rec := httptest.NewRecorder()
handler.ServeHTTP(rec, req) handler.ServeHTTP(rec, req)
assert.Equal(t, http.StatusTooManyRequests, rec.Code) assert.Equal(t, http.StatusTooManyRequests, rec.Code)
// IP2 should still work // IP2 should still work
req2 := httptest.NewRequestWithContext(t.Context(), http.MethodPost, "/login", nil) req2 := httptest.NewRequest(http.MethodPost, "/login", nil)
req2.RemoteAddr = "10.0.0.2:1234" req2.RemoteAddr = "10.0.0.2:1234"
rec2 := httptest.NewRecorder() rec2 := httptest.NewRecorder()
handler.ServeHTTP(rec2, req2) handler.ServeHTTP(rec2, req2)
@@ -96,13 +96,13 @@ func TestLoginRateLimitReturns429Body(t *testing.T) {
// Exhaust burst // Exhaust burst
for range 5 { for range 5 {
req := httptest.NewRequestWithContext(t.Context(), http.MethodPost, "/login", nil) req := httptest.NewRequest(http.MethodPost, "/login", nil)
req.RemoteAddr = "172.16.0.1:5555" req.RemoteAddr = "172.16.0.1:5555"
rec := httptest.NewRecorder() rec := httptest.NewRecorder()
handler.ServeHTTP(rec, req) handler.ServeHTTP(rec, req)
} }
req := httptest.NewRequestWithContext(t.Context(), http.MethodPost, "/login", nil) req := httptest.NewRequest(http.MethodPost, "/login", nil)
req.RemoteAddr = "172.16.0.1:5555" req.RemoteAddr = "172.16.0.1:5555"
rec := httptest.NewRecorder() rec := httptest.NewRecorder()
handler.ServeHTTP(rec, req) handler.ServeHTTP(rec, req)
+2 -2
View File
@@ -121,7 +121,7 @@ func getSessionCookie(t *testing.T, svc *auth.Service) *http.Cookie {
require.NoError(t, err) require.NoError(t, err)
recorder := httptest.NewRecorder() recorder := httptest.NewRecorder()
request := httptest.NewRequestWithContext(t.Context(), http.MethodGet, "/", nil) request := httptest.NewRequest(http.MethodGet, "/", nil)
err = svc.CreateSession(recorder, request, user) err = svc.CreateSession(recorder, request, user)
require.NoError(t, err) require.NoError(t, err)
@@ -380,7 +380,7 @@ func TestDestroySessionMaxAge(testingT *testing.T) {
defer cleanup() defer cleanup()
recorder := httptest.NewRecorder() recorder := httptest.NewRecorder()
request := httptest.NewRequestWithContext(t.Context(), http.MethodGet, "/", nil) request := httptest.NewRequest(http.MethodGet, "/", nil)
err := svc.DestroySession(recorder, request) err := svc.DestroySession(recorder, request)
require.NoError(t, err) require.NoError(t, err)