refactor: implement architecture review action plan - #251
Merged
Conversation
Targeted repair series from a full architecture review of all 12 subsystems; the top-level shape was judged sound, so this is repairs, not re-architecture. Correctness fixes: - Guard crypto.Endpoint.Decrypt against short/malformed ciphertext (was a process-crashing panic on stored-data input) - Join daemon worker goroutines before shutdown in Run and RunOneshot, so cleanup can no longer race a controller using the WireGuard client - Warn instead of silently dropping invalid peer public keys in config - Fix the contrib Cloudflare exec plugin's double-hash record naming, making it interoperable with the builtin plugin and shell sibling Structural/DI repairs: - Narrow consumer-owned interfaces for PingMonitorController, plugin.Manager, and Daemon's controller fields; test seam for internal/wg/client_ctrl.go - Collapse duplicated Linux/Darwin-BSD STUN client code into a shared file; extract shared endpoint-selection and STUN-discovery logic (internal/ctrl/discover.go, endpoint_select.go) used by both desktop and mobile, removing drifted duplicates - Resolve proxy.enabled as truly per-interface instead of a global OR - Implement a real protected http.Transport for mobile plugin traffic (previous comment claiming protection was false) - Restore missing wire.Bind directives so `go generate wire.go` works Test coverage: - Ping retry/backoff state machine, daemon signal/ticker/shutdown, mobile package, BPF filter/payload offsets, STUN Read error paths, wgproxy escape watchers, repo concurrency (-race), contrib plugin smoke tests, mobile config protocol validation Hygiene: - One cleanup pass per subsystem; docs/architecture.md records the previously undocumented patterns Deliberate behavior changes: invalid peer keys now warn; cloudflare exec plugin DNS names change (self-heals on next publish, see its README); mobile config rejects unknown protocol strings; mobile dualstack uses desktop's warn-and-continue policy; mixed proxy.enabled configs behave per-interface. No config-format, plugin wire-protocol, or CLI changes. Signed-off-by: Date Huang <tjjh89017@hotmail.com>
tjjh89017
force-pushed
the
refactor/arch-review-plan
branch
from
July 29, 2026 06:19
da039de to
c4c23b8
Compare
This was referenced Jul 29, 2026
… tags Signed-off-by: Date Huang <tjjh89017@hotmail.com>
Corrects the golangci build-tags list, wire regeneration command (the directive lives in wire_gen.go, so 'go generate wire.go' was a no-op), plugin manager path, entity constructor signatures (firewallMark, DeviceId/PeerPublicKey types), mock-generation scope, protocol default-vs-validation attribution, STUN method signatures and the Windows stub, plugin-type extension steps (no PluginType constant), CI gate names, and release archive naming. Signed-off-by: Date Huang <tjjh89017@hotmail.com>
tjjh89017
added a commit
that referenced
this pull request
Jul 29, 2026
#251 added script-level smoke tests for the contrib plugins but they were never invoked by any Makefile target or GitHub workflow, only guarding regressions when run manually. Add plugin-test/contrib-test targets (root Makefile -> contrib/Makefile -> per-plugin Makefiles) that run each plugin's smoke_test.sh or go test, wire a new contrib-test CI job into main.yml, and document the smoke tests in contrib/README.md and CLAUDE.md. Signed-off-by: Date Huang <tjjh89017@hotmail.com>
4 tasks
tjjh89017
added a commit
that referenced
this pull request
Jul 29, 2026
Batches six minor findings flagged during #251's review: - internal/config/config.go: use %d directly instead of %s + strconv.Itoa for the proxy listen/fib validation error messages - contrib/cloudflare-shell/smoke_test.sh: fix a garbled header comment - internal/ctrl/publish.go: remove a dead trailing continue (already the last statement in its loop body) - internal/wg: add a test (client_ctrl_windows_test.go, windows-only since the mapping itself is Windows-only) for the access-denied -> ErrElevationRequired path, previously untested - internal/ctrl/discover_test.go: replace the "must not be called" sentinel error, which DiscoverEndpoints' single-family error handling silently swallowed, with a resolver stub that fails the test immediately if invoked - internal/daemon: replace daemon_signal_test.go's flaky fixed 50ms sleep with a signalReady readiness channel closed by Run right after signal.Notify registers Signed-off-by: Date Huang <tjjh89017@hotmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements the prioritized refactor plan produced by an earlier architecture-review pass (
tmp/arch-review/refactor-plan.md), which independently reviewed all 12 subsystems of this codebase and concluded the top-level shape is sound — this PR is a targeted repair series, not a re-architecture. All 35 items (34 planned + 1 discovered mid-loop) landed, were independently code-reviewed, and were spot-checked a second time via random sampling; every item passed both gates.P0 — Correctness fixes (crash/interop risk)
crypto.Endpoint.Decryptagainst short/malformed ciphertext (was a process-crashing panic on attacker/operator-controlled input)main's cleanup can no longer race a controller still using the WireGuard client (both theRunandRunOneshotcode paths)P1 — Structural/DI repairs
PingMonitorController,plugin.Manager, andDaemon's four controller fields — closes the recurring pattern of concrete-type coupling that was blocking test coverage in several placesinternal/wg/client_ctrl.go(the default WireGuard backend)proxy.enabledper-interface vs. global-OR mismatch (chosen: option (a), per-device — see behavior notes)http.Transportfor mobile's plugin managerP2 — Test coverage
Read's error paths, wgproxy's Darwin/Windows escape watchers,repo.Devices/repo.Peersconcurrency (-race), and script-level smoke tests for all 4 contrib pluginsP3 — Hygiene / doc drift
ctrl,entity/repo,config,plugin,stun,wgproxy/routeprobe, composition root,crypto/logger,contrib, and CI/e2e configdocs/architecture.mdrecording the recorded-but-undocumented patterns this review surfaced (narrow-interface style, why proxy wiring lives inmain, the plugin registry'sinit()self-registration, etc.)Discovered mid-loop:
wire.gowas missing severalwire.Binddirectives from earlier interface-extraction work, sogo generate wire.go/thewireCLI's actual codegen path (go generate .) had been silently broken for a while — the already-committedwire_gen.gostill worked via Go's structural typing, but regeneration would fail. Fixed;go generate .now succeeds cleanly with a no-op diff.Externally-visible behavior changes (all deliberate, all called out in the plan)
contrib/cloudflare/README.md's new compatibility note for the one-time re-publish/pin-old-binary options.proxy.enabled: resolved as truly per-interface (option (a)) — a mixed config (one interface enabled, one not) now behaves as documented instead of collapsing to a global ORNo config-file-format changes, no plugin wire-protocol changes (exec JSON shape, shell variable protocol,
pluginapi.Storeall unchanged), no CLI flag changes.Test plan
go build/go vetclean across linux/darwin/freebsd/windows throughoutgo test ./...passes (one pre-existing, unrelated sandbox network-permission failure ininternal/plugin/dialer, confirmed present before this branch too)go generate .(Wire codegen) succeeds cleanly"",builtin_all,builtin_cloudflare,builtin_opendht, both together)-tags mobileAdditional minor behavior deltas surfaced by post-hoc review (all benign)
info(was zerolog'stracedefault) on an unparseable level — unreachable via normal config loading, which rejects unknown levels first