Repository navigation
Preserve Tailscale access across Nightly Iroh upgrades - #8457
4 commits merged into
Conversation
📝 WalkthroughWalkthrough
ChangesListener enablement behavior
Estimated code review effort: 2 (Simple) | ~10 minutes Suggested reviewers: Important Pre-merge checks failedPlease resolve all errors before merging. Addressing warnings is optional. ❌ Failed checks (1 error)
✅ Passed checks (24 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Greptile SummaryThis PR changes the default behavior of
Confidence Score: 5/5The change is narrowly scoped to the listener default policy and all three build flavors are covered by deterministic tests; no regressions were introduced. The production logic is a straightforward three-branch fallback (canonical key → legacy key → build-flavor default). Explicit overrides continue to win regardless of flavor, the stable opt-in contract is unchanged, and the dev/nightly compatibility default is now tested directly rather than through runtime bundle detection. The stale-assertion issue raised by a previous review is resolved, and the previously missing legacy-key-false-on-nightly test has been added. No files require special attention. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A["isListeningEnabled(defaults:)"] -->|"passes BuildFlavor.current"| B["isListeningEnabled(defaults:buildFlavor:)"]
B --> C{"canonical key set?"}
C -->|yes| D["return override (true/false)"]
C -->|no| E{"legacy key set?"}
E -->|yes| F["return legacyOverride (true/false)"]
E -->|no| G{"buildFlavor != .stable?"}
G -->|".dev or .nightly"| H["return true (listener on by default)"]
G -->|".stable"| I["return false (opt-in only)"]
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
A["isListeningEnabled(defaults:)"] -->|"passes BuildFlavor.current"| B["isListeningEnabled(defaults:buildFlavor:)"]
B --> C{"canonical key set?"}
C -->|yes| D["return override (true/false)"]
C -->|no| E{"legacy key set?"}
E -->|yes| F["return legacyOverride (true/false)"]
E -->|no| G{"buildFlavor != .stable?"}
G -->|".dev or .nightly"| H["return true (listener on by default)"]
G -->|".stable"| I["return false (opt-in only)"]
Reviews (2): Last reviewed commit: "test(mobile): make Tailscale flavor cove..." | Re-trigger Greptile |
| @Test func nightlyPreservesLegacyListenerWhenNoSettingWasEverWritten() throws { | ||
| let suiteName = "MobileHostServiceSettingsTests.NightlyCompatibility.\(UUID().uuidString)" | ||
| let defaults = try #require(UserDefaults(suiteName: suiteName)) | ||
| defer { defaults.removePersistentDomain(forName: suiteName) } | ||
|
|
||
| #expect(MobileHostService.isListeningEnabled(defaults: defaults, buildFlavor: .nightly)) | ||
| } | ||
|
|
||
| @Test func explicitDisableWinsOverNightlyCompatibility() throws { | ||
| let suiteName = "MobileHostServiceSettingsTests.NightlyDisabled.\(UUID().uuidString)" | ||
| let defaults = try #require(UserDefaults(suiteName: suiteName)) | ||
| defer { defaults.removePersistentDomain(forName: suiteName) } | ||
|
|
||
| defaults.set(false, forKey: MobileHostService.listeningEnabledDefaultsKey) | ||
|
|
||
| #expect(!MobileHostService.isListeningEnabled(defaults: defaults, buildFlavor: .nightly)) | ||
| } | ||
|
|
||
| @Test func stableWithoutExplicitOptInKeepsLegacyListenerOff() throws { | ||
| let suiteName = "MobileHostServiceSettingsTests.StableDefault.\(UUID().uuidString)" | ||
| let defaults = try #require(UserDefaults(suiteName: suiteName)) | ||
| defer { defaults.removePersistentDomain(forName: suiteName) } | ||
|
|
||
| #expect(!MobileHostService.isListeningEnabled(defaults: defaults, buildFlavor: .stable)) | ||
| } |
There was a problem hiding this comment.
No test for legacy-key explicit-false in nightly
explicitDisableWinsOverNightlyCompatibility covers the canonical key set to false, but there is no corresponding test for the legacy key ("cmuxMobilePairingHostEnabled") set to false in a nightly build. The code at line 464 returns legacyOverride immediately (so false wins correctly), but the symmetry gap means a future reordering of the two early-return guards could silently break the "explicit legacy off on nightly" contract without a failing test.
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
Summary
This is compatibility ingress only. An older iOS app can still reach an updated Nightly Mac, where the Mac performs same-account Stack authentication. A new iOS app still requires Iroh from a truly old Mac because that Mac has no cryptographic challenge that can attest a raw Tailscale route.
Verification
9a688df060fails before the policy overload existsxcodebuild -project cmux.xcodeproj -scheme cmux-unit -configuration Debug -destination "platform=macOS" -derivedDataPath /tmp/cmux-tsmigr test -only-testing:cmuxTests/MobileHostServiceSettingsTests CODE_SIGNING_ALLOWED=NO(14 passed)swift test --package-path Packages/iOS/CmuxMobileTransport --filter CmxNetworkByteTransportFactorySecurityTests(5 passed)swift test --package-path Packages/iOS/CmuxMobileShell --filter IrohReconnectRouteSelectionTests(24 passed)tsmigrsucceeded: https://github.com/manaflow-ai/cmux/actions/runs/29676343291Need help on this PR? Tag
/codesmithwith what you need. Autofix is disabled.Summary by cubic
Preserves Tailscale pairing access across Nightly Iroh upgrades by keeping the legacy mobile listener on for dev/nightly builds when no preference exists. Explicit settings still win, and stable builds remain opt-in.
isListeningEnabled(defaults:buildFlavor:)for deterministic behavior; added tests for nightly compatibility, explicit and legacy disables, and stable default.Written for commit a05a0cc. Summary will update on new commits.
Summary by CodeRabbit