From c19b39a343c68208c74b4d73997900834f2cf642 Mon Sep 17 00:00:00 2001
From: Ethan <39577870+ethanndickson@users.noreply.github.com>
Date: Thu, 26 Jun 2025 12:24:10 +1000
Subject: [PATCH 1/2] chore: append bundle version to mach service name (#191)

We append the CFBundleVersion to the service name to ensure a new service is used for each version. This works around the issue described in https://github.com/coder/coder-desktop-macos/issues/121, presumably caused by the XPC service cache not being invalidated on update.

![image](https://github.com/user-attachments/assets/5b1f2d1d-7aa1-4f58-92b0-ecee712f9131)
---
 Coder-Desktop/Coder-Desktop/Info.plist                   | 7 ++++++-
 Coder-Desktop/Coder-Desktop/VPN/VPNSystemExtension.swift | 5 +++--
 Coder-Desktop/VPN/Info.plist                             | 7 ++++++-
 3 files changed, 15 insertions(+), 4 deletions(-)

diff --git a/Coder-Desktop/Coder-Desktop/Info.plist b/Coder-Desktop/Coder-Desktop/Info.plist
index a9555823..654a5179 100644
--- a/Coder-Desktop/Coder-Desktop/Info.plist
+++ b/Coder-Desktop/Coder-Desktop/Info.plist
@@ -29,7 +29,12 @@
 	<key>NetworkExtension</key>
 	<dict>
 		<key>NEMachServiceName</key>
-		<string>$(TeamIdentifierPrefix)com.coder.Coder-Desktop.VPN</string>
+		<!-- We append the CFBundleVersion to the service name to ensure a new
+		 service is used for each version. This works around the issue described
+		 in https://github.com/coder/coder-desktop-macos/issues/121, presumably
+		 caused by the XPC service cache not being invalidated on update.
+		-->
+		<string>$(TeamIdentifierPrefix)com.coder.Coder-Desktop.VPN.$(CURRENT_PROJECT_VERSION)</string>
 	</dict>
 	<key>SUPublicEDKey</key>
 	<string>Ae2oQLTcx89/a73XrpOt+IVvqdo+fMTjo3UKEm77VdA=</string>
diff --git a/Coder-Desktop/Coder-Desktop/VPN/VPNSystemExtension.swift b/Coder-Desktop/Coder-Desktop/VPN/VPNSystemExtension.swift
index cb8db684..c5e4ea08 100644
--- a/Coder-Desktop/Coder-Desktop/VPN/VPNSystemExtension.swift
+++ b/Coder-Desktop/Coder-Desktop/VPN/VPNSystemExtension.swift
@@ -183,6 +183,7 @@ class SystemExtensionDelegate<AsyncDelegate: SystemExtensionAsyncRecorder>:
         if existing.bundleVersion == `extension`.bundleVersion {
             return .replace
         }
+        // TODO: Workaround disabled, as we're trying another workaround
         // To work around the bug described in
         // https://github.com/coder/coder-desktop-macos/issues/121,
         // we're going to manually reinstall after the replacement is done.
@@ -190,8 +191,8 @@ class SystemExtensionDelegate<AsyncDelegate: SystemExtensionAsyncRecorder>:
         // it looks for an extension with the *current* version string.
         // There's no way to modify the deactivate request to use a different
         // version string (i.e. `existing.bundleVersion`).
-        logger.info("App upgrade detected, replacing and then reinstalling")
-        action = .replacing
+        // logger.info("App upgrade detected, replacing and then reinstalling")
+        // action = .replacing
         return .replace
     }
 }
diff --git a/Coder-Desktop/VPN/Info.plist b/Coder-Desktop/VPN/Info.plist
index 97d4cce6..0040d95c 100644
--- a/Coder-Desktop/VPN/Info.plist
+++ b/Coder-Desktop/VPN/Info.plist
@@ -9,7 +9,12 @@
 	<key>NetworkExtension</key>
 	<dict>
 		<key>NEMachServiceName</key>
-		<string>$(TeamIdentifierPrefix)com.coder.Coder-Desktop.VPN</string>
+		<!-- We append the CFBundleVersion to the service name to ensure a new
+		 service is used for each version. This works around the issue described
+		 in https://github.com/coder/coder-desktop-macos/issues/121, presumably
+		 caused by the XPC service cache not being invalidated on update.
+		-->
+		<string>$(TeamIdentifierPrefix)com.coder.Coder-Desktop.VPN.$(CURRENT_PROJECT_VERSION)</string>
 		<key>NEProviderClasses</key>
 		<dict>
 			<key>com.apple.networkextension.packet-tunnel</key>

From 15f1890fea076bc5d1ffbffb2b686496ec5e7f7e Mon Sep 17 00:00:00 2001
From: Ethan <39577870+ethanndickson@users.noreply.github.com>
Date: Wed, 9 Jul 2025 20:00:46 +1000
Subject: [PATCH 2/2] fix: correct remote file picker dropdown chevron
 alignment (#192)

There appears to be a bug when a View created using `NSView` is inside a `DisclosureGroup` label - regardless of the size of the `NSView`, it breaks the alignment of the chevron that's included on the DisclosureGroup label by default:
![](https://github.com/user-attachments/assets/d6a14a29-1b79-4a82-ac9f-62cf88142140)

In #184 we added an `NSView` to the spinner, causing this issue.

This is almost certainly a SwiftUI bug, and so we'll work around it by placing the spinner and error symbol to the right of the label by just setting a trailing padding on the text.
The end result (with spinners on):
![](https://github.com/user-attachments/assets/50a7a7d3-bc68-4e02-b023-505b05759bf9)
---
 .../Views/FileSync/FilePicker.swift            | 18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)

diff --git a/Coder-Desktop/Coder-Desktop/Views/FileSync/FilePicker.swift b/Coder-Desktop/Coder-Desktop/Views/FileSync/FilePicker.swift
index 6f392961..9ec26231 100644
--- a/Coder-Desktop/Coder-Desktop/Views/FileSync/FilePicker.swift
+++ b/Coder-Desktop/Coder-Desktop/Views/FileSync/FilePicker.swift
@@ -123,12 +123,18 @@ struct FilePickerEntry: View {
         } label: {
             Label {
                 Text(entry.name)
-                ZStack {
-                    CircularProgressView(value: nil, strokeWidth: 2, diameter: 10)
-                        .opacity(entry.isLoading && entry.error == nil ? 1 : 0)
-                    Image(systemName: "exclamationmark.triangle.fill")
-                        .opacity(entry.error != nil ? 1 : 0)
-                }
+                    // The NSView within the CircularProgressView breaks
+                    // the chevron alignment within the DisclosureGroup view.
+                    // So, we overlay the progressview with a manual offset
+                    .padding(.trailing, 20)
+                    .overlay(alignment: .trailing) {
+                        ZStack {
+                            CircularProgressView(value: nil, strokeWidth: 2, diameter: 10)
+                                .opacity(entry.isLoading && entry.error == nil ? 1 : 0)
+                            Image(systemName: "exclamationmark.triangle.fill")
+                                .opacity(entry.error != nil ? 1 : 0)
+                        }
+                    }
             } icon: {
                 Image(systemName: "folder")
             }.help(entry.error != nil ? entry.error!.description : entry.absolute_path)
