shared bwrap sandbox, skip for super admin, extend to pi and terminals
- extract buildSandboxPrefix/buildRunuserSuffix into shared sandbox.ts - super admin bypasses bwrap for full host access (claude, pi, terminal) - member pi processes now use bwrap instead of sudo -u - member terminals now use bwrap instead of sudo -u - mount /run for systemd-resolved DNS inside sandbox - pass role through claude spawn params and channel types Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -439,6 +439,7 @@ async function handleClaudeCodeChat(
|
||||
sessionKey: sessionId,
|
||||
cwd,
|
||||
model,
|
||||
role: ws.data.role,
|
||||
onEvent,
|
||||
});
|
||||
|
||||
@@ -560,7 +561,7 @@ async function handleStop(ws: ServerWebSocket<WSData>): Promise<void> {
|
||||
if (session?.piProcess) {
|
||||
try {
|
||||
if (session.model.startsWith('claude-code')) {
|
||||
sidecar.killClaude(sessionId);
|
||||
sidecar.killClaude(sessionId, session.email);
|
||||
logger.info('Killed Claude Code process via sidecar', { sessionId });
|
||||
} else {
|
||||
sidecar.abortPi(sessionId, randomUUID());
|
||||
|
||||
@@ -123,7 +123,6 @@ async function handleCommand(ws, msg) {
|
||||
const cwd = config.cwd ?? process.cwd();
|
||||
const homeDir = config.homeDir ?? process.cwd();
|
||||
const userLabel = config.userLabel ?? 'officer';
|
||||
const username = config.username ?? null;
|
||||
const cols = config.cols ?? 80;
|
||||
const rows = config.rows ?? 24;
|
||||
const isHost = !!config.host;
|
||||
@@ -136,11 +135,8 @@ async function handleCommand(ws, msg) {
|
||||
spawnCommand = shell.command;
|
||||
spawnArgs = shell.args ?? [];
|
||||
ptyEnv = { ...process.env, TERM: 'xterm-256color', ...(config.env ?? {}) };
|
||||
} else if (username) {
|
||||
spawnCommand = 'sudo';
|
||||
spawnArgs = ['-u', username, '-i', '/bin/zsh'];
|
||||
ptyEnv = { TERM: 'xterm-256color' };
|
||||
} else {
|
||||
// Sandboxed mode: shell config contains the full bwrap command
|
||||
spawnCommand = shell.command;
|
||||
spawnArgs = shell.args ?? [];
|
||||
|
||||
@@ -150,20 +146,11 @@ async function handleCommand(ws, msg) {
|
||||
console.error('[pty-sidecar] ensureUserFiles failed:', err);
|
||||
}
|
||||
|
||||
ptyEnv = {
|
||||
...process.env,
|
||||
HOME: homeDir,
|
||||
ZDOTDIR: homeDir,
|
||||
ZSH: `${homeDir}/.oh-my-zsh`,
|
||||
SHELL: shell.command,
|
||||
USER: userLabel,
|
||||
LOGNAME: userLabel,
|
||||
OFFICER_TERMINAL_USER: userLabel,
|
||||
TERM: 'xterm-256color',
|
||||
};
|
||||
// bwrap sets env vars internally via --setenv, so use minimal host env
|
||||
ptyEnv = { TERM: 'xterm-256color' };
|
||||
}
|
||||
|
||||
const ptyCwd = username ? undefined : cwd;
|
||||
const ptyCwd = isHost ? cwd : undefined;
|
||||
|
||||
let term;
|
||||
try {
|
||||
|
||||
@@ -4,6 +4,7 @@ import { dirname, join } from 'node:path';
|
||||
import { getHomeDir } from '@@/data-path';
|
||||
import { sendPtyCommand, sendPtyCommandAsync, on, isTerminalConnected } from '@@/sidecar-registry';
|
||||
import type { PtyInitConfig } from '../../sidecar/protocol';
|
||||
import { buildSandboxPrefix, buildRunuserSuffix, SANDBOX_HOME } from '../../sidecar/sandbox';
|
||||
|
||||
type WSData = {
|
||||
userId: number;
|
||||
@@ -81,10 +82,21 @@ export const terminalWebsocket = {
|
||||
mkdirSync(dirname(homeDir), { recursive: true });
|
||||
mkdirSync(homeDir, { recursive: true });
|
||||
|
||||
// Build bwrap command for sandboxed terminal
|
||||
const prefix = buildSandboxPrefix(email);
|
||||
prefix.push('--setenv', 'ZDOTDIR', SANDBOX_HOME);
|
||||
prefix.push('--setenv', 'ZSH', `${SANDBOX_HOME}/.oh-my-zsh`);
|
||||
prefix.push('--setenv', 'SHELL', '/bin/zsh');
|
||||
prefix.push('--setenv', 'USER', email);
|
||||
prefix.push('--setenv', 'LOGNAME', email);
|
||||
prefix.push('--setenv', 'OFFICER_TERMINAL_USER', email);
|
||||
prefix.push('--setenv', 'TERM', 'xterm-256color');
|
||||
const bwrapArgs = [...prefix, ...buildRunuserSuffix(), '/bin/zsh', '-i'];
|
||||
|
||||
config = {
|
||||
sessionId,
|
||||
username,
|
||||
cwd: resolveCwd(homeDir, ws.data.cwd),
|
||||
shell: { command: bwrapArgs[0]!, args: bwrapArgs.slice(1) },
|
||||
cwd: SANDBOX_HOME,
|
||||
homeDir,
|
||||
userLabel: email,
|
||||
cols: ws.data.cols,
|
||||
|
||||
Reference in New Issue
Block a user