Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ concurrency:
jobs:
test:
name: test
runs-on: ${{ github.repository_owner == 'coder' && 'depot-macos-latest' || 'macos-latest'}}
runs-on: ${{ github.repository_owner == 'coder' && 'depot-macos-26' || 'macos-26'}}
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
Expand All @@ -34,7 +34,7 @@ jobs:
- name: Switch XCode Version
uses: maxim-lobanov/setup-xcode@ed7a3b1fda3918c0306d1b724322adc0b8cc0a90 # v1.7.0
with:
xcode-version: "16.4.0"
xcode-version: "26.5.0"

- name: Setup Nix
uses: ./.github/actions/nix-devshell
Expand All @@ -43,7 +43,7 @@ jobs:

format:
name: fmt
runs-on: ${{ github.repository_owner == 'coder' && 'depot-macos-latest' || 'macos-latest'}}
runs-on: ${{ github.repository_owner == 'coder' && 'depot-macos-26' || 'macos-26'}}
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
Expand All @@ -55,7 +55,7 @@ jobs:
- name: Switch XCode Version
uses: maxim-lobanov/setup-xcode@ed7a3b1fda3918c0306d1b724322adc0b8cc0a90 # v1.7.0
with:
xcode-version: "16.4.0"
xcode-version: "26.5.0"

- name: Setup Nix
uses: ./.github/actions/nix-devshell
Expand All @@ -64,7 +64,7 @@ jobs:

lint:
name: lint
runs-on: ${{ github.repository_owner == 'coder' && 'depot-macos-latest' || 'macos-latest'}}
runs-on: ${{ github.repository_owner == 'coder' && 'depot-macos-26' || 'macos-26'}}
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ concurrency:
jobs:
build:
name: Build Coder Desktop
runs-on: ${{ github.repository_owner == 'coder' && 'depot-macos-latest' || 'macos-latest'}}
runs-on: ${{ github.repository_owner == 'coder' && 'depot-macos-26' || 'macos-26'}}
if: ${{ github.repository_owner == 'coder' }}
permissions:
# To upload assets to the release
Expand All @@ -43,7 +43,7 @@ jobs:
- name: Switch XCode Version
uses: maxim-lobanov/setup-xcode@ed7a3b1fda3918c0306d1b724322adc0b8cc0a90 # v1.7.0
with:
xcode-version: "16.4.0"
xcode-version: "26.5.0"

- name: Setup Nix
uses: ./.github/actions/nix-devshell
Expand Down Expand Up @@ -107,7 +107,7 @@ jobs:

update-cask:
name: Update homebrew-coder cask
runs-on: ${{ github.repository_owner == 'coder' && 'depot-macos-latest' || 'macos-latest'}}
runs-on: ${{ github.repository_owner == 'coder' && 'depot-macos-26' || 'macos-26'}}
if: ${{ github.repository_owner == 'coder' && github.event_name == 'release' }}
needs: build
steps:
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
36 changes: 36 additions & 0 deletions Coder-Desktop/Coder-Desktop/AppIcon.icon/icon.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"fill" : {
"solid" : "display-p3:0.00000,0.00000,0.00000,1.00000"
},
"groups" : [
{
"layers" : [
{
"glass" : true,
"image-name" : "04_Coder_Shorthand_Logo_RGB_White.svg",
"name" : "04_Coder_Shorthand_Logo_RGB_White",
"position" : {
"scale" : 1.5,
"translation-in-points" : [
0,
0
]
}
}
],
"shadow" : {
"kind" : "neutral",
"opacity" : 0.5
},
"translucency" : {
"enabled" : true,
"value" : 0.5
}
}
],
"supported-platforms" : {
"squares" : [
"macOS"
]
}
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

This file was deleted.

1 change: 1 addition & 0 deletions Coder-Desktop/Coder-Desktop/Views/LoginForm.swift
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ struct LoginForm: View {

private var sessionTokenPage: some View {
VStack(alignment: .leading, spacing: 0) {
Spacer()
Form {
Section {
TextField(
Expand Down
2 changes: 1 addition & 1 deletion Coder-Desktop/VPN/PacketTunnelProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider, @unchecked Sendable {
return nil
}

override func startTunnel(
override nonisolated(nonsending) func startTunnel(
options _: [String: NSObject]?
) async throws {
globalHelperXPCClient.ptp = self
Expand Down
7 changes: 5 additions & 2 deletions Coder-Desktop/VPNLib/TunnelDaemon.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,17 @@ public actor TunnelDaemon {
}

private var monitorTask: Task<Void, Never>?
private var onFail: (TunnelDaemonError) -> Void
private var onFail: @Sendable (TunnelDaemonError) -> Void

public var writeHandle: FileHandle { tunnelReadPipe.fileHandleForWriting }
public var readHandle: FileHandle { tunnelWritePipe.fileHandleForReading }

var pid: pid_t?

public init(binaryPath: URL, onFail: @escaping (TunnelDaemonError) -> Void) async throws(TunnelDaemonError) {
public init(
binaryPath: URL,
onFail: @Sendable @escaping (TunnelDaemonError) -> Void
) async throws(TunnelDaemonError) {
self.onFail = onFail
tunnelReadPipe = Pipe()
tunnelWritePipe = Pipe()
Expand Down
37 changes: 21 additions & 16 deletions Coder-Desktop/VPNLibTests/TunnelDaemonTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,21 @@ struct TunnelDaemonTests {
let executableURL = try createTempExecutable(content: longRunningScript)
defer { try? FileManager.default.removeItem(at: executableURL) }

var failureCalled = false
let daemon = try await TunnelDaemon(binaryPath: executableURL) { _ in
failureCalled = true
let (errors, continuation) = AsyncStream.makeStream(of: TunnelDaemonError.self)
let daemon = try await TunnelDaemon(binaryPath: executableURL) { error in
continuation.yield(error)
}

await #expect(daemon.state.isRunning)
#expect(!failureCalled)
await #expect(daemon.readHandle.fileDescriptor >= 0)
await #expect(daemon.writeHandle.fileDescriptor >= 0)

try await daemon.close()
await #expect(daemon.state.isStopped)

continuation.finish()
let failure = await errors.first(where: { _ in true })
#expect(failure == nil, "onFail should not have been called")
}

@Test func daemonHandlesFailure() async throws {
Expand All @@ -45,14 +48,15 @@ struct TunnelDaemonTests {
let executableURL = try createTempExecutable(content: immediateExitScript)
defer { try? FileManager.default.removeItem(at: executableURL) }

var capturedError: TunnelDaemonError?
let (errors, continuation) = AsyncStream.makeStream(of: TunnelDaemonError.self)
let daemon = try await TunnelDaemon(binaryPath: executableURL) { error in
capturedError = error
continuation.yield(error)
}

#expect(await eventually(timeout: .milliseconds(500), interval: .milliseconds(10)) { @MainActor in
capturedError != nil
})
guard let capturedError = await errors.first(where: { _ in true }) else {
Issue.record("onFail was never called")
return
}

if case let .terminated(termination) = capturedError {
if case let .exited(status) = termination {
Expand All @@ -61,7 +65,7 @@ struct TunnelDaemonTests {
Issue.record("Expected exited termination, got \(termination)")
}
} else {
Issue.record("Expected terminated error, got \(String(describing: capturedError))")
Issue.record("Expected terminated error, got \(capturedError)")
}

await #expect(daemon.state.isFailed)
Expand All @@ -77,9 +81,9 @@ struct TunnelDaemonTests {
let executableURL = try createTempExecutable(content: script)
defer { try? FileManager.default.removeItem(at: executableURL) }

var capturedError: TunnelDaemonError?
let (errors, continuation) = AsyncStream.makeStream(of: TunnelDaemonError.self)
let daemon = try await TunnelDaemon(binaryPath: executableURL) { error in
capturedError = error
continuation.yield(error)
}

await #expect(daemon.state.isRunning)
Expand All @@ -91,9 +95,10 @@ struct TunnelDaemonTests {

kill(pid, SIGKILL)

#expect(await eventually(timeout: .milliseconds(500), interval: .milliseconds(10)) { @MainActor in
capturedError != nil
})
guard let capturedError = await errors.first(where: { _ in true }) else {
Issue.record("onFail was never called")
return
}

if case let .terminated(termination) = capturedError {
if case let .unhandledException(status) = termination {
Expand All @@ -102,7 +107,7 @@ struct TunnelDaemonTests {
Issue.record("Expected unhandledException termination, got \(termination)")
}
} else {
Issue.record("Expected terminated error, got \(String(describing: capturedError))")
Issue.record("Expected terminated error, got \(capturedError)")
}
}

Expand Down
3 changes: 3 additions & 0 deletions Coder-Desktop/project.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ options:
fileTypes:
proto:
buildPhase: none
"icon":
file: true


settings:
base:
Expand Down