Skip to content

Full codebase audit: Linux support merge, Svelte 5 fixes, perf, #20/#22/#32/#34, dead code purge, 3-OS CI - #37

Closed
korjwl1 wants to merge 15 commits into
mainfrom
audit/full-sweep
Closed

Full codebase audit: Linux support merge, Svelte 5 fixes, perf, #20/#22/#32/#34, dead code purge, 3-OS CI#37
korjwl1 wants to merge 15 commits into
mainfrom
audit/full-sweep

Conversation

@korjwl1

@korjwl1 korjwl1 commented Aug 5, 2026

Copy link
Copy Markdown
Owner

Consolidated audit branch (originally staged on main by mistake — main has been restored; this PR is the review path).

Contents (13 commits)

Verification

🤖 Generated with Claude Code

axelrindle and others added 15 commits August 3, 2026 08:53
… Svelte 5/Vite 8 upgrade, wireguard-go bump (Refs #6, #25)
…der perf (Refs #35)

- Restore file-drop overlay: Svelte 5 prunes child-combinator rules with
  runtime-added ancestor classes; use descendant combinator
- Remove dead CSS (import-modal remnants in App.svelte, use-current-network
  remnants in AutomationEditor)
- Remove 4 never-imported components (MiniMode, SplitTunnelUI,
  ScriptWarning, KeyGenerator) and unused tPlain translator
- Prune 100 unused i18n keys per locale (en/ko/ja), all statically verified
- Gate store notifications in stores/tunnels.js: Svelte object stores
  re-notify unconditionally, causing full re-sorts and reactive recompute
  at 1 Hz while idle
- Key LogViewer rows by monotonic id (ring-buffer wrap rewrote all 1000
  rows per record) and TunnelList rows by name
- Settings: carry trusted_ssids from fresh fetch (lost-update with CLI)
- Drop frontend/frontend/bindings stubs committed by accident in bootstrap

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… for unreachable hosts (Fixes #32)

Router-sourced 'Destination host unreachable' replies carry no RTT token
yet ping.exe can exit 0; report unreachable instead of a made-up number.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…mer race (Refs #35)

- Linux: don't register tray.OnClick — Wails StatusNotifier fires it on
  the dbusmenu 'opened' event too, raising the window on every right-click
- Linux: serialize showDock; concurrent SetFrameless toggles could map the
  window permanently undecorated
- helper: shutdown AfterFunc re-checks it is still the current timer under
  h.mu (Stop() can't cancel an already-running callback); armShutdownTimer
  also stops a stale pending timer when a tunnel is active
- macOS: showDock retry goroutine bails on quit via package appQuitting —
  Show() on a destroyed window re-runs window creation
- macOS: track SSID warm-up retry goroutine in healthWg
- Linux: reap pkexec to avoid one zombie per spawn attempt

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…s cross-check; validate automation rules on save (Refs #35)

Removed (never reachable from any platform, GUI binding, or cgo export):
notify package, diag CIDR/speedtest, config keygen, storage.atomicRename,
tunnel.ClearAllActiveStates, update.BrewUpgradeCommand,
network.OriginalNetworkState, windows VerifyIpForwardRoute (superseded by
batch variant), ipc.MultiStatusResponse, wifi.DefaultRules.

Wired wifi.ValidateRule into SaveAutomationRules — saves silently no-op'd
malformed rules. Derive ipc.ProtocolVersion from ProtocolMajor/Minor so a
constant bump can't leave the wire string behind.

Also fix TunnelDetail autoLatency frozen at first computation: the dep-less
$: statement never re-ran, so the latency-target label/tooltip kept showing
the first-selected tunnel's endpoint forever (pre-existing, found in audit).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- darwin: reapply() verified DNS drift before rewriting — every route
  event (roam, DHCP renew, sleep/wake) was spawning 10-20 networksetup
  writes and HUP'ing mDNSResponder, wiping the machine-wide DNS cache
- darwin: loop watchdog reads interface counters via IFMIB sysctl instead
  of exec'ing netstat every 5s per full-tunnel connection (~17k
  spawns/day). NET_RT_IFLIST2 was rejected empirically: its if_msghdr2
  ifi_ibytes wraps at 32 bits; only IFMIB carries true 64-bit counters.
  netstat kept as fallback; live cross-check test added
- helper: latency probes drop to 5min cadence with no GUI subscribed —
  the headless helper (wg-quick semantics) pinged every 30s forever
- wifi: SSID poll relaxes to 60s when an event watcher (NM DBus/wlanapi)
  is attached; Linux burned ~17k nmcli spawns/day alongside a working
  DBus watcher. Watchers now report attachment
- helper: reuse the diff's JSON bytes in the 1Hz status broadcast
  instead of marshalling the same struct twice
- gui: config watcher 1s → 3s (runs for the GUI lifetime, also hidden)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…on services, failed-verify and ForceShutdown paths (Fixes #34)

Four gaps left tunnel DNS state behind after disconnect:
- RestoreDNSFromSnapshot only wrote -setdnsservers; search domains from
  DNS= hostnames persisted on every service forever. The snapshot now
  carries servers AND search domains (DNSSnapshot), and the restore
  iterates the union of snapshot, per-manager captures, and live
  services — so services that appeared mid-session (Ethernet plug,
  iPhone USB) are cleaned with their own captured originals
- SetDNS commits dnsActive BEFORE verification: a verify failure used
  to return with dnsActive=false, so rollback and crash recovery both
  no-op'd and the user was stuck on tunnel DNS unrecoverably
- ForceShutdown (helper-upgrade path) restores DNS best-effort before
  os.Exit — utun dies with the process but networksetup overrides don't
- Crash-recovery journal gains pre_mod_search (additive; old journals
  restore search domains to Empty, which is correct for the common case)

Also: darwin ping -W is milliseconds, not seconds — "-W 3" meant 3ms;
now 3000. Regression test injects run() and asserts both servers and
search domains are restored per service.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…(Refs #35)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e right network (Fixes #22)

- Default-route selection now requires RTF_UP + /0 netmask, picks the
  lowest metric, and skips tunnel/virtual interfaces — previously the
  first 00000000-destination row won, so a wg0 default route or a downed
  secondary uplink could supply the gateway
- ARP lookup is scoped to the route's device and requires ATF_COM —
  previously any row with a matching IP won, so a docker bridge sharing
  192.168.x.1 with the LAN (or a stale incomplete entry) could supply
  the MAC. Gateway-MAC is a trust signal for Automation rules
- Physical-interface classification consults /sys/class/net/<if>/device
  on Linux: docker0, virbr0, tailscale0, veth*, vmnet*, CNI bridges have
  no backing device and no longer satisfy subnet rules for networks the
  machine isn't on. Name denylist kept for the other platforms
- Parsers extracted into an untagged file with fixture tests that run on
  every platform; Linux CI exercises the full path

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ID verification (Fixes #20)

The pipe SDDL granted GRGW to Interactive Users (S-1-5-4) — every
logged-on account on a multi-user machine could drive the SYSTEM helper
(disconnect tunnels, disable kill switch, forge SSIDs into automation,
force shutdown). And verifyPeerUID was a stub Windows always skipped:
--uid was never passed there and os.Getuid() is -1 on Windows anyway.

- GUI captures its token user SID and forwards it via --owner-sid
  (validated against a strict SID pattern before touching the PowerShell
  argv or the security descriptor)
- Pipe SDDL now grants GRGW to that SID only; falls back to the old IU
  grant when no SID was supplied (helper spawned by an older GUI)
- Per-connection verifyPeer: GetNamedPipeClientProcessId → process token
  → EqualSid against the owner (SYSTEM also allowed). Defense in depth
  on top of the ACL; the owner's own elevated processes keep the same
  user SID so admin terminals still work
- Unix path unchanged (SO_PEERCRED/Getpeereid UID check as before)

Verified: darwin+windows builds, vet, full test suite, SID-injection
unit tests. Behavioral multi-user validation still needs a Windows
machine — noted on the issue.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…Linux-only test fixture bug (Refs #25, #35)

- CI now runs on pull_request + workflow_dispatch only — a bare push
  (including to main) triggers nothing; releases remain tag-only
- macOS and Windows join Ubuntu: frontend build + go test + vet each
  (Windows without -race: needs cgo/mingw; Linux -race covers shared code)
- TestMatchAsset_FindsPlatformAsset used a linux-amd64 decoy asset that
  legitimately out-matched the expected one the first time the suite ran
  on Linux — platform-neutral decoy now

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@korjwl1

korjwl1 commented Aug 5, 2026

Copy link
Copy Markdown
Owner Author

Closing — work continues on agent/linux-support-testing as intended; this PR was opened without being asked for.

@korjwl1 korjwl1 closed this Aug 5, 2026
@korjwl1
korjwl1 deleted the audit/full-sweep branch August 5, 2026 11:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment