Skip to content

refactor(runtime): extract entrypoint preload modules#3109

Merged
cv merged 110 commits into
mainfrom
refactor/runtime-preload-modules
May 6, 2026
Merged

refactor(runtime): extract entrypoint preload modules#3109
cv merged 110 commits into
mainfrom
refactor/runtime-preload-modules

Conversation

@cv

@cv cv commented May 6, 2026

Copy link
Copy Markdown
Collaborator

Summary

Extracts the Node.js runtime preload bodies from scripts/nemoclaw-start.sh into standalone preload modules under nemoclaw-blueprint/scripts/. The entrypoint now copies those modules from a Landlock-readable install path into /tmp before registering them via NODE_OPTIONS.

Changes

  • Add standalone preload modules for sandbox safety net, Slack channel guard, Telegram diagnostics, Nemotron inference fix, ciao network guard, and seccomp guard.
  • Update nemoclaw-start.sh to install preloads from files instead of inline heredocs.
  • Copy all blueprint preload scripts into /usr/local/lib/nemoclaw/preloads/ in the sandbox image.
  • Update preload/entrypoint tests to use module files as the source of truth.

Type of Change

  • Code change (feature, bug fix, or refactor)
  • Code change with doc updates
  • Doc only (prose changes, no code sample modifications)
  • Doc only (includes code sample changes)

Verification

  • npx prek run --all-files passes
  • npm test passes
  • Tests added or updated for new or changed behavior
  • No secrets, API keys, or credentials committed
  • Docs updated for user-facing behavior changes
  • make docs builds without warnings (doc changes only)
  • Doc pages follow the style guide (doc changes only)
  • New doc pages include SPDX header and frontmatter (new pages only)

Signed-off-by: Carlos Villela cvillela@nvidia.com

Summary by CodeRabbit

  • New Features

    • Added Telegram integration diagnostics with sensitive data redaction
    • Enhanced error handling for Slack, network, and sandbox environments
  • Bug Fixes

    • Improved resilience for specific AI model inference requests
    • Fixed network interface handling in restricted environments
    • Prevented gateway crashes from Slack and CIAO-related errors
  • Chores

    • Refactored preload architecture from inline to external modular scripts
    • Updated runtime configuration and test infrastructure

cv added 30 commits May 2, 2026 13:36
@cv cv self-assigned this May 6, 2026
@copy-pr-bot

copy-pr-bot Bot commented May 6, 2026

Copy link
Copy Markdown

Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually.

Contributors can view more details about this message here.

@coderabbitai

coderabbitai Bot commented May 6, 2026

Copy link
Copy Markdown
Contributor

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 346371d2-a417-4170-a1f6-02fff6b5d7e9

📥 Commits

Reviewing files that changed from the base of the PR and between fc95743 and 292218f.

📒 Files selected for processing (16)
  • Dockerfile
  • nemoclaw-blueprint/scripts/ciao-network-guard.js
  • nemoclaw-blueprint/scripts/http-proxy-fix.js
  • nemoclaw-blueprint/scripts/nemotron-inference-fix.js
  • nemoclaw-blueprint/scripts/sandbox-safety-net.js
  • nemoclaw-blueprint/scripts/seccomp-guard.js
  • nemoclaw-blueprint/scripts/slack-channel-guard.js
  • nemoclaw-blueprint/scripts/slack-token-rewriter.js
  • nemoclaw-blueprint/scripts/telegram-diagnostics.js
  • scripts/nemoclaw-start.sh
  • test/http-proxy-fix-sync.test.ts
  • test/local-slack-auth-test.sh
  • test/nemoclaw-start.test.ts
  • test/nemotron-inference-fix.test.ts
  • test/seccomp-guard.test.ts
  • test/slack-token-rewriter-sync.test.ts

📝 Walkthrough

Walkthrough

This PR extracts multiple inline Node.js preload scripts into external blueprint files, updates the Dockerfile to install those preloads into /usr/local/lib/nemoclaw/preloads/, rewires scripts/nemoclaw-start.sh to emit and load preloads at runtime via NODE_OPTIONS, and updates tests to reference the new preload sources.

Changes

Preloads extraction, Dockerfile install, startup wiring & tests

Layer / File(s) Summary
Data / Assets
nemoclaw-blueprint/scripts/* (ciao-network-guard.js, nemotron-inference-fix.js, sandbox-safety-net.js, seccomp-guard.js, slack-channel-guard.js, telegram-diagnostics.js)
Adds six new preload scripts implementing guards, diagnostics, and request-body fixes; each is self-contained and invoked immediately at load time.
Dockerfile: runtime assets
Dockerfile
Adds copy/install of blueprint preload assets and related runtime files into /usr/local/lib/nemoclaw/preloads/, adjusts permissions for preloads and existing OpenClaw plugin dirs, and removes the prior ws-proxy-fix inline copy step.
Startup wiring / emission
scripts/nemoclaw-start.sh
Replaces inline heredocs with external preload source variables (_*_SOURCE) and runtime emit calls; updates NODE_OPTIONS to --require emitted preload scripts (sandbox-safety-net, slack/rewriter/guard, telegram diagnostics, nemotron fix, ciao guard, ws proxy fix, seccomp guard).
Wrapper / small comment updates
nemoclaw-blueprint/scripts/http-proxy-fix.js, nemoclaw-blueprint/scripts/slack-token-rewriter.js
Shortened/updated header comments to reference Dockerfile-based preload placement and NODE_OPTIONS loading.
Test harness: resolve preloads from blueprint
test/nemoclaw-start.test.ts, test/http-proxy-fix-sync.test.ts, test/slack-token-rewriter-sync.test.ts, test/nemotron-inference-fix.test.ts, test/seccomp-guard.test.ts, test/local-slack-auth-test.sh
Tests updated to read preload content from nemoclaw-blueprint/scripts (PRELOAD_SCRIPTS), inject canonical preload source paths dynamically (JSON-stringified), and validate emitted runtime files and permissions; some test descriptions updated from "heredoc sync" to "preload sync".

Sequence Diagram(s)

sequenceDiagram
    participant Docker as Docker build
    participant Image as Runtime Image (/usr/local/lib/nemoclaw/preloads)
    participant Start as scripts/nemoclaw-start.sh
    participant Node as Node process (NODE_OPTIONS preload)
    participant Backend as application modules / network

    Docker->>Image: COPY blueprint preload scripts + plugins
    Image->>Start: preloads available at build-time path
    Start->>Node: emit preload files to /tmp and set NODE_OPTIONS --require
    Node->>Node: load preloads (guards, diagnostics, fixes) at require time
    Node->>Backend: runtime behavior (HTTP intercepts, network guards, safety net)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

  • NVIDIA/NemoClaw#3109: Overlapping extraction of entrypoint preload modules, Dockerfile and start-script changes for blueprint preloads.
  • NVIDIA/NemoClaw#2630: Related changes to Slack token-rewriter preload and startup wiring.
  • NVIDIA/NemoClaw#2829: Moves preload sourcing from heredocs to external blueprint files; overlaps in test and script updates.

Suggested reviewers

  • prekshivyas
  • ericksoa
  • cjagwani

Poem

🐇 I hopped the scripts from inline nests to shelves,

Preloads snug in blueprints, saving future elves.
Docker packed them up, the start script set them free,
Node wakes with guardians, watching runtime sea.
A rabbit's little dance for safer startup glee.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/runtime-preload-modules

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

@cv

cv commented May 6, 2026

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 6, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cv cv added NemoClaw CLI refactor PR restructures code without intended behavior change labels May 6, 2026

@cjagwani cjagwani left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

byte-equivalent extraction — verified for all 8 modules. emit_sandbox_sourced_file <"$_SOURCE" is a shell-level stdin copy, no parsing or substitution can drift. sync tests (http-proxy-fix-sync, slack-token-rewriter-sync) enforce equality. /usr/local/lib/nemoclaw/preloads/ install path is immutable + atomic mv to /tmp with 444 root:root.

@cv cv marked this pull request as ready for review May 6, 2026 21:16
@cv cv changed the base branch from refactor/internal-installer-plan to main May 6, 2026 21:16
@cv cv enabled auto-merge (squash) May 6, 2026 21:16
Signed-off-by: Carlos Villela <cvillela@nvidia.com>
@cv cv requested a review from prekshivyas May 6, 2026 21:18

@prekshivyas prekshivyas left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pure code-organization move. Six runtime preload bodies (sandbox-safety-net, ciao-network-guard, slack-channel-guard, telegram-diagnostics, nemotron-inference-fix, seccomp-guard) extracted from scripts/nemoclaw-start.sh heredocs into standalone .js files under nemoclaw-blueprint/scripts/. Spot-verified each new module against the deleted heredoc body — byte-for-byte identical JS logic, no behavior change. The two pre-existing modules (http-proxy-fix.js, slack-token-rewriter.js) only got header comment updates documenting the new Dockerfile-copy path; bodies unchanged.

Architecture: Dockerfile now does COPY nemoclaw-blueprint/scripts/*.js /usr/local/lib/nemoclaw/preloads/ at image build with mode 644. Entrypoint reads via <\"$..._SOURCE\" redirect to write into /tmp for NODE_OPTIONS=--require, preserving the Landlock-readable staging path that OpenShell ≥0.0.36 requires for non-root sandbox processes. The ws-proxy-fix.js path also reorganized to /usr/local/lib/nemoclaw/preloads/ for consistency — declared via the Dockerfile diff and reflected in seccomp-guard.test.ts.

Security review: preloads remain root-owned mode 644, Landlock copy-to-/tmp mechanism preserved verbatim, NODE_OPTIONS=--require /tmp/... registration unchanged. No new attack surface — JS bodies move from one source-controlled location to another, both auditable and version-controlled. Byte-for-byte sync tests (http-proxy-fix-sync.test.ts, slack-token-rewriter-sync.test.ts) still pin canonical bytes; with the new architecture the entrypoint literally < redirects from the same canonical file, so byte equality is intrinsic.

Test adaptations are right-sized: startScriptHeredoc() helper falls back to reading the preload file when the heredoc marker isn't present, end-to-end behavior assertions unchanged. Each affected test gets a _..._SOURCE substitution to point at the local copy. local-slack-auth-test.sh swaps sed-extract-from-script for cp $GUARD_SOURCE $GUARD_JS — cleaner.

Minor nit (non-blocking): Dockerfile comment "Copy NODE_OPTIONS preload modules to a Landlock-accessible path" reads slightly imprecise — /usr/local/lib/nemoclaw/preloads/ is itself blocked by Landlock for non-root, which is exactly why the entrypoint stages copies under /tmp. Phrasing nit only.

CI: pr.yaml lightweight checks pass (commit-lint, dco, layer-boundary, check-hash, changes, get-pr-info). build-sandbox-images (validates the Dockerfile reorganization) and other rollup checks plus self-hosted run still in progress at approval time.

Signed-off-by: Carlos Villela <cvillela@nvidia.com>
@cv cv merged commit ac6d9b8 into main May 6, 2026
12 checks passed
lcsmontiel added a commit to lcsmontiel/NemoClaw that referenced this pull request May 19, 2026
Follow-up to NVIDIA#2344 (the http.request wrapper for NVIDIA#2109). PR NVIDIA#2344
covers axios / follow-redirects / proxy-from-env, all of which flow
through Node's http.request and EnvHttpProxyAgent. This change covers
an additional code path the Microsoft Teams adapter uses: native
fetch() with a custom undici dispatcher.

When OpenClaw's Teams adapter handles a channel @mention it calls the
Microsoft Graph API via:

    fetch('https://graph.microsoft.com/v1.0/teams/.../messages/...',
          { dispatcher: customUndiciAgent })

The custom dispatcher routes the request through its own connection
pool, bypassing the default EnvHttpProxyAgent — which is the only
thing routing HTTPS through the OpenShell L7 proxy. Direct egress to
graph.microsoft.com is blocked by the sandbox network namespace and
surfaces as ECONNREFUSED. Channel @mentions silently fail; DMs work
because the webhook payload carries the message body and no Graph
call is needed.

Wrap globalThis.fetch in the same preload that wraps http.request.
When fetch() is called with a custom dispatcher and an HTTPS URL,
strip the dispatcher and let EnvHttpProxyAgent handle the request.
Non-HTTPS URLs and dispatcher-free calls pass through unchanged so
intra-sandbox HTTP traffic and any non-proxy use of the dispatcher
option keep working.

Refinements over the originally proposed fix:
  - URL extraction handles all three fetch() input forms — string,
    URL object (.href), Request object (.url) — in that order. A
    naive url?.url check would miss URL instances (which have .href,
    not .url) and silently leave the dispatcher attached, defeating
    the fix on callers that pass URL instances.
  - One-shot console.warn so the strip is auditable in logs without
    spamming on every call. The flag is closure-scoped so a process
    restart re-arms it.
  - Defensive typeof origFetch === function guard so a Node runtime
    that ever ships without globalThis.fetch silently no-ops instead
    of throwing at preload time.

After NVIDIA#3109 the preload is delivered as a standalone module copied
from /usr/local/lib/nemoclaw/preloads/ at boot, so this PR only
touches the canonical http-proxy-fix.js — no heredoc to keep in sync.
http-proxy-fix-sync.test.ts already runs the entrypoint block end-to-
end and reads the generated file; extended with explicit assertions
for http.request and globalThis.fetch wrapper presence so a future
deletion of either wrapper trips the test.

Verified end-to-end on a real proxy-enabled sandbox: bot replies to
Teams channel @mentions; DM regression check passes; non-Graph
fetch() and fetch() without a custom dispatcher unaffected.
@cv cv deleted the refactor/runtime-preload-modules branch May 27, 2026 21:18
@wscurran wscurran added area: cli Command line interface, flags, terminal UX, or output and removed NemoClaw CLI labels Jun 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: cli Command line interface, flags, terminal UX, or output refactor PR restructures code without intended behavior change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants