diff --git a/docs/archive/plans/2026-05-09-middleware-test-backfill-phase1.md b/docs/archive/plans/2026-05-09-middleware-test-backfill-phase1.md new file mode 100644 index 0000000..77c21d9 --- /dev/null +++ b/docs/archive/plans/2026-05-09-middleware-test-backfill-phase1.md @@ -0,0 +1,139 @@ +# Middleware Test Backfill Phase 1 Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Raise confidence in the backend request chain by backfilling focused unit tests for the auth, RBAC, error recovery, and trace ID middleware. + +**Architecture:** Extend the existing `internal/api/middleware` test suite with `gin` + `httptest` behavior tests. Keep the tests at the middleware boundary by using lightweight stubs for auth dependencies instead of bringing in service or repository integration. + +**Tech Stack:** Go, Gin, `net/http/httptest`, existing JWT manager, package-local test helpers + +--- + +### Task 1: Add auth middleware regression tests + +**Files:** +- Modify: `internal/api/middleware/auth_bootstrap_test.go` +- Test: `internal/api/middleware/auth_bootstrap_test.go` + +- [ ] **Step 1: Write failing tests** + +```go +func TestAuthMiddleware_RequiredRejectsMissingToken(t *testing.T) {} +func TestAuthMiddleware_RequiredRejectsInvalidToken(t *testing.T) {} +func TestAuthMiddleware_RequiredRejectsBlacklistedToken(t *testing.T) {} +func TestAuthMiddleware_RequiredRejectsInactiveUser(t *testing.T) {} +func TestAuthMiddleware_RequiredInjectsIdentityAndAuthorizations(t *testing.T) {} +func TestAuthMiddleware_OptionalAllowsAnonymousRequest(t *testing.T) {} +func TestAuthMiddleware_ExtractTokenCases(t *testing.T) {} +``` + +- [ ] **Step 2: Run auth middleware tests to verify red** + +Run: `go test ./internal/api/middleware -run 'TestAuthMiddleware_(RequiredRejectsMissingToken|RequiredRejectsInvalidToken|RequiredRejectsBlacklistedToken|RequiredRejectsInactiveUser|RequiredInjectsIdentityAndAuthorizations|OptionalAllowsAnonymousRequest|ExtractTokenCases)' -count=1` +Expected: FAIL because the new tests do not exist yet. + +- [ ] **Step 3: Add the minimal test helpers and assertions** + +```go +type authStubUserRepo struct { + user *domain.User + err error +} + +func (s authStubUserRepo) GetByID(_ context.Context, _ int64) (*domain.User, error) { + return s.user, s.err +} +``` + +- [ ] **Step 4: Run auth middleware tests to verify green** + +Run: `go test ./internal/api/middleware -run 'TestAuthMiddleware_(RequiredRejectsMissingToken|RequiredRejectsInvalidToken|RequiredRejectsBlacklistedToken|RequiredRejectsInactiveUser|RequiredInjectsIdentityAndAuthorizations|OptionalAllowsAnonymousRequest|ExtractTokenCases)' -count=1` +Expected: PASS + +### Task 2: Add RBAC middleware regression tests + +**Files:** +- Create: `internal/api/middleware/rbac_test.go` +- Test: `internal/api/middleware/rbac_test.go` + +- [ ] **Step 1: Write failing RBAC tests** + +```go +func TestRequirePermissionRejectsMissingPermission(t *testing.T) {} +func TestRequirePermissionAllowsMatchingPermission(t *testing.T) {} +func TestRequireAllPermissionsRequiresEveryCode(t *testing.T) {} +func TestRequireAnyPermissionIsAliasOfRequirePermission(t *testing.T) {} +func TestRequireRoleAndAdminOnly(t *testing.T) {} +func TestRBACHelpersHandleMissingContextValues(t *testing.T) {} +``` + +- [ ] **Step 2: Run RBAC tests to verify red** + +Run: `go test ./internal/api/middleware -run 'Test(RequirePermissionRejectsMissingPermission|RequirePermissionAllowsMatchingPermission|RequireAllPermissionsRequiresEveryCode|RequireAnyPermissionIsAliasOfRequirePermission|RequireRoleAndAdminOnly|RBACHelpersHandleMissingContextValues)' -count=1` +Expected: FAIL because the test file does not exist yet. + +- [ ] **Step 3: Add the minimal behavior tests** + +```go +router.Use(func(c *gin.Context) { + c.Set(ContextKeyRoleCodes, []string{"viewer"}) + c.Set(ContextKeyPermissionCodes, []string{"user:read"}) + c.Next() +}) +``` + +- [ ] **Step 4: Run RBAC tests to verify green** + +Run: `go test ./internal/api/middleware -run 'Test(RequirePermissionRejectsMissingPermission|RequirePermissionAllowsMatchingPermission|RequireAllPermissionsRequiresEveryCode|RequireAnyPermissionIsAliasOfRequirePermission|RequireRoleAndAdminOnly|RBACHelpersHandleMissingContextValues)' -count=1` +Expected: PASS + +### Task 3: Extend runtime middleware tests for error and trace handling + +**Files:** +- Modify: `internal/api/middleware/runtime_test.go` +- Test: `internal/api/middleware/runtime_test.go` + +- [ ] **Step 1: Write failing tests for uncovered branches** + +```go +func TestTraceID_GetTraceIDHandlesMissingAndPresentValue(t *testing.T) {} +func TestErrorHandler_ApplicationErrorPreservesStatusAndReason(t *testing.T) {} +func TestRecover_ReturnsInternalServerErrorPayload(t *testing.T) {} +``` + +- [ ] **Step 2: Run targeted runtime tests to verify red** + +Run: `go test ./internal/api/middleware -run 'Test(TraceID_GetTraceIDHandlesMissingAndPresentValue|ErrorHandler_ApplicationErrorPreservesStatusAndReason|Recover_ReturnsInternalServerErrorPayload)' -count=1` +Expected: FAIL because the new tests do not exist yet. + +- [ ] **Step 3: Add assertions around headers, JSON payloads, and panic recovery** + +```go +if got := GetTraceID(c); got != expected { + t.Fatalf("GetTraceID() = %q, want %q", got, expected) +} +``` + +- [ ] **Step 4: Run targeted runtime tests to verify green** + +Run: `go test ./internal/api/middleware -run 'Test(TraceID_GetTraceIDHandlesMissingAndPresentValue|ErrorHandler_ApplicationErrorPreservesStatusAndReason|Recover_ReturnsInternalServerErrorPayload)' -count=1` +Expected: PASS + +### Task 4: Run package verification and capture the outcome + +**Files:** +- Modify: `internal/api/middleware/auth_bootstrap_test.go` +- Modify: `internal/api/middleware/rbac_test.go` +- Modify: `internal/api/middleware/runtime_test.go` + +- [ ] **Step 1: Run the full middleware package tests** + +Run: `go test ./internal/api/middleware -count=1` +Expected: PASS + +- [ ] **Step 2: Run focused coverage for the middleware package** + +Run: `go test ./internal/api/middleware -cover -count=1` +Expected: PASS with higher coverage than the current baseline for auth/RBAC/error/trace paths. +