From b35a3856a28a08bda81443a6702e1ee1d4f40103 Mon Sep 17 00:00:00 2001 From: Olcan Date: Fri, 9 May 2025 08:44:40 -0700 Subject: [PATCH] fix debugging with seatbelt, including in strict profile (#300) --- .../cli/src/utils/sandbox-macos-strict.sb | 3 ++ packages/cli/src/utils/sandbox.ts | 19 ++++++++- scripts/sandbox_command.sh | 40 ++++++++++--------- scripts/start.sh | 1 + 4 files changed, 42 insertions(+), 21 deletions(-) diff --git a/packages/cli/src/utils/sandbox-macos-strict.sb b/packages/cli/src/utils/sandbox-macos-strict.sb index 29f46a84..1a7c63d0 100644 --- a/packages/cli/src/utils/sandbox-macos-strict.sb +++ b/packages/cli/src/utils/sandbox-macos-strict.sb @@ -76,6 +76,9 @@ ;; allow outbound network connections (allow network-outbound) +;; allow inbound network connections to debugging port +(allow network-inbound (local ip (string-append "*:" "9229"))) + ;; allow communication with sysmond for process listing (e.g. for pgrep) (allow mach-lookup (global-name "com.apple.sysmond")) diff --git a/packages/cli/src/utils/sandbox.ts b/packages/cli/src/utils/sandbox.ts index b26e8b39..73f50e83 100644 --- a/packages/cli/src/utils/sandbox.ts +++ b/packages/cli/src/utils/sandbox.ts @@ -46,6 +46,7 @@ export function sandbox_command(sandbox?: string | boolean): string { } } else { // if we are on macOS (Darwin) and sandbox-exec is available, use that for minimal sandboxing + // unless SEATBELT_PROFILE is set to 'none', which we allow as an escape hatch if ( os.platform() === 'darwin' && execSync('command -v sandbox-exec || true').toString().trim() && @@ -145,8 +146,18 @@ function entrypoint(workdir: string): string[] { export async function start_sandbox(sandbox: string) { if (sandbox === 'sandbox-exec') { + // disallow BUILD_SANDBOX + if (process.env.BUILD_SANDBOX) { + console.error('ERROR: cannot BUILD_SANDBOX when using MacOC Seatbelt'); + process.exit(1); + } const profile = (process.env.SEATBELT_PROFILE ??= 'minimal'); console.log(`using macos seatbelt (profile: ${profile}) ...`); + // if DEBUG is set, convert to --inspect-brk in NODE_OPTIONS + if (process.env.DEBUG) { + process.env.NODE_OPTIONS ??= ''; + process.env.NODE_OPTIONS += ` --inspect-brk`; + } const args = [ '-D', `TARGET_DIR=${fs.realpathSync(process.cwd())}`, @@ -158,8 +169,11 @@ export async function start_sandbox(sandbox: string) { new URL(`sandbox-macos-${profile}.sb`, import.meta.url).pathname, 'bash', '-c', - `SANDBOX=sandbox-exec NODE_OPTIONS="${process.env.NODE_OPTIONS}" ` + - process.argv.map((arg) => quote([arg])).join(' '), + [ + `SANDBOX=sandbox-exec`, + `NODE_OPTIONS="${process.env.NODE_OPTIONS}"`, + ...process.argv.map((arg) => quote([arg])), + ].join(' '), ]; spawnSync(sandbox, args, { stdio: 'inherit' }); return; @@ -268,6 +282,7 @@ export async function start_sandbox(sandbox: string) { // expose env-specified ports on the sandbox ports().forEach((p) => args.push('--publish', `${p}:${p}`)); + // if DEBUG is set, expose debugging port if (process.env.DEBUG) { const debugPort = process.env.DEBUG_PORT || '9229'; args.push(`--publish`, `${debugPort}:${debugPort}`); diff --git a/scripts/sandbox_command.sh b/scripts/sandbox_command.sh index f527292c..1eed9ad3 100755 --- a/scripts/sandbox_command.sh +++ b/scripts/sandbox_command.sh @@ -54,35 +54,37 @@ if [ -z "${GEMINI_CODE_SANDBOX:-}" ]; then done fi -# if GEMINI_CODE_SANDBOX is still not set, then exit immediately w/ code 1 -if [ -z "${GEMINI_CODE_SANDBOX:-}" ]; then exit 1; fi - # lowercase GEMINI_CODE_SANDBOX GEMINI_CODE_SANDBOX=$(echo "${GEMINI_CODE_SANDBOX:-}" | tr '[:upper:]' '[:lower:]') -# if GEMINI_CODE_SANDBOX is set to 0 or false, then exit immediately w/ code 1 -if [[ "${GEMINI_CODE_SANDBOX:-}" =~ ^(0|false)$ ]]; then - exit 1 -fi - -# if GEMINI_CODE_SANDBOX is set to 1 or true, then try to use docker or podman +# if GEMINI_CODE_SANDBOX is set to 1|true, then try to use docker or podman +# if non-empty and not 0|false, treat as custom command and check that it exists +# if empty or 0|false, then fail silently (after checking for possible fallbacks) +command="" if [[ "${GEMINI_CODE_SANDBOX:-}" =~ ^(1|true)$ ]]; then if command -v docker &>/dev/null; then - if [ "$QUIET" = false ]; then echo "docker"; fi - exit 0 + command="docker" elif command -v podman &>/dev/null; then - if [ "$QUIET" = false ]; then echo "podman"; fi - exit 0 + command="podman" else echo "ERROR: install docker or podman or specify command in GEMINI_CODE_SANDBOX" >&2 exit 1 fi +elif [ -n "${GEMINI_CODE_SANDBOX:-}" ] && [[ ! "${GEMINI_CODE_SANDBOX:-}" =~ ^(0|false)$ ]]; then + if ! command -v "$GEMINI_CODE_SANDBOX" &>/dev/null; then + echo "ERROR: missing sandbox command '$GEMINI_CODE_SANDBOX' (from GEMINI_CODE_SANDBOX)" >&2 + exit 1 + fi + command="$GEMINI_CODE_SANDBOX" +else + # if we are on macOS and sandbox-exec is available, use that for minimal sandboxing + # unless SEATBELT_PROFILE is set to 'none', which we allow as an escape hatch + if [ "$(uname)" = "Darwin" ] && command -v sandbox-exec &>/dev/null && [ "${SEATBELT_PROFILE:-}" != "none" ]; then + command="sandbox-exec" + else # GEMINI_CODE_SANDBOX is empty or 0|false, so we fail w/o error msg + exit 1 + fi fi -if ! command -v "$GEMINI_CODE_SANDBOX" &>/dev/null; then - echo "ERROR: missing sandbox command '$GEMINI_CODE_SANDBOX' (from GEMINI_CODE_SANDBOX)" >&2 - exit 1 -fi - -if [ "$QUIET" = false ]; then echo "$GEMINI_CODE_SANDBOX"; fi +if [ "$QUIET" = false ]; then echo "$command"; fi exit 0 diff --git a/scripts/start.sh b/scripts/start.sh index 797670fa..2caf540d 100755 --- a/scripts/start.sh +++ b/scripts/start.sh @@ -20,6 +20,7 @@ node ./scripts/check-build-status.js # if debugging is enabled and sandboxing is disabled, use --inspect-brk flag # note with sandboxing this flag is passed to the binary inside the sandbox +# inside sandbox SANDBOX should be set and sandbox_command.sh should fail node_args=() if [ -n "${DEBUG:-}" ] && ! scripts/sandbox_command.sh -q; then if [ -n "${SANDBOX:-}" ]; then