feat: Tenable-style patch_status - pending_updates, last_patch, reboot_pending across full stack
This commit is contained in:
218
PROBLEMS.md
218
PROBLEMS.md
@@ -1,157 +1,99 @@
|
||||
# AetherForge — Problem Audit
|
||||
# Problems
|
||||
|
||||
Findings grouped by severity. Updated after full bug-hunt pass (May 2026).
|
||||
Findings from systematic bug-hunt and test expansion (May 2026).
|
||||
|
||||
**Last verified:** run `test.bat` from project root (all phases) or see [tests/README.md](tests/README.md).
|
||||
**Verification:** `test.bat` from project root, or `go test ./...` in `server`/`agent` and `npm test` in `server/web`. AI handler only: `cd server && go test ./internal/api/... -run AI -v`.
|
||||
|
||||
---
|
||||
|
||||
## Fixed (this pass)
|
||||
## Open
|
||||
|
||||
| ID | Fix |
|
||||
|----|-----|
|
||||
| B1 | **Pool jobs stop after disconnect** — `readLoop` now waits for reconnect instead of exiting; login tracked by `loginRequestID` not hardcoded `1` |
|
||||
| B2 | **Fusion upload disk exhaustion** — `io.LimitReader` + reject unknown upload size |
|
||||
| B3 | **Artifact path traversal** — `safePathUnderRoot()`; `export_dir` limited to `fusion-deliverables/<title>/`; build ID validated before serve |
|
||||
| B4 | **Multipart forge without fusion** — `prep_exe` only required when `fusion_enabled` |
|
||||
| B5 | **Build succeeds when DB insert fails** — forge now fails if `InsertBuild` errors |
|
||||
| B6 | **Query limit DoS** — stats/shares `limit` capped at 1000 |
|
||||
| B7 | **SPA static `..` traversal** — blocked in router fallback |
|
||||
| B8 | **React 18 + R3F v9 crash** — pinned `@react-three/fiber@8` / `drei@9` (blank black screen) |
|
||||
| B9 | **SessionGate stale token on network error** — catch sets `authed=false` |
|
||||
| B10 | **AgentsPage notes/tags wiped while typing** — drafts sync only on agent switch |
|
||||
| B11 | **WS reconnect timer stacking** — clear timer + close existing socket before reconnect |
|
||||
| B12 | **Dashboard bulk select limited to top 12** — “Select all filtered” in FleetToolbar |
|
||||
| B13 | **Dashboard bulk errors silent** — catch + alert |
|
||||
| B14 | **AI `restart_miner` missing `.exe`** — normalize image name for taskkill/stat/start |
|
||||
| B15 | **AI reinstall `http.Get` no timeout** — uses `httpClient` |
|
||||
| B16 | **Fusion `worker_first` blocked forever** — worker launches async; media runs immediately |
|
||||
| B17 | **Agent empty `new_job`** — logs error and re-requests job |
|
||||
| B18 | **Agent WS read deadline** — `PongHandler` extends deadline on server ping |
|
||||
| B19 | **Windows-only forge/agent** — cross-platform workers (Linux/macOS), universal ZIP, Spread Kit, OS badges on dashboard |
|
||||
| B20 | **generateBuiltinConfig / BuiltinConfig mismatch** — added `BackupServerURLs`, `ServiceMasquerade`, `ServiceName`, `ServiceDonor` to `BuiltinConfig`; template now matches struct exactly; new unit test `TestGenerateBuiltinConfigValid` guards against regression |
|
||||
| B21 | **Fusion media files not copied for Linux/macOS** — `prepareFusionProject` now copies `media_linux.go`, `media_darwin.go`, `cache_unix.go`, `cache_windows.go`; removed deleted `media_stub.go` from copy list |
|
||||
| B22 | **Universal fusion launch scripts called `worker --spread-install`** — replaced with `fusionUniversalStartSh/Bat/Command()` that invoke the `runner` binary per-platform; README updated with per-OS instructions |
|
||||
| B23 | **Dashboard WS concurrent write race** — introduced `DashboardConn` wrapper with `sync.Mutex`; `broadcastDashboard` and `runPingLoopDash` serialize writes per connection |
|
||||
| B24 | **Spread kit `FileSize`/`BundleSize` from worker stat** — both now use ZIP stat; also fixed same issue in `finishUniversalFusion` |
|
||||
| B25 | **InsertBuild errors silently ignored in universal paths** — now logged; error returned without failing the build (ZIP is still valid) |
|
||||
| B26 | **Duplicate `auto_start` key in `spreadKitPreset`** — removed duplicate that caused TS1117 compile error |
|
||||
| B27 | **AgentsPage empty state Windows-only message** — updated to mention Windows, Linux, and macOS |
|
||||
| B28 | **H15: submitShare conn data race** — `c.conn` now snapshotted under mutex before use |
|
||||
| B29 | **H14: mergeConfig bool corruption** — `mergeConfigExplicit` only applies booleans when the parent JSON key was present; partial PUT can no longer reset `UseTLS`, `SilentMode`, `AutoStart`, etc. to false |
|
||||
| B30 | **M13: command_result dropped** — replaced single `latestMessage` slot with `commandResults` FIFO queue (cap 50); `AgentRemoteActions` iterates all new entries so no result is missed |
|
||||
| B31 | **L6: terminalLog memory leak** — capped at 500 entries; oldest lines dropped automatically |
|
||||
| B32 | **H17: pool requestID race** — `requestID` increments in `subscribe()` and `submitShareToPool()` now guarded by the write lock |
|
||||
| B33 | **M20: AutoSpread goroutine storm** — `/24` sweep uses a 16-slot semaphore on both Windows and Unix; max 16 concurrent spread attempts at any time |
|
||||
| B34 | **H16: AI reinstall on Windows** — move-old trick: live exe renamed to `.exe.old` before replacing; restored on failure |
|
||||
| B35 | **M17: MaxAgents TOCTOU** — count check moved inside the write lock at registration time; two concurrent new agents can no longer both slip past the cap |
|
||||
| B36 | **M18: GetAgentLog blocks** — `?refresh=1` now fire-and-forget; result arrives via WS `command_result` broadcast instead of 1.8 s polling loop |
|
||||
| B37 | **M16: Earnings estimator race** — `AbortController` per fetch; stale response ignored if a newer request already fired |
|
||||
| B38 | **M12: Duplicate WS connections** — `WebSocketProvider` mounts one connection at the `App` level; all components share it via context; `useWebSocket()` is now a thin context read |
|
||||
| B39 | **M15: Re-forge without prep file** — clear error message shown immediately when `fusion_enabled` but no payload uploaded, with instructions to re-upload first |
|
||||
| B40 | **L1/L2: Dead CSS + duplicate imports** — removed dead `.agent-actions` rule from `FleetPanels.css`; removed redundant CSS imports from `AgentsPage`, `DashboardPage`, `BuilderPage` (each component already imports its own CSS) |
|
||||
| B41 | **L7: Matrix animation restarts on share** — `recentShares` moved to a `useRef` read inside the draw loop; `useEffect` dependency list now only contains `active` |
|
||||
| B42 | **L9: Blueprint file permissions** — `os.WriteFile` mode changed from `0644` to `0600` |
|
||||
### 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** — Unauthenticated agent WebSocket (`/ws/agent`); any client can claim any `agent_id`. Suggested fix: bind `agent_id` to fleet secret baked into forged binary (S2 from prior audit).
|
||||
- [CRITICAL] **server/internal/api/websocket.go** — Unauthenticated dashboard WebSocket (`/ws/dashboard`); full fleet telemetry without login. Suggested fix: require Basic auth or session cookie on WS upgrade.
|
||||
- [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; no error returned.
|
||||
- [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/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/internal/api/config_handler.go** — Settings config import shallow-merge.
|
||||
- [LOW] **server/internal/builder/fusion_media.go** — XOR media crypto — weak confidentiality by design.
|
||||
- [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/pages/AgentsPage.test.tsx** — Vitest stderr `ECONNREFUSED :3000` when detail panel mounts `AgentRemoteActions`; tests pass but component may hit live fetch — mock in follow-up.
|
||||
|
||||
### Untested packages (next coverage targets)
|
||||
|
||||
- [LOW] **server/internal/maintenance/** — No unit tests for retention jobs (uses `db.ListBuildsOlderThan`; db layer now covered).
|
||||
- [LOW] **server/internal/models/** — No unit tests.
|
||||
- [LOW] **server/internal/ollama/** — No unit tests.
|
||||
- [LOW] **server/internal/sys/** — No unit tests.
|
||||
- [LOW] **server/web/src/help/buildManager.ts**, **cheatSheetContent.ts** — No unit tests yet.
|
||||
|
||||
---
|
||||
|
||||
## Fixed (this session)
|
||||
|
||||
- **server/web/src/pages/AgentsPage.tsx** — Bulk command errors now alert user (parity with Dashboard B13).
|
||||
- **server/web/src/pages/DashboardPage.tsx** — Share log table uses composite React key when `share.id` absent; exported `formatShareTime` helper.
|
||||
- **server/web/src/pages/AgentsPage.tsx** — `listAgents` no longer overwrites live WS agent list when socket already connected (`isConnectedRef` guard).
|
||||
- **server/web/src/pages/** — Added `DashboardPage.test.tsx` (11) and `AgentsPage.test.tsx` (11); vitest config extended for `.tsx` + `@testing-library/react`.
|
||||
- **server/internal/db/retention.go** — `ListBuildsOlderThan` used a partial column list; now uses `buildSelectCols` + `scanBuild` for consistent full `BuildRecord` fields.
|
||||
- **server/internal/api/integration_test.go** — Integration tests used stale hardcoded `drjones`/`czapiewski` credentials; server now generates random `admin` password on first run. Tests seed deterministic `users.json` before router init.
|
||||
- **server/web/src/help/fleetAnalytics.ts** — `contributionBars` included offline agents in total hashrate denominator, skewing contribution percentages on the dashboard.
|
||||
- **server/web/src/pages/SettingsPage.tsx** — Access Control help text still referenced removed default credentials; updated to describe first-run console password.
|
||||
- **server/internal/api/ai_handler_test.go** — Expanded unit tests for `HandleDecide`, `HandleReport`, `HandleHeartbeat`, engine lifecycle, numeric constants (1000 report cap, 60s heartbeat, 120-char reasoning truncate), Ollama-failure sleep fallback, event broadcaster, `recordActivity` merge.
|
||||
- **server/web/src/help/forgeCompatibility.ts** — Wallet preflight message said length 95–106 but validator accepts 90–106; message aligned with `looksLikeXMRWallet()`.
|
||||
- **server/web/src/help/** — Added/expanded vitest coverage: `forgeCompatibility.test.ts` (37), `forgeRules.test.ts` (46), `settingHelp.test.ts` (8).
|
||||
- **server/web/src/types/index.test.ts** — Structural fixture tests for all major exported interfaces (20 tests); documents no runtime type guards.
|
||||
|
||||
---
|
||||
|
||||
## Fixed (earlier passes)
|
||||
|
||||
| ID | Fix |
|
||||
|----|-----|
|
||||
| C1 | `BroadcastServerLog` on `WSHub` |
|
||||
| C2 | `EncodeToString` in agent download handler |
|
||||
| C3 | `AgentRemoteActions` legacy props |
|
||||
| C4 | `useWebSocket` `latestMessage` + Agents detail wiring |
|
||||
| C5 | Agent handlers: `ps`, `netstat`, `users`, `software`, `screenshot` |
|
||||
| C6 | `NewMeshNode(c)` in `NewAgentClient` |
|
||||
| H1 | WS reconnect: only mark offline if closing conn is still active |
|
||||
| H2 | WS pre-auth guard on agent message types |
|
||||
| H3 | Share submit via async pool queue |
|
||||
| H4 | Fleet broadcast `all` fails when zero agents connected |
|
||||
| H5–H8 | AI: build ID reinstall, uptime, sleep parse, decide HTTP/error field |
|
||||
| H10 | Download uses `EncodeToString` |
|
||||
| H13 | `run.bat` fails on frontend build error; kills stale server before bind |
|
||||
| M3 | `stats_update` includes memory, uptime, shares |
|
||||
| M5 | Removed blocking 800ms sleep in `GetAgentLog` |
|
||||
| M8 | `GetEngine` lock pattern simplified |
|
||||
| M10 | CORS: `AllowCredentials: false` with `AllowedOrigins: *` |
|
||||
| M11 | Blueprint delete returns boolean `success` |
|
||||
See git history and prior audit IDs (B1–B42, C1–C6, H1–H8, etc.) in README / tests/README.md.
|
||||
|
||||
---
|
||||
|
||||
## Still open — Critical / security
|
||||
## Recommended next section
|
||||
|
||||
| ID | Issue | Notes |
|
||||
|----|-------|-------|
|
||||
| S1 | **Unauthenticated build downloads** | `/api/v1/builds/{id}/download` and `/artifact/` bypass auth (intentional for agent reinstall — UUID is the secret) |
|
||||
| S2 | **Unauthenticated agent WebSocket** | `/ws/agent` — any client can claim any `agent_id` |
|
||||
| S3 | **Unauthenticated dashboard WebSocket** | `/ws/dashboard` — full fleet telemetry without login |
|
||||
| S4 | **Unauthenticated AI endpoints** | `/api/v1/agent/decide`, `/report`, `/heartbeat` — SSRF via caller-supplied Ollama URL |
|
||||
| S5 | **Default credentials in source** | `drjones` / `czapiewski` until `data/users.json` exists |
|
||||
| S6 | **Plaintext passwords** | `users.json` stores cleartext; any authed user can POST `/users` |
|
||||
| S7 | **Remote code execution via API** | Authenticated users can send `powershell`/`exec`/`upload` to any online agent — by design, treat as root |
|
||||
1. **server/web/src/pages/** — Add `BuilderPage`, `SettingsPage`, `CalibratePage` coverage (Dashboard + Agents done)
|
||||
2. **server/web/src/components/** — Fleet panels, forge form, WebSocket provider
|
||||
3. **server/web/src/help/buildManager.ts**, **cheatSheetContent.ts** — remaining untested help modules
|
||||
4. **server/internal/maintenance/** — retention job unit tests
|
||||
5. **Agent WS token auth** (S2) — security hardening
|
||||
|
||||
---
|
||||
|
||||
## Still open — High
|
||||
## Test run snapshot (this session)
|
||||
|
||||
| ID | Issue | Notes |
|
||||
|----|-------|-------|
|
||||
| H9 | `upload_log` returns content in tool report only | No dedicated log ingest API |
|
||||
| H11 | `AutoSpread` runs when baked `true` in forge | Feature-gated but dangerous if enabled |
|
||||
| H12 | Process hollowing with `-tags hollow` + forge flag | Bounds/reloc issues in `hollow_windows.go` |
|
||||
|
||||
---
|
||||
|
||||
## Still open — Medium / UX
|
||||
|
||||
| ID | Issue | Notes |
|
||||
|----|-------|-------|
|
||||
| M1 | Compact agent list default | Expand on click |
|
||||
| M6 | Remote actions disabled unless `online` | By design |
|
||||
| M9 | Fusion uses vendored `go-winres` | Optional via run.bat |
|
||||
| M14 | **Batch forge no cancel/abort** | State updates after navigate away |
|
||||
| M19 | **`SetJob` non-atomic** | Partial engine update on multi-thread miners (low real-world impact) |
|
||||
|
||||
---
|
||||
|
||||
## Still open — Low
|
||||
|
||||
| ID | Issue |
|
||||
|----|-------|
|
||||
| L3 | WS payloads typed in two places (`types/ws.ts` + Go) |
|
||||
| L4 | No integration tests for remote actions |
|
||||
| L5 | Mesh P2P requires build tag `p2p` |
|
||||
| L8 | Settings config import shallow-merge |
|
||||
| L10 | XOR media crypto — weak confidentiality by design |
|
||||
|
||||
---
|
||||
|
||||
## Verification
|
||||
|
||||
Run the full suite:
|
||||
|
||||
```bat
|
||||
test.bat
|
||||
```
|
||||
|
||||
Or manually:
|
||||
|
||||
```bat
|
||||
cd server && go test ./... && go build .
|
||||
cd ..\agent && go test ./... && go build .
|
||||
cd ..\server\web && npm test && npm run build
|
||||
run.bat
|
||||
```
|
||||
|
||||
See **[tests/README.md](tests/README.md)** for phase breakdown and E2E options.
|
||||
|
||||
---
|
||||
|
||||
## Priority for next pass
|
||||
|
||||
1. **Agent WS token auth** — bind `agent_id` to build secret baked into each forged binary; verify on connect (S2)
|
||||
2. **Dashboard WS auth** — require session cookie on WS upgrade (S3)
|
||||
3. **Process hollowing bounds + reloc** — fix `hollow_windows.go` (H12)
|
||||
4. **Batch forge cancel** — AbortController + server-side queue cancel (M14)
|
||||
| Suite | Result |
|
||||
|-------|--------|
|
||||
| `server` Go tests | PASS (all packages) |
|
||||
| `server/internal/api` `-run AI` | PASS (17 tests) |
|
||||
| `agent` Go tests | PASS |
|
||||
| `server/web` vitest (page tests) | PASS — 2 files, 22 tests |
|
||||
| `server/web` vitest (full suite) | Run `npm test` for current count |
|
||||
|
||||
Reference in New Issue
Block a user