Skip to content

ci: add nightly E2E with inference test - #386

Merged
jacobtomlinson merged 12 commits into
NVIDIA:mainfrom
jayavenkatesh19:nightly-e2e-v2
Mar 19, 2026
Merged

ci: add nightly E2E with inference test#386
jacobtomlinson merged 12 commits into
NVIDIA:mainfrom
jayavenkatesh19:nightly-e2e-v2

Conversation

@jayavenkatesh19

@jayavenkatesh19 jayavenkatesh19 commented Mar 19, 2026

Copy link
Copy Markdown
Contributor

This adds a nightly workflow that replicates a typical user flow: run install.sh --non-interactive on a clean Ubuntu
runner, set up everything (Node, openshell, NemoClaw, gateway, sandbox, inference), then verify the sandbox
is working with live inference from build.nvidia.com

What's in the workflow:

  • Schedule (midnight UTC) + manual dispatch
  • Runs on ubuntu-latest directly, not inside Docker as openshell needs to create a privileged K3s container and nesting that inside another container doesn't work (I tried)
  • Needs NVIDIA_API_KEY repo secret, GITHUB_TOKEN for openshell install via gh CLI
  • 45 min timeout, uploads install log on failure

What changed in test-full-e2e.sh:

  • Uses install.sh --non-interactive (thanks to feat: add non-interactive mode for CI/CD onboarding #318) instead of manual npm install && npm link + piped stdin onboard
  • Removed the inference config fallback that was silently fixing things when onboard failed. If onboard breaks, the
    test should break
  • Added checks for policy presets (verifies onboard actually applied them)
  • Sandbox name comes from env var now, not hardcoded
  • Output goes through background tail -f instead of tee because openshell's port-forward holds the pipe open
    forever

Tested on my fork, with an API key created from my account. @jacobtomlinson

@jacobtomlinson or @ericksoa, can we configure an API key to add NVIDIA_API_KEY to the repo secrets for the nightly CI pipeline to work?

This workflow also faces the issue of the API key being briefly visible in the process run, which is tracked by #325, and any fixes made to close that issue can be made here to fix the vulnerability as well.

Summary by CodeRabbit

  • Chores
    • Added an automated nightly end-to-end workflow with daily schedule, manual trigger option, concurrency control, timeout, and failure artifact capture for diagnostics.
  • Tests
    • Consolidated e2e install/onboard into a non-interactive pipeline, enforced non-interactive runs, improved environment handling and cleanup, strengthened sandbox/service and network policy validations, and added CLI log retrieval for troubleshooting.

@coderabbitai

coderabbitai Bot commented Mar 19, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Adds a nightly E2E GitHub Actions workflow and refactors the E2E script to run a non-interactive installer, adjust sandbox/policy/CLI checks, make openshell teardown conditional, and upload install logs on failure.

Changes

Cohort / File(s) Summary
CI/CD Workflow
.github/workflows/nightly-e2e.yaml
Adds nightly-e2e workflow (daily cron + workflow_dispatch), sets contents: read, concurrency nightly-e2e (cancel-in-progress), runs full-e2e job (ubuntu-latest, 45m), checks out repo, executes test/e2e/test-full-e2e.sh, passes secrets/env, and uploads /tmp/nemoclaw-e2e-install.log on failure (ignore missing).
E2E Test Script
test/e2e/test-full-e2e.sh
Refactors to run bash install.sh --non-interactive, requires NEMOCLAW_NON_INTERACTIVE, derives sandbox from NEMOCLAW_SANDBOX_NAME, sources ~/.bashrc/nvm, ensures $HOME/.local/bin on PATH, conditionally deletes openshell sandbox, fails fast on install errors, verifies nemoclaw/openshell on PATH, checks sandbox via nemoclaw list/status, validates openshell inference includes nvidia-nim, inspects openshell policy get --full for network_policies and optional registry endpoints, adds nemoclaw <sandbox> logs phase, and retains destroy + list removal checks (fixed-string grep).

Sequence Diagram(s)

sequenceDiagram
    participant GH as GitHub Actions Runner
    participant Script as test/e2e/test-full-e2e.sh
    participant Installer as install.sh
    participant CLI as Nemoclaw / OpenShell CLIs
    participant NVIDIA as NVIDIA Cloud API
    participant Store as Artifact Store

    rect rgba(100,150,240,0.5)
    GH->>Script: triggered (cron or workflow_dispatch)
    end
    Script->>Installer: bash install.sh --non-interactive
    Installer-->>Script: exit code + logs
    alt install failed
        Script->>Store: upload /tmp/nemoclaw-e2e-install.log (ignore-missing)
    else install succeeded
        Script->>CLI: nemoclaw list / nemoclaw status
        CLI->>NVIDIA: provider/status queries (e.g., nvidia-nim)
        Script->>CLI: openshell inference get (verify nvidia-nim)
        Script->>CLI: openshell policy get --full (verify network_policies)
        Script->>CLI: nemoclaw <sandbox> logs
    end
    Script->>GH: job completes
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 I nudged the nightly cron with glee,
Installers hummed while I sipped my tea,
Sandboxes woke and policies peeped,
Logs tucked safe if something weeped,
A quiet hop — tests through the night for me.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'ci: add nightly E2E with inference test' accurately describes the main changes: a new CI workflow and refactored E2E test script for nightly validation with inference testing.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
📝 Coding Plan
  • Generate coding plan for human review comments

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

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
test/e2e/test-full-e2e.sh (1)

185-188: status_output is captured but unused.

The variable captures command output but only the exit code is checked. Consider either verifying the output content (e.g., checking for expected sandbox state) or simplifying to avoid the unused variable warning.

Option 1: Verify output content
 status_output=$(nemoclaw "$SANDBOX_NAME" status 2>&1)
-[ $? -eq 0 ] \
-  && pass "nemoclaw ${SANDBOX_NAME} status exits 0" \
-  || fail "nemoclaw ${SANDBOX_NAME} status failed"
+if [ $? -eq 0 ]; then
+  pass "nemoclaw ${SANDBOX_NAME} status exits 0"
+  echo "$status_output" | grep -qi "running\|ready" \
+    && pass "Sandbox status indicates running" \
+    || info "Sandbox status: ${status_output:0:100}"
+else
+  fail "nemoclaw ${SANDBOX_NAME} status failed"
+fi
Option 2: Simplify to avoid unused variable
-status_output=$(nemoclaw "$SANDBOX_NAME" status 2>&1)
-[ $? -eq 0 ] \
+nemoclaw "$SANDBOX_NAME" status > /dev/null 2>&1 \
   && pass "nemoclaw ${SANDBOX_NAME} status exits 0" \
   || fail "nemoclaw ${SANDBOX_NAME} status failed"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/e2e/test-full-e2e.sh` around lines 185 - 188, The script captures the
output into status_output but never uses it; update the nemoclaw status check so
either (a) assert expected content by testing status_output for a known string
(e.g., grep/[[ "$status_output" =~ "expected state" ]]) before calling
pass/fail, or (b) drop the capture and run nemoclaw "$SANDBOX_NAME" status
directly (so only the exit code is checked). Modify the block around the status
command and the pass/fail invocation—references: variable status_output, command
nemoclaw, and the pass/fail helper—to implement one of these two fixes and
remove the unused-variable warning.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@test/e2e/test-full-e2e.sh`:
- Line 115: The cd invocation at test/e2e/test-full-e2e.sh (the line containing
cd "$REPO") must be made fail-fast so the script stops if the directory change
fails; update that cd "$REPO" command to exit the script on failure (use a
short-circuit exit on nonzero status) so subsequent commands do not run in the
wrong directory.

---

Nitpick comments:
In `@test/e2e/test-full-e2e.sh`:
- Around line 185-188: The script captures the output into status_output but
never uses it; update the nemoclaw status check so either (a) assert expected
content by testing status_output for a known string (e.g., grep/[[
"$status_output" =~ "expected state" ]]) before calling pass/fail, or (b) drop
the capture and run nemoclaw "$SANDBOX_NAME" status directly (so only the exit
code is checked). Modify the block around the status command and the pass/fail
invocation—references: variable status_output, command nemoclaw, and the
pass/fail helper—to implement one of these two fixes and remove the
unused-variable warning.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f235b653-d043-4792-a1f1-7f2bdb836342

📥 Commits

Reviewing files that changed from the base of the PR and between 3ba517d and 0076e61.

📒 Files selected for processing (2)
  • .github/workflows/nightly-e2e.yaml
  • test/e2e/test-full-e2e.sh

Comment thread test/e2e/test-full-e2e.sh Outdated

@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 (1)
test/e2e/test-full-e2e.sh (1)

185-188: Unused variable status_output.

Static analysis flagged status_output as unused. Either incorporate it into the pass/fail message or remove the capture.

-status_output=$(nemoclaw "$SANDBOX_NAME" status 2>&1)
-[ $? -eq 0 ] \
-  && pass "nemoclaw ${SANDBOX_NAME} status exits 0" \
-  || fail "nemoclaw ${SANDBOX_NAME} status failed"
+if nemoclaw "$SANDBOX_NAME" status > /dev/null 2>&1; then
+  pass "nemoclaw ${SANDBOX_NAME} status exits 0"
+else
+  fail "nemoclaw ${SANDBOX_NAME} status failed"
+fi

Alternatively, include the output in the failure message for debugging:

 status_output=$(nemoclaw "$SANDBOX_NAME" status 2>&1)
-[ $? -eq 0 ] \
-  && pass "nemoclaw ${SANDBOX_NAME} status exits 0" \
-  || fail "nemoclaw ${SANDBOX_NAME} status failed"
+if [ $? -eq 0 ]; then
+  pass "nemoclaw ${SANDBOX_NAME} status exits 0"
+else
+  fail "nemoclaw ${SANDBOX_NAME} status failed: ${status_output:0:200}"
+fi
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/e2e/test-full-e2e.sh` around lines 185 - 188, The captured variable
status_output is unused; either remove the capture or include it in the
messages. Fix by using the command substitution result when checking exit
status: reference the status_output variable so failure logs include it (e.g.,
include status_output in the fail message) or simply run nemoclaw without
assigning to status_output and keep the existing status check; update the
pass/fail invocations that currently reference ${SANDBOX_NAME} status to also
reference status_output when logging failures for debugging.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@test/e2e/test-full-e2e.sh`:
- Around line 185-188: The captured variable status_output is unused; either
remove the capture or include it in the messages. Fix by using the command
substitution result when checking exit status: reference the status_output
variable so failure logs include it (e.g., include status_output in the fail
message) or simply run nemoclaw without assigning to status_output and keep the
existing status check; update the pass/fail invocations that currently reference
${SANDBOX_NAME} status to also reference status_output when logging failures for
debugging.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3ac12d0b-b0ef-49b3-abfd-a3dce817e361

📥 Commits

Reviewing files that changed from the base of the PR and between 0076e61 and 4e508f2.

📒 Files selected for processing (2)
  • .github/workflows/nightly-e2e.yaml
  • test/e2e/test-full-e2e.sh
✅ Files skipped from review due to trivial changes (1)
  • .github/workflows/nightly-e2e.yaml

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
test/e2e/test-full-e2e.sh (1)

217-225: ⚠️ Potential issue | 🟠 Major

Avoid putting NVIDIA_API_KEY in process arguments.

Line 220 interpolates the secret into curl's -H argument, exposing it to process inspection (visible via ps on CI runners). Use curl's --config - to pass configuration via stdin instead:

Proposed fix
-api_response=$(curl -s --max-time 30 \
-  -X POST https://integrate.api.nvidia.com/v1/chat/completions \
-  -H "Content-Type: application/json" \
-  -H "Authorization: Bearer $NVIDIA_API_KEY" \
-  -d '{
+api_response=$(curl --config - <<EOF
+silent
+max-time = 30
+request = "POST"
+url = "https://integrate.api.nvidia.com/v1/chat/completions"
+header = "Content-Type: application/json"
+header = "Authorization: Bearer $NVIDIA_API_KEY"
+data = '{
     "model": "nvidia/nemotron-3-super-120b-a12b",
     "messages": [{"role": "user", "content": "Reply with exactly one word: PONG"}],
     "max_tokens": 100
-  }' 2>/dev/null) || true
+  }'
+EOF
+2>/dev/null) || true
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/e2e/test-full-e2e.sh` around lines 217 - 225, The curl invocation that
builds api_response embeds the secret via the -H "Authorization: Bearer
$NVIDIA_API_KEY" argument which can leak the key in process listings; change the
call that sets api_response to use curl's --config - option and pass the headers
and request body via stdin (so the NVIDIA_API_KEY is not present in the process
arguments), ensuring the same URL, method, JSON payload
(model/messages/max_tokens) and timeout are preserved; update the code that
currently references the inline -H Authorization header to instead read the
Authorization header from the --config - input and keep the surrounding error
handling (2>/dev/null) and the || true behavior intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@test/e2e/test-full-e2e.sh`:
- Around line 179-182: The test currently greps command output regardless of the
command's exit status (e.g., the nemoclaw list invocation that sets
list_output), which can mask failures; update each place where output is
captured and asserted (commands like nemoclaw list and any similar captures
around the SANDBOX_NAME checks) to first check the command exit status and fail
with the command's output if it failed, only proceeding to grep/assert the
content when the command succeeded; use the captured variable (e.g.,
list_output) and the command's exit code to determine pass/fail and include the
raw output in failure messages for debugging.
- Around line 180-182: Replace the regex grep usage with fixed-string matching
to avoid treating SANDBOX_NAME as a regex: change occurrences that use grep -q
"$SANDBOX_NAME" (e.g., the snippet using echo "$list_output" | grep -q
"$SANDBOX_NAME") to use grep -Fq -- "$SANDBOX_NAME" instead, and apply the same
replacement for the other occurrences noted (around the 302-304 check); keep the
surrounding logic (&& pass ... || fail ...) unchanged.

---

Outside diff comments:
In `@test/e2e/test-full-e2e.sh`:
- Around line 217-225: The curl invocation that builds api_response embeds the
secret via the -H "Authorization: Bearer $NVIDIA_API_KEY" argument which can
leak the key in process listings; change the call that sets api_response to use
curl's --config - option and pass the headers and request body via stdin (so the
NVIDIA_API_KEY is not present in the process arguments), ensuring the same URL,
method, JSON payload (model/messages/max_tokens) and timeout are preserved;
update the code that currently references the inline -H Authorization header to
instead read the Authorization header from the --config - input and keep the
surrounding error handling (2>/dev/null) and the || true behavior intact.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 05a71b34-34b9-494b-99ae-e62512f2553a

📥 Commits

Reviewing files that changed from the base of the PR and between 4e508f2 and 4db0ada.

📒 Files selected for processing (1)
  • test/e2e/test-full-e2e.sh

Comment thread test/e2e/test-full-e2e.sh Outdated
Comment thread test/e2e/test-full-e2e.sh Outdated

@jacobtomlinson jacobtomlinson left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Amazing work Jaya thank you! I've added the secret. Let's merge and then we can verify it runs happily overnight and fix any issues tomorrow.

@jacobtomlinson
jacobtomlinson merged commit ffdccaf into NVIDIA:main Mar 19, 2026
3 checks passed
Ryuketsukami pushed a commit to Ryuketsukami/NemoClaw that referenced this pull request Mar 24, 2026
* ci: add nightly full E2E with install.sh, policy enforcement, and CLI tests

* fix: pass GITHUB_TOKEN for openshell install via gh CLI

* fix: avoid tee pipe hang from openshell background port-forward

* fix: use SSH for sandbox command execution test

* refactor: remove OpenShell-tested checks from NemoClaw E2E

* fixed section header

Signed-off-by: Jaya Venkatesh <jjayabaskar@nvidia.com>

* ci: skip nightly E2E on forks without secrets

* fix: fail-fast on cd and include status output in failure message

* fix: validate command exit status before assertions and use fixed-string grep

---------

Signed-off-by: Jaya Venkatesh <jjayabaskar@nvidia.com>
jessesanford pushed a commit to jessesanford/NemoClaw that referenced this pull request Mar 24, 2026
* ci: add nightly full E2E with install.sh, policy enforcement, and CLI tests

* fix: pass GITHUB_TOKEN for openshell install via gh CLI

* fix: avoid tee pipe hang from openshell background port-forward

* fix: use SSH for sandbox command execution test

* refactor: remove OpenShell-tested checks from NemoClaw E2E

* fixed section header

Signed-off-by: Jaya Venkatesh <jjayabaskar@nvidia.com>

* ci: skip nightly E2E on forks without secrets

* fix: fail-fast on cd and include status output in failure message

* fix: validate command exit status before assertions and use fixed-string grep

---------

Signed-off-by: Jaya Venkatesh <jjayabaskar@nvidia.com>
mafueee pushed a commit to mafueee/NemoClaw that referenced this pull request Mar 28, 2026
Signed-off-by: Will Burford <will@lmstudio.ai>
@wscurran wscurran added area: ci CI workflows, checks, release automation, or GitHub Actions area: e2e End-to-end tests, nightly failures, or validation infrastructure chore Build, CI, dependency, or tooling maintenance labels Jun 3, 2026
@wscurran wscurran added feature PR adds or expands user-visible functionality and removed CI/CD feature PR adds or expands user-visible functionality labels Jun 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: ci CI workflows, checks, release automation, or GitHub Actions area: e2e End-to-end tests, nightly failures, or validation infrastructure chore Build, CI, dependency, or tooling maintenance

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants