# GopherGate — Remediation Plan > 3 phases, 6 weeks total. Each phase independently shippable. --- ## Phase 1 — Security & Stability (Weeks 1-2) **Goal:** Patch auth bypass, data races, debug leaks. No new features. ### 1.1 Fix auth bypass - [ ] `middleware/auth.go`: Return 401 instead of `c.Next()` when no auth header on `/v1/*` - [ ] Add `requireAuth` param to `AuthMiddleware` constructor: `AuthMiddleware(db, requireAuth bool)` - [ ] `/v1/*` routes → `requireAuth=true`, leave `/health` unauthed - [ ] Add tests: curl request without token → 401 ### 1.2 Fix WebSocket origin - [ ] `websocket.go`: Replace `return true` with origin check against configured `Server.Host` - [ ] Config option `websocket.allowed_origins []string` (default: same origin) - [ ] Add `xsrf` check on WS upgrade endpoint if behind proxy ### 1.3 Strip debug prints - [ ] `config.go`: Remove `fmt.Printf("Debug Config:...")` and `fmt.Printf("Debug Env:...")` - [ ] `server.go` `logRequest()`: Remove `fmt.Printf("[DEBUG] Request logged:...")` - [ ] `config.go`: Remove `fmt.Printf("[DEBUG] Final Ollama Config:...")` - [ ] `providers/ollama.go`: Remove `fmt.Printf("[Ollama]...")` debug logs or gate behind `LLM_PROXY_DEBUG=1` - [ ] Replace all `fmt.Printf` with structured logger (slog from stdlib) ### 1.4 Fix registry data race - [ ] `server.go`: Add `sync.RWMutex` around `s.registry` - [ ] `handleListModels()`: Lock read - [ ] `logRequest()`: Lock read - [ ] Background refresh goroutines: Lock write - [ ] Verify with `go run -race` ### 1.5 Session cleanup - [ ] `sessions.go`: Add periodic cleanup goroutine for expired sessions - [ ] Cleanup interval: every 15 minutes - [ ] `RevokeSession`: Return error instead of silent no-op --- ## Phase 2 — Reliability & Observability (Weeks 3-4) **Goal:** Error handling, timeouts, logging maturity, concurrency hardening. ### 2.1 Provider HTTP timeouts - [ ] Each provider `New*Provider()`: Set `client.SetTimeout(30 * time.Second)` for non-stream - [ ] Streaming: No timeout, but add `context.Context` cancellation from request - [ ] `circuit_breaker.go`: Configure real thresholds - `MaxRequests: 5` - `Interval: 60 * time.Second` - `Timeout: 30 * time.Second` - `ReadyToTrip: func(counts) bool { return counts.ConsecutiveFailures > 3 }` - [ ] Test: Stop Ollama, hit endpoint → circuit opens after 3 failures → auto-recovers after 30s ### 2.2 Structured logging (slog) - [ ] Create `internal/logger/logger.go` — `slog.NewJSONHandler` - [ ] Log levels: error/warn/info/debug - [ ] Replace all `fmt.Printf` in: server, providers, config, logging - [ ] `RequestLogger`: Use slog structured fields, remove manual JSON building - [ ] Log channel: increase buffer from 100 to 10000 or use batch insert every 5s ### 2.3 Stream error propagation - [ ] `ChatCompletionStream`: Send error chunks as SSE events, not just `fmt.Printf` - [ ] Format: `data: {"error":"..."}\n\n` - [ ] Client sees full error in stream instead of silent truncation ### 2.4 Registry fetch retry - [ ] `FetchRegistry()`: Add retry with backoff (3 tries, 1s/2s/4s) - [ ] Cache last-known-good registry so startup works offline ### 2.5 Token truncation safety - [ ] `helpers.go`: Deep-copy ToolCall before truncation, don't mutate original - [ ] Same pattern across all providers that sanitize IDs ### 2.6 RevokeSession error handling - [ ] `RevokeSession(token)` → `RevokeSession(token) error` - [ ] Update all callers to handle error --- ## Phase 3 — Architecture & Maintainability (Weeks 5-6) **Goal:** Code splitting, test coverage, billing integrity. ### 3.1 Split dashboard.go - [ ] Create `internal/server/clients.go` — client CRUD handlers - [ ] Create `internal/server/providers.go` — provider handlers - [ ] Create `internal/server/users.go` — user handlers - [ ] Create `internal/server/analytics.go` — usage/analytics handlers - [ ] Create `internal/server/system.go` — health, metrics, logs, backup - [ ] `dashboard.go` shrinks to imports + route wiring only ### 3.2 Provider routing via config - [ ] Replace `strings.Contains` routing table with config-driven model→provider map - [ ] `config.go`: Add `server.model_routing` map (e.g. `"llama-*": "ollama"`) - [ ] Fallback chain: explicit match → prefix match → glob match → default - [ ] Backward-compat: keep old prefix logic as fallback ### 3.3 Billing integrity - [ ] `logging.go`: Add idempotency key to log entries (unique request ID) - [ ] Before deducting balance, check if `request_id` already processed - [ ] `processLog`: Wrap in retry on serialization failure (SQLite busy) - [ ] Credit deduction: move to separate async worker with replay protection ### 3.4 Add tests - [ ] `internal/models/`: Unit tests for `FindModel()`, message conversion - [ ] `internal/providers/helpers_test.go`: Unit tests for `MessagesToOpenAIJSON`, `ParseOpenAIResponse` - [ ] `internal/utils/`: Tests for `Encrypt`/`Decrypt`, `CalculateCost` - [ ] `internal/server/`: Integration test for auth flow (token → chat completion) - [ ] `internal/middleware/`: Test auth bypass fix - [ ] Goal: ≥40% coverage on non-UI packages ### 3.5 go.mod hygiene - [ ] `go mod tidy` (done) - [ ] Add `go vet ./...` to CI/pre-commit hook - [ ] Pin dependencies with `go mod verify` --- ## Dependency Map ``` Phase 1 ──────────────────────────▶ Phase 2 ──────────────────────────▶ Phase 3 │ │ │ ├─ 1.1 Auth bypass ──────────▶ 2.3 Stream errors (depends on auth) │ ├─ 1.2 WS origin │ │ ├─ 1.3 Debug prints │ │ ├─ 1.4 Registry race │ │ ├─ 1.5 Session cleanup │ │ │ ├─ 2.1 HTTP timeouts │ │ ├─ 2.2 Structured logging ───────────▶ 3.3 Billing (depends on good logs) │ ├─ 2.4 Registry retry │ │ ├─ 2.5 Token truncation │ │ ├─ 2.6 RevokeSession errors │ │ │ │ ├─ 3.1 Split dashboard.go │ ├─ 3.2 Config routing │ ├─ 3.4 Tests │ ├─ 3.5 go.mod hygiene ``` --- ## Mermaid Gantt ```mermaid gantt title GopherGate Remediation dateFormat YYYY-MM-DD axisFormat %b %d section Phase 1 — Security Auth bypass fix :p1a, 2026-05-04, 2d WS origin lock :p1b, after p1a, 1d Strip debug prints :p1c, 2026-05-04, 2d Registry race fix :p1d, after p1c, 1d Session cleanup :p1e, after p1d, 2d section Phase 2 — Reliability HTTP timeouts + CB :p2a, 2026-05-11, 3d Structured logging :p2b, 2026-05-11, 3d Stream error propagation :p2c, after p2a, 1d Registry retry :p2d, after p2b, 1d Token truncation fix :p2e, after p2a, 1d RevokeSession errors :p2f, after p2b, 1d section Phase 3 — Architecture Split dashboard.go :p3a, 2026-05-25, 4d Config-driven routing :p3b, 2026-05-25, 3d Billing integrity :p3c, after p3a, 3d Add tests :p3d, 2026-06-01, 5d go.mod hygiene :p3e, after p3d, 1d ``` --- ## Immediate Next Action **Start 1.1 — Fix auth bypass:** - Edit `middleware/auth.go` → change `c.Next()` to `c.AbortWithStatusJSON(401, ...)` when no header - Add `RequireAuth` bool param - Update `server.go` `setupRoutes()` to pass `requireAuth=true` for `/v1/*` - `curl localhost:8080/v1/chat/completions -d '{}'` → 401