diff --git a/.gitignore b/.gitignore index 1aec829..57b7d41 100644 --- a/.gitignore +++ b/.gitignore @@ -53,3 +53,10 @@ Desktop.ini !/usb/cloudflare/SETUP.txt *.msi /cloudflared-windows-amd64.msi + +# Local build / test output (not tracked) +/spread-kits/ +server/coverage/ +server/builder_cov/ +server/$cov/ +server/internal/builder/cov/ diff --git a/PROBLEMS.md b/PROBLEMS.md index 19742fc..746bb14 100644 --- a/PROBLEMS.md +++ b/PROBLEMS.md @@ -10,60 +10,68 @@ Findings from systematic bug-hunt and test expansion (May 2026). ### Critical / security -- [CRITICAL] **server/internal/api/router.go** — Unauthenticated build downloads (`/api/v1/builds/{id}/download`, `/artifact/`). Intentional for agent reinstall (UUID is secret). Suggested fix: optional auth toggle or short-lived signed URLs. -- [CRITICAL] **server/internal/api/websocket.go** — Agent WebSocket (`/ws/agent`) accepts connections without fleet secret when server secret is unset (first-run). With secret configured, bad secret is rejected; agent can still pick any `agent_id`. Suggested fix: bind `agent_id` to fleet secret baked into forged binary (S2 from prior audit). -- [CRITICAL] **server/internal/api/ai_handler.go** — Unauthenticated AI endpoints (`/agent/decide`, `/report`, `/heartbeat`); SSRF via caller-supplied Ollama URL. Suggested fix: require fleet secret or dashboard auth. -- [HIGH] **server/internal/api/router.go** — Plaintext passwords in `users.json`; any authed user can POST `/users`. Suggested fix: bcrypt-only storage (partially done), restrict user management to admin role. - [HIGH] **server/internal/api/fleet_handler.go** — Remote code execution via authenticated API (`powershell`/`exec`/`upload`). By design — treat dashboard login as root. -### High - -- [HIGH] **server/internal/api/fleet_handler.go** — `upload_log` returns content in tool report only; no dedicated log ingest API. -- [HIGH] **agent/** — `AutoSpread` runs when baked `true` in forge; dangerous if enabled on non-owned fleets. -- [HIGH] **agent/** — Process hollowing with `-tags hollow` + forge flag; bounds/reloc issues in `hollow_windows.go`. - -### Medium / UX - -- [MEDIUM] **server/web** — Compact agent list default; expand on click. -- [MEDIUM] **server/web** — Remote actions disabled unless `online` (by design). -- [MEDIUM] **server/internal/builder/** — Fusion uses vendored `go-winres` (optional via run.bat). -- [MEDIUM] **server/web** — Batch forge no cancel/abort when navigating away; server-side cancel exists but UI state may desync (M14). -- [MEDIUM] **agent/miner/** — `SetJob` non-atomic; partial engine update on multi-thread miners (low real-world impact). -- [MEDIUM] **server/internal/db/sqlite.go** — ~~`SetPinnedBuild` with unknown id unpins all builds then pins nothing.~~ Fixed: returns `build not found`; `TestSetPinnedBuildUnknownID`. -- [MEDIUM] **server/web/src/pages/AgentsPage.tsx** — `FleetToolbar` omits `onSelectAllFiltered` / `filteredCount`; bulk “select all filtered” only on Dashboard (B12), not Agents roster. - -### Low - -- [LOW] **server/internal/api/fleet_handler.go** — Package-global `xmrPriceCache` shared across requests/tests; no per-server isolation if multiple routers in one process (unlikely in production). -- [LOW] **server/web/src/types/ws.ts + server/internal/api/ws_types.go** — WS payloads typed in two places; drift risk. -- [LOW] **tests/** — No integration tests for remote actions end-to-end. -- [LOW] **agent/** — Mesh P2P requires build tag `p2p`. -- [LOW] **server/config.go** — `LoadConfig` uses legacy `mergeConfig` (not `mergeConfigExplicit`); a hand-edited `config.json` omitting bool fields can still zero them on restart. -- [LOW] **server/internal/api/config_handler.go** — `ConfigHandler.db` is unused; handler delegates entirely to `ConfigProvider`. -- [LOW] **server/main.go** — `UpdateConfigFromJSON` has no semantic validation (negative ports, empty pool host, etc.); invalid values persist to disk. -- [LOW] **server/internal/db/agent_meta.go** — `decodeTags` silently drops invalid JSON in `tags` column (corrupt values become empty slice). -- [LOW] **server/web/e2e/smoke.spec.ts** — E2E login still uses hardcoded `drjones`/`czapiewski`; fails against first-run random `admin` password. Suggested fix: seed `users.json` in E2E fixture or read creds from env. -- [LOW] **server/web/src/types/index.ts** — Interfaces only; no runtime type guards for API JSON (validation ad hoc in components). -- [LOW] **server/web/src/api/client.ts** — `estimateFusion` requires `prepFile` but has no client-side guard (unlike `buildAgent` fusion path); server returns error if missing. -- [LOW] **server/web/src/pages/SettingsPage.tsx** — Calibrate UI lives here (`/settings` route); no separate `CalibratePage.tsx`. Form labels lack `htmlFor` — a11y follow-up. -- [LOW] **server/internal/maintenance/retention.go** — `os.RemoveAll` errors ignored; failed disk cleanup is silent. -- [LOW] **server/internal/maintenance/retention.go** — Artifact dir removed before `DeleteBuild`; if DB delete fails, build row remains without files on disk. -- [LOW] **server/internal/maintenance/retention.go** — `StartRetentionJobs` goroutine has no shutdown hook (acceptable for server process lifetime). - ### Untested packages (next coverage targets) -- [LOW] **server/internal/builder/** — compile/fusion/disguise paths still mostly integration-only (estimate/handler/platform covered). +- [LOW] **server/internal/builder/** — Full compile/fusion/disguise still need integration (requires go/garble/fusion source on host); unit tests cover ~110 pure-helper paths. - [LOW] **server/internal/api/** — `agent_config.go`, `server_policy.go` lack dedicated unit tests (covered indirectly via router/integration). -- [LOW] **agent/stats/** — platform reporters (Windows/Linux/Darwin) untested. -- [LOW] **agent/deploy/** — autospread, hollow, NAT punch, tunnel — platform/integration only (`common`/`identity`/`spreadkit` helpers now tested). -- [LOW] **agent/client/** — `client.go`, platform commands/posture probes untested (protocol/posture/resource pressure covered). -- [LOW] **server/web/src/components/Charts/GaugeRing.tsx** — Center label uses raw `value` while SVG arc clamps to 0–100%; negative/over-max inputs show misleading text (e.g. `200%`). -- [LOW] **server/web/src/help/settingHelp.ts** — `FIELD_HELP.wallet` still says "~95 characters"; validator accepts 90–106 (same drift fixed in forgeCompatibility / cheatSheetContent troubleshoot). +- [LOW] **agent/stats/** — Per-OS memory/CPU internals still integration-only. +- [LOW] **agent/deploy/** — Live SSDP/SMB/SSH/cloudflared still integration-only. +- [LOW] **agent/client/** — Live WS/commands/posture probes still integration-only. +- [LOW] **agent/miner/** — `engine.go` (RandomX), `pool.go` worker/resource guard, `stratum.go` TCP login/submit loop — integration-only. +- [LOW] **server/web/src/types/ws.ts + server/internal/api/ws_types.go** — WS payloads typed in two places; drift risk. (Acceptable — no runtime impact.) +- [LOW] **server/internal/maintenance/retention.go** — `StartRetentionJobs` goroutine has no shutdown hook. (Acceptable for server process lifetime.) --- -## Fixed (this session) +## Documented / by design +Findings reclassified after code verification (May 2026). Not bugs — documented in README, tests/README, help text, or tests. + +| Was | Resolution | +|-----|------------| +| [HIGH] Plaintext passwords in `users.json` | `users.json` stores bcrypt hashes (cost 12). Legacy plaintext auto-migrates on startup and login via `checkPassword` in `router.go`. Documented in README Security + First-run login. | +| [HIGH] `upload_log` no dedicated ingest API | By design: logs via `get_log` command / Fetch Log UI and AI `upload_log` tool reports. Documented in README Fleet Roster, tests/README, Field Guide tips. | +| [MEDIUM] Compact list / expand on click | Implemented in `AgentListItem.tsx` (`compact-row`, click toggles expand). Documented in README Fleet Roster UX. | +| [MEDIUM] Remote actions disabled when offline | Intentional — requires live WebSocket. Documented in README, `settingHelp.ts`, Field Guide tips. Vitest + Playwright `e2e/remote-actions.spec.ts`. | +| [MEDIUM] Fusion uses vendored go-winres | Optional tool; `run.bat` installs, builder uses `go run github.com/tc-hib/go-winres`. Documented in README Forge section. | +| [LOW] SettingsPage = Calibrate / no CalibratePage | Nav label **Calibrate** → route `/settings` → `SettingsPage`. Navigation table in README. (A11y `htmlFor` remains in Open.) | +| [LOW] `types/index.ts` no runtime guards | Compile-time contracts only; comment block at top of file + tests/README Architecture note. | +| [LOW] No e2e for remote actions | Added `server/web/e2e/remote-actions.spec.ts` (offline agent mock → disabled buttons). Vitest coverage in `components.test.tsx`. | +| [LOW] Mesh P2P needs `p2p` tag | Forge adds `-tags p2p` when mesh enabled (`compile.go`); manual builds documented in README agent section. | + +--- + +## Fixed (this session — May 2026 full pass) + +- **[MEDIUM] server/web/src/pages/BuilderPage.tsx** — Added `useEffect` cleanup on unmount that calls `api.cancelBuild(cancelTokenRef.current)` and sets `batchCancelRef.current = true`. Navigating away from the Forge page now cancels any in-progress server-side compile (M14 UI desync closed). +- **[MEDIUM] agent/miner/pool.go** — Added atomic `jobGen` counter incremented in `SetJob`. Workers snapshot `jobGen` before each 256-nonce inner loop and break early when it changes, eliminating the "stale batch" window. Engine updates moved outside the pool write-lock (each `Engine` has its own `RWMutex`). +- **[LOW] server/internal/api/fleet_handler.go** — `xmrPriceCache` moved from package-global vars (`xmrPriceMu`, `xmrPriceCache`) into `FleetHandler` struct fields (`xmrPriceMu`, `xmrPriceCache`). Multiple routers in one process no longer share a stale cache. Tests updated. +- **[LOW] server/config.go** — `LoadConfig` now calls `mergeConfigExplicit` (with a key-presence map) instead of legacy `mergeConfig`. Boolean fields absent from a hand-edited `config.json` now keep `DefaultConfig` values rather than being zeroed on restart. +- **[LOW] server/internal/api/config_handler.go** — Removed unused `db *db.Database` field from `ConfigHandler` and updated `NewConfigHandler` signature. All call sites updated (`router_test.go`, `integration_test.go`, `config_handler_test.go`, `main.go`). +- **[LOW] server/main.go** — `UpdateConfigFromJSON` now validates semantic constraints before merging: port ranges 1–65535, pool port range, non-negative max_agents/stats_retention_hours/build_retention_days/max_build_size_mb. Invalid values return `"invalid config: …"` 400 without touching disk. +- **[LOW] server/internal/db/agent_meta.go** — `decodeTags` now logs corrupt tag JSON via `log.Printf` instead of silently discarding it. +- **[LOW] server/web/src/pages/SettingsPage.tsx** — All `