Skip to content

refactor(cli): move dns proxy setup behind internal command - #3075

Merged
cv merged 99 commits into
mainfrom
refactor/internal-dns-setup-proxy
May 6, 2026
Merged

refactor(cli): move dns proxy setup behind internal command#3075
cv merged 99 commits into
mainfrom
refactor/internal-dns-setup-proxy

Conversation

@cv

@cv cv commented May 6, 2026

Copy link
Copy Markdown
Collaborator

Summary

Moves scripts/setup-dns-proxy.sh behind a hidden oclif-native nemoclaw internal dns setup-proxy command. The shell script is now a compatibility wrapper while DNS proxy orchestration, payload construction, sandbox pod selection, and verification live in typed TypeScript.

Changes

  • Add hidden internal command internal dns setup-proxy <gateway-name> <sandbox-name>.
  • Add TypeScript DNS setup domain helpers for proxy payloads, pod/namespace selection, gateway parsing, and safety validation.
  • Add action-layer DNS proxy setup orchestration using Docker adapter boundaries.
  • Replace scripts/setup-dns-proxy.sh with a thin wrapper and update tests for wrapper/internal-command behavior.

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

    • DNS proxy setup for sandbox environments: automated pod discovery, DNS validation, network configuration, and readiness verification.
    • Added a compatibility wrapper to route DNS proxy setup through available CLI paths.
  • Tests

    • Comprehensive test coverage for DNS proxy setup flows, helpers, and error cases.

cv added 30 commits May 2, 2026 13:36
@cv cv self-assigned this May 6, 2026
@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: bbf299f3-bc13-4872-90a8-638681254190

📥 Commits

Reviewing files that changed from the base of the PR and between 489198d and f4914e6.

📒 Files selected for processing (3)
  • src/lib/actions/dns.test.ts
  • src/lib/actions/dns.ts
  • src/lib/domain/dns/setup-proxy.ts

📝 Walkthrough

Walkthrough

Adds DNS proxy setup: new domain helpers, a core runSetupDnsProxy action, a hidden oclif internal command, tests, and converts the shell script into a compatibility wrapper that delegates to the Node.js CLI or falls back to the CLI's internal command.

Changes

DNS Proxy Setup Infrastructure

Layer / File(s) Summary
Domain Helpers & Constants
src/lib/domain/dns/setup-proxy.ts, src/lib/domain/dns/setup-proxy.test.ts
Adds DNS defaults, Python code generators for the proxy and readiness probe, pod/namespace selection and veth parsing helpers, resolv.conf builder, and DNS address safety validation; unit tests for these helpers.
Core Action Types & Orchestration
src/lib/actions/dns.ts, src/lib/actions/dns.test.ts
Introduces SetupDnsProxyOptions, SetupDnsProxyDeps, SetupDnsProxyResult and implements runSetupDnsProxy() which discovers the openshell cluster and sandbox pod, determines/validates DNS upstream, writes & launches a Python DNS proxy inside the pod, probes readiness, configures sandbox networking (resolv.conf, iptables when present), verifies runtime state, and returns detailed results; adds tests for success and unsafe-upstream rejection flows.
CLI Command Wiring
src/commands/internal/dns/setup-proxy.ts, test/internal-cli.test.ts
Adds a hidden, strict oclif command internal dns setup-proxy <gateway-name> <sandbox-name> that delegates to runSetupDnsProxy; includes a CLI test validating the subcommand help and routing.
Shell Wrapper Delegation
scripts/setup-dns-proxy.sh
Replaces in-script DNS setup logic with a compatibility wrapper that resolves a configurable Node.js CLI path and delegates to node "$CLI_JS" internal dns setup-proxy "$@" when present, otherwise falls back to nemoclaw internal dns setup-proxy "$@".

Sequence Diagram

sequenceDiagram
    actor User
    participant CLI as oclif CLI
    participant Action as runSetupDnsProxy
    participant Docker as Docker/K8s
    participant Pod as Sandbox Pod
    participant Kernel as Host Network

    User->>CLI: internal dns setup-proxy gateway sandbox
    CLI->>Action: invoke(gatewayName, sandboxName)
    Action->>Docker: discover openshell cluster container
    Docker-->>Action: cluster container info
    Action->>Docker: fetch Kubernetes DNS endpoints
    Docker-->>Action: upstream IP (or default)
    Action->>Docker: list pods and select sandbox pod
    Docker-->>Action: pod name
    Action->>Pod: write /tmp/dns-proxy.py and readiness probe
    Action->>Pod: start proxy (nohup) and clear old PID
    Pod-->>Action: process started
    Action->>Pod: run readiness probe (DNS query to veth gateway)
    Pod-->>Action: probe result (ok/timeout)
    Action->>Kernel: configure iptables rule (if available)
    Kernel-->>Action: rule applied / unavailable
    Action->>Pod: write resolv.conf in sandbox namespace (if possible)
    Pod-->>Action: config applied
    Action-->>CLI: return SetupDnsProxyResult (exitCode, verification metrics)
    CLI-->>User: exit code and messages
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

🐰 In sandbox burrows a proxy takes flight,
Python scripts humming through day and night,
Pods find their gateway, iptables sing,
DNS whispers answered on a tiny wing,
Hooray — the sandbox hops back into sight.

🚥 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 accurately reflects the main change: moving DNS proxy setup from a shell script to an internal oclif command, which is the primary objective of this refactoring PR.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ 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/internal-dns-setup-proxy

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

@cv
cv marked this pull request as draft May 6, 2026 06:15
@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.

@cv cv added NemoClaw CLI refactor PR restructures code without intended behavior change labels May 6, 2026
@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.

@coderabbitai coderabbitai Bot 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.

🧹 Nitpick comments (3)
src/lib/domain/dns/setup-proxy.ts (1)

57-64: 💤 Low value

Consider documenting the substring matching behavior.

selectSandboxPod uses includes() for substring matching, which means sandboxName="box" would match pod/toolbox-xyz. This appears intentional for prefix-style naming (e.g., box[1] matching box[1]-abc), but a brief comment would clarify the design intent.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/domain/dns/setup-proxy.ts` around lines 57 - 64, The function
selectSandboxPod currently uses substring matching via includes() which can
match partial names (e.g., sandboxName "box" matching "pod/toolbox-xyz"); add a
concise comment above selectSandboxPod documenting this intentional substring
matching behavior and the expected naming pattern (e.g., prefix-style names like
"box[1]" matching "box[1]-abc"), and note that it deliberately strips a leading
"pod/" via replace so callers rely on that output format; this clarifies intent
without changing logic.
scripts/setup-dns-proxy.sh (1)

7-14: 💤 Low value

Usage message inconsistency with argument validation.

The usage string uses [gateway-name] which conventionally indicates an optional argument, but line 11 requires at least 2 arguments. The oclif command also marks both arguments as required. Consider updating the usage to <gateway-name> <sandbox-name> for consistency.

📝 Suggested fix
-# Usage: ./scripts/setup-dns-proxy.sh [gateway-name] <sandbox-name>
+# Usage: ./scripts/setup-dns-proxy.sh <gateway-name> <sandbox-name>

And similarly in line 12:

-  echo "Usage: $0 [gateway-name] <sandbox-name>"
+  echo "Usage: $0 <gateway-name> <sandbox-name>"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/setup-dns-proxy.sh` around lines 7 - 14, The usage message is
inconsistent: the echo currently shows "[gateway-name] <sandbox-name>" but the
script's argument check in the same file (the if [ "$#" -lt 2 ] block) and the
oclif command treat both arguments as required; update the usage string to
"<gateway-name> <sandbox-name>" so it matches the validation, i.e., change the
echo/usage text in the setup-dns-proxy.sh script to use angle brackets for both
arguments and ensure the Usage comment at the top is likewise updated to "Usage:
./scripts/setup-dns-proxy.sh <gateway-name> <sandbox-name>" to keep all
references consistent.
src/lib/actions/dns.ts (1)

340-376: 💤 Low value

Consider adding a small delay after launching the proxy before probing.

The proxy is launched with nohup (line 357) and immediately probed in the loop (lines 363-375). Since the proxy needs time to bind to port 53 and start listening, the first few probe attempts will likely fail. This works correctly but a brief initial delay could reduce unnecessary probe iterations.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/actions/dns.ts` around lines 340 - 376, After launching the DNS proxy
with the kctl(...) call that runs nohup python3 /tmp/dns-proxy.py (the block
using shellSingleQuote(dnsUpstream) and vethGateway), add a short sleep (e.g.
sleep(500)–sleep(1000)) immediately before the probe loop that calls
buildDnsReadyProbePython so the proxy has time to bind to port 53; keep the
existing probe loop (dnsReady, attempt loop and probe via kctl) unchanged—just
insert the brief delay after the kctl that starts the proxy to reduce needless
early probe failures.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@scripts/setup-dns-proxy.sh`:
- Around line 7-14: The usage message is inconsistent: the echo currently shows
"[gateway-name] <sandbox-name>" but the script's argument check in the same file
(the if [ "$#" -lt 2 ] block) and the oclif command treat both arguments as
required; update the usage string to "<gateway-name> <sandbox-name>" so it
matches the validation, i.e., change the echo/usage text in the
setup-dns-proxy.sh script to use angle brackets for both arguments and ensure
the Usage comment at the top is likewise updated to "Usage:
./scripts/setup-dns-proxy.sh <gateway-name> <sandbox-name>" to keep all
references consistent.

In `@src/lib/actions/dns.ts`:
- Around line 340-376: After launching the DNS proxy with the kctl(...) call
that runs nohup python3 /tmp/dns-proxy.py (the block using
shellSingleQuote(dnsUpstream) and vethGateway), add a short sleep (e.g.
sleep(500)–sleep(1000)) immediately before the probe loop that calls
buildDnsReadyProbePython so the proxy has time to bind to port 53; keep the
existing probe loop (dnsReady, attempt loop and probe via kctl) unchanged—just
insert the brief delay after the kctl that starts the proxy to reduce needless
early probe failures.

In `@src/lib/domain/dns/setup-proxy.ts`:
- Around line 57-64: The function selectSandboxPod currently uses substring
matching via includes() which can match partial names (e.g., sandboxName "box"
matching "pod/toolbox-xyz"); add a concise comment above selectSandboxPod
documenting this intentional substring matching behavior and the expected naming
pattern (e.g., prefix-style names like "box[1]" matching "box[1]-abc"), and note
that it deliberately strips a leading "pod/" via replace so callers rely on that
output format; this clarifies intent without changing logic.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 1ad1fcb4-52ad-4900-b0bf-287f8b4cc40d

📥 Commits

Reviewing files that changed from the base of the PR and between bb7ebc3 and 489198d.

📒 Files selected for processing (7)
  • scripts/setup-dns-proxy.sh
  • src/commands/internal/dns/setup-proxy.ts
  • src/lib/actions/dns.test.ts
  • src/lib/actions/dns.ts
  • src/lib/domain/dns/setup-proxy.test.ts
  • src/lib/domain/dns/setup-proxy.ts
  • test/internal-cli.test.ts

@cv

cv commented May 6, 2026

Copy link
Copy Markdown
Collaborator Author

Automated PR review summary

Reviewed PR #3075: refactor(cli): move dns proxy setup behind internal command

Recommendation

  • Recommendation: PASS
  • Highest observed severity: low
  • Block merge: no
  • Why: The highest-risk downside if merged would be broken post-creation sandbox DNS or a newly introduced command-injection path in the wrapper/internal-command handoff. In this environment, the wrapper successfully configured DNS in the real sandbox with 4/4 verification passes, and hostile sandbox/gateway argv payloads did not produce evidence of shell execution. I found no PR-specific regression that should block merge.
  • Reviewer summary: Reviewed the DNS setup-proxy refactor with real NemoClaw/OpenShell sandbox execution and targeted hostile-input probes. The hidden internal command is wired, the compatibility wrapper still works end-to-end, and the tested metacharacter inputs were handled as data rather than triggering shell execution.

Installation and setup findings

  • Nemoclaw was installed from the local repository via the standard installer entrypoint and verified against the actual NemoClaw-managed sandbox. What went well: the CLI linked correctly, onboarding created sandbox nemoclaw-install-check, SSH into that sandbox worked, 2+2=4 executed inside it, and an in-sandbox OpenClaw prompt returned 4. What was incomplete: the original installer process exceeded the 600 second timeout while still applying additional policy presets, so the onboarding session file remained in progress even though the sandbox and core functionality were already working.

What was validated

  • The PR revision was checked out in an isolated review environment.
  • The local checkout was installed using the repository installer flow as closely as the environment allowed.
  • Adversarial, PR-specific probes were then run against the installed environment and relevant repository context.
  • Diff summary:
 .../skills/nemoclaw-contributor-create-pr/SKILL.md |   20 +-
 .../nemoclaw-maintainer-pr-comparator/SKILL.md     |  121 ---
 .../checks/tier-0-gates.md                         |   61 --
 .../checks/tier-1-correctness.md                   |   86 --
 .../checks/tier-2-quality.md                       |   64 --
 .../repo-policy.md                                 |   86 --
 .../scripts/check-coderabbit-threads.sh            |  105 --
 .../scripts/collect-gates.sh                       |   84 --
 .../scripts/find-candidates.sh                     |   86 --
 .../scripts/parse-supersession.sh                  |   68 --
 .../scripts/render-verdict.py                      |  232 -----
 .../templates/verdict.md                           |   88 --
 .../tiebreakers.md                                 |   61 --
 .../validation/backtest.md                         |   69 --
 .agents/skills/nemoclaw-skills-guide/SKILL.md      |    2 +-
 .../references/agent-skills.md                     |    4 +-
 .../nemoclaw-user-configure-inference/SKILL.md     |  329 ++----
 .../references/inference-options.md                |    4 +-
 .../references/set-up-sub-agent.md                 |  120 ---
 .../referenc
...[truncated]

Failing tests and unresolved impact

  • No failing adversarial tests were captured.

Passing tests and why they mattered

Passing test 1: Wrapper and hidden command still perform real DNS proxy setup

  • What was tested: The refactor preserved runtime behavior: the hidden internal dns setup-proxy command is wired in, and the legacy shell wrapper still routes to it successfully against a real NemoClaw/OpenShell sandbox.
  • Why it mattered: If false, post-sandbox DNS setup regresses and outbound name resolution breaks for real sandboxes.
  • Observed result: Installed CLI showed internal dns setup-proxy --help; wrapper usage still present; wrapper run against nemoclaw-install-check reported DNS forwarder running plus PASS for resolv.conf, iptables UDP 53 rule, and getent hosts github.com (4 passed, 0 failed).
  • Command: bash /tmp/pr3075-probe1.sh
  • Recommended follow-up coverage: Add or retain an integration regression test that exercises the installed wrapper and internal command routing together, since unit tests would not catch end-to-end CLI handoff regressions.

Passing test 2: Adversarial sandbox-name input does not trigger shell injection

  • What was tested: Moving orchestration into TypeScript removed shell-script injection exposure for malicious sandbox names; a name containing shell metacharacters should fail cleanly as data.
  • Why it mattered: If false, a crafted sandbox name could execute unintended commands on the host-side orchestration path.
  • Observed result: nemoclaw internal dns setup-proxy nemoclaw 'nemoclaw-install-check;echo PWNED' returned exit 1 with Could not find pod for sandbox ...; no separate injected-command output was observed.
  • Command: bash /tmp/pr3075-probe2.sh
  • Recommended follow-up coverage: Add an integration/regression test for sandbox names containing shell metacharacters so pod selection and command construction stay data-safe.

Passing test 3: Adversarial gateway-name quoting does not escape wrapper/internal command path

  • What was tested: The compatibility wrapper preserves argv boundaries and the TypeScript path does not eval gateway input, so quote/semicolon payloads in gateway names should not execute.
  • Why it mattered: If false, the compatibility wrapper could reintroduce command-injection risk despite the TypeScript refactor.
  • Observed result: Probe printed NO_INJECTION; wrapper execution with a quote/semicolon-bearing gateway argument still completed DNS setup successfully on the real sandbox and no injected marker appeared.
  • Command: bash /tmp/pr3075-probe3.sh
  • Recommended follow-up coverage: Add a regression test for wrapper forwarding with hostile gateway strings, because the risk is specifically in shell-to-CLI argument preservation.

Bottom line

  • Based on the install evidence and adversarial probes, this PR looks reasonable to approve.

@cv
cv marked this pull request as ready for review May 6, 2026 19:14
@cv
cv changed the base branch from refactor/internal-dns-coredns to main May 6, 2026 19:14
@cv
cv enabled auto-merge (squash) May 6, 2026 19:14
Signed-off-by: Carlos Villela <cvillela@nvidia.com>

@prekshivyas prekshivyas left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM. Same #3074 Bash → TypeScript port pattern — 7 files / +583 / -315.

314 lines of scripts/setup-dns-proxy.sh logic moved into:

  • src/lib/actions/dns.ts (+339) — proxy setup orchestration, extends the same action module from #3074.
  • src/lib/domain/dns/setup-proxy.ts (+89) — pure domain helpers (proxy payload, pod/namespace selection, gateway parsing, safety validation).
  • src/commands/internal/dns/setup-proxy.ts (+31) — hidden oclif command nemoclaw internal dns setup-proxy <gateway-name> <sandbox-name>.

scripts/setup-dns-proxy.sh becomes a thin 8-line wrapper that delegates — preserves the public entrypoint.

+115 new test lines (+64 action, +42 domain, +10 internal-command routing). CI: pr.yaml mostly green (lint/dco/check-hash/legacy-path-guard/changes PASS); macos-e2e/wsl-e2e/checks still in flight at review time. No failures.

@cv
cv merged commit 757adcb into main May 6, 2026
12 of 13 checks passed
@cv
cv deleted the refactor/internal-dns-setup-proxy branch May 27, 2026 21:17
@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.

3 participants