fix(debugger): fix nsjail sandbox for debugger execution
Multiple fixes to make nsjail work correctly: 1. Use absolute paths for python3 and bun binaries (/usr/bin/python3, /usr/bin/bun) since nsjail's execve doesn't use PATH 2. Update cwd to use temp directory when code is written there, so nsjail can find the script files (was using /debugger as cwd before) 3. Bind-mount /tmp from host instead of using tmpfs, so the temp directories with scripts are accessible inside the sandbox 4. Add /debugger directory mount so Python debugger server script is accessible inside nsjail 5. Add PATH environment variable to nsjail config All debugger tests now pass with ENABLE_NSJAIL=true. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -76,8 +76,8 @@ function parseConfig(): ServiceConfig {
|
||||
binaryPath: process.env.DAP_NSJAIL_PATH || 'nsjail',
|
||||
extraArgs: []
|
||||
},
|
||||
pythonPath: process.env.DAP_PYTHON_PATH || 'python3',
|
||||
bunPath: process.env.DAP_BUN_PATH || 'bun',
|
||||
pythonPath: process.env.DAP_PYTHON_PATH || '/usr/bin/python3',
|
||||
bunPath: process.env.DAP_BUN_PATH || '/usr/bin/bun',
|
||||
windmillPath: process.env.DAP_WINDMILL_PATH,
|
||||
debug: process.env.DAP_DEBUG === 'true'
|
||||
}
|
||||
@@ -355,7 +355,7 @@ function spawnProcess(options: SpawnOptions): Subprocess {
|
||||
// Add any extra nsjail arguments
|
||||
nsjailCmd.push(...config.nsjail.extraArgs)
|
||||
|
||||
// Add working directory binding if specified
|
||||
// Add working directory if specified
|
||||
if (options.cwd) {
|
||||
nsjailCmd.push('--cwd', options.cwd)
|
||||
}
|
||||
@@ -892,7 +892,7 @@ class PythonDebugSession extends BaseDebugSession {
|
||||
const args = request.arguments || {}
|
||||
let code = args.code as string | undefined
|
||||
this.scriptPath = args.program as string | undefined
|
||||
const cwd = (args.cwd as string) || process.cwd()
|
||||
let cwd = (args.cwd as string) || process.cwd()
|
||||
this.callMain = (args.callMain as boolean) || false
|
||||
this.mainArgs = (args.args as Record<string, unknown>) || {}
|
||||
this.envVars = (args.env as Record<string, string>) || {}
|
||||
@@ -950,6 +950,9 @@ sys.stdout.flush()
|
||||
this.tempFile = join(this.tempDir, 'script.py')
|
||||
await writeFile(this.tempFile, code)
|
||||
this.scriptPath = this.tempFile
|
||||
// Use temp directory as cwd so debugger can find the script
|
||||
cwd = this.tempDir
|
||||
logger.info(`Wrote Python code to ${this.tempFile}, cwd=${cwd}`)
|
||||
} catch (error) {
|
||||
this.sendResponse(request, false, {}, `Failed to create temp file: ${error}`)
|
||||
return
|
||||
|
||||
@@ -619,7 +619,7 @@ export class DebugSession {
|
||||
private nsjailConfig?: NsjailConfig
|
||||
|
||||
// Custom bun binary path (can be overridden)
|
||||
private bunPath: string = 'bun'
|
||||
private bunPath: string = '/usr/bin/bun'
|
||||
|
||||
// Windmill binary path for prepare-deps CLI (optional, for dependency installation)
|
||||
private windmillPath?: string
|
||||
@@ -630,7 +630,7 @@ export class DebugSession {
|
||||
constructor(ws: WebSocket, options?: { nsjailConfig?: NsjailConfig; bunPath?: string; windmillPath?: string }) {
|
||||
this.ws = ws
|
||||
this.nsjailConfig = options?.nsjailConfig
|
||||
this.bunPath = options?.bunPath || 'bun'
|
||||
this.bunPath = options?.bunPath || '/usr/bin/bun'
|
||||
this.windmillPath = options?.windmillPath
|
||||
}
|
||||
|
||||
@@ -1314,7 +1314,7 @@ export class DebugSession {
|
||||
const args = request.arguments || {}
|
||||
let code = args.code as string | undefined
|
||||
this.scriptPath = args.program as string | undefined
|
||||
const cwd = (args.cwd as string) || process.cwd()
|
||||
let cwd = (args.cwd as string) || process.cwd()
|
||||
this.callMain = (args.callMain as boolean) || false
|
||||
this.mainArgs = (args.args as Record<string, unknown>) || {}
|
||||
this.envVars = (args.env as Record<string, string>) || {}
|
||||
@@ -1393,7 +1393,9 @@ export class DebugSession {
|
||||
this.tempFile = join(this.tempDir, 'script.ts')
|
||||
await writeFile(this.tempFile, code)
|
||||
this.scriptPath = this.tempFile
|
||||
logger.info(`Wrote code to ${this.tempFile}`)
|
||||
// Use temp directory as cwd so bun can find the script and node_modules
|
||||
cwd = this.tempDir
|
||||
logger.info(`Wrote code to ${this.tempFile}, cwd=${cwd}`)
|
||||
// Log lines around breakpoint for debugging
|
||||
const lines = code.split('\n')
|
||||
for (let i = 24; i < Math.min(30, lines.length); i++) {
|
||||
|
||||
@@ -55,12 +55,19 @@ mount {
|
||||
mandatory: false
|
||||
}
|
||||
|
||||
# Temporary filesystem for /tmp (writable)
|
||||
# Bind-mount /tmp from host (job directories are created here)
|
||||
mount {
|
||||
src: "/tmp"
|
||||
dst: "/tmp"
|
||||
fstype: "tmpfs"
|
||||
is_bind: true
|
||||
rw: true
|
||||
options: "size=500000000"
|
||||
}
|
||||
|
||||
# Debugger scripts directory (for Python debugger server)
|
||||
mount {
|
||||
src: "/debugger"
|
||||
dst: "/debugger"
|
||||
is_bind: true
|
||||
}
|
||||
|
||||
# Device nodes
|
||||
@@ -94,3 +101,4 @@ iface_no_lo: true
|
||||
|
||||
envar: "HOME=/root"
|
||||
envar: "TMPDIR=/tmp"
|
||||
envar: "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||
|
||||
Reference in New Issue
Block a user