Four defects, all found by the owner on the live router, all of the same family: something declared itself working while it was not. WIREGUARD WAS DEAD IN THE SHIPPED BINARY (B17). Setting up WireGuard gave "create WireGuard device: gVisor is not included in this build". The router tag set carried with_wireguard and with_awg but not with_gvisor, so sing-tun compiled its stub instead of the netstack every WireGuard device needs. FEATURES.md marks WireGuard [MVP] and AmneziaWG "a driving requirement", so this was a broken promise, not a trim. The tag itself was the small half. The tag set was the ONE build configuration nothing in the repo tested: TestAmneziaWGEndpoint passes because tests build with the full upstream tags. So the set now lives in one file (scripts/router-tags.sh) and two guards hold it to the feature list -- a static check that needs no tags, no Linux and no network (so the next such gap fails on the developer's machine), and a behavioural one that constructs every declared protocol through box.New UNDER THE SHIPPED TAGS, where skipping is forbidden. Removing the tag now fails with the feature name, the missing tag, and why: "Either add the tag back, or stop declaring the feature -- those are the only two honest options." Cost: +2.8 MB raw, +0.6-0.7 MB packed per arch. D23; D9 corrected. THE PANEL CALLED A DIRECT-ONLY ROUTER "PROTECTED" (B16). The headline came from plane === 'full', which reports whether the data plane is installed -- nft table, policy routing, live engine -- and says nothing about where the traffic goes. On a config with one `default -> direct` rule and no groups the plane is fully installed and every packet leaves in the clear, so the worst possible state rendered as the reassuring one. The verdict is now computed on the daemon FROM THE GENERATED OPTIONS at the moment they reach the engine, not from the model: buildRoute changes the answer (a scheduled rule outside its window is never emitted, only the last condition-less rule reaches Final, an unresolved target is rewritten by ruleKillFallback), and re-deriving it anywhere else is a second implementation that will drift -- model/reachability.go exists because two already did. Four verdicts, not three: `blocked` is separate because under a closed kill-switch with no catch-all nothing leaks, and calling that "going out directly" is a lie in the alarm direction. Rider: Overview's defaultTarget printed the highest-Order enabled rule as the default; a rule becomes Final by having no conditions, whatever its Order. "PREVENT THIS PAGE FROM CREATING ADDITIONAL DIALOGS" KILLED EVERY DELETE (B15). Once the browser suppresses dialogs, window.confirm returns false immediately, so all 15 confirmations across 7 pages read as "cancelled" and silently did nothing, with no way to recover from inside the panel. Replaced with an in-app dialog the browser cannot mute: focus trapped and parked on Cancel, Esc and veil cancel, focus returned to the opener, crit styling for destructive commits. useConfirm() throws if the provider is missing rather than falling back to a quiet false -- the failure mode being fixed. HYSTERIA2 AND TUIC NODES WERE DROPPED (B6). No share-link parser existed, so a feed's nodes of those types vanished. The real landmine was one layer up: ParseSubscriptionBody splits a feed by scheme prefix before parsing, so without schemePrefixes the links were gone before any parser ran and the fix would have looked complete. Undeliverable parameters are refused when the node cannot work or would be less secure than the link asked (obfs, pinSHA256, tuic v4/non-UUID) and flagged via Proxy.Warnings when it survives -- shaterd nodes shows both. uTLS is dropped for QUIC: it cannot produce a QUIC TLS config, and that fails at dial time, not at box.New. Also: nodes added by hand can be named and renamed. The name is the outbound tag, so a rename rewrites every reference in one PUT -- rule targets, group members, chain hops, detours -- in the spelling each already uses, and is refused outright when a group answers to the same bare name. Subscription nodes state why they cannot be renamed instead of hiding the control. go build, go vet, go test ./shater/... (13 packages), panel npm run build and npm test (13/13) all green. NOT yet verified on hardware. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01H4PcWfrBRyg4eWN58axaGN
26 lines
632 B
JSON
26 lines
632 B
JSON
{
|
|
"name": "shater-panel",
|
|
"private": true,
|
|
"version": "0.2.0",
|
|
"type": "module",
|
|
"description": "shater admin panel — Faceplate SPA, embedded in the forked sing-box binary",
|
|
"scripts": {
|
|
"dev": "vite",
|
|
"build": "tsc --noEmit && vite build",
|
|
"preview": "vite preview",
|
|
"typecheck": "tsc --noEmit",
|
|
"test": "node --test src/*.test.ts"
|
|
},
|
|
"dependencies": {
|
|
"react": "^18.3.1",
|
|
"react-dom": "^18.3.1"
|
|
},
|
|
"devDependencies": {
|
|
"@types/react": "^18.3.12",
|
|
"@types/react-dom": "^18.3.1",
|
|
"@vitejs/plugin-react": "^4.3.4",
|
|
"typescript": "^5.6.3",
|
|
"vite": "^5.4.11"
|
|
}
|
|
}
|