Skip to content

fix(corp-dns + menubar): bundle plumbing, /usr/local/bin symlink, live clash-api polling#31

Merged
fitz123 merged 23 commits into
mainfrom
corp-dns-plumbing-and-menubar-ergonomics
May 21, 2026
Merged

fix(corp-dns + menubar): bundle plumbing, /usr/local/bin symlink, live clash-api polling#31
fitz123 merged 23 commits into
mainfrom
corp-dns-plumbing-and-menubar-ergonomics

Conversation

@fitz123
Copy link
Copy Markdown
Owner

@fitz123 fitz123 commented May 21, 2026

Summary

Three coordinated fixes that surfaced from one incident: toggling with_corp_dns: true in the bundle broke every client because the renderer demands corp-DNS values from env vars nothing populates.

  • Corp-DNS values now travel in the published bundle. A single make publish-bundle propagates internal_dns_1 + company_domain to every client; per-Mac plist edits no longer required. buildSyncEnv takes precedence: bundle-supplied values win over env vars. Backward-compatible via omitempty.
  • bb-vpn symlink moved to /usr/local/bin/ so sudo bb-vpn … and bare bb-vpn … both resolve cleanly. ~/.local/bin/ isn't in sudo's secure_path. Postinstall is idempotent + defensive against foreign symlinks.
  • Menubar shows live urltest pick (server name + host) via sing-box's clash-api at 127.0.0.1:9090. Replaces the external ifconfig.co country probe. Bundled metacubexd UI ships at /Library/Application Support/bb-dpi/ui/ for offline access via "Open dashboard…". bundles/current.json loosened to 0o644 so the menubar (console-user-context) can read tag→host map.

Rollout sequencing (load-bearing)

bundle.Parse() uses DisallowUnknownFields(). Pre-PR bb-vpn binaries will REJECT any bundle that carries the new internal_dns_1 / company_domain fields with parse_failed (daemons keep running on cached config; no new bundles land). Deploy the .pkg to every client FIRST, then make publish-bundle. Rollback path: republish with with_corp_dns: falseomitempty drops the fields cleanly.

Today's fleet is one client (macold). Phase-7 fleet rollout will need the same gate.

Multi-phase review history

23 commits = 11 implementation + 12 review-fix. Review pipeline: 5-agent comprehensive → critical re-check → smells → codex iter 1 (4 MAJOR fixed) → codex iter 2 (only MINOR; loop exits) → final 2-agent critical sweep (clean).

Notable bugs caught by review:

  • chmod-heal lives in PromoteBundle but Tick skips PromoteBundle on render-no-op path → moved heal into the unconditional path (codex iter 1)
  • menubar's bundle-map mtime cache updated before read succeeded → permission-denied + later chmod would leave it permanently stuck (codex iter 1)
  • publish-bundle passed hand-edited internal_dns_1/company_domain through verbatim when with_corp_dns: false → strip explicitly (codex iter 1)
  • test-publish-bundle's missing-env case silently passed when dev shell exported the vars → unset in run_dryrun (phase 1)
  • ATS may block menubar's localhost HTTP on some macOS versions → NSAllowsLocalNetworking (phase 1)

Test plan

  • make test-bb-vpn clean (all 7 packages)
  • make test-publish-bundle clean (12/12 assertions including new corp-DNS strip/leak guards)
  • make build-menubar produces universal binary
  • make build-pkg produces ad-hoc-signed .pkg
  • Upgrade-install on macold preserves identity.json
  • which bb-vpn returns /usr/local/bin/bb-vpn
  • sudo bb-vpn status works without absolute path
  • sudo bb-vpn sync exits clean; last_error empty
  • current.json mode 0o644 after install
  • Bundled metacubexd UI present at /Library/Application Support/bb-dpi/ui/
  • clash-api /proxies/auto returns 200 with valid now field
  • Manual: menubar shows exit server: <name> (<host>) row (operator screenshot)
  • Manual: "Open dashboard…" opens metacubexd in browser (operator)
  • Manual: menubar refreshes within ~5s on urltest swap (operator)

fitz123 added 23 commits May 21, 2026 23:37
Copilot AI review requested due to automatic review settings May 21, 2026 21:04
@fitz123
Copy link
Copy Markdown
Owner Author

fitz123 commented May 21, 2026

@copilot please re-review — fixes pushed since the last review

Copy link
Copy Markdown
Contributor

Copilot AI commented May 21, 2026

@copilot please re-review — fixes pushed since the last review

Re-reviewed the latest pushed fixes at 13c91b2: local regression checks are clean (make test-bb-vpn and make test-publish-bundle both pass), and I don’t see any new follow-up changes needed from my side.

@fitz123 fitz123 merged commit e7c0dd9 into main May 21, 2026
5 checks passed
@fitz123 fitz123 deleted the corp-dns-plumbing-and-menubar-ergonomics branch May 21, 2026 21:08
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes three related client-side operational gaps discovered during a corp-DNS incident: it propagates corp-DNS settings through the published bundle (instead of relying on per-machine env), moves the bb-vpn convenience symlink to /usr/local/bin so it works under sudo, and updates the menubar app to show the live urltest-selected exit (and serve a bundled metacubexd dashboard) via sing-box’s clash-api on localhost.

Changes:

  • Bundle publishing: embed internal_dns_1 and company_domain into the bundle when with_corp_dns: true, and strip them when false (with new script-level tests).
  • Packaging: ship offline metacubexd UI assets in the .pkg, add a preinstall cleanup for legacy UI dirs, and switch the CLI symlink to /usr/local/bin/bb-vpn.
  • Menubar: replace external public-IP/country probing with local clash-api polling for the currently selected auto outbound and add “Open dashboard…” (plus ATS opt-in for local HTTP).

Reviewed changes

Copilot reviewed 59 out of 60 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
scripts/test-publish-bundle Adds corp-DNS embedding/stripping regression tests and hardens env isolation for test cases.
scripts/publish-bundle Sources .env and conditionally injects/strips corp-DNS fields in the render block before publishing.
README.md Updates menubar behavior documentation (live exit server via clash-api + bundled dashboard).
docs/release.md Documents parse-strict rollout sequencing, bundled UI, symlink location, and updated verification steps.
config/client/sing-box-skeleton.json Removes external UI download config; keeps external_ui: "ui" for bundled UI serving.
client/pkg-build/uninstall.sh Removes /usr/local/bin/bb-vpn symlink (defensively) and sweeps legacy per-user symlinks.
client/pkg-build/README.md Documents ui/ payload requirements/refresh workflow and symlink behavior.
client/pkg-build/preinstall.sh New preinstall script to remove any pre-existing ui/ dir before payload extraction.
client/pkg-build/postinstall.sh Creates /usr/local/bin/bb-vpn symlink and keeps it idempotent/defensive.
client/pkg-build/install-page-template.html Updates operator instructions to use sudo bb-vpn ... and references exit server display.
client/pkg-build/build.sh Enforces presence of UI assets, stages them into the .pkg, and installs preinstall script.
client/menubar/Info.plist Adds ATS exception for local networking to allow HTTP polling of 127.0.0.1:9090.
client/menubar/BBVPN/StatusModel.swift Replaces ifconfig-based country probe with clash-api polling + bundle map caching to display exit server: name (host).
client/menubar/BBVPN/EnrollHandler.swift Adds currentBundleURL for reading /Library/.../bundles/current.json.
client/menubar/BBVPN/BBVPNApp.swift Updates UI row label and adds “Open dashboard…” menu item.
client/bb-vpn/pkg/state/state_test.go Adds tests guarding bundle file-mode contracts and chmod-heal behavior.
client/bb-vpn/pkg/state/bundles.go Makes current.json world-readable (0o644), keeps snapshots root-only, and adds chmod-heal on short-circuit.
client/bb-vpn/pkg/launchctl/sync.go Passes bundle into buildSyncEnv, heals current bundle mode on no-op path, and implements bundle-first corp-DNS precedence.
client/bb-vpn/pkg/launchctl/sync_test.go Adds unit tests for buildSyncEnv precedence/fallback behavior and chmod-heal regression guard.
client/bb-vpn/pkg/bundle/bundle.go Extends bundle render schema with optional corp-DNS fields (omitempty).
client/bb-vpn/pkg/bundle/bundle_test.go Adds roundtrip/omitempty tests and validates legacy compatibility (no Validate() tightening).
client/bb-vpn/internal/tests/golden/skeletons/sing-box-skeleton.json Updates golden skeleton to match removal of external UI download keys.
client/bb-vpn/internal/tests/golden/expected/proto-xhttp_ts-on_corp-on_n3/sing-box.json Updates golden expected sing-box config for clash_api UI settings.
client/bb-vpn/internal/tests/golden/expected/proto-xhttp_ts-on_corp-on_n2/sing-box.json Updates golden expected sing-box config for clash_api UI settings.
client/bb-vpn/internal/tests/golden/expected/proto-xhttp_ts-on_corp-on_n1/sing-box.json Updates golden expected sing-box config for clash_api UI settings.
client/bb-vpn/internal/tests/golden/expected/proto-xhttp_ts-on_corp-off_n3/sing-box.json Updates golden expected sing-box config for clash_api UI settings.
client/bb-vpn/internal/tests/golden/expected/proto-xhttp_ts-on_corp-off_n2/sing-box.json Updates golden expected sing-box config for clash_api UI settings.
client/bb-vpn/internal/tests/golden/expected/proto-xhttp_ts-on_corp-off_n1/sing-box.json Updates golden expected sing-box config for clash_api UI settings.
client/bb-vpn/internal/tests/golden/expected/proto-xhttp_ts-off_corp-on_n3/sing-box.json Updates golden expected sing-box config for clash_api UI settings.
client/bb-vpn/internal/tests/golden/expected/proto-xhttp_ts-off_corp-on_n2/sing-box.json Updates golden expected sing-box config for clash_api UI settings.
client/bb-vpn/internal/tests/golden/expected/proto-xhttp_ts-off_corp-on_n1/sing-box.json Updates golden expected sing-box config for clash_api UI settings.
client/bb-vpn/internal/tests/golden/expected/proto-xhttp_ts-off_corp-off_n3/sing-box.json Updates golden expected sing-box config for clash_api UI settings.
client/bb-vpn/internal/tests/golden/expected/proto-xhttp_ts-off_corp-off_n2/sing-box.json Updates golden expected sing-box config for clash_api UI settings.
client/bb-vpn/internal/tests/golden/expected/proto-xhttp_ts-off_corp-off_n1/sing-box.json Updates golden expected sing-box config for clash_api UI settings.
client/bb-vpn/internal/tests/golden/expected/proto-tcp-vision_ts-on_corp-on_n3/sing-box.json Updates golden expected sing-box config for clash_api UI settings.
client/bb-vpn/internal/tests/golden/expected/proto-tcp-vision_ts-on_corp-on_n2/sing-box.json Updates golden expected sing-box config for clash_api UI settings.
client/bb-vpn/internal/tests/golden/expected/proto-tcp-vision_ts-on_corp-on_n1/sing-box.json Updates golden expected sing-box config for clash_api UI settings.
client/bb-vpn/internal/tests/golden/expected/proto-tcp-vision_ts-on_corp-off_n3/sing-box.json Updates golden expected sing-box config for clash_api UI settings.
client/bb-vpn/internal/tests/golden/expected/proto-tcp-vision_ts-on_corp-off_n2/sing-box.json Updates golden expected sing-box config for clash_api UI settings.
client/bb-vpn/internal/tests/golden/expected/proto-tcp-vision_ts-on_corp-off_n1/sing-box.json Updates golden expected sing-box config for clash_api UI settings.
client/bb-vpn/internal/tests/golden/expected/proto-tcp-vision_ts-off_corp-on_n3/sing-box.json Updates golden expected sing-box config for clash_api UI settings.
client/bb-vpn/internal/tests/golden/expected/proto-tcp-vision_ts-off_corp-on_n2/sing-box.json Updates golden expected sing-box config for clash_api UI settings.
client/bb-vpn/internal/tests/golden/expected/proto-tcp-vision_ts-off_corp-on_n1/sing-box.json Updates golden expected sing-box config for clash_api UI settings.
client/bb-vpn/internal/tests/golden/expected/proto-tcp-vision_ts-off_corp-off_n3/sing-box.json Updates golden expected sing-box config for clash_api UI settings.
client/bb-vpn/internal/tests/golden/expected/proto-tcp-vision_ts-off_corp-off_n2/sing-box.json Updates golden expected sing-box config for clash_api UI settings.
client/bb-vpn/internal/tests/golden/expected/proto-tcp-vision_ts-off_corp-off_n1/sing-box.json Updates golden expected sing-box config for clash_api UI settings.
client/bb-vpn/internal/tests/golden/expected/proto-all_ts-on_corp-on_n3/sing-box.json Updates golden expected sing-box config for clash_api UI settings.
client/bb-vpn/internal/tests/golden/expected/proto-all_ts-on_corp-on_n2/sing-box.json Updates golden expected sing-box config for clash_api UI settings.
client/bb-vpn/internal/tests/golden/expected/proto-all_ts-on_corp-on_n1/sing-box.json Updates golden expected sing-box config for clash_api UI settings.
client/bb-vpn/internal/tests/golden/expected/proto-all_ts-on_corp-off_n3/sing-box.json Updates golden expected sing-box config for clash_api UI settings.
client/bb-vpn/internal/tests/golden/expected/proto-all_ts-on_corp-off_n2/sing-box.json Updates golden expected sing-box config for clash_api UI settings.
client/bb-vpn/internal/tests/golden/expected/proto-all_ts-on_corp-off_n1/sing-box.json Updates golden expected sing-box config for clash_api UI settings.
client/bb-vpn/internal/tests/golden/expected/proto-all_ts-off_corp-on_n3/sing-box.json Updates golden expected sing-box config for clash_api UI settings.
client/bb-vpn/internal/tests/golden/expected/proto-all_ts-off_corp-on_n2/sing-box.json Updates golden expected sing-box config for clash_api UI settings.
client/bb-vpn/internal/tests/golden/expected/proto-all_ts-off_corp-on_n1/sing-box.json Updates golden expected sing-box config for clash_api UI settings.
client/bb-vpn/internal/tests/golden/expected/proto-all_ts-off_corp-off_n3/sing-box.json Updates golden expected sing-box config for clash_api UI settings.
client/bb-vpn/internal/tests/golden/expected/proto-all_ts-off_corp-off_n2/sing-box.json Updates golden expected sing-box config for clash_api UI settings.
client/bb-vpn/internal/tests/golden/expected/proto-all_ts-off_corp-off_n1/sing-box.json Updates golden expected sing-box config for clash_api UI settings.
AGENTS.md Updates CLI/symlink documentation to reflect /usr/local/bin/bb-vpn.
.gitignore Ignores .claude/scheduled_tasks.lock.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +139 to +144
USR_LOCAL_BIN="/usr/local/bin"
USR_LOCAL_LINK="$USR_LOCAL_BIN/bb-vpn"
BB_VPN_TARGET="$APP_SUPPORT/bin/bb-vpn"
mkdir -p "$USR_LOCAL_BIN"
if [[ -e "$USR_LOCAL_LINK" || -L "$USR_LOCAL_LINK" ]]; then
if [[ -L "$USR_LOCAL_LINK" ]]; then
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants