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>
230 lines
10 KiB
Markdown
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).
|