Files
Redflag/docs/A3_PreFix_Tests.md
jpetree331 ee246771dc test(security): A-3 pre-fix tests for auth middleware coverage bugs
Pre-fix test suite documenting 8 auth middleware bugs found during
the A-3 recon audit. Tests are written to FAIL where they assert
correct post-fix behavior, and PASS where they document current
buggy behavior. No bugs are fixed in this commit.

Tests added:
- F-A3-11 CRITICAL: WebAuthMiddleware leaks JWT secret to stdout
  (3 tests: secret in output, emoji in output, ETHOS format)
- F-A3-7 CRITICAL: Config download requires no auth (2 tests)
- F-A3-6 HIGH: Update package download requires no auth (2 tests)
- F-A3-10 HIGH: Scheduler stats accepts agent JWT (2 tests)
- F-A3-12 MEDIUM: Cross-type JWT token confusion (2 tests)
- F-A3-2 MEDIUM: /auth/verify dead endpoint (2 tests)
- F-A3-13 LOW: RequireAdmin middleware missing (1 test + 1 build-tagged)
- F-A3-9 MEDIUM: Agent self-unregister no rate limit (2 tests)

Current state: 10 FAIL, 7 PASS, 1 SKIP (build-tagged), 1 unchanged
See docs/A3_PreFix_Tests.md for full inventory.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 21:54:48 -04:00

230 lines
10 KiB
Markdown

# A-3 Pre-Fix Test Suite
**Date:** 2026-03-28
**Branch:** culurien
**Purpose:** Document auth middleware coverage bugs BEFORE fixes are applied.
**Reference:** A-3 Auth Middleware Audit (recon findings F-A3-1 through F-A3-14)
These tests prove that the bugs exist today and will prove the fixes work
when applied. Do NOT modify these tests before the fix is ready — they are
the regression baseline.
---
## Test Files Created
| File | Package | Bugs Documented |
|------|---------|-----------------|
| `aggregator-server/internal/api/middleware/auth_secret_leak_test.go` | `middleware_test` | F-A3-11 (agent-side baseline) |
| `aggregator-server/internal/api/handlers/auth_middleware_leak_test.go` | `handlers_test` | F-A3-11 (web middleware leak) |
| `aggregator-server/internal/api/handlers/downloads_auth_test.go` | `handlers_test` | F-A3-7, F-A3-6 |
| `aggregator-server/internal/api/middleware/scheduler_auth_test.go` | `middleware_test` | F-A3-10 |
| `aggregator-server/internal/api/middleware/token_confusion_test.go` | `middleware_test` | F-A3-12 |
| `aggregator-server/internal/api/handlers/auth_verify_test.go` | `handlers_test` | F-A3-2 |
| `aggregator-server/internal/api/middleware/require_admin_test.go` | `middleware_test` | F-A3-13 |
| `aggregator-server/internal/api/middleware/require_admin_behavior_test.go` | `middleware_test` | F-A3-13 (build-tagged, cannot compile yet) |
| `aggregator-server/internal/api/handlers/agent_unregister_test.go` | `handlers_test` | F-A3-9 |
---
## How to Run
```bash
# Middleware tests (scheduler, token confusion, RequireAdmin, agent auth)
cd aggregator-server && go test ./internal/api/middleware/... -v
# Handler tests (JWT leak, downloads auth, verify, unregister)
cd aggregator-server && go test ./internal/api/handlers/... -v
# Run specific test groups
cd aggregator-server && go test ./internal/api/middleware/... -v -run TestScheduler
cd aggregator-server && go test ./internal/api/middleware/... -v -run TestToken
cd aggregator-server && go test ./internal/api/middleware/... -v -run TestRequireAdmin
cd aggregator-server && go test ./internal/api/handlers/... -v -run TestWebAuth
cd aggregator-server && go test ./internal/api/handlers/... -v -run TestConfigDownload
cd aggregator-server && go test ./internal/api/handlers/... -v -run TestAuthVerify
```
---
## Test Inventory
### File 1: `middleware/auth_secret_leak_test.go` — Agent Middleware Baseline
#### `TestAgentAuthMiddlewareDoesNotLogSecret`
- **Bug:** F-A3-11 (baseline contrast — agent middleware is clean)
- **Asserts:** Agent AuthMiddleware does NOT print JWT secret to stdout
- **Current state:** PASS (agent middleware is not affected)
- **Purpose:** Establishes that the leak is specific to WebAuthMiddleware
#### `TestAgentAuthMiddlewareLogHasNoEmoji`
- **Bug:** F-A3-11 (baseline contrast)
- **Asserts:** Agent AuthMiddleware stdout has no emoji characters
- **Current state:** PASS
### File 2: `handlers/auth_middleware_leak_test.go` — WebAuth Secret Leak
#### `TestWebAuthMiddlewareDoesNotLogSecret`
- **Bug:** F-A3-11 CRITICAL
- **Asserts:** WebAuthMiddleware stdout does NOT contain the JWT secret string
- **Current state:** FAIL — auth.go:128 prints `h.jwtSecret` directly
- **After fix:** PASS — remove secret from log output
#### `TestWebAuthMiddlewareLogFormatHasNoEmoji`
- **Bug:** F-A3-11 CRITICAL
- **Asserts:** WebAuthMiddleware stdout has no emoji (specifically U+1F513), word "secret" absent
- **Current state:** FAIL — output contains lock emoji and word "secret"
- **After fix:** PASS — use `[WARNING] [server] [auth]` format
#### `TestWebAuthMiddlewareLogFormatCompliant`
- **Bug:** F-A3-11 CRITICAL
- **Asserts:** If stdout output exists, lines start with `[TAG]` pattern, no secret in output
- **Current state:** FAIL — output is emoji-prefixed, contains secret
- **After fix:** PASS — ETHOS-compliant format or no stdout output
### File 3: `handlers/downloads_auth_test.go` — Unauthenticated Downloads
#### `TestConfigDownloadRequiresAuth`
- **Bug:** F-A3-7 CRITICAL
- **Asserts:** GET /downloads/config/:agent_id returns 401/403 without auth
- **Current state:** FAIL — returns 200 (no auth middleware on route)
- **After fix:** PASS — add AuthMiddleware or WebAuthMiddleware
#### `TestConfigDownloadCurrentlyUnauthenticated`
- **Bug:** F-A3-7 CRITICAL
- **Asserts:** Config download succeeds without auth (documents bug)
- **Current state:** PASS — no auth middleware, request reaches handler
- **After fix:** FAIL — update to assert 401
#### `TestUpdatePackageDownloadRequiresAuth`
- **Bug:** F-A3-6 HIGH
- **Asserts:** GET /downloads/updates/:package_id returns 401/403 without auth
- **Current state:** FAIL — returns 200 (no auth middleware)
- **After fix:** PASS — add AuthMiddleware
#### `TestUpdatePackageDownloadCurrentlyUnauthenticated`
- **Bug:** F-A3-6 HIGH
- **Asserts:** Update package download succeeds without auth (documents bug)
- **Current state:** PASS
- **After fix:** FAIL — update to assert 401
### File 4: `middleware/scheduler_auth_test.go` — Scheduler Wrong Auth
#### `TestSchedulerStatsRequiresAdminAuth`
- **Bug:** F-A3-10 HIGH
- **Asserts:** Agent JWT is rejected on /scheduler/stats (should require admin)
- **Current state:** FAIL — agent JWT accepted (200)
- **After fix:** PASS — change to WebAuthMiddleware
#### `TestSchedulerStatsCurrentlyAcceptsAgentJWT`
- **Bug:** F-A3-10 HIGH
- **Asserts:** Agent JWT is accepted on /scheduler/stats (documents bug)
- **Current state:** PASS — AuthMiddleware accepts agent JWT
- **After fix:** FAIL — update to assert rejection
### File 5: `middleware/token_confusion_test.go` — Cross-Type Token Confusion
#### `TestWebTokenRejectedByAgentAuthMiddleware`
- **Bug:** F-A3-12 MEDIUM
- **Asserts:** Web/admin JWT is rejected by agent AuthMiddleware
- **Current state:** FAIL — web JWT passes agent auth (shared secret, no audience check)
- **After fix:** PASS — add issuer/audience claims or separate secrets
#### `TestAgentTokenRejectedByWebAuthMiddleware`
- **Bug:** F-A3-12 MEDIUM
- **Asserts:** Agent JWT is rejected by WebAuthMiddleware
- **Current state:** FAIL — agent JWT passes web auth (shared secret, claims parse succeeds)
- **After fix:** PASS — add issuer/audience claims or separate secrets
### File 6: `handlers/auth_verify_test.go` — Dead Verify Endpoint
#### `TestAuthVerifyAlwaysReturns401WithoutMiddleware`
- **Bug:** F-A3-2 MEDIUM
- **Asserts:** /auth/verify returns 401 even with valid JWT (no middleware sets context)
- **Current state:** PASS — documents the dead endpoint
- **After fix:** N/A (test documents pre-fix state)
#### `TestAuthVerifyWorksWithMiddleware`
- **Bug:** F-A3-2 MEDIUM
- **Asserts:** /auth/verify returns 200 when WebAuthMiddleware is applied
- **Current state:** PASS — demonstrates the fix is just adding middleware to the route
- **Note:** This test already passes because it applies WebAuthMiddleware directly. The bug is in the route registration (main.go:388), not in the handler code.
### File 7: `middleware/require_admin_test.go` — Missing RequireAdmin
#### `TestRequireAdminMiddlewareExists`
- **Bug:** F-A3-13 LOW
- **Asserts:** RequireAdmin function exists in middleware package (AST scan)
- **Current state:** FAIL — function not found
- **After fix:** PASS — implement RequireAdmin()
### File 8: `middleware/require_admin_behavior_test.go` — RequireAdmin Behavior
- **Build tag:** `//go:build ignore` — cannot compile until RequireAdmin exists
- **Bug:** F-A3-13 LOW
- **Contains:** `TestRequireAdminBlocksNonAdminUsers` — tests admin vs non-admin role check
- **Current state:** Cannot compile (skipped)
- **After fix:** Remove build tag, test should PASS
### File 9: `handlers/agent_unregister_test.go` — Missing Rate Limit
#### `TestAgentSelfUnregisterHasNoRateLimit`
- **Bug:** F-A3-9 MEDIUM
- **Asserts:** Documents that DELETE /:id route has no rate limiter
- **Current state:** PASS — documents the bug
#### `TestAgentSelfUnregisterShouldHaveRateLimit`
- **Bug:** F-A3-9 MEDIUM
- **Asserts:** DELETE /:id SHOULD have rate limiter in middleware chain
- **Current state:** FAIL — no rate limiter on route
- **After fix:** PASS — add rate limiter
---
## State-Change Summary
| Test | Current | After Fix |
|------|---------|-----------|
| TestAgentAuthMiddlewareDoesNotLogSecret | PASS | PASS (unchanged) |
| TestAgentAuthMiddlewareLogHasNoEmoji | PASS | PASS (unchanged) |
| TestWebAuthMiddlewareDoesNotLogSecret | **FAIL** | PASS |
| TestWebAuthMiddlewareLogFormatHasNoEmoji | **FAIL** | PASS |
| TestWebAuthMiddlewareLogFormatCompliant | **FAIL** | PASS |
| TestConfigDownloadRequiresAuth | **FAIL** | PASS |
| TestConfigDownloadCurrentlyUnauthenticated | PASS | FAIL (update) |
| TestUpdatePackageDownloadRequiresAuth | **FAIL** | PASS |
| TestUpdatePackageDownloadCurrentlyUnauthenticated | PASS | FAIL (update) |
| TestSchedulerStatsRequiresAdminAuth | **FAIL** | PASS |
| TestSchedulerStatsCurrentlyAcceptsAgentJWT | PASS | FAIL (update) |
| TestWebTokenRejectedByAgentAuthMiddleware | **FAIL** | PASS |
| TestAgentTokenRejectedByWebAuthMiddleware | **FAIL** | PASS |
| TestAuthVerifyAlwaysReturns401WithoutMiddleware | PASS | PASS (unchanged) |
| TestAuthVerifyWorksWithMiddleware | PASS | PASS (unchanged) |
| TestRequireAdminMiddlewareExists | **FAIL** | PASS |
| TestRequireAdminBlocksNonAdminUsers | SKIP (build tag) | PASS |
| TestAgentSelfUnregisterHasNoRateLimit | PASS | PASS (unchanged) |
| TestAgentSelfUnregisterShouldHaveRateLimit | **FAIL** | PASS |
**Bold FAIL** = tests that assert correct post-fix behavior (will flip to PASS after fix).
Regular PASS = tests that document current buggy state (some will flip to FAIL after fix).
---
## Notes
1. **TestAuthVerifyWorksWithMiddleware** passes even in pre-fix state because it
directly applies WebAuthMiddleware to the test router. The bug is not in the
handler but in the route registration (main.go:388 missing middleware). This
test validates that the fix is a one-line change.
2. **TestAgentTokenRejectedByWebAuthMiddleware** reveals that JWT cross-type
confusion works in BOTH directions: agent tokens pass web auth AND web tokens
pass agent auth. The `jwt.ParseWithClaims` call succeeds because both claim
types share the same signing key and the JSON unmarshaling is permissive.
3. **require_admin_behavior_test.go** uses `//go:build ignore` because it
references `middleware.RequireAdmin` which does not exist. Enable this test
when F-A3-13 is fixed by removing the build tag.
4. All A-2 tests continue to pass (no regressions from A-3 test additions).