Skip to content

Keep local cwd out of remote workspace auto-resume - #9511

Closed
austinywang wants to merge 2 commits into
mainfrom
issue-7575-testremoteworkspaceautoresumekeepsremote
Closed

austinywang wants to merge 2 commits into
mainfrom
issue-7575-testremoteworkspaceautoresumekeepsremote

Conversation

@austinywang

@austinywang austinywang commented Aug 4, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • ignore an untrusted local workspace directory when recreating a remote terminal
  • prevent the captured local agent cwd from becoming a remote auto-resume prefix while retaining it for launch-argument sanitization
  • extend the existing regression to cover both local cwd fallbacks and preserve the trusted remote-directory control case

Fixes #7575

Testing

  • Hosted exact-test red run at the test-only commit: run 30875357096
  • Hosted exact-test green run at the fix commit: run 30875358658
  • Fleet macOS runner, -only-testing:cmuxTests/AgentSessionAutoResumeSettingsTests/testRemoteWorkspaceAutoResumeKeepsRemoteStartupCommand: test-only commit failed with the local workspace cwd in requestedWorkingDirectory and startup input; fix commit passed 1 test with 0 failures
  • ./scripts/reload-cloud.sh --tag sym7575 on the fix commit: cloud build 30874356769 (BUILD_OK; cloud path used, no local fallback)
  • Tagged-socket dogfood: restored a disposable remote agent snapshot over SSH to the macOS fleet host. The recreated terminal reported requested_working_directory: null, retained /usr/bin/ssh -tt ardrec@aws-m4pro-5 as its startup command, and executed the resume command without either local cwd sentinel. The tagged app was then quit and its isolated socket/session fixtures removed.

View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.


Summary by cubic

Stop using the local working directory when auto-resuming a remote workspace. Only remote-provenance paths are used, and the SSH startup command stays intact. Fixes #7575.

  • Bug Fixes
    • For remote restores, ignore the local cwd; Workspace now prefers only saved remote directories and passes allowCapturedWorkingDirectoryFallback: false.
    • Added allowCapturedWorkingDirectoryFallback to resume/relaunch builders to control cwd prefixing and sanitization.
    • Expanded tests to cover sessions with and without a remote cwd; verify no local paths appear in input and the ssh -tt command is preserved.

Written for commit 1f09cd7. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • Bug Fixes
    • Improved session restoration for remote terminals by avoiding inappropriate local-directory fallbacks.
    • Remote sessions now rely on their saved directory when available, while local sessions retain existing fallback behavior.
    • Added controls to prevent captured working directories from being reused when restoring or resuming sessions.
  • Tests
    • Expanded coverage for remote session auto-resume and restoration scenarios.

@coderabbitai

coderabbitai Bot commented Aug 4, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Resume and restore flows now accept a policy that controls captured working-directory fallback. Remote workspaces use saved remote directories only, while local workspaces retain local-directory fallback behavior. Tests cover remote restores without saved directories.

Changes

Remote restore working-directory handling

Layer / File(s) Summary
Fallback policy propagation
Sources/AgentRelaunchCommandBuilder.swift, Sources/RestorableAgentSession.swift, Sources/SessionRestorableAgentSnapshot+Commands.swift
Resume and relaunch command generation now accepts the captured-working-directory fallback policy. Explicit preferred directories remain eligible.
Local and remote workspace restoration
Sources/Workspace.swift
Remote terminal and agent restores no longer use local or captured directories as fallbacks. Local restores retain currentDirectory fallback.
Remote auto-resume validation
cmuxTests/AgentSessionAutoResumeSettingsTests.swift
Tests cover missing remote directories, remote panel directory setup, and generated SSH startup commands.

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

Sequence Diagram(s)

sequenceDiagram
  participant Workspace
  participant RestorableAgentSession
  participant AgentRelaunchCommandBuilder
  Workspace->>RestorableAgentSession: provide remote resume input
  RestorableAgentSession->>RestorableAgentSession: exclude captured directory fallback
  RestorableAgentSession->>AgentRelaunchCommandBuilder: build SSH resume command
  AgentRelaunchCommandBuilder-->>Workspace: return command without local directory
Loading

Possibly related PRs

  • manaflow-ai/cmux#9205: Modifies resume working-directory propagation in the same command and restore paths.
  • manaflow-ai/cmux#9265: Changes working-directory fallback behavior in RestorableAgentSession.swift and Workspace.swift.
  • manaflow-ai/cmux#8634: Prevents local working-directory fallback during remote terminal restoration.

Suggested reviewers: lawrencecchen, azooz2003-bit

🚥 Pre-merge checks | ✅ 25
✅ Passed checks (25 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the primary change: preventing local working-directory use during remote workspace auto-resume.
Description check ✅ Passed The description covers the change, rationale, linked issue, and testing, but omits the template's demo video and checklist sections.
Linked Issues check ✅ Passed The changes address issue #7575 by blocking local cwd leakage during remote auto-resume while preserving the remote SSH startup command.
Out of Scope Changes check ✅ Passed The code and test changes remain within the issue scope of controlling working-directory fallbacks for remote auto-resume.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Cmux Swift Actor Isolation ✅ Passed The production diff adds only synchronous cwd parameters and selection logic; existing builders and Sendable snapshot remain unchanged, and Workspace access stays within its existing @MainActor type.
Cmux Swift Blocking Runtime ✅ Passed The production diff adds only working-directory fallback parameters and selection logic; it introduces no blocking or timing primitives, and Workspace.swift retains its existing 8 matches unchanged.
Cmux Browser Automation Off-Main ✅ Passed HEAD changes only agent restore and workspace cwd code; no TerminalController or ControlCommandExecutionPolicy browser automation routing changes, so this check is not triggered.
Cmux Expensive Synchronous Load ✅ Passed The PR adds no synchronous history/file/JSON load. The existing Workspace fallback remains unchanged and uses SharedLiveAgentIndex.shared before RestorableAgentSessionIndex.load().
Cmux Cache Substitution Correctness ✅ Passed The diff changes working-directory fallback policy only; it does not replace any fresh persistence, history, undo, or snapshot read with a cache.
Cmux No Hacky Sleeps ✅ Passed The commit changes only four Swift files; this rule excludes Swift, and the diff contains no TypeScript, JavaScript, shell, or build/runtime timing changes.
Cmux Algorithmic Complexity ✅ Passed The diff adds only scalar branching and a bounded 1–3 candidate loop; the existing two-directory sanitizer remains fixed-size, with no scalable nested scan or hot-path sort/filter introduced.
Cmux Swift Concurrency ✅ Passed The PR adds only synchronous working-directory parameters and branching; the full diff adds no DispatchQueue, Task, Combine, or completion-handler patterns.
Cmux Swift @Concurrent ✅ Passed The complete PR diff adds no async, nonisolated, or @concurrent declarations. Changed command builders and Workspace.createPanel remain synchronous; no new UI-isolated heavy async call exists.
Cmux Swift Package Boundaries ✅ Passed The diff only changes internal app-target restore orchestration in four Sources files; no package target changes are needed, and shared pure argv logic already resides in CMUXAgentLaunch.
Cmux Swiftpm Lockfiles ✅ Passed The full PR diff changes only Swift sources and one test; it contains no Package.swift, Package.resolved, .gitignore, workflow, or Xcode project changes covered by this rule.
Cmux Swift Logging ✅ Passed The HEAD diff only changes working-directory selection and parameter propagation; it adds no print, debugPrint, dump, NSLog, Logger, file logging, or sensitive-value diagnostics.
Cmux User-Facing Error Privacy ✅ Passed The production diff changes working-directory selection and command construction only; it adds no user-facing errors, alerts, raw messages, credentials, or other prohibited diagnostic text.
Cmux Full Internationalization ✅ Passed The production diff changes working-directory fallback logic and adds no new user-facing text, locale data, web messages, or catalog entries requiring internationalization.
Cmux Swiftui State Layout ✅ Passed The diff adds no SwiftUI state, layout readers, lazy-row store references, or render-time mutations; it only changes restore-command and working-directory logic.
Cmux Architecture Rethink ✅ Passed The diff is a small, synchronous cwd correctness fix. Workspace owns the remote provenance invariant, and the option flows through shared pure command builders without new state, timing repair, obs...
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PR changes working-directory restore logic and tests only; no standalone NSWindow, NSPanel, WindowGroup, identifier, or close-shortcut routing code was added.
Cmux Source Artifacts ✅ Passed The full topic diff changes only four Swift source files under Sources/ and one Swift test under cmuxTests; it adds no logs, caches, temp folders, build output, binaries, or artifact directories.
Cmux No Test Or Debug Seam In Production Source ✅ Passed The production diff only adds cwd-fallback parameters and selection logic; it adds no #if DEBUG block, test/debug-named member, visibility widening, or test accessor.
Cmux No Ambient Global State ✅ Passed The production diff adds parameters and local logic only; resumeWorkingDirectory and all touched static methods pre-exist, with no new file-scope state, namespace type, or singleton.
✨ 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 issue-7575-testremoteworkspaceautoresumekeepsremote

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.

@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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
Sources/RestorableAgentSession.swift (1)

330-354: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Apply the fallback policy to custom {{cwd}} templates.

When a custom registration uses {{cwd}}, resumeArguments reaches customTemplateArguments, which still resolves it from workingDirectory ?? launchCommand?.workingDirectory. If remote restore passes allowCapturedWorkingDirectoryFallback: false and has no trusted directory, this path still inserts the captured local directory into the command sent to the remote terminal.

Pass the policy through resumeArguments, customResumeArguments, and customTemplateArguments. When the policy is disabled, do not use launchCommand?.workingDirectory. Let a required {{cwd}} template value fail command generation. Add a remote custom-agent regression test for this case.

As per path instructions, “When the trusted remote directory is absent, fail closed rather than reusing a captured local cwd.”

🤖 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 `@Sources/RestorableAgentSession.swift` around lines 330 - 354, The custom
registration resume path must honor allowCapturedWorkingDirectoryFallback when
resolving {{cwd}}. Thread this flag through resumeArguments,
customResumeArguments, and customTemplateArguments; when disabled, exclude
launchCommand?.workingDirectory from fallback resolution so required templates
fail command generation without a trusted directory. Add a regression test
covering remote custom-agent restore with no trusted directory.

Source: Path instructions

🤖 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.

Outside diff comments:
In `@Sources/RestorableAgentSession.swift`:
- Around line 330-354: The custom registration resume path must honor
allowCapturedWorkingDirectoryFallback when resolving {{cwd}}. Thread this flag
through resumeArguments, customResumeArguments, and customTemplateArguments;
when disabled, exclude launchCommand?.workingDirectory from fallback resolution
so required templates fail command generation without a trusted directory. Add a
regression test covering remote custom-agent restore with no trusted directory.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 884343c2-4a9a-4a1d-9891-f6132a82f289

📥 Commits

Reviewing files that changed from the base of the PR and between ed44c7d and 1f09cd7.

📒 Files selected for processing (5)
  • Sources/AgentRelaunchCommandBuilder.swift
  • Sources/RestorableAgentSession.swift
  • Sources/SessionRestorableAgentSnapshot+Commands.swift
  • Sources/Workspace.swift
  • cmuxTests/AgentSessionAutoResumeSettingsTests.swift

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

stale-revisit Closed after 30+ days without activity; preserved for possible revisit or reopening.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

testRemoteWorkspaceAutoResumeKeepsRemoteStartupCommand fails on current main (XCTAssertNil '/Users/runner')

3 participants