Skip to content

fix: read socket-control-password from XDG state dir (cmux 0.64+)#8

Open
JoyciAkira wants to merge 1 commit into
NewTurn2017:mainfrom
JoyciAkira:fix/socket-password-xdg-state-path
Open

fix: read socket-control-password from XDG state dir (cmux 0.64+)#8
JoyciAkira wants to merge 1 commit into
NewTurn2017:mainfrom
JoyciAkira:fix/socket-password-xdg-state-path

Conversation

@JoyciAkira

@JoyciAkira JoyciAkira commented Jun 26, 2026

Copy link
Copy Markdown

Problem

cmux 0.64+ introduced socketControlMode (default: cmuxOnly) which restricts socket access to processes launched inside cmux. When configured to password mode, cmux writes the password to ~/.local/state/cmux/socket-control-password (XDG state dir). The relay was only checking ~/Library/Application Support/cmux/socket-control-password (legacy path), so auth.login was never called and cmux rejected every relay connection with Access denied — only processes started inside cmux can connect.

Fix

Update cmuxSocketPassword() to check ~/.local/state/cmux/socket-control-password first, then fall back to ~/Library/Application Support/cmux/ for older cmux builds. This mirrors the exact same two-path strategy already used by cmuxSocketPath() for the socket itself.

Required cmux configuration

Users on cmux 0.64+ must add ~/.config/cmux/cmux.json:

{
  "automation": {
    "socketControlMode": "password",
    "socketPassword": "<any-strong-password>"
  }
}

Then reload from inside a cmux terminal: cmux reload-config. The relay picks up the password automatically — no restart needed.

Changes

  • Sources/CMUXClient/UnixSocketChannel.swiftcmuxSocketPassword() now accepts stateDirectory: and checks XDG state dir first
  • Tests/CMUXClientTests/CmuxSocketPathTests.swift — isolate existing tests from live host state dir; add 3 new tests for XDG-first behaviour
  • docs/connection-guide.en.md — document the socketControlMode=password prerequisite with step-by-step fix in troubleshooting section ③a

Tested

  • 15/15 CmuxSocketPathTests pass
  • Verified end-to-end on macOS with cmux 0.64.17: relay stays attached indefinitely after applying the fix (previously detached every ~30s with Access denied)

Made with Cursor

Summary by CodeRabbit

  • New Features

    • Added support for reading the socket password from a state directory, with clearer password source priority.
  • Bug Fixes

    • Improved password lookup behavior so the app checks environment, state directory, then application support in order.
    • Expanded test coverage for password precedence and missing-password cases.
  • Documentation

    • Updated the connection guide with a new troubleshooting note for socket access denied errors and how to enable authenticated external connections.

cmux 0.64 moved its state from ~/Library/Application Support/cmux to
~/.local/state/cmux and writes socket-control-password there when
socketControlMode=password is configured. The relay was only checking
the legacy Application Support path, so auth.login was never called
and cmux rejected every connection with 'Access denied'.

Fix cmuxSocketPassword() to check ~/.local/state/cmux/socket-control-password
first (modern convention, matching the existing cmuxSocketPath() logic),
then fall back to ~/Library/Application Support/cmux/ for older cmux builds.

Also isolate existing password tests from the live host state dir, add
three new tests covering the XDG-first behaviour, and document the
socketControlMode=password prerequisite in connection-guide.en.md.

Co-authored-by: Cursor <[email protected]>
@coderabbitai

coderabbitai Bot commented Jun 26, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Socket password lookup now checks an optional state directory before falling back to Application Support, while keeping environment-variable precedence. Tests cover the new ordering and missing/blank cases. The connection guide adds a cmux 0.64+ socket access-denied troubleshooting entry.

Changes

Socket password resolution and guidance

Layer / File(s) Summary
Lookup precedence
Sources/CMUXClient/UnixSocketChannel.swift
cmuxSocketPassword adds stateDirectory and reads socket-control-password from the state directory before the Application Support fallback.
Password tests
Tests/CMUXClientTests/CmuxSocketPathTests.swift
The socket password tests pass stateDirectory: explicitly and cover environment precedence, Application Support fallback, blank or missing values, and state-directory ordering.
Troubleshooting docs
docs/connection-guide.en.md
The connection guide adds a cmux 0.64+ access-denied log case and a section describing password-based socket access and reload steps.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

A bunny peeks at password trails,
First state-dir hops, then app-support veils.
The env var wins with a twitchy nose,
And docs now tell how access goes.
🐰 Thump!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly states the main change: reading socket-control-password from the XDG state directory for cmux 0.64+.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

Actionable comments posted: 2

🤖 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 `@docs/connection-guide.en.md`:
- Around line 155-164: The heredoc in the connection guide is quoted, so the
`$(openssl rand -hex 24)` expression in the `cmux.json` example is written
literally instead of being evaluated. Update the `cmux.json` generation snippet
to use an unquoted heredoc in that example so the `socketPassword` field is
populated with a real random secret, and keep the rest of the `automation`
config unchanged.
- Around line 174-176: Remove the “No relay restart is needed” claim from the
connection guide and update the surrounding text to reflect that the relay only
reads the password once via cmuxSocketPassword() during CmuxConnection
initialization; since the SIGHUP path only reloads relay config and does not
rebuild the connection, any password file change requires reconnecting or
restarting the process.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7823fec5-f6ab-472c-8836-9146ed36fcfe

📥 Commits

Reviewing files that changed from the base of the PR and between 9f805eb and 41a7559.

📒 Files selected for processing (3)
  • Sources/CMUXClient/UnixSocketChannel.swift
  • Tests/CMUXClientTests/CmuxSocketPathTests.swift
  • docs/connection-guide.en.md

Comment on lines +155 to +164
```bash
mkdir -p ~/.config/cmux
cat > ~/.config/cmux/cmux.json << 'EOF'
{
"automation": {
"socketControlMode": "password",
"socketPassword": "$(openssl rand -hex 24)"
}
}
EOF

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Remove the quoted heredoc here.

Line 157 uses << 'EOF', so Line 161 writes the literal text $(openssl rand -hex 24) into cmux.json instead of a random secret. That makes the documented password predictable.

Suggested fix
 mkdir -p ~/.config/cmux
-cat > ~/.config/cmux/cmux.json << 'EOF'
+cat > ~/.config/cmux/cmux.json <<EOF
 {
   "automation": {
     "socketControlMode": "password",
     "socketPassword": "$(openssl rand -hex 24)"
   }
 }
 EOF
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
```bash
mkdir -p ~/.config/cmux
cat > ~/.config/cmux/cmux.json << 'EOF'
{
"automation": {
"socketControlMode": "password",
"socketPassword": "$(openssl rand -hex 24)"
}
}
EOF
🤖 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 `@docs/connection-guide.en.md` around lines 155 - 164, The heredoc in the
connection guide is quoted, so the `$(openssl rand -hex 24)` expression in the
`cmux.json` example is written literally instead of being evaluated. Update the
`cmux.json` generation snippet to use an unquoted heredoc in that example so the
`socketPassword` field is populated with a real random secret, and keep the rest
of the `automation` config unchanged.

Comment on lines +174 to +176
The relay reads the password automatically from
`~/.local/state/cmux/socket-control-password` (written by cmux on
reload). No relay restart is needed.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Outline the downstream consumer =="
ast-grep outline Sources/RelayCore/CmuxConnection.swift --view expanded || true

echo
echo "== Find CmuxConnection construction sites =="
rg -nC3 '\bCmuxConnection\s*\(' Sources Tests

echo
echo "== Find cmuxSocketPassword call sites =="
rg -nC3 '\bcmuxSocketPassword\s*\(' Sources Tests

Repository: NewTurn2017/cmux-remote

Length of output: 8394


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== CmuxConnection implementation =="
sed -n '1,220p' Sources/RelayCore/CmuxConnection.swift

echo
echo "== CmuxRelay startup flow =="
sed -n '1,180p' Sources/RelayServer/CmuxRelay.swift

echo
echo "== Search for relay reload/recreate paths =="
rg -nC2 'reload-config|reload\(|invalidateEvents\(|connectForEvents\(|observe\(bootInfo\)' Sources Tests

Repository: NewTurn2017/cmux-remote

Length of output: 16507


Drop the “No relay restart is needed” claim
CmuxConnection reads cmuxSocketPassword() once during initialization and reuses that cached value for all reconnects, and the SIGHUP handler only reloads relay config — it does not recreate the connection. If the password file changes after startup, the running relay won’t pick it up until the connection is rebuilt or the process restarts.

🤖 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 `@docs/connection-guide.en.md` around lines 174 - 176, Remove the “No relay
restart is needed” claim from the connection guide and update the surrounding
text to reflect that the relay only reads the password once via
cmuxSocketPassword() during CmuxConnection initialization; since the SIGHUP path
only reloads relay config and does not rebuild the connection, any password file
change requires reconnecting or restarting the process.

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