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
102 changes: 5 additions & 97 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -383,25 +383,7 @@ jobs:
- name: Select Xcode
run: |
set -euo pipefail
if [ -d "/Applications/Xcode.app/Contents/Developer" ]; then
XCODE_DIR="/Applications/Xcode.app/Contents/Developer"
else
XCODE_APP="$(
find /Applications -maxdepth 1 -name 'Xcode*.app' -print 2>/dev/null \
| sort \
| tail -n 1 \
|| true
)"
if [ -n "$XCODE_APP" ]; then
XCODE_DIR="$XCODE_APP/Contents/Developer"
else
echo "No Xcode.app found under /Applications" >&2
exit 1
fi
fi
echo "DEVELOPER_DIR=$XCODE_DIR" >> "$GITHUB_ENV"
export DEVELOPER_DIR="$XCODE_DIR"
xcodebuild -version
./scripts/select-ci-xcode.sh

- name: Capture Ghostty revision
id: ghostty-revision
Expand Down Expand Up @@ -752,25 +734,7 @@ jobs:
- name: Select Xcode
run: |
set -euo pipefail
if [ -d "/Applications/Xcode.app/Contents/Developer" ]; then
XCODE_DIR="/Applications/Xcode.app/Contents/Developer"
else
XCODE_APP="$(
find /Applications -maxdepth 1 -name 'Xcode*.app' -print 2>/dev/null \
| sort \
| tail -n 1 \
|| true
)"
if [ -n "$XCODE_APP" ]; then
XCODE_DIR="$XCODE_APP/Contents/Developer"
else
echo "No Xcode.app found under /Applications" >&2
exit 1
fi
fi
echo "DEVELOPER_DIR=$XCODE_DIR" >> "$GITHUB_ENV"
export DEVELOPER_DIR="$XCODE_DIR"
xcodebuild -version
./scripts/select-ci-xcode.sh

- name: Capture Ghostty revision
id: ghostty-revision
Expand Down Expand Up @@ -981,25 +945,7 @@ jobs:
- name: Select Xcode
run: |
set -euo pipefail
if [ -d "/Applications/Xcode.app/Contents/Developer" ]; then
XCODE_DIR="/Applications/Xcode.app/Contents/Developer"
else
XCODE_APP="$(
find /Applications -maxdepth 1 -name 'Xcode*.app' -print 2>/dev/null \
| sort \
| tail -n 1 \
|| true
)"
if [ -n "$XCODE_APP" ]; then
XCODE_DIR="$XCODE_APP/Contents/Developer"
else
echo "No Xcode.app found under /Applications" >&2
exit 1
fi
fi
echo "DEVELOPER_DIR=$XCODE_DIR" >> "$GITHUB_ENV"
export DEVELOPER_DIR="$XCODE_DIR"
xcodebuild -version
./scripts/select-ci-xcode.sh

- name: Prepare isolated DerivedData
run: |
Expand Down Expand Up @@ -1351,26 +1297,7 @@ jobs:
- name: Select Xcode
run: |
set -euo pipefail
if [ -d "/Applications/Xcode.app/Contents/Developer" ]; then
XCODE_DIR="/Applications/Xcode.app/Contents/Developer"
else
XCODE_APP="$(
find /Applications -maxdepth 1 -name 'Xcode*.app' -print 2>/dev/null \
| sort \
| tail -n 1 \
|| true
)"
if [ -n "$XCODE_APP" ]; then
XCODE_DIR="$XCODE_APP/Contents/Developer"
else
echo "No Xcode.app found under /Applications" >&2
exit 1
fi
fi
echo "DEVELOPER_DIR=$XCODE_DIR" >> "$GITHUB_ENV"
export DEVELOPER_DIR="$XCODE_DIR"
xcodebuild -version
xcrun --sdk macosx --show-sdk-path
./scripts/select-ci-xcode.sh

- name: Capture Ghostty revision
id: ghostty-revision
Expand Down Expand Up @@ -1513,26 +1440,7 @@ jobs:
- name: Select Xcode
run: |
set -euo pipefail
if [ -d "/Applications/Xcode.app/Contents/Developer" ]; then
XCODE_DIR="/Applications/Xcode.app/Contents/Developer"
else
XCODE_APP="$(
find /Applications -maxdepth 1 -name 'Xcode*.app' -print 2>/dev/null \
| sort \
| tail -n 1 \
|| true
)"
if [ -n "$XCODE_APP" ]; then
XCODE_DIR="$XCODE_APP/Contents/Developer"
else
echo "No Xcode.app found under /Applications" >&2
exit 1
fi
fi
echo "DEVELOPER_DIR=$XCODE_DIR" >> "$GITHUB_ENV"
export DEVELOPER_DIR="$XCODE_DIR"
xcodebuild -version
xcrun --sdk macosx --show-sdk-path
./scripts/select-ci-xcode.sh

- name: Prepare isolated DerivedData
run: |
Expand Down
20 changes: 1 addition & 19 deletions .github/workflows/perf-activation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -152,25 +152,7 @@ jobs:
- name: Select Xcode
run: |
set -euo pipefail
if [ -d "/Applications/Xcode.app/Contents/Developer" ]; then
XCODE_DIR="/Applications/Xcode.app/Contents/Developer"
else
XCODE_APP="$(
find /Applications -maxdepth 1 -name 'Xcode*.app' -print 2>/dev/null \
| sort \
| tail -n 1 \
|| true
)"
if [ -n "$XCODE_APP" ]; then
XCODE_DIR="$XCODE_APP/Contents/Developer"
else
echo "No Xcode.app found under /Applications" >&2
exit 1
fi
fi
echo "DEVELOPER_DIR=$XCODE_DIR" >> "$GITHUB_ENV"
export DEVELOPER_DIR="$XCODE_DIR"
xcodebuild -version
./scripts/select-ci-xcode.sh

- name: Download pre-built GhosttyKit.xcframework
env:
Expand Down
11 changes: 1 addition & 10 deletions .github/workflows/reload-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -78,16 +78,7 @@ jobs:
- name: Select Xcode
run: |
set -euo pipefail
if [ -d "/Applications/Xcode.app/Contents/Developer" ]; then
XCODE_DIR="/Applications/Xcode.app/Contents/Developer"
else
XCODE_APP="$(find /Applications -maxdepth 1 -name 'Xcode*.app' -print 2>/dev/null | sort | tail -n 1 || true)"
[ -n "$XCODE_APP" ] || { echo "No Xcode.app under /Applications" >&2; exit 1; }
XCODE_DIR="$XCODE_APP/Contents/Developer"
fi
echo "DEVELOPER_DIR=$XCODE_DIR" >> "$GITHUB_ENV"
export DEVELOPER_DIR="$XCODE_DIR"
xcodebuild -version
./scripts/select-ci-xcode.sh

- name: Install zig
run: ./scripts/install-zig-ci.sh
Expand Down
21 changes: 1 addition & 20 deletions .github/workflows/test-depot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,26 +52,7 @@ jobs:
- name: Select Xcode
run: |
set -euo pipefail
if [ -d "/Applications/Xcode.app/Contents/Developer" ]; then
XCODE_DIR="/Applications/Xcode.app/Contents/Developer"
else
XCODE_APP="$(
find /Applications -maxdepth 1 -name 'Xcode*.app' -print 2>/dev/null \
| sort \
| tail -n 1 \
|| true
)"
if [ -n "$XCODE_APP" ]; then
XCODE_DIR="$XCODE_APP/Contents/Developer"
else
echo "No Xcode.app found under /Applications" >&2
exit 1
fi
fi
echo "DEVELOPER_DIR=$XCODE_DIR" >> "$GITHUB_ENV"
export DEVELOPER_DIR="$XCODE_DIR"
xcodebuild -version
xcrun --sdk macosx --show-sdk-path
./scripts/select-ci-xcode.sh

- name: Download pre-built GhosttyKit.xcframework
env:
Expand Down
21 changes: 1 addition & 20 deletions .github/workflows/test-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,26 +93,7 @@ jobs:
- name: Select Xcode
run: |
set -euo pipefail
if [ -d "/Applications/Xcode.app/Contents/Developer" ]; then
XCODE_DIR="/Applications/Xcode.app/Contents/Developer"
else
XCODE_APP="$(
find /Applications -maxdepth 1 -name 'Xcode*.app' -print 2>/dev/null \
| sort \
| tail -n 1 \
|| true
)"
if [ -n "$XCODE_APP" ]; then
XCODE_DIR="$XCODE_APP/Contents/Developer"
else
echo "No Xcode.app found under /Applications" >&2
exit 1
fi
fi
echo "DEVELOPER_DIR=$XCODE_DIR" >> "$GITHUB_ENV"
export DEVELOPER_DIR="$XCODE_DIR"
xcodebuild -version
xcrun --sdk macosx --show-sdk-path
./scripts/select-ci-xcode.sh

- name: Download pre-built GhosttyKit.xcframework
env:
Expand Down
20 changes: 1 addition & 19 deletions .github/workflows/tmux-corpus.yml
Original file line number Diff line number Diff line change
Expand Up @@ -90,25 +90,7 @@ jobs:
- name: Select Xcode
run: |
set -euo pipefail
if [ -d "/Applications/Xcode.app/Contents/Developer" ]; then
XCODE_DIR="/Applications/Xcode.app/Contents/Developer"
else
XCODE_APP="$(
find /Applications -maxdepth 1 -name 'Xcode*.app' -print 2>/dev/null \
| sort \
| tail -n 1 \
|| true
)"
if [ -n "$XCODE_APP" ]; then
XCODE_DIR="$XCODE_APP/Contents/Developer"
else
echo "No Xcode.app found under /Applications" >&2
exit 1
fi
fi
echo "DEVELOPER_DIR=$XCODE_DIR" >> "$GITHUB_ENV"
export DEVELOPER_DIR="$XCODE_DIR"
xcodebuild -version
./scripts/select-ci-xcode.sh

- name: Cache GhosttyKit.xcframework
id: cache-ghosttykit
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ private final class NonViewTextDelegate: NSObject, NSTextViewDelegate {}
@Test func doesNotReadTextViewDelegateForClassification() {
final class DelegateTrackingTextView: NSTextView {
private(set) var delegateReadCount = 0
override var delegate: NSTextViewDelegate? {
override var delegate: (any NSTextViewDelegate)? {
get {
delegateReadCount += 1
return super.delegate
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ public final class RemoteDaemonRPCClient: @unchecked Sendable {
var webSocketSession: URLSession?
var webSocketTask: URLSessionWebSocketTask?
var webSocketDelegate: RemoteDaemonWebSocketDelegate?
var webSocketKeepaliveTimer: DispatchSourceTimer?
var webSocketKeepaliveTimer: (any DispatchSourceTimer)?
var webSocketKeepaliveTimeoutWorkItem: DispatchWorkItem?
var webSocketKeepaliveInFlight = false
var isClosed = true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ public struct RemoteSessionProcessRunner: RemoteSessionProcessRunning {
private final class PipeCaptureState: @unchecked Sendable {
var stdoutData = Data()
var stderrData = Data()
var stdoutReadError: Error?
var stderrReadError: Error?
var stdoutReadError: (any Error)?
var stderrReadError: (any Error)?
}

/// Runs the request to completion on the calling thread; see
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ extension RemoteSessionCoordinator {
let isCancelled: @Sendable () -> Bool = {
box.hasValue
}
let complete: @Sendable (Result<RemotePTYBridgeServer.Endpoint, Error>) -> Void = { result in
let complete: @Sendable (Result<RemotePTYBridgeServer.Endpoint, any Error>) -> Void = { result in
if box.setIfEmpty(result) {
semaphore.signal()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ extension RemoteSessionCoordinator {
public func uploadDroppedFiles(
_ fileURLs: [URL],
operation: any RemoteTransferCancelling,
completion: @escaping @Sendable (Result<[String], Error>) -> Void
completion: @escaping @Sendable (Result<[String], any Error>) -> Void
) {
queue.async { [weak self] in
guard let self else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public final class RemoteSessionCoordinator: @unchecked Sendable {
var remotePortScanCoalesceTask: Task<Void, Never>?
var remotePortScanCoalesceToken: UUID?
var remotePortScanBurstTask: Task<Void, Never>?
var remotePortPollTimer: DispatchSourceTimer?
var remotePortPollTimer: (any DispatchSourceTimer)?
var remotePortPollMode: RemotePortPollingMode?
var polledRemotePorts: [Int] = []
var remotePortPollBaselinePorts: Set<Int>?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ internal import Foundation
/// shape, not a state machine).
final class LockedResult<T>: @unchecked Sendable {
private let lock = NSLock()
private var value: Result<T, Error>?
private var value: Result<T, any Error>?

/// Stores `result` only when no result is set yet; returns whether this
/// call stored it (the first-writer-wins latch).
func setIfEmpty(_ result: Result<T, Error>) -> Bool {
func setIfEmpty(_ result: Result<T, any Error>) -> Bool {
lock.lock()
defer { lock.unlock() }
guard value == nil else { return false }
Expand All @@ -29,7 +29,7 @@ final class LockedResult<T>: @unchecked Sendable {
}

/// The stored result, if any.
var current: Result<T, Error>? {
var current: Result<T, any Error>? {
lock.lock()
defer { lock.unlock() }
return value
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ struct PendingPTYBridgeStart {
let command: String?
let requireExisting: Bool
let isCancelled: () -> Bool
let completion: (Result<RemotePTYBridgeServer.Endpoint, Error>) -> Void
let completion: (Result<RemotePTYBridgeServer.Endpoint, any Error>) -> Void
}
Original file line number Diff line number Diff line change
Expand Up @@ -314,8 +314,7 @@ public struct SocketControlSettings {
var buffer = [CChar](repeating: 0, count: Int(MAXPATHLEN))
let length = readlink(path, &buffer, buffer.count - 1)
guard length > 0 else { return nil }
buffer[Int(length)] = 0
let target = String(cString: buffer)
let target = String(decoding: buffer.prefix(Int(length)).map { UInt8(bitPattern: $0) }, as: UTF8.self)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate this helper and its callers/tests.
rg -n -C3 '\bsymbolicLinkTarget\s*\(' --type swift
rg -n -C3 '\bcanonicalSocketPath\s*\(' --type swift
rg -n -C3 'symlink\(' --type swift

Repository: manaflow-ai/cmux

Length of output: 10184


🏁 Script executed:

# Read the complete function around line 317
sed -n '313,327p' Packages/macOS/CmuxSettings/Sources/CmuxSettings/SocketControl/SocketControlSettings.swift

Repository: manaflow-ai/cmux

Length of output: 835


🏁 Script executed:

# Check for any existing tests of invalid UTF-8 or malformed symlink targets
rg -n 'invalid|malform|UTF-8|utf8|non.*utf|encode' --type swift cmuxTests/ Packages/macOS/CmuxControlSocket/Tests/ | grep -i 'symlink\|readlink\|target' | head -20

Repository: manaflow-ai/cmux

Length of output: 2305


🏁 Script executed:

# Search test files for symbolicLinkTarget or canonicalSocketPath testing
rg -n 'symbolicLinkTarget|canonicalSocketPath' --type swift cmuxTests/ Packages/

Repository: manaflow-ai/cmux

Length of output: 1223


🏁 Script executed:

# Check if there's any documentation or test comment about encoding expectations
rg -n 'readlink|symlink.*UTF|encoding' --type swift Packages/macOS/CmuxSettings/Sources/CmuxSettings/SocketControl/SocketControlSettings.swift -B2 -A2

Repository: manaflow-ai/cmux

Length of output: 463


🏁 Script executed:

# Check macOS/POSIX docs and any similar code patterns in the repo
rg -n 'String\(decoding.*UTF8' --type swift | head -15

Repository: manaflow-ai/cmux

Length of output: 2097


🏁 Script executed:

# Look for existing failable UTF-8 decoding patterns in the codebase
rg -n 'String\(bytes.*encoding.*utf' --type swift | head -15

Repository: manaflow-ai/cmux

Length of output: 2110


🏁 Script executed:

# Check if there are any symlink-related security or correctness comments
rg -n 'symbolicLink|readlink' --type swift -B3 -A3 cmuxTests/CMUXCLIErrorOutputRegressionTests.swift

Repository: manaflow-ai/cmux

Length of output: 42


Use a failable UTF-8 decode for readlink bytes.

String(decoding:as:) silently replaces invalid UTF-8 bytes with U+FFFD, which can corrupt symlink target canonicalization. Symlink paths from readlink() should fail fast on invalid UTF-8. The codebase uses the failable pattern String(bytes:encoding:.utf8) elsewhere for untrusted binary data (ControlClientLineReader.swift, CmuxTopProcessArguments.swift, TerminalSSHSessionDetector.swift).

Suggested fix
-        let target = String(decoding: buffer.prefix(Int(length)).map { UInt8(bitPattern: $0) }, as: UTF8.self)
+        let targetBytes = buffer.prefix(Int(length)).map { UInt8(bitPattern: $0) }
+        guard let target = String(bytes: targetBytes, encoding: .utf8) else {
+            return nil
+        }
🧰 Tools
🪛 SwiftLint (0.64.0)

[Warning] 317-317: Prefer failable String(bytes:encoding:) initializer when converting Data to String

(optional_data_string_conversion)

🤖 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
`@Packages/macOS/CmuxSettings/Sources/CmuxSettings/SocketControl/SocketControlSettings.swift`
at line 317, The readlink buffer decoding on line 317 uses String(decoding:as:)
which silently replaces invalid UTF-8 bytes with U+FFFD, corrupting symlink
target canonicalization. Replace this with the failable UTF-8 decode pattern
String(bytes:encoding:.utf8) that is already used elsewhere in the codebase
(ControlClientLineReader.swift, CmuxTopProcessArguments.swift,
TerminalSSHSessionDetector.swift) for untrusted binary data. This will ensure
that invalid UTF-8 sequences in the readlink result cause the operation to fail
fast instead of being silently corrupted.

Source: Linters/SAST tools

if target.hasPrefix("/") {
return target
}
Expand Down
Loading
Loading