Skip to content

Commit db7dedc

Browse files
committed
all
1 parent 7aab81e commit db7dedc

File tree

4 files changed

+109
-10
lines changed

4 files changed

+109
-10
lines changed

debugger/README.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,11 @@ bun run debug/dap_debug_service.ts
5151
Options:
5252
- `--port PORT` - Server port (default: 5679)
5353
- `--host HOST` - Server host (default: 0.0.0.0)
54-
- `--nsjail` - Enable nsjail sandboxing
54+
- `--python-path PATH` - Python binary path (default: python3)
55+
- `--bun-path PATH` - Bun binary path (default: bun)
56+
- `--nsjail` - Enable nsjail sandboxing for debugger processes
5557
- `--nsjail-config PATH` - Path to nsjail config file
58+
- `--nsjail-path PATH` - Path to nsjail binary (default: nsjail)
5659

5760
### Endpoints
5861

@@ -66,10 +69,11 @@ Options:
6669
|----------|-------------|---------|
6770
| `DAP_PORT` | Server port | 5679 |
6871
| `DAP_HOST` | Server host | 0.0.0.0 |
69-
| `DAP_NSJAIL_ENABLED` | Enable nsjail | false |
70-
| `DAP_NSJAIL_CONFIG` | nsjail config path | - |
7172
| `DAP_PYTHON_PATH` | Python binary path | python3 |
7273
| `DAP_BUN_PATH` | Bun binary path | bun |
74+
| `DAP_NSJAIL_ENABLED` | Enable nsjail sandboxing | false |
75+
| `DAP_NSJAIL_PATH` | nsjail binary path | nsjail |
76+
| `DAP_NSJAIL_CONFIG` | nsjail config file path | - |
7377

7478
### Frontend Integration
7579

debugger/dap_debug_service.ts

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ import { tmpdir } from 'node:os'
3535
import { join } from 'node:path'
3636

3737
// Import the working Bun debug session from the standalone server
38-
import { DebugSession as BunDebugSessionWorking } from './dap_websocket_server_bun'
38+
import { DebugSession as BunDebugSessionWorking, type NsjailConfig } from './dap_websocket_server_bun'
3939

4040
// ============================================================================
4141
// Configuration
@@ -808,14 +808,30 @@ const server = Bun.serve({
808808

809809
let session: BaseDebugSession
810810

811+
// Build nsjail config to pass to debuggers
812+
const nsjailConfig: NsjailConfig | undefined = config.nsjail.enabled
813+
? {
814+
enabled: true,
815+
binaryPath: config.nsjail.binaryPath,
816+
configPath: config.nsjail.configPath,
817+
extraArgs: config.nsjail.extraArgs
818+
}
819+
: undefined
820+
811821
if (path === '/python') {
812822
session = new PythonDebugSession(wsWrapper)
813823
} else if (path === '/typescript' || path === '/bun' || path === '/') {
814824
// Use the working Bun debug session from dap_websocket_server_bun.ts
815-
session = new BunDebugSessionWorking(wsWrapper as unknown as WebSocket) as unknown as BaseDebugSession
825+
session = new BunDebugSessionWorking(wsWrapper as unknown as WebSocket, {
826+
nsjailConfig,
827+
bunPath: config.bunPath
828+
}) as unknown as BaseDebugSession
816829
} else {
817830
logger.warn(`Unknown path: ${path}, defaulting to TypeScript`)
818-
session = new BunDebugSessionWorking(wsWrapper as unknown as WebSocket) as unknown as BaseDebugSession
831+
session = new BunDebugSessionWorking(wsWrapper as unknown as WebSocket, {
832+
nsjailConfig,
833+
bunPath: config.bunPath
834+
}) as unknown as BaseDebugSession
819835
}
820836

821837
sessions.set(ws, session)

debugger/dap_websocket_server_bun.ts

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,14 @@ const logger = {
108108
error: (...args: unknown[]) => console.error('[ERROR]', new Date().toISOString(), ...args)
109109
}
110110

111+
// Nsjail configuration for sandboxed execution
112+
export interface NsjailConfig {
113+
enabled: boolean
114+
binaryPath: string
115+
configPath?: string
116+
extraArgs?: string[]
117+
}
118+
111119
/**
112120
* VLQ (Variable-Length Quantity) decoder for source maps.
113121
* Returns array of decoded integers from VLQ string.
@@ -290,8 +298,16 @@ export class DebugSession {
290298
// Track if current pause is due to a breakpoint (for line number correction)
291299
private pausedAtBreakpoint = false
292300

293-
constructor(ws: WebSocket) {
301+
// Nsjail configuration for sandboxed execution
302+
private nsjailConfig?: NsjailConfig
303+
304+
// Custom bun binary path (can be overridden)
305+
private bunPath: string = 'bun'
306+
307+
constructor(ws: WebSocket, options?: { nsjailConfig?: NsjailConfig; bunPath?: string }) {
294308
this.ws = ws
309+
this.nsjailConfig = options?.nsjailConfig
310+
this.bunPath = options?.bunPath || 'bun'
295311
}
296312

297313
private nextSeq(): number {
@@ -965,8 +981,29 @@ export class DebugSession {
965981
const inspectPort = 9229 + Math.floor(Math.random() * 1000)
966982
const inspectUrl = `127.0.0.1:${inspectPort}`
967983

968-
// Use --inspect-wait to wait for debugger connection before running
969-
logger.info(`Starting Bun with --inspect-wait=${inspectUrl}`)
984+
// Build the command - optionally wrapped with nsjail
985+
let cmd: string[] = [this.bunPath, `--inspect-wait=${inspectUrl}`, this.scriptPath]
986+
987+
if (this.nsjailConfig?.enabled) {
988+
const nsjailCmd = [this.nsjailConfig.binaryPath]
989+
990+
if (this.nsjailConfig.configPath) {
991+
nsjailCmd.push('--config', this.nsjailConfig.configPath)
992+
}
993+
994+
if (this.nsjailConfig.extraArgs) {
995+
nsjailCmd.push(...this.nsjailConfig.extraArgs)
996+
}
997+
998+
nsjailCmd.push('--cwd', cwd)
999+
nsjailCmd.push('--')
1000+
nsjailCmd.push(...cmd)
1001+
1002+
cmd = nsjailCmd
1003+
logger.info(`Starting Bun with nsjail: ${cmd.join(' ')}`)
1004+
} else {
1005+
logger.info(`Starting Bun with --inspect-wait=${inspectUrl}`)
1006+
}
9701007

9711008
// Create a promise to wait for the WebSocket URL
9721009
const wsUrlPromise = new Promise<string>((resolve, reject) => {
@@ -981,7 +1018,7 @@ export class DebugSession {
9811018
})
9821019

9831020
this.process = spawn({
984-
cmd: ['bun', `--inspect-wait=${inspectUrl}`, this.scriptPath],
1021+
cmd,
9851022
cwd,
9861023
stdout: 'pipe',
9871024
stderr: 'pipe',

debugger/test_debug_service.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,16 @@
99
*
1010
* Then run this test:
1111
* bun run test_debug_service.ts
12+
*
13+
* To test with nsjail enabled:
14+
* bun run dap_debug_service.ts --nsjail --nsjail-config /path/to/config.cfg
15+
* bun run test_debug_service.ts --nsjail
1216
*/
1317

18+
import { spawn } from 'bun'
19+
1420
const SERVICE_URL = 'ws://localhost:5679'
21+
const TEST_NSJAIL = process.argv.includes('--nsjail')
1522

1623
const TS_TEST_CODE = `let counter = 0
1724
console.log("TS: Starting")
@@ -448,6 +455,16 @@ async function testHealthEndpoint(): Promise<boolean> {
448455
return false
449456
}
450457

458+
// If testing nsjail mode, verify nsjail is enabled in health response
459+
if (TEST_NSJAIL) {
460+
if (data.nsjail !== true) {
461+
console.log(' ❌ FAIL: nsjail should be enabled but health shows false')
462+
console.log(' → Make sure you started the server with: bun run dap_debug_service.ts --nsjail')
463+
return false
464+
}
465+
console.log(' ✓ nsjail mode confirmed enabled')
466+
}
467+
451468
console.log(' ✓ Health endpoint works!')
452469
return true
453470
} catch (error) {
@@ -456,9 +473,34 @@ async function testHealthEndpoint(): Promise<boolean> {
456473
}
457474
}
458475

476+
async function checkNsjailAvailable(): Promise<boolean> {
477+
try {
478+
const proc = spawn({
479+
cmd: ['nsjail', '--version'],
480+
stdout: 'pipe',
481+
stderr: 'pipe'
482+
})
483+
const exitCode = await proc.exited
484+
return exitCode === 0
485+
} catch {
486+
return false
487+
}
488+
}
489+
459490
async function main() {
460491
console.log('='.repeat(60))
461492
console.log('DAP Debug Service Tests')
493+
if (TEST_NSJAIL) {
494+
console.log('Mode: NSJAIL ENABLED')
495+
const nsjailAvailable = await checkNsjailAvailable()
496+
if (!nsjailAvailable) {
497+
console.log('\n⚠️ WARNING: nsjail not found in PATH')
498+
console.log(' Tests will verify nsjail configuration is passed correctly,')
499+
console.log(' but actual sandboxed execution cannot be tested.')
500+
}
501+
} else {
502+
console.log('Mode: Standard (no nsjail)')
503+
}
462504
console.log('='.repeat(60))
463505

464506
let passed = 0

0 commit comments

Comments
 (0)