From 8466c7aa9b8874c4fe3c5c143c01525d4cc7a9bf Mon Sep 17 00:00:00 2001 From: AetherForge Date: Thu, 4 Jun 2026 20:41:44 -0700 Subject: [PATCH] =?UTF-8?q?fix:=202026-06-04=20audit=20pass=20=E2=80=94=20?= =?UTF-8?q?README,=20USB=20pack,=20multi-area=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WS ticket dashboard auth, builder universal signing/size limits/fusion obfuscation/dropper bundles, Path Tracer WireGuard topology, SessionGate degraded mode and download timeouts, server bootstrap (data dir, cloudflared dedupe, config port precedence), agent mesh/miner/spread fixes. README refreshed; usb bundle repacked; PROBLEMS.md audit log updated. --- LAUNCH.bat | 34 +- PROBLEMS.md | 285 +++++-------- README.md | 32 +- agent/client/client.go | 1 + agent/client/cve_scan_windows.go | 11 +- agent/client/mesh_p2p.go | 77 +++- agent/client/mesh_p2p_stub.go | 3 +- agent/client/mesh_p2p_test.go | 49 +++ agent/client/mesh_test.go | 20 + agent/cmd/mine-validate/main.go | 2 +- agent/deploy/autospread.go | 47 +-- agent/deploy/autospread_unix.go | 43 +- agent/deploy/natpunch.go | 8 +- agent/deploy/passive_spread_windows.go | 10 +- agent/deploy/subnet.go | 109 +++++ agent/deploy/subnet_test.go | 62 +++ agent/miner/engine.go | 14 +- agent/miner/engine_test.go | 13 +- devrun.bat | 21 +- mining pools to use.txt | 21 - pack-usb.bat | 6 + scripts/usb-start-cloudflared.ps1 | 52 +++ server/config.go | 33 +- server/config_test.go | 65 ++- server/internal/alerts/evaluator.go | 6 +- server/internal/api/agent_ws_limiter.go | 41 ++ server/internal/api/ai_handler.go | 1 + server/internal/api/beacon.go | 17 +- server/internal/api/beacon_test.go | 8 + server/internal/api/dropper_handler.go | 40 +- server/internal/api/dropper_handler_test.go | 67 +++- server/internal/api/fleet_handler.go | 54 ++- server/internal/api/fleet_handler_test.go | 26 ++ server/internal/api/handlers.go | 4 + server/internal/api/handlers_test.go | 4 +- server/internal/api/integration_test.go | 4 +- server/internal/api/pathtracer_handler.go | 122 ++++-- .../internal/api/pathtracer_handler_test.go | 378 ++++++++++++++++++ server/internal/api/router.go | 77 +++- server/internal/api/router_test.go | 80 +++- server/internal/api/server_info.go | 125 +++++- server/internal/api/server_info_test.go | 25 +- server/internal/api/websocket.go | 44 +- server/internal/api/websocket_test.go | 12 + server/internal/api/ws_ticket.go | 54 +++ server/internal/builder/build_universal.go | 20 +- server/internal/builder/estimate.go | 52 ++- server/internal/builder/estimate_test.go | 41 +- server/internal/builder/fusion_media.go | 17 +- server/internal/builder/fusion_media_test.go | 14 +- server/internal/builder/handler.go | 19 +- server/internal/builder/handler_serve_test.go | 31 ++ server/internal/builder/limits.go | 27 ++ server/internal/builder/limits_test.go | 33 +- server/internal/builder/pathforge.go | 49 ++- server/internal/builder/pathforge_test.go | 73 ++++ server/internal/builder/sign_stub.go | 14 + server/internal/builder/sign_windows.go | 23 +- server/internal/builder/winres.go | 21 + server/internal/builder/winres_test.go | 29 ++ .../internal/cloudflared/launcher_windows.go | 12 + server/internal/db/agent_meta.go | 8 +- server/internal/db/agent_meta_test.go | 31 ++ server/internal/db/spread_stats.go | 2 +- server/internal/db/sqlite.go | 5 +- server/internal/pool/manager.go | 2 +- server/internal/pool/manager_test.go | 8 + server/main.go | 44 +- server/main_test.go | 12 + server/web/src/api/auth.test.ts | 61 ++- server/web/src/api/auth.ts | 91 ++++- server/web/src/api/client.test.ts | 24 ++ server/web/src/api/client.ts | 127 ++++-- server/web/src/api/download.test.ts | 21 +- server/web/src/api/download.ts | 39 +- .../src/components/Charts/HashrateChart.tsx | 8 +- .../web/src/components/Fleet/FleetPanels.tsx | 29 +- server/web/src/components/SessionGate.tsx | 262 +++++++----- .../components/Visual/VisualComponents.tsx | 4 +- server/web/src/components/components.test.tsx | 47 ++- .../src/context/WebSocketProvider.test.tsx | 40 +- server/web/src/context/WebSocketProvider.tsx | 52 ++- server/web/src/help/chartSampleData.test.ts | 47 +-- server/web/src/help/chartSampleData.ts | 75 +--- .../web/src/help/forgeCompatibility.test.ts | 35 +- server/web/src/help/forgeCompatibility.ts | 31 +- server/web/src/help/forgeFormNormalize.ts | 2 +- server/web/src/help/forgeValidation.ts | 2 +- server/web/src/pages/AgentsPage.tsx | 20 +- server/web/src/pages/BuildManagerPage.tsx | 78 ++-- server/web/src/pages/BuilderPage.tsx | 106 ++++- server/web/src/pages/DashboardPage.test.tsx | 10 +- server/web/src/pages/DashboardPage.tsx | 131 +++--- server/web/src/pages/Pages.css | 20 + server/web/src/styles/global.css | 12 + server/web/vitest-summary.txt | 49 +++ usb/AetherForge.exe | Bin 12817408 -> 12957696 bytes usb/LAUNCH.bat | 34 +- usb/agent/client/aggressive_commands.go | 24 +- usb/agent/client/client.go | 134 ++++++- usb/agent/miner/engine.go | 14 +- 101 files changed, 3369 insertions(+), 1054 deletions(-) create mode 100644 agent/client/mesh_p2p_test.go create mode 100644 agent/client/mesh_test.go create mode 100644 agent/deploy/subnet.go create mode 100644 agent/deploy/subnet_test.go delete mode 100644 mining pools to use.txt create mode 100644 scripts/usb-start-cloudflared.ps1 create mode 100644 server/internal/api/agent_ws_limiter.go create mode 100644 server/internal/api/pathtracer_handler_test.go create mode 100644 server/internal/api/ws_ticket.go create mode 100644 server/internal/builder/pathforge_test.go create mode 100644 server/internal/builder/winres_test.go create mode 100644 server/web/vitest-summary.txt diff --git a/LAUNCH.bat b/LAUNCH.bat index e31d031..c51c9b0 100644 --- a/LAUNCH.bat +++ b/LAUNCH.bat @@ -105,13 +105,16 @@ if not exist "%ROOT%\data\uploads" mkdir "%ROOT%\data\uploads" if not exist "%ROOT%\data\blueprints" mkdir "%ROOT%\data\blueprints" if not exist "%ROOT%\data\preps" mkdir "%ROOT%\data\preps" -:: Cloudflare Zero Trust connector starts inside AetherForge.exe when a token is set -:: (Calibrate -^> Cloudflare Tunnel Token, or data\cloudflared-token.txt, or AF_TUNNEL_TOKEN). - :: ---------------------------------------------------------------- :: 5. Detect LAN IP for display :: ---------------------------------------------------------------- set "SERVER_PORT=8989" +set "CONFIG_FILE=%ROOT%\data\config.json" +if exist "%CONFIG_FILE%" ( + for /f "usebackq delims=" %%P in (`powershell -NoProfile -Command "try { $j = Get-Content -Raw '%CONFIG_FILE%' | ConvertFrom-Json; if ($j.port) { $j.port } } catch { }"`) do ( + if not "%%P"=="" set "SERVER_PORT=%%P" + ) +) for /f "tokens=2 delims=:" %%I in ('ipconfig ^| findstr /i "IPv4" ^| findstr /v "127.0.0.1"') do ( set "LAN_IP=%%I" goto lan_done @@ -136,18 +139,37 @@ echo LAN: http://%LAN_IP%:%SERVER_PORT% echo Data: %ROOT%\data\ echo. echo Login accounts: admin + comrade ^(passwords below after start^). -echo Cloudflare: paste token in Calibrate or data\cloudflared-token.txt — server starts connector. +echo Cloudflare tunnel starts below ^(LAUNCH + server^). echo Press Ctrl+C to stop. echo ================================================================ echo. +:: Start Cloudflare connector before server ^(works with old or new AetherForge.exe^) +set "CF_SCRIPT=%ROOT%\scripts\usb-start-cloudflared.ps1" +if not exist "%CF_SCRIPT%" set "CF_SCRIPT=%ROOT%\..\scripts\usb-start-cloudflared.ps1" +if exist "%CF_SCRIPT%" ( + powershell -NoProfile -ExecutionPolicy Bypass -File "%CF_SCRIPT%" -DeckRoot "%ROOT%" +) else ( + echo [Tunnel] WARNING: scripts\usb-start-cloudflared.ps1 missing - repack usb folder. +) +echo. + :: Open browser after short delay start "" powershell -NoProfile -WindowStyle Hidden -Command "Start-Sleep -Seconds 3; Start-Process 'http://localhost:%SERVER_PORT%/'" -:: Launch server -"%ROOT%\AetherForge.exe" -port %SERVER_PORT% -data "%ROOT%\data" +:: Launch server (LAUNCH already started cloudflared above — tell server not to spawn a second copy) +set "AF_TUNNEL_EXTERNAL=1" +"%ROOT%\AetherForge.exe" -data "%ROOT%\data" set "EC=!ERRORLEVEL!" +if exist "%ROOT%\data\cloudflared.pid" ( + for /f "usebackq" %%P in ("%ROOT%\data\cloudflared.pid") do ( + taskkill /F /PID %%P >nul 2>nul + ) + del "%ROOT%\data\cloudflared.pid" 2>nul +) +taskkill /F /IM cloudflared.exe >nul 2>nul + echo. if "!EC!"=="0" ( echo [Server] Stopped normally. diff --git a/PROBLEMS.md b/PROBLEMS.md index f3fc586..c8c320a 100644 --- a/PROBLEMS.md +++ b/PROBLEMS.md @@ -1,191 +1,128 @@ -# Problems -Findings from systematic bug-hunt and test expansion (May 2026). +## Builder / Forge -**Verification:** `test.bat` from project root (→ `scripts/test-suite.ps1`), or `go test ./...` in `server`/`agent` and `npm test` in `server/web`. Live API matrix: `scripts/smoke-test.ps1` with server on :8989. AI handler only: `cd server && go test ./internal/api/... -run AI -v`. +*Scope: B-01–B-13 (2026-06-04 pass). `go test ./internal/builder/... ./internal/api/...` — run after changes.* + +### Fixed in this pass + +| ID | Fix | +|----|-----| +| B-01 | `checkBuildSizeFile` enforced on universal/spread-kit and universal-fusion ZIP outputs (`limits.go`, `build_universal.go`). | +| B-02 | `signExecutable` runs on spread-kit workers and universal-fusion runners when `sign_build` is set (`build_universal.go`). | +| B-03 | Dropper `/get` resolves `DownloadURL` artifact paths before `FilePath` (`dropper_handler.go`; `dataDir` on handler). | +| B-04 | Fusion launcher compile respects `shouldObfuscate` / garble (`fusion_media.go`). | +| B-05 | Fusion estimate uses paired/embedded sizing; removed stale `"video"` kind branch (`estimate.go`). | +| B-06 | Estimate adds `signingToolMissingNote` when cert configured but signtool/osslsigncode absent (`estimate.go`, `sign_*.go`). | +| B-07 | Universal fusion README `RunnerName` uses `disguisedRunnerName(payloadBase)` (`build_universal.go`). | +| B-08 | `publishFusionDeliverable` falls back to `dataDir` when `projectRoot` empty (`fusion_media.go`). | +| B-09 | PathForge `Placed` excludes hint file from count (`pathforge.go`). | +| B-10 | Multipart parse limit raised to `multipartMaxMemory` (2 GiB + headroom) (`limits.go`, `handler.go`). | +| B-11 | Dropper PS1 ZIP handler also tries `start.bat` / `deploy.bat` (`dropper_handler.go`). | +| B-12 | `DownloadBuild` Content-Disposition uses `FileName` (`handler.go`). | +| B-13 | `resolveToolPaths` probes bundled `toolchain/gopath/bin` for garble and go-winres (`winres.go`). | + +### Open + +*(none in B-01–B-13 scope)* --- -## Open +## Dashboard (React/Vite) -### Critical / security +*Audit fixes: 2026-06-04. `npm run test -- --run` in `server/web` — pass.* -- [HIGH] **server/internal/api/fleet_handler.go** — Remote code execution via authenticated API (`powershell`/`exec`/`upload`). By design — treat dashboard login as root. +### Fixed in this pass -### Frontend production (server/web) +| Fix | Area | +|-----|------| +| SessionGate distinguishes 401 vs transport errors; network blip keeps saved credentials with degraded banner | `SessionGate.tsx` | +| Session expiry message when 401 clears auth mid-session (`consumeAuthExpiredFlag`) | `auth.ts`; `client.ts`; `SessionGate.tsx` | +| Download timeouts + AbortError messaging: `downloadAuthedFile`, `downloadAgentLog`, `downloadBackup` (5 min / 10 min) | `download.ts`; `client.ts` | +| Agent log `refresh=1` uses 90s timeout (long-poll) | `client.ts` | +| Re-forge requires confirmation before compile; fusion prep picker highlights on missing payload | `BuilderPage.tsx` | +| BuildManager delete/pin errors surfaced; dropper copy clarifies pinned vs latest; `serverBase` prefers `suggested_url` via parallel `getServerInfo` | `BuildManagerPage.tsx` | -- [LOW] **server/web** — Vite build still warns on `three` vendor chunk (~760 kB gzip ~201 kB). Split out of `DashboardPage`; inherent library size — revisit on next Three/R3F bump. -- [LOW] **server/web** — `npm audit fix` (no `--force`, May 2026) applied **0** semver-safe patches; **6 remain** (5 moderate, 1 critical). **Critical:** `happy-dom@15.x` (Vitest DOM env only — not shipped; fix needs `happy-dom@20.9+`, major bump). **Moderate:** `esbuild@0.21.x` via `vite@5` → `vitest`/`vite-node` (dev-server SSRF — [GHSA-67mh-4wv8-2f99]; prod build unaffected; fix needs `vite@8+`, major bump). Do **not** run `npm audit fix --force` — also pulls Recharts v3 / React 19 transitives. Planned upgrade batch: Vite 8 + Vitest 3 + happy-dom 20 + Recharts 3 + React 18→19. -- [LOW] **server/web** — Transitive `three-mesh-bvh@0.7.8` deprecated vs pinned `three@0.170` (drei pulls 0.7.x; needs `0.8.0+` on next Three/R3F bump). `@types/three` now pinned to `0.170.0` (aligned with runtime). +### Open (document-only / deferred) -### Untested packages (next coverage targets) - -- [LOW] **server/internal/builder/** — Unit tests cover compile/fusion/disguise **helpers** (fake-go success/fail/cancel, `compileWorker`, `buildFileFusion` paired/embedded, spread-kit/fusion finish paths, manifest patching). **Integration-only** (needs real toolchain on host): successful agent/fusion `go build`/`garble` binaries, Windows PE disguise (`go-winres`, system icon extract), code signing (`signtool`/`osslsigncode`), Darwin `.app` bundle, full `buildAgent`/`buildUniversalAgent` happy-path end-to-end. -- [LOW] **agent/stats/** — Live kernel/sysctl/vm_stat sampling still integration-only; unit tests cover pure parsers (`parseKB`, `parseMeminfo`, `parseVmStat*`, `filetimeToUint64`, `cpuBusyPercentFromDeltas`). -- [LOW] **agent/deploy/** — Live SSDP multicast/SMB/SSH/cloudflared still integration-only; unit tests cover UPnP XML/URL/SOAP helpers, SSDP LOCATION parsing, passive-spread name/launcher helpers, and platform stubs (`go test ./deploy/...`). -- [LOW] **agent/client/** — Live WS/commands/posture probes still integration-only; unit tests cover pure helpers in `client.go`/`ai.go` (`truncateStr`, JSON types, job payload parsing, mock HTTP for `/decide`/`/heartbeat`/`/report`). -- [LOW] **agent/miner/** — RandomX hashing (`engine.go`), pool worker loop, and stratum TCP login/submit still integration-only; unit tests cover target/schedule helpers, stratum wire types, resource-limit guards, and hex/target math (no VM, no live TCP). -- [LOW] ~~**server/web/src/types/ws.ts + server/internal/api/ws_types.go** — WS payloads typed in two places; drift risk.~~ **Fixed May 2026** — `testdata/ws_types_fixture.json` golden file; Go `ws_types_test.go` reflects struct tags; TS `ws.test.ts` asserts same keys/shapes. - ---- - -## 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; `devrun.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 — dead code / wiring pass) - -- **[LOW] server/web + server/internal/db** — `BuildRecord.extra_files` persisted in SQLite (`extra_files` JSON column). Build Manager lists extra artifact downloads via `api.buildArtifactUrl` for historical builds, not only the post-forge strip on Forge. -- **[LOW] server/internal/api/router.go + server/web/src/api/client.ts** — Documented agent-only `POST /agent/{decide,report,heartbeat}` (fleet-secret REST; intentionally omitted from dashboard client). -- **[LOW] server/web/src/types/index.ts** — `BuildRecord.download_url` required in TS; added `BuildExtraFile` type. Build Manager uses stored `download_url` for primary download (ZIP/artifact paths). - -- **server/web/src/api/client.ts** — Added `rotateFleetSecret()` for `POST /server/rotate-secret` (was raw `fetch` in Calibrate only). -- **server/web/src/pages/SettingsPage.tsx** — Fleet secret rotation uses `api.rotateFleetSecret()`. -- **server/web/src/pages/BuilderPage.tsx** — Wired `blueprintDiff` + `compareBlueprint` / `blueprintName` into a dismissible diff panel after blueprint load/import; extra forge artifacts use `api.buildArtifactUrl` on the last-build strip. -- **server/web/src/pages/BuildManagerPage.tsx** — Primary download uses stored `build.download_url` when present (artifact/ZIP paths from universal/Fusion builds). - -## Fixed (this session — frontend production pass) - -- **[LOW] server/web** — Vite large-chunk warning for `DashboardPage` (~898 kB → ~33 kB): `manualChunks` splits `three` / `recharts` / `vendor` in `vite.config.ts`; lazy `HashrateChart`, `FleetTopologyMap`, and `MatrixStreamOverlay` in `DashboardPage.tsx`. `npm run build` PASS (remaining warning is isolated `three` chunk only). -- **[LOW] server/web** — React Router v7 future flags (`v7_startTransition`, `v7_relativeSplatPath`) opted in via shared `routerFuture` in `main.tsx` and Vitest `MemoryRouter` wrappers; Vitest stderr warnings cleared. -- **[LOW] server/web/package.json** — Moved `@types/qrcode` and `@types/three` to `devDependencies` (types-only; runtime deps unchanged). `npm ci`, `npm run build`, `npm test -- --run`, and `depcheck` all PASS (33 files / 372 tests). - ---- - -## 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 `