Compare commits

...

3 Commits

Author SHA1 Message Date
aaddrick
3c43aef219 docs(troubleshooting): tighten LUKS workaround framing (#590)
Per contrarian review on #614:

- Reframe the LUKS-passphrase-equals-login-password line as an
  informed tradeoff (single compromise unlocks both, equivalent to
  eCryptfs's existing threat surface) rather than a setup tip.
- Spell out the confidentiality posture vs eCryptfs explicitly so a
  privacy-conscious user evaluating the move doesn't downgrade
  silently. Note that pam_mount failure makes writes fail loudly
  (ENOENT through the symlink) rather than landing on plaintext.
- Add a CLAUDE_CONFIG_DIR escape hatch — users who've reconfigured
  Claude Code's home dir can't blindly follow the ~/.claude symlink
  step; the constraint is the underlying NAME_MAX, not the path.
- Add mountpoint and readlink verification commands alongside the
  existing getconf NAME_MAX check so the workaround surfaces its
  own success criteria.

Co-Authored-By: Claude <claude@anthropic.com>
2026-05-16 10:32:56 -04:00
aaddrick
43f1d71109 test(doctor): cover df failure path for filename-limit check (#590)
Extend _install_df_shim with an empty-arg → exit-1 mode (matching the
_install_getconf_shim convention), then add a sixth case asserting
that when df --output=fstype fails, the NAME_MAX warn still fires but
the eCryptfs/LUKS-specific hint is silently skipped.

Per @sabiut's non-blocking ask on #614.

Co-Authored-By: Claude <claude@anthropic.com>
2026-05-16 10:14:13 -04:00
aaddrick
f3553ad6d3 docs(troubleshooting): symlink ~/.claude/ onto LUKS volume for cowork (#590)
The eCryptfs workaround as written relocated ~/.config/Claude and
~/.cache/claude-desktop-debian but left ~/.claude/ on the encrypted
home, which is where Claude Code creates the long-named per-session
project dirs that overflow NAME_MAX=143. Add a third mv+ln pair for
~/.claude/ (with a fresh-install mkdir fallback), and call out in the
prose that ~/.claude/ is the load-bearing path for cowork.

Per @sabiut's review on #614.

Co-Authored-By: Claude <claude@anthropic.com>
2026-05-16 10:14:10 -04:00
2 changed files with 58 additions and 8 deletions

View File

@@ -256,6 +256,10 @@ getconf NAME_MAX $HOME # eCryptfs reports 143; ext4 reports 255
**Workaround:** move Claude's data onto a separate LUKS-encrypted
ext4 volume (NAME_MAX = 255) and symlink the original paths back.
`~/.claude/` is the critical one — that's where Claude Code creates
the long-named per-session dirs that overflow the limit — and
`~/.config/Claude/` plus `~/.cache/claude-desktop-debian/` are
relocated alongside it so all Claude state lives on the same volume.
This keeps the data encrypted at rest while sidestepping the
eCryptfs filename-length cap.
@@ -274,18 +278,34 @@ sudo chown "$USER:$USER" /mnt/claude-secure
mv ~/.config/Claude /mnt/claude-secure/Claude-config
mv ~/.cache/claude-desktop-debian /mnt/claude-secure/claude-cache
# ~/.claude may not exist yet on a fresh install — create the target
# either way so the symlink below resolves.
if [ -e ~/.claude ]; then
mv ~/.claude /mnt/claude-secure/claude-home
else
mkdir -p /mnt/claude-secure/claude-home
fi
ln -s /mnt/claude-secure/Claude-config ~/.config/Claude
ln -s /mnt/claude-secure/claude-cache ~/.cache/claude-desktop-debian
ln -s /mnt/claude-secure/claude-home ~/.claude
# 3. Verify the filename limit
# 3. Verify the filename limit and the symlinks
getconf NAME_MAX /mnt/claude-secure # should print 255
mountpoint /mnt/claude-secure # confirms the volume is mounted
readlink ~/.claude # /mnt/claude-secure/claude-home
readlink ~/.config/Claude # /mnt/claude-secure/Claude-config
```
**If you've set `CLAUDE_CONFIG_DIR`** (or otherwise reconfigured
Claude Code to use a directory other than `~/.claude/`), the
`~/.claude` symlink above doesn't apply — adapt the path to wherever
your Claude Code config actually lives. The constraint is the same:
the directory tree where Claude Code creates per-session project
dirs must sit on a filesystem with `NAME_MAX` ≥ ~200.
**Auto-mount at login** with `pam_mount` so the volume unlocks
transparently each session without a manual `cryptsetup open`. If
your login password matches the LUKS passphrase, the unlock is
silent:
without a manual `cryptsetup open`:
```bash
sudo apt install libpam-mount
@@ -306,8 +326,19 @@ Add a `<volume>` entry to `/etc/security/pam_mount.conf.xml`
**Notes:**
- Tested on Linux Mint with LightDM as the display manager.
- The LUKS passphrase must match your login password for the
transparent unlock to work.
- **LUKS passphrase tradeoff:** for `pam_mount` to unlock silently
at login the LUKS passphrase must match your login password. That
means one compromise unlocks both your session and the encrypted
volume — equivalent to the threat surface eCryptfs already had,
but worth a deliberate choice. Use a distinct LUKS passphrase if
you'd rather be prompted on each unlock.
- **Confidentiality posture vs eCryptfs.** The LUKS image lives at
`/opt/claude-secure.img`, outside `$HOME` and outside whatever
encryption envelope eCryptfs gives you. If `pam_mount` ever fails
silently — wrong passphrase, mount race at login, profile error —
Claude won't start (the symlink targets won't exist), so writes
fail loudly rather than landing on plaintext disk. Verify with
`mountpoint /mnt/claude-secure` after login if you're unsure.
- 2 GB is a conservative starting size; the Claude config
directory can exceed 500 MB once cowork session history
accumulates. Resize if needed.

View File

@@ -346,17 +346,25 @@ SHIM
}
# Install a df shim that emits a single-column fstype listing matching
# the `df --output=fstype` shape the helper relies on.
# the `df --output=fstype` shape the helper relies on. Empty $1 → shim
# exits 1 so callers can test the "df failed" path.
_install_df_shim() {
mkdir -p "$TEST_TMP/bin"
local fstype="$1"
cat > "$TEST_TMP/bin/df" <<SHIM
if [[ -z $fstype ]]; then
cat > "$TEST_TMP/bin/df" <<'SHIM'
#!/usr/bin/env bash
exit 1
SHIM
else
cat > "$TEST_TMP/bin/df" <<SHIM
#!/usr/bin/env bash
cat <<'OUT'
Type
${fstype}
OUT
SHIM
fi
chmod +x "$TEST_TMP/bin/df"
export PATH="$TEST_TMP/bin:$PATH"
}
@@ -405,3 +413,14 @@ SHIM
[[ $status -eq 0 ]]
[[ -z $output ]]
}
@test "_doctor_check_filename_limit: df failure suppresses eCryptfs hint, keeps warn" {
_install_getconf_shim '143'
_install_df_shim ''
run _doctor_check_filename_limit
[[ $status -eq 0 ]]
[[ $output == *'[WARN]'* ]]
[[ $output == *'NAME_MAX=143'* ]]
[[ $output != *'eCryptfs'* ]]
[[ $output != *'LUKS'* ]]
}