Skip to content

prevent PacketTunnel from wedging during cold startup - #8946

Open
atavism wants to merge 8 commits into
mainfrom
atavism/issue-3747
Open

prevent PacketTunnel from wedging during cold startup#8946
atavism wants to merge 8 commits into
mainfrom
atavism/issue-3747

Conversation

@atavism

@atavism atavism commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Resolves https://github.com/getlantern/engineering/issues/3747

Summary by CodeRabbit

  • Bug Fixes

    • Improved VPN reliability when multiple connection or server-selection requests occur simultaneously.
    • Prevented conflicting VPN start and stop actions, including during transitions, with clearer error messages.
    • Improved cancellation and coordination of overlapping VPN operations.
    • Improved IPC startup and shutdown handling to avoid stale connections, lifecycle conflicts, and invalid client access.
    • Improved VPN behavior across connected, disconnected, and transitional states.
  • Tests

    • Added coverage for concurrent VPN requests, VPN state transitions, and IPC lifecycle coordination.

Copilot AI lite review requested due to automatic review settings August 3, 2026 15:27
@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 348993b6-8f17-4031-b8a9-38d9a52496f7

📥 Commits

Reviewing files that changed from the base of the PR and between b0c443e and 9c63d1f.

📒 Files selected for processing (4)
  • lantern-core/mobile/mobile_test.go
  • macos/Runner/VPN/VPNBase.swift
  • macos/Runner/VPN/VPNManager.swift
  • macos/RunnerTests/RunnerTests.swift
🚧 Files skipped from review as they are similar to previous changes (4)
  • macos/Runner/VPN/VPNBase.swift
  • macos/RunnerTests/RunnerTests.swift
  • macos/Runner/VPN/VPNManager.swift
  • lantern-core/mobile/mobile_test.go

📝 Walkthrough

Walkthrough

The PR coordinates IPC startup and shutdown, serializes VPN connection requests, and adds explicit macOS tunnel state decisions with cancellation and concurrency tests.

Changes

VPN lifecycle reliability

Layer / File(s) Summary
IPC lifecycle coordination
lantern-core/mobile/mobile.go, lantern-core/mobile/mobile_test.go
IPC clients are published atomically. Startup and shutdown coordinate through lifecycle flags and generation checks. Tests cover nonblocking client reads and busy startup detection.
VPN connection serialization
lantern-core/vpn_tunnel/vpn_tunnel.go, lantern-core/vpn_tunnel/vpn_tunnel_test.go
VPN connection operations use a semaphore-protected helper and a narrower client interface. Tests verify serialization and timeout behavior.
macOS tunnel lifecycle coordination
macos/Runner/VPN/VPNBase.swift, macos/Runner/VPN/VPNManager.swift, macos/RunnerTests/RunnerTests.swift
Start and stop operations use explicit NEVPNStatus decisions, cancellation, localized errors, and an actor-based operation coordinator. Tests cover overlapping operations, handoff, timeout, and state transitions.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant VPNManager
  participant VPNLifecycleCoordinator
  participant MobileIPC
  participant VPNTunnel
  VPNManager->>VPNLifecycleCoordinator: acquire start or stop operation
  VPNManager->>MobileIPC: start or connect through IPC
  MobileIPC->>VPNTunnel: serialize connection request
  VPNLifecycleCoordinator-->>VPNManager: cancel or reject conflicting operation
  VPNManager->>VPNLifecycleCoordinator: complete operation
Loading

Possibly related issues

  • Issue 3747: The PR implements IPC lifecycle coordination, serialized VPN connections, and macOS start/stop coordination described by the issue.

Suggested reviewers: copilot

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 22.73% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies preventing PacketTunnel wedging during cold startup, which matches the primary change.
Linked Issues check ✅ Passed The changes address IPC startup, VPN connection serialization, connecting-state handling, cancellation, and stop behavior required by issue [#3747].
Out of Scope Changes check ✅ Passed The code and tests remain focused on IPC lifecycle and macOS VPN startup, serialization, cancellation, and recovery for issue [#3747].
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch atavism/issue-3747

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 aims to prevent the macOS/iOS PacketTunnel (and related mobile IPC plumbing) from wedging during cold startup by making VPN lifecycle operations more deterministic and adding concurrency safeguards and tests.

Changes:

  • Adds explicit state gating for VPN start/stop based on NEVPNStatus, with a new operationInProgress error surfaced to callers.
  • Serializes core “connect/select server” requests in lantern-core/vpn_tunnel to avoid overlapping tunnel operations.
  • Refactors mobile IPC client access to avoid blocking on lifecycle locks, and adds targeted concurrency tests.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
macos/RunnerTests/RunnerTests.swift Adds unit tests validating new VPN start/stop state gating behavior.
macos/Runner/VPN/VPNManager.swift Uses shared helpers to decide whether to start/stop vs. message the extension, improving state handling.
macos/Runner/VPN/VPNBase.swift Introduces operationInProgress error + helper functions to map NEVPNStatus to actions/errors.
lantern-core/vpn_tunnel/vpn_tunnel.go Adds request serialization around connect/select operations to prevent overlapping calls.
lantern-core/vpn_tunnel/vpn_tunnel_test.go Adds a concurrency test asserting connect requests are serialized.
lantern-core/mobile/mobile.go Makes IPC client access atomic and adds lifecycle guards/cancelation behavior for start/close races.
lantern-core/mobile/mobile_test.go Adds a regression test ensuring getClient() doesn’t block on the IPC lifecycle mutex.

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

Comment thread lantern-core/mobile/mobile.go
Comment thread lantern-core/vpn_tunnel/vpn_tunnel.go

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
lantern-core/mobile/mobile.go (1)

289-343: 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Bound the IPC start path

StartIPCServer sets ipcStarting before backend.NewLocalBackend, be.Start(), and server.Start(), but the backend construction does not consume the passed context, so context.Background() provides no deadline. Start ipc.StartIPCServer with a context deadline as in StartVPN/StopVPN so a wedged backend startup cannot leave ipcStarting forever and block later calls with errLanternNotReady.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lantern-core/mobile/mobile.go` around lines 289 - 343, Update StartIPCServer
to use a bounded context with a deadline, matching the established
StartVPN/StopVPN pattern, and pass it to backend.NewLocalBackend instead of
context.Background(). Ensure the timeout covers backend construction and startup
so ipcStarting cannot remain set indefinitely while preserving the existing
cleanup and cancellation behavior.
🧹 Nitpick comments (1)
macos/RunnerTests/RunnerTests.swift (1)

10-33: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add test coverage for the .invalid branch.

testVPNStartStates and testVPNStopStates do not cover .invalid, which both shouldStartNewTunnel and shouldStopTunnel map to VPNManagerError.loadingProviderFailed. Add assertions for .invalid to lock in this error-mapping behavior for a critical-path decision helper.

✅ Proposed additional assertions
     for status in [NEVPNStatus.connecting, .disconnecting, .reasserting] {
       XCTAssertThrowsError(try shouldStartNewTunnel(for: status)) { error in
         guard let vpnError = error as? VPNManagerError,
           case .operationInProgress = vpnError
         else {
           return XCTFail("Expected operationInProgress for \(status), got \(error)")
         }
       }
     }
+
+    XCTAssertThrowsError(try shouldStartNewTunnel(for: .invalid)) { error in
+      guard let vpnError = error as? VPNManagerError,
+        case .loadingProviderFailed = vpnError
+      else {
+        return XCTFail("Expected loadingProviderFailed for .invalid, got \(error)")
+      }
+    }
   }

   func testVPNStopStates() throws {
     for status in [NEVPNStatus.connected, .connecting, .reasserting] {
       XCTAssertTrue(try shouldStopTunnel(for: status))
     }
     for status in [NEVPNStatus.disconnected, .disconnecting] {
       XCTAssertFalse(try shouldStopTunnel(for: status))
     }
+
+    XCTAssertThrowsError(try shouldStopTunnel(for: .invalid)) { error in
+      guard let vpnError = error as? VPNManagerError,
+        case .loadingProviderFailed = vpnError
+      else {
+        return XCTFail("Expected loadingProviderFailed for .invalid, got \(error)")
+      }
+    }
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@macos/RunnerTests/RunnerTests.swift` around lines 10 - 33, Add `.invalid`
coverage to both `testVPNStartStates` and `testVPNStopStates`, asserting that
`shouldStartNewTunnel(for:)` and `shouldStopTunnel(for:)` throw
`VPNManagerError.loadingProviderFailed`. Keep the existing status assertions
unchanged and verify the specific error case rather than only checking that an
error occurs.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@lantern-core/vpn_tunnel/vpn_tunnel.go`:
- Around line 42-45: Replace the plain connectMu mutex acquisition in
connectToServer with a context-aware semaphore wait that can return when ctx is
canceled or reaches its deadline. Preserve serialized access to the VPN status,
server selection, and connection operations, and release the semaphore after the
existing deferred critical-section cleanup.

In `@macos/Runner/VPN/VPNManager.swift`:
- Around line 143-146: Serialize the shared VPNManager operations invoked by
MethodHandler: update startVPN, connectToServer, and stopVPN so their
independent Tasks cannot concurrently call startTunnel(), connectToServer(), or
stopTunnel(). Add a lock, serial queue, or actor/@MainActor isolation around
these entry points, preserving the existing already-connected
triggerExtensionMethod behavior while preventing overlapping tunnel operations.

---

Outside diff comments:
In `@lantern-core/mobile/mobile.go`:
- Around line 289-343: Update StartIPCServer to use a bounded context with a
deadline, matching the established StartVPN/StopVPN pattern, and pass it to
backend.NewLocalBackend instead of context.Background(). Ensure the timeout
covers backend construction and startup so ipcStarting cannot remain set
indefinitely while preserving the existing cleanup and cancellation behavior.

---

Nitpick comments:
In `@macos/RunnerTests/RunnerTests.swift`:
- Around line 10-33: Add `.invalid` coverage to both `testVPNStartStates` and
`testVPNStopStates`, asserting that `shouldStartNewTunnel(for:)` and
`shouldStopTunnel(for:)` throw `VPNManagerError.loadingProviderFailed`. Keep the
existing status assertions unchanged and verify the specific error case rather
than only checking that an error occurs.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 9f11171f-288b-416e-9bb7-41745f6e5b99

📥 Commits

Reviewing files that changed from the base of the PR and between d5379bf and ff31932.

📒 Files selected for processing (7)
  • lantern-core/mobile/mobile.go
  • lantern-core/mobile/mobile_test.go
  • lantern-core/vpn_tunnel/vpn_tunnel.go
  • lantern-core/vpn_tunnel/vpn_tunnel_test.go
  • macos/Runner/VPN/VPNBase.swift
  • macos/Runner/VPN/VPNManager.swift
  • macos/RunnerTests/RunnerTests.swift

Comment thread lantern-core/vpn_tunnel/vpn_tunnel.go
Comment thread macos/Runner/VPN/VPNManager.swift
Copilot AI review requested due to automatic review settings August 3, 2026 18:06

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@lantern-core/mobile/mobile_test.go`:
- Around line 38-47: Update the test setup around StartIPCServer to save all
lifecycle fields, explicitly set ipcServer to nil, ipcStarting to true, and
ipcClosing to false before asserting errIPCLifecycleBusy, then restore each
saved value in t.Cleanup instead of forcing ipcStarting to false.

In `@macos/Runner/VPN/VPNManager.swift`:
- Line 12: Update the VPNManager start/stop lifecycle around operationGate,
startTunnel(), and stopTunnel() so a stop request can cancel an in-progress
startup after startVPNTunnel() while preserving serialized profile persistence
through saveThenLoadProvider(). Add a cancellation-capable transition that
releases or coordinates the gate safely, lets stopTunnel() reach the .connecting
teardown path and invoke stopVPNTunnel(), and prevents races with startup
completion. Add a test that pauses startup after startVPNTunnel() and verifies
stopTunnel() sends the teardown request.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 7d518c4e-d5e5-4af5-8128-d007084147c0

📥 Commits

Reviewing files that changed from the base of the PR and between ff31932 and 11e957d.

📒 Files selected for processing (7)
  • lantern-core/mobile/mobile.go
  • lantern-core/mobile/mobile_test.go
  • lantern-core/vpn_tunnel/vpn_tunnel.go
  • lantern-core/vpn_tunnel/vpn_tunnel_test.go
  • macos/Runner/VPN/VPNBase.swift
  • macos/Runner/VPN/VPNManager.swift
  • macos/RunnerTests/RunnerTests.swift
🚧 Files skipped from review as they are similar to previous changes (3)
  • lantern-core/vpn_tunnel/vpn_tunnel.go
  • lantern-core/mobile/mobile.go
  • lantern-core/vpn_tunnel/vpn_tunnel_test.go

Comment thread lantern-core/mobile/mobile_test.go
Comment thread macos/Runner/VPN/VPNManager.swift Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated no new comments.

Suppressed comments (1)

macos/Runner/VPN/VPNManager.swift:200

  • stopTunnel() now throws for NEVPNStatus.invalid (via shouldStopTunnel) after syncStatus() returns early when no VPN profile exists. This can surface a user-visible STOP_FAILED even though there’s simply nothing to stop (e.g., first launch/no profile). Consider treating .invalid as a no-op in stopTunnel (or explicitly detecting the "no configured profile" case) to keep stop idempotent.
    let status = manager.connection.status
    if try !shouldStopTunnel(for: status) {
      appLogger.log("VPN is already stopped or stopping: \(status)")
      return
    }

Copilot AI review requested due to automatic review settings August 3, 2026 19:51

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated no new comments.

Suppressed comments (1)

macos/Runner/VPN/VPNManager.swift:207

  • connectToServer(serverName:operationID:) checks canContinueConnectionOperation right after setupVPN(), but a stop request can cancel the operation after that guard and before startVPNTunnel(...) is invoked. In that case we can still start a new tunnel even though beginStopOperation() is pending, which undermines the intended handoff/cancellation behavior. Add a second canContinueConnectionOperation guard immediately before starting the tunnel (mirroring startTunnel(operationID:)).
    try self.manager.connection.startVPNTunnel(options: options)

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
macos/Runner/VPN/VPNManager.swift (1)

138-147: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract the connection-operation wrapper.

startTunnel() and connectToServer(serverName:) repeat the same begin/do/catch/end sequence. Each copy must call endConnectionOperation on both the success path and the failure path. A missed call leaves a stop request suspended in beginStopOperation. One helper removes that risk for future entry points.

♻️ Proposed helper
+  private func withConnectionOperation<T>(
+    _ body: (UInt) async throws -> T
+  ) async throws -> T {
+    let operationID = try await lifecycleCoordinator.beginConnectionOperation()
+    defer { Task { await lifecycleCoordinator.endConnectionOperation(operationID) } }
+    return try await body(operationID)
+  }
+
   func startTunnel() async throws {
-    let operationID = try await lifecycleCoordinator.beginConnectionOperation()
-    do {
-      try await startTunnel(operationID: operationID)
-    } catch {
-      await lifecycleCoordinator.endConnectionOperation(operationID)
-      throw error
-    }
-    await lifecycleCoordinator.endConnectionOperation(operationID)
+    try await withConnectionOperation { operationID in
+      try await self.startTunnel(operationID: operationID)
+    }
   }

Note: defer cannot await, so the sketch spawns a detached release. If you prefer a deterministic release, keep the explicit do/catch inside the single helper instead.

Also applies to: 173-184

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@macos/Runner/VPN/VPNManager.swift` around lines 138 - 147, Extract the
duplicated begin/do/catch/end lifecycle sequence from startTunnel() and
connectToServer(serverName:) into one async helper, ensuring
endConnectionOperation is awaited on both success and failure paths before
returning or rethrowing. Update both entry points to use this helper so future
connection operations share the same deterministic cleanup.
macos/RunnerTests/RunnerTests.swift (1)

70-80: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Bound the spin loop and drop the misleading expectation.

Line 73 fulfills stopStarted before the task calls beginStopOperation(). The expectation therefore does not prove that the stop request set stopPending. The loop at Lines 78-80 provides the real synchronization, because canContinueConnectionOperation returns false only after stopPending becomes true.

The loop has no deadline. If the coordinator regresses and never sets stopPending, this test hangs the test run instead of failing. Add a deadline.

💚 Proposed bounded wait
-    let stopStarted = expectation(description: "Stop requested")
-
     let stopTask = Task {
-      stopStarted.fulfill()
       return try await coordinator.beginStopOperation()
     }
-    await fulfillment(of: [stopStarted])
 
-    while await coordinator.canContinueConnectionOperation(operationID) {
+    let deadline = Date().addingTimeInterval(5)
+    while await coordinator.canContinueConnectionOperation(operationID) {
+      if Date() > deadline {
+        stopTask.cancel()
+        return XCTFail("Stop request did not take ownership of the manager")
+      }
       await Task.yield()
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@macos/RunnerTests/RunnerTests.swift` around lines 70 - 80, Remove the
misleading stopStarted expectation and its fulfillment from the stopTask setup,
since it occurs before beginStopOperation. Bound the synchronization loop around
coordinator.canContinueConnectionOperation(operationID) with a deadline or
timeout so the test fails instead of hanging if stopPending is never set, while
preserving the existing Task.yield behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@macos/Runner/VPN/VPNBase.swift`:
- Around line 65-76: Update beginStopOperation to wait for the active connection
handoff only up to a defined deadline, then resume the stop flow and force
teardown when the deadline expires. Coordinate the timeout with the existing
stopWaiters/endConnectionOperation wakeup path so each continuation is resumed
exactly once, while preserving the current operationInProgress guard and
immediate false result when no connection is active.

---

Nitpick comments:
In `@macos/Runner/VPN/VPNManager.swift`:
- Around line 138-147: Extract the duplicated begin/do/catch/end lifecycle
sequence from startTunnel() and connectToServer(serverName:) into one async
helper, ensuring endConnectionOperation is awaited on both success and failure
paths before returning or rethrowing. Update both entry points to use this
helper so future connection operations share the same deterministic cleanup.

In `@macos/RunnerTests/RunnerTests.swift`:
- Around line 70-80: Remove the misleading stopStarted expectation and its
fulfillment from the stopTask setup, since it occurs before beginStopOperation.
Bound the synchronization loop around
coordinator.canContinueConnectionOperation(operationID) with a deadline or
timeout so the test fails instead of hanging if stopPending is never set, while
preserving the existing Task.yield behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d8d81a63-49ca-47ca-97f7-8c359d4e1c35

📥 Commits

Reviewing files that changed from the base of the PR and between 11e957d and b0c443e.

📒 Files selected for processing (4)
  • lantern-core/mobile/mobile_test.go
  • macos/Runner/VPN/VPNBase.swift
  • macos/Runner/VPN/VPNManager.swift
  • macos/RunnerTests/RunnerTests.swift
🚧 Files skipped from review as they are similar to previous changes (1)
  • lantern-core/mobile/mobile_test.go

Comment thread macos/Runner/VPN/VPNBase.swift
Copilot AI review requested due to automatic review settings August 3, 2026 20:17

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

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

Comment thread macos/RunnerTests/RunnerTests.swift Outdated
Copilot AI review requested due to automatic review settings August 4, 2026 06:17

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated no new comments.

Suppressed comments (1)

macos/Runner/VPN/VPNManager.swift:238

  • The canceledConnectionOperation branch here is redundant/unreachable: the function returns earlier when canceledConnectionOperation is true, so this conditional adds dead code and makes the stop decision harder to follow. You can simplify to a single shouldStopTunnel(for:) call.
    if canceledConnectionOperation {
      shouldStop = true
    } else {
      shouldStop = try shouldStopTunnel(for: status)
    }

@jigar-f

jigar-f commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

@atavism Is this ready for review?

Copilot AI review requested due to automatic review settings August 6, 2026 12:35

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated no new comments.

Suppressed comments (5)

macos/Runner/VPN/VPNManager.swift:197

  • Same as above: throwing CancellationError here makes client-visible errors unclear. Prefer a VPNManagerError so callers get a stable, localizedDescription-backed message.
    guard await lifecycleCoordinator.canContinueConnectionOperation(operationID) else {
      throw CancellationError()
    }

macos/Runner/VPN/VPNManager.swift:179

  • Same as above: this CancellationError will be shown to users via error.localizedDescription (CONNECT_TO_SERVER_FAILED). Use VPNManagerError.operationInProgress (or another LocalizedError) for a clearer message.
    guard await lifecycleCoordinator.canContinueConnectionOperation(operationID) else {
      throw CancellationError()
    }

macos/Runner/VPN/VPNManager.swift:163

  • Same as above: throwing CancellationError after save/load can surface a confusing error to callers. Prefer throwing VPNManagerError.operationInProgress so UI gets a clear, user-facing message.
    guard await lifecycleCoordinator.canContinueConnectionOperation(operationID) else {
      throw CancellationError()
    }

macos/Runner/VPN/VPNManager.swift:149

  • Throwing CancellationError here can leak an unhelpful/opaque localizedDescription up to the Flutter layer (MethodHandler wraps it as START_FAILED). Since this path really means a stop operation has taken ownership, return a VPNManagerError with a clear message instead.

This issue also appears in the following locations of the same file:

  • line 161
  • line 177
  • line 195
    guard await lifecycleCoordinator.canContinueConnectionOperation(operationID) else {
      throw CancellationError()
    }

macos/Runner/VPN/VPNManager.swift:238

  • This branch is dead code: stopTunnelAfterHandoff returns early when canceledConnectionOperation is true, so the if/else here will always take the else path. Simplify to avoid misleading control flow.
    let shouldStop: Bool
    if canceledConnectionOperation {
      shouldStop = true
    } else {
      shouldStop = try shouldStopTunnel(for: status)

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