# 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).
