Skip to content

Clear SSH auth marker after successful startup - #8410

Merged
austinywang merged 5 commits into
mainfrom
fix-ssh-auth-marker-cleanup
Jul 18, 2026
Merged

austinywang merged 5 commits into
mainfrom
fix-ssh-auth-marker-cleanup

Conversation

@austinywang

@austinywang austinywang commented Jul 18, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • remove the owned foreground-auth .inflight marker after successful native SSH authentication
  • use one shared success-cleanup sequence for both CLI workspace startup and restored SSH PTY attach
  • preserve cleanup order: clear marker, release the shared auth lock, then disable exit/signal traps
  • cover both generated shell-command paths with executable regressions

Context

Follow-up to #8308. That PR was squash-merged before its post-review marker-cleanup repair landed. Canonical review of this follow-up then found the same lifecycle bug in the app-side restored attach generator, so this PR fixes the duplicated behavior at its shared SSHConnectionSharingOptions owner.

Red/green proof

CLI startup

Test-only commit ea95d3e35b failed as expected:

Executed 1 test, with 1 failure
XCTAssertFalse failed - Successful foreground authentication must remove its owned in-flight marker before releasing the lock

Fix commit 52869a58de passes that path.

Restored SSH PTY attach

Test-only commit 546f860fde failed as expected:

totalTestCount: 1
failedTests: 1
Expectation failed: the foreground-auth .inflight marker still existed

Shared fix commit 843336561f makes both selected behavioral tests pass:

totalTestCount: 2
passedTests: 2
failedTests: 0
result: Passed

Focused command:

xcodebuild test -quiet \
  -project cmux.xcodeproj \
  -scheme cmux-unit \
  -configuration Debug \
  -destination 'platform=macOS' \
  -derivedDataPath /tmp/cmux-issue-8300-autoreview-tests \
  -only-testing:cmuxTests/CLINotifyProcessIntegrationRegressionTests/testSSHStartupRemovesForegroundAuthInflightMarkerAfterSuccess \
  -only-testing:cmuxTests/SSHForegroundAuthenticationMarkerCleanupTests

Verification

  • focused generated-command behavior: 2 tests passed
  • CmuxFoundation: 111 tests passed
  • CmuxCore: 52 tests passed
  • CmuxRemoteSession: 103 tests passed
  • scripts/check-pbxproj.sh
  • scripts/check-package-resolved-policy.py
  • scripts/check-workspace-package-groups.py --check
  • scripts/lint-pbxproj-test-wiring.sh (528 test files)
  • git diff --check
  • merge-conflict gate against current origin/main: clean

The Swift file-length budget script and TSV are absent on this branch; the new test is 112 lines and no budget file changed.

No app reload or launch was performed. No user-facing strings or localization catalogs changed.

Summary by CodeRabbit

  • Bug Fixes
    • Improved SSH foreground authentication flow to consistently clear in-progress (“inflight”) marker files after a successful startup.
    • Enhanced SSH startup handling for workspace creation responses that include additional surface identifiers, improving marker lifecycle reliability.
  • Tests
    • Added regression coverage to verify in-flight marker cleanup and startup behavior during restored foreground authentication scenarios.
    • Updated startup command test fixtures to better reflect the expanded workspace creation payload.

@coderabbitai

coderabbitai Bot commented Jul 18, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 527ef56d-7011-4d4e-9f79-3a452a3f770b

📥 Commits

Reviewing files that changed from the base of the PR and between 8433365 and 2ffc96b.

📒 Files selected for processing (1)
  • cmuxTests/SSHForegroundAuthenticationMarkerCleanupTests.swift

📝 Walkthrough

Walkthrough

The SSH foreground authentication startup flow now centralizes successful cleanup commands, reuses one sharing-options instance for related paths and defaults, and exits explicitly after cleanup. Regression tests verify removal of the .inflight marker after successful authentication.

Changes

SSH authentication lifecycle

Layer / File(s) Summary
Centralize successful authentication cleanup
Packages/macOS/CmuxFoundation/Sources/..., Sources/SSHPTYAttachStartupCommandBuilder.swift, CLI/cmux.swift
Adds shared cleanup commands for clearing the inflight marker, unlocking the auth descriptor, removing traps, and explicitly exiting after successful foreground authentication.
Verify successful startup cleanup
cmuxTests/SSHStartupSignalLifecycleTests.swift
Adds a startup regression test, imports CmuxFoundation, and includes surface_id in the mocked workspace.create response.
Exercise restored authentication cleanup
cmuxTests/SSHForegroundAuthenticationMarkerCleanupTests.swift, cmux.xcodeproj/project.pbxproj
Adds and registers a serialized test that runs generated shell commands with fake scripts and verifies inflight marker removal while the lock remains held.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant SSHStartupTest
  participant SSHPTYAttachStartupCommandBuilder
  participant AuthenticationShell
  participant AuthInflightMarker
  SSHStartupTest->>SSHPTYAttachStartupCommandBuilder: generate startup command
  SSHPTYAttachStartupCommandBuilder->>AuthenticationShell: run foreground authentication
  AuthenticationShell->>AuthInflightMarker: remove .inflight marker
  AuthenticationShell-->>SSHStartupTest: return successful startup status
Loading

Possibly related PRs

  • manaflow-ai/cmux#8308: Refactors the same foreground SSH authentication locking and inflight-marker handling paths.
🚥 Pre-merge checks | ✅ 25
✅ Passed checks (25 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: clearing the SSH auth marker after successful startup.
Description check ✅ Passed The description includes summary, context, and testing details, and is mostly complete despite missing demo video and checklist items.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Cmux Swift Actor Isolation ✅ Passed No new actor-isolation annotations or cross-actor accesses were introduced; the changes are synchronous shell-script assembly plus a pure Sendable value-type helper.
Cmux Swift Blocking Runtime ✅ Passed Diff only refactors existing auth-lock cleanup into a shared shell-line helper and adds test scaffolding; no new Swift waits, sleeps, semaphores, or main-queue sync were introduced.
Cmux Browser Automation Off-Main ✅ Passed The only changed file is an SSH startup test helper; no browser.* commands, routing, or main-actor/off-main browser code changed.
Cmux Expensive Synchronous Load ✅ Passed Touched production code only assembles SSH shell lines; no new RestorableAgentSessionIndex.load/Data(contentsOf:)/JSON decode was added to the startup paths.
Cmux Cache Substitution Correctness ✅ Passed No production path replaces an authoritative read with a cached value; the diff only shares SSH auth cleanup logic and reuses the same options instance.
Cmux No Hacky Sleeps ✅ Passed Diff only touches Swift/test scaffolding and project wiring; no new shell/TS/JS/build-runtime sleeps or fixed waits were introduced.
Cmux Algorithmic Complexity ✅ Passed Production edits only factor out a 3-line cleanup list and reuse an existing options object; no new scalable collection rescans/sorts were introduced.
Cmux Swift Concurrency ✅ Passed Diff only refactors shell cleanup helpers and adds XCTest regressions; no new DispatchQueue, Combine, completion-handler, or fire-and-forget Task patterns appear.
Cmux Swift @Concurrent ✅ Passed No changed Swift code adds/uses @concurrent, nonisolated async, or UI-isolated heavy async helpers; the new tests and helpers are synchronous.
Cmux Swift Package Boundaries ✅ Passed Shared SSH auth cleanup logic was extracted into CmuxFoundation; the app-side builder now just composes shell glue around it.
Cmux Swiftpm Lockfiles ✅ Passed PR only wires a new test file into the Xcode project; no Package.resolved, .gitignore, workflow, or SwiftPM dependency changes are present.
Cmux Swift Logging ✅ Passed Production diff adds no print/debugPrint/dump/NSLog/Logger changes; touched code only reuses shell cleanup lines, and test stdout is allowed.
Cmux User-Facing Error Privacy ✅ Passed The diff adds internal shell-command cleanup and tests only; no user-facing error/alert/copy changes or exposed secrets/provider details were introduced.
Cmux Full Internationalization ✅ Passed PASS — the patch only adds internal shell-command cleanup and tests; no user-facing Swift text, catalogs, Info.plist, or locale routing/messages were changed.
Cmux Swiftui State Layout ✅ Passed No SwiftUI state/layout code changed: the PR only touches CLI/foundation logic and tests, with no SwiftUI imports or state/layout patterns.
Cmux Architecture Rethink ✅ Passed Shared cleanup is centralized in SSHConnectionSharingOptions with a clear marker-before-unlock invariant; no new timing workaround or duplicate wiring was introduced.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed No touched Swift code adds or changes standalone cmux-owned windows; diff only adjusts SSH auth cleanup and tests, so the auxiliary-window shortcut rule isn’t implicated.
Cmux Source Artifacts ✅ Passed All changed paths are intentional source/test/project files; no artifact, cache, DerivedData, or scratch directories were added.
Cmux No Test Or Debug Seam In Production Source ✅ Passed PASS: The new helper is used by production callers, and the touched production Sources file adds no debug/test-only seam or DEBUG-gated test accessor.
Cmux No Ambient Global State ✅ Passed The PR adds an instance method on SSHConnectionSharingOptions and test methods/helpers inside test types; no new file-scope globals, namespaces, or singletons appear.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-ssh-auth-marker-cleanup

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.

@greptile-apps

greptile-apps Bot commented Jul 18, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a marker lifecycle bug: the .inflight file created during foreground SSH authentication was never removed on the success path, only on abort/signal paths via the EXIT trap. The fix adds a shared successfulForegroundAuthenticationCleanupShellLines() method to SSHConnectionSharingOptions that emits the ordered cleanup — clear marker, release advisory lock, disarm traps — and wires both the CLI workspace startup path (CLI/cmux.swift) and the app-side restored-attach path (SSHPTYAttachStartupCommandBuilder.swift) to call it.

  • SSHConnectionSharingOptions.successfulForegroundAuthenticationCleanupShellLines() is added as the single canonical source of the three-step cleanup; this eliminates the prior drift between the two call sites (the builder was missing cmux_ssh_clear_auth_inflight entirely).
  • The SSHPTYAttachStartupCommandBuilder.sshForegroundAuthCommand is updated to reuse one sharingOptions instance and append the shared cleanup, matching the CLI pattern.
  • Two new regression tests — one XCTest, one Swift Testing — verify the inflight marker is absent after a successful run on each path.

Confidence Score: 5/5

Safe to merge — the change is a targeted bug fix with no new state, no architectural risk, and two dedicated regression tests covering both affected paths.

The fix is surgical: one new pure-factory method on an existing value type, two call sites updated to use it, and the shared three-step cleanup sequence (clear marker → release lock → disarm traps) is correctly ordered in both the CLI and the app-side builder. The cmux_ssh_clear_auth_inflight function is already defined in the script body before the new call site in both paths. The regression tests directly verify the inflight marker is absent after success and match the red/green proof described in the PR.

No files require special attention.

Important Files Changed

Filename Overview
Packages/macOS/CmuxFoundation/Sources/CmuxFoundation/SSHConnectionSharingOptions.swift Adds successfulForegroundAuthenticationCleanupShellLines() — a pure factory returning the three-step marker-clear/lock-release/trap-disarm sequence. Correct ordering, no instance state dependency, well documented.
Sources/SSHPTYAttachStartupCommandBuilder.swift Replaces inline lock-release-only cleanup with the shared three-step sequence; reuses one SSHConnectionSharingOptions instance across the auth command; changes the array from let to var to allow appending. Functionally equivalent to the CLI path now.
CLI/cmux.swift Extracts one SSHConnectionSharingOptions instance to avoid re-creating it, replaces the inline two-line cleanup with the shared three-line cleanup. The cmux_ssh_clear_auth_inflight function definition already exists in the script body before the new call site.
cmuxTests/SSHForegroundAuthenticationMarkerCleanupTests.swift New Swift Testing suite covering the restored-attach generator path; sets up fake ssh/cmux binaries, runs the generated command, and asserts the inflight marker is absent after the auth subshell exits.
cmuxTests/SSHStartupSignalLifecycleTests.swift Adds testSSHStartupRemovesForegroundAuthInflightMarkerAfterSuccess to the existing XCTest-based integration regression suite; also wires surface_id into the workspace_create mock response so the startup command can populate CMUX_SURFACE_ID.
cmux.xcodeproj/project.pbxproj Adds build-file and file-reference entries for SSHForegroundAuthenticationMarkerCleanupTests.swift to both the file group and the test target build phase. Mechanical wiring, correct.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant Shell as /bin/zsh -fc
    participant Inflight as .inflight marker
    participant Lock as advisory lock fd
    participant Traps as EXIT/HUP/INT/TERM traps

    Shell->>Inflight: write $$ (PID)
    Shell->>Traps: trap cmux_ssh_clear_auth_inflight EXIT/HUP/INT/TERM
    Shell->>Lock: zsystem flock -t 45 ... (acquire)
    Shell->>Shell: ssh ... true (authenticate)

    alt SSH succeeds
        Shell->>Inflight: cmux_ssh_clear_auth_inflight (remove marker)
        Shell->>Lock: zsystem flock -u (release)
        Shell->>Traps: trap - EXIT HUP INT TERM (disarm)
        Shell->>Shell: exit 0
    else SSH fails / signal
        Traps-->>Inflight: cmux_ssh_clear_auth_inflight (EXIT trap fires)
        Shell->>Shell: exit non-zero
    end
Loading
%%{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"}}}%%
sequenceDiagram
    participant Shell as /bin/zsh -fc
    participant Inflight as .inflight marker
    participant Lock as advisory lock fd
    participant Traps as EXIT/HUP/INT/TERM traps

    Shell->>Inflight: write $$ (PID)
    Shell->>Traps: trap cmux_ssh_clear_auth_inflight EXIT/HUP/INT/TERM
    Shell->>Lock: zsystem flock -t 45 ... (acquire)
    Shell->>Shell: ssh ... true (authenticate)

    alt SSH succeeds
        Shell->>Inflight: cmux_ssh_clear_auth_inflight (remove marker)
        Shell->>Lock: zsystem flock -u (release)
        Shell->>Traps: trap - EXIT HUP INT TERM (disarm)
        Shell->>Shell: exit 0
    else SSH fails / signal
        Traps-->>Inflight: cmux_ssh_clear_auth_inflight (EXIT trap fires)
        Shell->>Shell: exit non-zero
    end
Loading

Reviews (3): Last reviewed commit: "test: drain SSH auth test stderr safely" | Re-trigger Greptile

@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

🤖 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 `@cmuxTests/SSHForegroundAuthenticationMarkerCleanupTests.swift`:
- Around line 104-110: Update the process execution flow around process.run() so
stderrPipe.fileHandleForReading.readDataToEndOfFile() is performed before
process.waitUntilExit(). Preserve returning the termination status together with
the captured stderr after the pipe has been fully read.
🪄 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: 4926b29d-423e-4410-a210-0888ef05de88

📥 Commits

Reviewing files that changed from the base of the PR and between 52869a5 and 8433365.

📒 Files selected for processing (5)
  • CLI/cmux.swift
  • Packages/macOS/CmuxFoundation/Sources/CmuxFoundation/SSHConnectionSharingOptions.swift
  • Sources/SSHPTYAttachStartupCommandBuilder.swift
  • cmux.xcodeproj/project.pbxproj
  • cmuxTests/SSHForegroundAuthenticationMarkerCleanupTests.swift

Comment thread cmuxTests/SSHForegroundAuthenticationMarkerCleanupTests.swift
@austinywang
austinywang merged commit 2c07967 into main Jul 18, 2026
10 checks passed
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.

1 participant