Skip to content

fix(sandbox): guard unsupported openclaw config writes#2416

Open
nvshaxie wants to merge 1 commit intoNVIDIA:mainfrom
nvshaxie:fix/2145-openclaw-agents-guard
Open

fix(sandbox): guard unsupported openclaw config writes#2416
nvshaxie wants to merge 1 commit intoNVIDIA:mainfrom
nvshaxie:fix/2145-openclaw-agents-guard

Conversation

@nvshaxie
Copy link
Copy Markdown

@nvshaxie nvshaxie commented Apr 24, 2026

Summary

  • install a stable openclaw wrapper in the sandbox image so openclaw configure and openclaw agents add fail with actionable guidance instead of low-level permission errors
  • stage the wrapper into the optimized sandbox build context so nemoclaw onboard can copy it into rebuilt sandbox images
  • add regression coverage for wrapper installation and build-context staging

Test plan

  • Reproduced the original openclaw agents add ... sandbox failure on Brev before the fix
  • Rebuilt and reinstalled nemoclaw, then recreated the sandbox on Brev
  • Verified /usr/local/bin/openclaw resolves to the wrapper and /usr/local/bin/openclaw-real resolves to the real binary inside the sandbox
  • Verified openclaw agents add my_agent --workspace ~/.openclaw/workspace-my-agent now returns the new UX guard message
  • Verified openclaw configure now returns the new UX guard message
  • Verified openclaw --version still passes through to the real binary
  • Local vitest run in this workspace is currently blocked by the existing Node/vitest ERR_REQUIRE_ESM environment issue

Fixes #2145

Made with Cursor

Summary by CodeRabbit

  • New Features

    • Added OpenClaw sandbox wrapper that intercepts and blocks configuration changes and agent additions within managed environments, providing clear guidance on proper workflows.
    • Added security warning when local mode is invoked, indicating it bypasses gateway protections including secret scanning and network policy enforcement.
  • Tests

    • Added comprehensive test coverage for wrapper behavior and Docker integration.

Use a stable openclaw wrapper in the sandbox image so unsupported config-mutating commands fail with actionable guidance instead of surfacing low-level permission errors.

Made-with: Cursor
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 24, 2026

📝 Walkthrough

Walkthrough

A wrapper script for the openclaw command is introduced to intercept and block certain operations (configure, agents add) within NemoClaw-managed sandboxes, emit security warnings for local mode usage, and forward remaining commands to the real executable. The Dockerfile is updated to install this wrapper as the primary openclaw binary, and the build context staging logic now includes the wrapper script.

Changes

Cohort / File(s) Summary
Dockerfile configuration
Dockerfile
Copies openclaw-wrapper.sh into the image, moves the original openclaw binary to openclaw-real, installs the wrapper as the new openclaw entrypoint with executable permissions, and adds a build-time path verification.
OpenClaw wrapper script
scripts/openclaw-wrapper.sh
New bash wrapper that blocks openclaw configure and openclaw agents add commands with error messages, displays a [SECURITY] warning when --local flag is detected, and forwards all other invocations to the real OpenClaw executable via exec.
Build context staging
src/lib/sandbox-build-context.ts
Updates stageOptimizedSandboxBuildContext to iterate over multiple startup scripts (nemoclaw-start.sh and openclaw-wrapper.sh) instead of copying a single file.
Wrapper functionality tests
test/openclaw-wrapper.test.ts
New test suite verifying the wrapper script contains expected command-blocking patterns and security warnings, and confirming the Dockerfile correctly installs the wrapper and moves the original binary aside.
Build context test updates
test/onboard.test.ts, test/sandbox-build-context.test.ts
Test assertions updated to verify openclaw-wrapper.sh is present in the generated build context.

Sequence Diagram(s)

sequenceDiagram
    actor User as User/Container
    participant Wrapper as openclaw-wrapper.sh
    participant RealCLI as openclaw-real

    User->>Wrapper: openclaw configure [args]
    Wrapper->>Wrapper: Detect 'configure' command
    Wrapper-->>User: Error: Config is read-only<br/>Exit sandbox & run nemoclaw onboard --resume

    User->>Wrapper: openclaw agents add [args]
    Wrapper->>Wrapper: Detect 'agents add' command
    Wrapper-->>User: Error: Adding agents unsupported<br/>in NemoClaw sandbox

    User->>Wrapper: openclaw agent [--local] [args]
    Wrapper->>Wrapper: Detect --local flag
    Wrapper-->>User: [SECURITY] Warning: Local mode<br/>bypasses gateway protections

    User->>Wrapper: openclaw tui [args]
    Wrapper->>Wrapper: No blocking rules match
    Wrapper->>RealCLI: exec openclaw-real tui [args]
    RealCLI-->>User: Execute command normally
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A wrapper so clever, a gatekeeper bold,
Blocks risky commands before chaos takes hold,
Configure? No way! Add agents? No thanks!
Local mode warnings keep secrets in banks,
While trusted commands hop right through! 🎯✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix(sandbox): guard unsupported openclaw config writes' directly and specifically describes the main change: adding a wrapper script to guard against unsupported OpenClaw configuration operations.
Linked Issues check ✅ Passed The PR fully addresses issue #2145 by installing a wrapper script that prevents permission-denied errors from config mutations (openclaw configure, openclaw agents add) with clear UX messages, matching the stated objective.
Out of Scope Changes check ✅ Passed All changes directly support the wrapper guard mechanism: the wrapper script, Dockerfile integration, build-context staging, and corresponding tests. No unrelated changes are present.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
⚔️ Resolve merge conflicts
  • Resolve merge conflict in branch fix/2145-openclaw-agents-guard

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (3)
Dockerfile (1)

258-265: Add a build-time passthrough smoke check after swapping binaries.

After the move/install, a quick openclaw --version check would fail fast if wrapper delegation breaks.

♻️ Suggested patch
 RUN OPENCLAW_BIN="$(command -v openclaw)" \
     && if [ "$OPENCLAW_BIN" != "/usr/local/bin/openclaw" ]; then \
         echo "Error: expected openclaw at /usr/local/bin/openclaw, got $OPENCLAW_BIN"; \
         exit 1; \
     fi \
     && mv "$OPENCLAW_BIN" /usr/local/bin/openclaw-real \
     && install -m 755 /usr/local/lib/nemoclaw/openclaw-wrapper.sh /usr/local/bin/openclaw \
-    && chmod 755 /usr/local/bin/openclaw-real
+    && chmod 755 /usr/local/bin/openclaw-real \
+    && /usr/local/bin/openclaw --version >/dev/null
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Dockerfile` around lines 258 - 265, Add a smoke-check that runs openclaw
--version after moving the real binary and installing the wrapper: after mv
"$OPENCLAW_BIN" /usr/local/bin/openclaw-real and install -m 755
.../openclaw-wrapper.sh /usr/local/bin/openclaw, invoke the wrapper with a quick
execution of openclaw --version (or command -v/openclaw-real if needed) and fail
the build if it returns non-zero; ensure the check references OPENCLAW_BIN,
/usr/local/bin/openclaw-real, and openclaw-wrapper.sh so it runs immediately
after the swap and exits with a non-zero status on failure.
scripts/openclaw-wrapper.sh (1)

45-45: Guard missing delegate binary with a clearer error before exec.

If /usr/local/bin/openclaw-real is absent, users get a raw shell error. An explicit check preserves the “actionable UX” goal even under wiring drift.

♻️ Suggested patch
+if [ ! -x "$REAL_OPENCLAW" ]; then
+  echo "Error: OpenClaw runtime binary not found at $REAL_OPENCLAW." >&2
+  echo "Rebuild the sandbox from the host with: nemoclaw onboard --resume" >&2
+  exit 1
+fi
+
 exec "$REAL_OPENCLAW" "$@"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/openclaw-wrapper.sh` at line 45, Add a guard before the final exec to
check that the delegate binary referenced by REAL_OPENCLAW exists and is
executable; if REAL_OPENCLAW is unset or not executable, print a clear error
message to stderr mentioning the missing path and how to fix it (e.g., install
the real binary or set REAL_OPENCLAW) and exit with a non-zero status instead of
falling through to exec; update the block around the existing exec
"$REAL_OPENCLAW" "$@" invocation to perform this check and early exit.
test/openclaw-wrapper.test.ts (1)

13-21: Cover the openclaw agent --local warning branch too.

The wrapper includes a security-warning path for --local; adding assertions here will keep that behavior regression-proof.

♻️ Suggested patch
   it("blocks config-mutating commands with actionable guidance", () => {
     const src = fs.readFileSync(WRAPPER, "utf-8");

     expect(src).toContain("openclaw configure");
     expect(src).toContain("nemoclaw onboard --resume");
     expect(src).toContain("openclaw agents add");
     expect(src).toContain("not currently supported");
+    expect(src).toContain("[SECURITY] Warning: 'openclaw agent --local' bypasses the NemoClaw gateway.");
+    expect(src).toContain("NOT enforced in local mode.");
     expect(src).toContain('exec "$REAL_OPENCLAW" "$@"');
   });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/openclaw-wrapper.test.ts` around lines 13 - 21, Update the test "blocks
config-mutating commands with actionable guidance" to also assert the wrapper
contains the warning branch for the agent --local path: read WRAPPER as before
and add expect assertions that src contains the `openclaw agent --local` (or
`agent --local`) token and the specific security-warning text emitted for the
--local branch, plus the existing `exec "$REAL_OPENCLAW" "$@"` assertion so the
--local warning branch is covered and cannot regress; look for these strings in
the test file `openclaw-wrapper.test.ts` around the existing expectations.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@Dockerfile`:
- Around line 258-265: Add a smoke-check that runs openclaw --version after
moving the real binary and installing the wrapper: after mv "$OPENCLAW_BIN"
/usr/local/bin/openclaw-real and install -m 755 .../openclaw-wrapper.sh
/usr/local/bin/openclaw, invoke the wrapper with a quick execution of openclaw
--version (or command -v/openclaw-real if needed) and fail the build if it
returns non-zero; ensure the check references OPENCLAW_BIN,
/usr/local/bin/openclaw-real, and openclaw-wrapper.sh so it runs immediately
after the swap and exits with a non-zero status on failure.

In `@scripts/openclaw-wrapper.sh`:
- Line 45: Add a guard before the final exec to check that the delegate binary
referenced by REAL_OPENCLAW exists and is executable; if REAL_OPENCLAW is unset
or not executable, print a clear error message to stderr mentioning the missing
path and how to fix it (e.g., install the real binary or set REAL_OPENCLAW) and
exit with a non-zero status instead of falling through to exec; update the block
around the existing exec "$REAL_OPENCLAW" "$@" invocation to perform this check
and early exit.

In `@test/openclaw-wrapper.test.ts`:
- Around line 13-21: Update the test "blocks config-mutating commands with
actionable guidance" to also assert the wrapper contains the warning branch for
the agent --local path: read WRAPPER as before and add expect assertions that
src contains the `openclaw agent --local` (or `agent --local`) token and the
specific security-warning text emitted for the --local branch, plus the existing
`exec "$REAL_OPENCLAW" "$@"` assertion so the --local warning branch is covered
and cannot regress; look for these strings in the test file
`openclaw-wrapper.test.ts` around the existing expectations.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: c22a511c-badc-4d7d-93af-560f0d6de836

📥 Commits

Reviewing files that changed from the base of the PR and between 99b72c4 and 9e3c97d.

📒 Files selected for processing (6)
  • Dockerfile
  • scripts/openclaw-wrapper.sh
  • src/lib/sandbox-build-context.ts
  • test/onboard.test.ts
  • test/openclaw-wrapper.test.ts
  • test/sandbox-build-context.test.ts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Error during attempt to add the second agent in the sandbox

1 participant