Skip to content

fix(watch): trust Tailscale certs + shared Keychain#327

Open
dimakis wants to merge 2 commits into
mainfrom
fix/watch-companion-plist
Open

fix(watch): trust Tailscale certs + shared Keychain#327
dimakis wants to merge 2 commits into
mainfrom
fix/watch-companion-plist

Conversation

@dimakis
Copy link
Copy Markdown
Owner

@dimakis dimakis commented May 16, 2026

Summary

  • Add TailscaleTrust.swift URLSession delegate so the watch app trusts Tailscale self-signed certs
  • Enable shared Keychain access group (com.mitzo.app) on both iOS and watchOS targets so the watch can read auth tokens from the phone
  • Update networking clients to use the trust delegate

Test plan

  • Build and deploy MitzoWatch target to physical Apple Watch
  • Verify watch connects to Mitzo server over Tailscale
  • Verify auth token sharing from phone to watch

🤖 Generated with Claude Code

dimakis added 2 commits April 28, 2026 08:41
watchOS requires the companion app bundle ID in the watch app's
Info.plist to install on device.

Made-with: Cursor
- Add TailscaleTrustDelegate that accepts TLS certs for *.ts.net,
  *.tail, and localhost hosts (matching Capacitor allowNavigation).
- Replace URLSession.shared with tailscaleURLSession in AuthManager,
  MitzoAPIClient, and MitzoWSClient. Fixes "Login failed" on watch
  caused by URLSession rejecting the self-signed Tailscale cert.
- Add keychain-access-groups to iOS App.entitlements so both iPhone
  and watch apps share the same Keychain access group.

Made-with: Cursor
@dimakis
Copy link
Copy Markdown
Owner Author

dimakis commented May 16, 2026

Centaur Review

Found 5 issue(s) (2 warning).

frontend/ios/MitzoShared/Sources/MitzoShared/Auth/AuthManager.swift

Sound approach — switches all Mitzo networking to a Tailscale-trusting URLSession and wires shared Keychain for watch. Main concerns: hardcoded Team ID hurts portability, and YapperClient was missed in the URLSession migration.

  • 🟡 unsafe_assumptions (L17): Team ID Y4QGXHYSY3 is hardcoded. The entitlements files use the build-time variable $(AppIdentifierPrefix) which adapts automatically, but the Swift code will break for anyone with a different Apple Developer account. For an open-source project that aims for portability, consider reading the prefix from a build-injected Info.plist key or a shared config. [fixable]

frontend/ios/MitzoShared/Sources/MitzoShared/Networking/YapperClient.swift

Sound approach — switches all Mitzo networking to a Tailscale-trusting URLSession and wires shared Keychain for watch. Main concerns: hardcoded Team ID hurts portability, and YapperClient was missed in the URLSession migration.

  • 🟡 bugs (L30): YapperClient still uses URLSession.shared (health check, line 30) and a bare URLSession(configuration: .default) (WebSocket, line 60). If Yapper is reachable over Tailscale, these calls will fail with a TLS error since they don't trust the Tailscale cert. The same pattern fixed in MitzoAPIClient, MitzoWSClient, and AuthManager was not applied here. [fixable]

frontend/ios/MitzoShared/Sources/MitzoShared/Networking/TailscaleTrust.swift

Sound approach — switches all Mitzo networking to a Tailscale-trusting URLSession and wires shared Keychain for watch. Main concerns: hardcoded Team ID hurts portability, and YapperClient was missed in the URLSession migration.

  • 🔵 unsafe_assumptions (L22): .tail is accepted as a trusted suffix but Capacitor's allowNavigation only lists *.ts.net. These are different layers (URLSession vs WKWebView), so they don't conflict functionally, but the mismatch is easy to forget. A comment noting why .tail is needed (MagicDNS short names) would help future readers. [fixable]
  • 🔵 unsafe_assumptions (L23): The delegate accepts the server trust credential without calling SecTrustEvaluateWithError — any certificate (self-signed, expired, etc.) from a matching host is trusted. This is intentional for Tailscale's own PKI, but it means a compromised DNS entry for a .ts.net domain would be trusted silently. Acceptable tradeoff for a Tailscale-only deployment, but worth a one-line comment stating the deliberate trust model.
  • 🔵 missing_tests: No tests for TailscaleTrustDelegate's host-matching logic. The suffix checks (.ts.net, .tail, localhost) are simple but a unit test would catch regressions if the allowed-host list changes. Existing tests in MitzoSharedTests only cover message encoding. [fixable]

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.

1 participant