Compare commits

...

2 Commits

Author SHA1 Message Date
aaddrick
27b7a639b3 style: simplify sessionDir, cwd derivation, and remove redundant checks
- Extract sessionDir to avoid duplicating /sessions/${name} template
- Simplify guestWorkDir logic with default-then-override pattern
- Remove redundant existsSync before recursive mkdirSync
- Consolidate duplicate log lines

Co-Authored-By: Claude <claude@anthropic.com>
2026-03-20 09:32:20 -04:00
aaddrick
35fe686c6e refactor: improve bwrap cwd derivation, restore mountBinds, clean up arg order
- Derive guest working directory from params.cwd when it contains
  /mnt/, falling back to the primaryMount heuristic only when needed.
  Log a warning when no primary mount is found.
- Restore this.mountBinds iteration so mounts registered via
  mountPath() are not silently dropped in the bwrap sandbox.
- Move --chdir into the main bwrapArgs array just before -- so it
  reads naturally (filesystem setup → chdir → isolation → command).
- Replace catch (_) with catch (no unused binding) to satisfy linters.

Co-Authored-By: Claude <claude@anthropic.com>
2026-03-20 09:30:04 -04:00

View File

@@ -809,7 +809,7 @@ class BwrapBackend extends LocalBackend {
try {
const target = fs.readlinkSync(dir);
bwrapArgs.push('--symlink', target, dir);
} catch (_) {
} catch {
if (fs.existsSync(dir)) {
bwrapArgs.push('--ro-bind', dir, dir);
}
@@ -842,15 +842,27 @@ class BwrapBackend extends LocalBackend {
// host directories at guest paths, matching the KVM backend
// layout. The claude-code-vm binary translates all paths to
// /sessions/ internally, so these must exist inside the sandbox.
const sessionMnt = `/sessions/${name}/mnt`;
bwrapArgs.push('--dir', `/sessions/${name}`);
const sessionDir = `/sessions/${name}`;
const sessionMnt = `${sessionDir}/mnt`;
bwrapArgs.push('--dir', sessionDir);
bwrapArgs.push('--dir', sessionMnt);
// Bind mounts from mountPath() calls (writable)
const boundPaths = new Set();
for (const [mountName, hostPath] of this.mountBinds) {
if (fs.existsSync(hostPath) && !boundPaths.has(hostPath)) {
const guestPath = `${sessionMnt}/${mountName}`;
bwrapArgs.push('--bind', hostPath, guestPath);
boundPaths.add(hostPath);
log(`BwrapBackend spawn: mountBind ${mountName}: ${hostPath} -> ${guestPath}`);
}
}
// Bind mounts from additionalMounts / mountMap
for (const [mountName, hostPath] of Object.entries(mountMap)) {
if (boundPaths.has(hostPath)) continue;
try {
if (!fs.existsSync(hostPath)) {
fs.mkdirSync(hostPath, { recursive: true });
}
fs.mkdirSync(hostPath, { recursive: true });
} catch (e) {
log(`BwrapBackend spawn: could not create ${hostPath}: ${e.message}`);
continue;
@@ -859,11 +871,34 @@ class BwrapBackend extends LocalBackend {
const mode = additionalMounts?.[mountName]?.mode;
const bindType = mode === 'ro' ? '--ro-bind' : '--bind';
bwrapArgs.push(bindType, hostPath, guestPath);
boundPaths.add(hostPath);
log(`BwrapBackend spawn: mount ${mountName}: ${hostPath} -> ${guestPath} (${mode || 'rw'})`);
}
// Namespace isolation + actual command
// Derive guest working directory from the spawn cwd param.
// cwd arrives as /sessions/<name> or /sessions/<name>/mnt/<mount>.
// If it already contains /mnt/, use it directly; otherwise append
// the first user mount to land inside the project directory.
const rawCwd = params.cwd || '';
let guestWorkDir = sessionMnt;
if (rawCwd.includes('/mnt/')) {
guestWorkDir = rawCwd;
} else {
const primaryMount = Object.keys(mountMap).find(
n => !n.startsWith('.') && n !== 'uploads',
);
if (primaryMount) {
guestWorkDir = `${sessionMnt}/${primaryMount}`;
} else {
log('BwrapBackend spawn: warning: no primary mount found, cwd set to session root');
}
}
// Namespace isolation + actual command.
// --chdir is placed here (just before --) so the sandbox
// filesystem is fully set up when it takes effect.
bwrapArgs.push(
'--chdir', guestWorkDir,
'--unshare-pid',
'--die-with-parent',
'--new-session',
@@ -872,21 +907,11 @@ class BwrapBackend extends LocalBackend {
...rawArgs,
);
// Use the primary user mount as cwd (first non-dotfile, non-uploads mount)
const primaryMount = Object.keys(mountMap).find(
n => !n.startsWith('.') && n !== 'uploads',
);
const guestWorkDir = primaryMount
? `${sessionMnt}/${primaryMount}`
: sessionMnt;
log(`BwrapBackend spawn: bwrap args=${JSON.stringify(bwrapArgs)}`);
log(`BwrapBackend spawn: cwd=${guestWorkDir}`);
log(`BwrapBackend spawn: cwd=${guestWorkDir}, bwrap args=${JSON.stringify(bwrapArgs)}`);
// Use host-side cwd for Node's spawn (guest paths don't exist
// on host). bwrap --chdir sets the actual cwd inside the sandbox.
this._spawnLocal(id, 'bwrap',
['--chdir', guestWorkDir, ...bwrapArgs],
this._spawnLocal(id, 'bwrap', bwrapArgs,
os.homedir(), mergedEnv);
return {};
}