Repository navigation
ci: route all macOS compile/test gates to Swift 6.3 Xcode (match what ships) - #6603
Conversation
The runner images ship Xcode 16.x (macOS 15 SDK / Swift 6.1) AND Xcode 26.x (macOS 26 SDK / Swift 6.3), but /Applications/Xcode.app is symlinked to 16.4. The old 'prefer /Applications/Xcode.app' selection pinned the test gate to Swift 6.1, while nightly + release already build on 26.x via select-nightly-xcodes.sh. That divergence lets code that compiles locally (6.3) and ships (6.3) fail only on the 6.1 test gate (isolated deinit, region-based isolation differences, etc). Add scripts/select-ci-xcode.sh: pick the highest macOS-SDK Xcode (falls back to newest available so it never hard-fails a runner without 26.x). Wire test-e2e's Select Xcode step to it. This aligns the test toolchain with what ships. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthroughInline Xcode-discovery shell logic scattered across six CI workflows is extracted into a new ChangesXcode CI Selection Extraction
Swift 6 Existential Type Migration
Symlink String Handling Improvement
Estimated code review effort🎯 2 (Simple) | ⏱️ ~13 minutes Possibly related PRs
Suggested reviewers
Poem
Important Pre-merge checks failedPlease resolve all errors before merging. Addressing warnings is optional. ❌ Failed checks (1 error, 1 warning)
✅ Passed checks (21 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
Greptile SummaryThis PR aligns all macOS CI compile/test gates with the Swift 6.3 toolchain (Xcode 26.x / macOS 26 SDK) that release and nightly already use, by introducing
Confidence Score: 5/5Safe to merge. All changes are either DRY refactors of duplicated CI shell blocks, mechanical Swift 6.3 existential-keyword additions, or a well-scoped deprecation fix — none alter production runtime logic. The CI changes remove six identical inline blocks and centralise them in a script whose selection logic is straightforward and tested in a live run. The Swift changes are purely syntactic No files require special attention. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A([select-ci-xcode.sh]) --> B[find Xcode*.app under /Applications]
B --> C{Any apps found?}
C -- No --> FAIL[exit 1]
C -- Yes --> D[For each Xcode.app in sort order]
D --> E[xcrun --sdk macosx --show-sdk-version\nwith per-app DEVELOPER_DIR]
E --> F{SDK version\nparseable?}
F -- No --> G[warn & skip]
G --> D
F -- Yes --> H[Compute rank =\nmaj×1000 + min]
H --> I{rank >= BEST_RANK?}
I -- No --> D
I -- Yes --> J[Update BEST_DIR / BEST_VER / BEST_RANK]
J --> D
D -- loop done --> K{BEST_DIR set?}
K -- No --> FAIL
K -- Yes --> L[Write DEVELOPER_DIR to GITHUB_ENV]
L --> M[export DEVELOPER_DIR in-process]
M --> N[xcodebuild -version]
N --> O[xcrun --sdk macosx --show-sdk-path\ndiagnostic only — uses in-process DEVELOPER_DIR]
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
A([select-ci-xcode.sh]) --> B[find Xcode*.app under /Applications]
B --> C{Any apps found?}
C -- No --> FAIL[exit 1]
C -- Yes --> D[For each Xcode.app in sort order]
D --> E[xcrun --sdk macosx --show-sdk-version\nwith per-app DEVELOPER_DIR]
E --> F{SDK version\nparseable?}
F -- No --> G[warn & skip]
G --> D
F -- Yes --> H[Compute rank =\nmaj×1000 + min]
H --> I{rank >= BEST_RANK?}
I -- No --> D
I -- Yes --> J[Update BEST_DIR / BEST_VER / BEST_RANK]
J --> D
D -- loop done --> K{BEST_DIR set?}
K -- No --> FAIL
K -- Yes --> L[Write DEVELOPER_DIR to GITHUB_ENV]
L --> M[export DEVELOPER_DIR in-process]
M --> N[xcodebuild -version]
N --> O[xcrun --sdk macosx --show-sdk-path\ndiagnostic only — uses in-process DEVELOPER_DIR]
Reviews (6): Last reviewed commit: "Merge branch 'main' into feat-ci-xcode-2..." | Re-trigger Greptile |
| - 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 | ||
| xcrun --sdk macosx --show-sdk-path |
There was a problem hiding this comment.
xcrun verification uses the unselected default Xcode
./scripts/select-ci-xcode.sh writes DEVELOPER_DIR to $GITHUB_ENV and runs export DEVELOPER_DIR inside its own subshell, but neither propagates to the parent shell running this step. GitHub Actions only makes $GITHUB_ENV entries available to subsequent steps, not the current one. So the xcrun --sdk macosx --show-sdk-path call on line 97 resolves against the system default (/Applications/Xcode.app → Xcode 16.4 / macOS 15 SDK), printing a misleading path in the log even though subsequent steps correctly use the new Xcode via DEVELOPER_DIR from $GITHUB_ENV.
The remaining macOS jobs still ran the old "prefer /Applications/Xcode.app" inline block, which pins them to Xcode 16.4 (macOS 15 SDK / Swift 6.1) because /Applications/Xcode.app is symlinked to 16.4 on the runner images. That is the same divergence the e2e gate already fixed: code that compiles locally (6.3) and ships via nightly/release (6.3) could fail only on these 6.1 gates. Replace the inline block with ./scripts/select-ci-xcode.sh (picks the highest macOS-SDK Xcode, falls back to newest) in the macOS jobs of ci.yml, perf-activation.yml, reload-build.yml, tmux-corpus.yml, and test-depot.yml. Trailing `xcrun --sdk macosx --show-sdk-path` diagnostics are preserved. Left intact: release.yml, nightly.yml, build-ghosttykit.yml (deliberate dual-Xcode split building the Ghostty universal CLI helper on a pre-26 Xcode). ci-macos-compat.yml is workflow_dispatch-only, already selects the newest Xcode (not the buggy symlink-preferring logic), and exports XCODE_VER for its cache key, so it is left as-is. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ed fix) The interim nonisolated deinit (09ecbb9) was rejected by BOTH toolchains: local Swift 6.3 and CI Swift 6.1 both forbid a nonisolated deinit reading the instance's own @mainactor stored properties. The original isolated deinit compiles cleanly on Swift 6.3 (the local refactor toolchain), restoring a green local build baseline for the batch integrators. It needs Swift 6.1's IsolatedDeinit only on the old CI gate, which is being retired by the move to the Swift 6.3 / Xcode 26 CI toolchain (PR #6603); there it is valid with no flag. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The trailing `xcrun --sdk macosx --show-sdk-path` lived in the workflow step *after* `./scripts/select-ci-xcode.sh`. The script runs in a subshell and only propagates DEVELOPER_DIR via GITHUB_ENV, which applies to later steps, not the current shell, so that bare xcrun resolved the stale xcode-select default (e.g. printed MacOSX15.5.sdk even though the build steps correctly used the selected Xcode 26.3 / MacOSX26.2 SDK). Move the diagnostic into the script, right after it exports DEVELOPER_DIR in-process, and drop the misleading trailing copies from ci.yml, test-e2e.yml, and test-depot.yml. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…e toolchain bump The macOS CI gates now build on Xcode 26.3 (Swift 6.3 / macOS 26 SDK). The 6.3 compiler surfaces warnings the 6.1 gate did not. Fix the safe, self-contained ones at the root cause (no -w, no warnings-as-errors disable, no #if): - SocketControlSettings: String(cString:) is deprecated; decode the readlink bytes explicitly with String(decoding:as: UTF8.self) over the valid prefix. - CmuxRemoteSession / CmuxRemoteDaemon / CmuxCommandPalette: write protocol existentials as `any P` (any Error, any DispatchSourceTimer, any NSTextViewDelegate) per [#ExistentialAny]. Purely syntactic; `any` compiles identically on the 16.x fallback toolchain. Deferred to a follow-up (see PR description): main-actor isolation / non-Sendable capture warnings in Sources/AppDelegate.swift (typing-sensitive, needs dogfood), CmuxRemoteSession captured-`self` Sendable-closure warnings (actor-model review), the bonsplit submodule onChange/bounds warnings (submodule PR), the Sparkle SUAppcastItem deprecation (private-API), and test-target concurrency warnings. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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
`@Packages/macOS/CmuxSettings/Sources/CmuxSettings/SocketControl/SocketControlSettings.swift`:
- 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.
🪄 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: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 541ee2c7-31c9-4381-9496-e91ce5cb60af
📒 Files selected for processing (13)
.github/workflows/ci.yml.github/workflows/test-depot.yml.github/workflows/test-e2e.ymlPackages/macOS/CmuxCommandPalette/Tests/CmuxCommandPaletteTests/FocusGuards/CommandPaletteFocusStealingTests.swiftPackages/macOS/CmuxRemoteDaemon/Sources/CmuxRemoteDaemon/Client/RemoteDaemonRPCClient.swiftPackages/macOS/CmuxRemoteSession/Sources/CmuxRemoteSession/Process/RemoteSessionProcessRunner.swiftPackages/macOS/CmuxRemoteSession/Sources/CmuxRemoteSession/Session/RemoteSessionCoordinator+PTYBridge.swiftPackages/macOS/CmuxRemoteSession/Sources/CmuxRemoteSession/Session/RemoteSessionCoordinator+Upload.swiftPackages/macOS/CmuxRemoteSession/Sources/CmuxRemoteSession/Session/RemoteSessionCoordinator.swiftPackages/macOS/CmuxRemoteSession/Sources/CmuxRemoteSession/Values/LockedResult.swiftPackages/macOS/CmuxRemoteSession/Sources/CmuxRemoteSession/Values/PendingPTYBridgeStart.swiftPackages/macOS/CmuxSettings/Sources/CmuxSettings/SocketControl/SocketControlSettings.swiftscripts/select-ci-xcode.sh
💤 Files with no reviewable changes (3)
- .github/workflows/test-depot.yml
- .github/workflows/test-e2e.yml
- .github/workflows/ci.yml
| 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) |
There was a problem hiding this comment.
🧩 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 swiftRepository: 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.swiftRepository: 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 -20Repository: 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 -A2Repository: 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 -15Repository: 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 -15Repository: 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.swiftRepository: 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
…ft 6.3) Incorporate the merged toolchain bump (cmux PR #6603) onto the isolated integration branch so its CI runs on Xcode 26.3 / Swift 6.3 — matching the local integrator build and main. Validates the whole refactor branch (incl. the restored Workspace isolated deinit) on the real CI toolchain, not just locally. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
What
Route all macOS compile/test CI gates at the newest macOS-26-SDK Xcode (Swift 6.3) instead of the runner's default
/Applications/Xcode.app(Xcode 16.4 / Swift 6.1), via a sharedscripts/select-ci-xcode.sh, and fix the warnings the 6.3 toolchain newly surfaces.Why
The Blacksmith/Warp runner images already have Xcode 16.0–16.4 and 26.0–26.3 installed.
/Applications/Xcode.appis symlinked to 16.4, and the old "prefer/Applications/Xcode.app" inline selection pinned the test/compile gates to Swift 6.1, while nightly and release already build on 26.x / Swift 6.3 viaselect-nightly-xcodes.sh. So the gates were older than what we ship: code that compiles locally (6.3) and in release (6.3) could fail only on the 6.1 gates (e.g.isolated deinit, region-based isolation).How
scripts/select-ci-xcode.shranks installed Xcodes by macOS SDK version and picks the highest (falls back to newest available, so it never hard-fails a runner lacking 26.x), exportsDEVELOPER_DIRtoGITHUB_ENV, and printsxcodebuild -version+xcrun --sdk macosx --show-sdk-pathin-process. Each macOS gate's "Select Xcode" step calls it.Workflows changed
test-e2e.yml— e2e gate.ci.yml— all five macOS jobs (app-host-unit-tests,swift-package-tests,tests-build-and-lag,release-build,ui-regressions).perf-activation.yml,reload-build.yml,tmux-corpus.yml,test-depot.yml— one macOS job each.select-ci-xcode.sh. Previously the trailingxcrun --sdk macosx --show-sdk-pathsat in the workflow step after the script and resolved the stale xcode-select default (printedMacOSX15.5.sdk), because the subshell'sDEVELOPER_DIRreaches only later steps viaGITHUB_ENV. Builds were always correct; only that log line lied.Warnings surfaced by the 6.3 toolchain (triage)
Diffing the 26.x run against the prior mixed run isolates 66 unique new compiler warnings (the mass
XCTest inconsistently importedwarnings pre-date the bump). Zero new compile errors. Fixed here (safe, self-contained, root-cause):String(cString:)→String(decoding:as: UTF8.self)inCmuxSettings/SocketControlSettings.swift.#ExistentialAny(any P): 11 sites inCmuxRemoteSession,CmuxRemoteDaemon,CmuxCommandPalette(tests). Purely syntactic;anycompiles identically on the 16.x fallback.Deferred to a focused follow-up (substantive but risky / submodule / non-shipping):
Sources/AppDelegate.swiftmain-actor-isolation + non-Sendable-capture warnings (~20) — typing/focus-sensitive file, needs careful concurrency review + dogfood.CmuxRemoteSessioncaptured-self[#SendableClosureCaptures](3) — actor-model review.vendor/bonsplitsubmodule:onChange(of:perform:)deprecation (3) + nonisolatedbounds(1) — requires a submodule PR.SUAppcastItem(dictionary:)deprecation (1) — vendor private-API.cmuxTests/(~22) — non-shipping.Deliberately left on the old toolchain
release.yml,nightly.yml,build-ghosttykit.yml— deliberate dual-Xcode split building the Ghostty universal CLI helper on a pre-26 Xcode (HELPER_DEVELOPER_DIRviaselect-nightly-xcodes.sh). Untouched. (ci.yml'srelease-ghostty-cli-helperbuilds the helper with zig, no Xcode selection, andrelease-builddownloads the prebuilt GhosttyKit — so convertingrelease-buildto 26.x is correct.)ci-macos-compat.yml—workflow_dispatch-only macOS-version compat matrix; already selects the newest Xcode (not the buggy symlink-preferring logic) and exportsXCODE_VERfor its cache key, so converting it would gain nothing and risk the cache key. Left as-is.test-ios.yml,ios-testflight.yml— iOS gates that still carry the identical buggy inline block onmacos-26runners. Out of scope for this macOS-gate PR (ios-testflight.ymlis a TestFlight submission path). Flagged as a recommended follow-up.Verification
ci.yml run on this branch selected Xcode 26.3 /
MacOSX26.2.sdkand all macOS jobs are green:app-host unit tests (1-4/4),swift-package-tests,tests-build-and-lag,ui-regressions,release-build. The standalone e2eAutomationSocketUITestsrun confirmsSelected Xcode … macOS SDK 26.2; its 4 test failures are a pre-existing GUI-activation limitation on the default runner (Failed to activate application … Running Background), reproduced identically on Xcode 16.4, not a toolchain regression.Need help on this PR? Tag
/codesmithwith what you need. Autofix is disabled.Summary by cubic
Route all macOS compile/test CI gates to the newest Xcode with the macOS 26 SDK (Swift 6.3) via
scripts/select-ci-xcode.sh. This aligns CI with release builds, replaces inline Xcode selection, and prints accurate SDK diagnostics; release/nightly and Ghostty dual-Xcode jobs are unchanged.String(cString:)withString(decoding:as:)inCmuxSettings/SocketControlSettings.anyexistentials inCmuxRemoteSession,CmuxRemoteDaemon, andCmuxCommandPalettetests.Written for commit b321e34. Summary will update on new commits.
Summary by CodeRabbit