Skip to content

test(e2e): cover openclaw → inference.local and stop matching prompt tokens - #2491

Closed
ericksoa wants to merge 1 commit into
mainfrom
test/honest-live-inference-coverage
Closed

test(e2e): cover openclaw → inference.local and stop matching prompt tokens#2491
ericksoa wants to merge 1 commit into
mainfrom
test/honest-live-inference-coverage

Conversation

@ericksoa

@ericksoa ericksoa commented Apr 26, 2026

Copy link
Copy Markdown
Contributor

Summary

The "live inference" assertions in cloud-e2e (test/e2e/test-full-e2e.sh) and the Hermes e2e are curl-from-sandbox checks. They prove that OpenShell's DNS forwarder + proxy can route inference.local; they never invoke openclaw's HTTP client and never touch openclaw's SSRF guard.

That is why every openclaw 4.9 nightly-e2e run gating PR #2464 reported [LIVE] Sandbox inference: model responded with PONG through sandbox PASS while real users were hitting SsrFBlockedError: Blocked hostname or private/internal/special-use IP address on the same release. The check that should have caught it (TC-SBX-02 in test-sandbox-operations.sh) was also a false-positive: it sent 'Say exactly: HELLO_E2E' and grepped the merged stdout/stderr for HELLO_E2E, which any error path that quoted the prompt back could satisfy.

This PR closes the coverage gap and stops the prompt-token false-positive class.

Related

Changes

  • test/e2e/test-full-e2e.sh
    • Phase 4b relabelled from [LIVE] Sandbox inference[ROUTING] inference.local DNS + OpenShell proxy reachable from sandbox. Comment points at the openclaw HTTP client gap.
    • New Phase 4c: runs openclaw agent --json over SSH inside the sandbox, parses result.payloads[].text, asserts the model answered 42 to "What is 6 multiplied by 7?". This is the only assertion in the suite that proves openclaw can complete a turn against inference.local.
  • test/e2e/test-hermes-e2e.sh: same [LIVE][ROUTING] relabel for the equivalent curl-only assertion.
  • test/e2e/test-sandbox-operations.sh TC-SBX-02: replaces the Say exactly: HELLO_E2E + merged-output grep with the arithmetic-via---json pattern. Three properties that prevent the prior false positive:
    1. --json routes openclaw logs to stderr (openclaw/src/commands/agent-via-gateway.ts:57); stderr is dropped, stdout is a clean JSON envelope.
    2. The expected token (42) is not a substring of the prompt, so an error path that echoes the prompt cannot satisfy the grep.
    3. Asserts on result.payloads[].text, not on merged stdout/stderr.
  • test/e2e/e2e-cloud-experimental/features/skill/verify-sandbox-skill-via-agent.sh:
    • Stops embedding ${VERIFY_TOKEN} in the prompt — the agent must read it from SKILL.md, which is the entire point of the test.
    • Refuses SKILL_VERIFY_PROMPT overrides that smuggle the token back in.
    • Adds a negative assertion on SsrFBlockedError, Blocked hostname, transport errors, and gateway unavailable markers before the positive grep, so an SSRF block can't be hidden by a coincidental token match.

Type of Change

  • Code change (feature, bug fix, or refactor)

Verification

  • bash -n and shellcheck -S warning clean on all four touched files.
  • No production code changed; nightly-e2e is the verification surface.
  • Tests added or updated for new or changed behavior — adds Phase 4c and tightens three existing assertions.
  • No secrets, API keys, or credentials committed.

npm test not relevant — this PR only edits e2e shell scripts. test-cli pre-commit hook skipped because it shells out to a real OpenShell gateway / Docker on a clean dev machine and times out (same pre-existing flake noted on #2490).

Sequencing

This PR is independent of #2490 but they are related: #2490 fixes the runtime regression, this PR fixes the tests that should have caught it. Either order works. Landing this first against an unfixed sandbox image will (correctly) red-light Phase 4c and TC-SBX-02 — that's the proof the new assertions actually see the regression.

Summary by CodeRabbit

Release Notes

  • Tests
    • Enhanced validation and error detection in sandbox skill verification testing
    • Improved agent response parsing and verification across multiple test suites
    • Refined test output clarity for connectivity and routing layer checks

…tokens

The "live inference" assertions in cloud-e2e (test-full-e2e.sh) and the
Hermes e2e were curl-from-sandbox checks. They prove OpenShell's DNS
forwarder + proxy can route inference.local; they never invoke openclaw's
HTTP client and never reach openclaw's SSRF guard. That is why every
openclaw 4.9 nightly-e2e run on PR #2464 reported [LIVE] Sandbox inference:
PASS while real users were getting SsrFBlockedError on the same release.

Changes:

* test-full-e2e.sh: relabel Phase 4b from [LIVE] to [ROUTING] with a comment
  pointing at #2490; add Phase 4c, an actual openclaw-mediated turn that
  runs `openclaw agent --json` over SSH, parses result.payloads[].text, and
  asserts the model produced "42" for "What is 6 multiplied by 7?". The
  expected token is not a substring of the prompt, --json routes logs to
  stderr, stderr is dropped — so prompt-echo on an error path cannot
  satisfy the grep.
* test-hermes-e2e.sh: same relabel for the equivalent curl assertion.
* test-sandbox-operations.sh TC-SBX-02: replace `Say exactly: HELLO_E2E`
  prompt + grep on merged stdout/stderr with the same arithmetic-via-JSON
  pattern. The previous assertion would match the prompt itself in any
  error path that quoted it back, including the openclaw 4.9 SSRF
  rejection — false positive that hid the regression for the entire
  4.2 → 4.7 → 4.8 → 4.9 bump series.
* verify-sandbox-skill-via-agent.sh: stop embedding ${VERIFY_TOKEN} in the
  prompt (the agent must read it from SKILL.md — that is the test). Add
  a guard that refuses SKILL_VERIFY_PROMPT overrides which smuggle the
  token back in, and a negative assertion on SsrFBlockedError, transport
  errors, and gateway-unavailable markers before the positive grep.

Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
@coderabbitai

coderabbitai Bot commented Apr 26, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

These changes refactor end-to-end test scripts to clarify the distinction between routing-layer validation (DNS/proxy reachability) and agent-mediated inference validation. Test prompts are updated with additional validation, and assertion logic is revised to use JSON parsing instead of substring matching.

Changes

Cohort / File(s) Summary
Skill Verification Prompt Validation
test/e2e/e2e-cloud-experimental/features/skill/verify-sandbox-skill-via-agent.sh
Updates agent prompt to retrieve verification token from SKILL.md, adds validation to prevent reintroduction of literal ${VERIFY_TOKEN}, and adds regex-based error detection (provider/transport/gateway/SSRF errors) to fail immediately on error-path conditions.
E2E Test Suite Refactoring
test/e2e/test-full-e2e.sh, test/e2e/test-hermes-e2e.sh, test/e2e/test-sandbox-operations.sh
Reclassifies curl-based sandbox checks as routing-layer validation (DNS/proxy reachability), updates messaging and labels accordingly. Adds Test 4c for openclaw agent validation with JSON response parsing and numeric boundary regex validation. Modifies test_sbx_02_connect_chat to use openclaw agent --json with JSON parsing instead of substring matching, extracts result.payloads[].text fields, and validates for integer 42 with improved error reporting.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 Our tests now dance with JSON grace,
Routing checks find their rightful place,
Token validators guard the gate,
E2E assertions validate! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'test(e2e): cover openclaw → inference.local and stop matching prompt tokens' directly and accurately summarizes the main changes: adding openclaw-mediated inference.local coverage and removing token-matching from prompts.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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 test/honest-live-inference-coverage

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/e2e-cloud-experimental/features/skill/verify-sandbox-skill-via-agent.sh (1)

99-105: Good early failure detection, but consider aligning error patterns with suite conventions.

The fail-fast on provider/transport errors is the right approach to prevent coincidental token matches from masking real failures.

However, the error pattern here is a subset of the standard patterns used elsewhere in the suite. Per test/e2e/test-inference-routing.sh:378-384, the canonical pattern includes additional codes like ETIMEDOUT, ENETUNREACH, EHOSTUNREACH, ENOTFOUND, "No route to host", dns, etc.

Consider aligning for consistency:

♻️ Suggested expanded pattern
-if printf '%s' "$raw_out" | grep -qiE "SsrFBlockedError|Blocked hostname|Blocked: resolves to|transport error|provider error|ECONNREFUSED|EAI_AGAIN|gateway unavailable"; then
+if printf '%s' "$raw_out" | grep -qiE "SsrFBlockedError|Blocked hostname|Blocked: resolves to|transport error|provider error|ECONNREFUSED|ETIMEDOUT|ENETUNREACH|EHOSTUNREACH|ENOTFOUND|EAI_AGAIN|No route to host|gateway unavailable|dns"; then
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@test/e2e/e2e-cloud-experimental/features/skill/verify-sandbox-skill-via-agent.sh`
around lines 99 - 105, Update the grep pattern that checks "$raw_out" in the
provider/transport error guard (the block using raw_out, agent_rc, SESSION_ID
and die) to match the canonical suite error tokens used elsewhere (e.g., include
ETIMEDOUT, ENETUNREACH, EHOSTUNREACH, ENOTFOUND, "No route to host", dns, etc.)
so the fail-fast behavior is consistent with test/e2e/test-inference-routing.sh;
modify the extended regex passed to grep -qiE to add these additional
keywords/phrases while preserving the existing terms and the die call that
reports the agent_rc and SESSION_ID.
🤖 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-sandbox-operations.sh`:
- Around line 291-294: The captured variable `raw` is polluted because
`sandbox_exec` merges remote stderr into its output; update the test to discard
remote stderr like `test-full-e2e.sh` by running the SSH command directly
(instead of via `sandbox_exec`) so the remote invocation of `openclaw agent
--json --session-id '${session_id}' ... 2>/dev/null` is executed on the remote
side, or alternatively implement a new helper `sandbox_exec_stdout_only` that
runs the remote command with stderr redirected to /dev/null and use that when
assigning `raw` (references: sandbox_exec, raw, session_id, and the `openclaw
agent` invocation).

---

Nitpick comments:
In
`@test/e2e/e2e-cloud-experimental/features/skill/verify-sandbox-skill-via-agent.sh`:
- Around line 99-105: Update the grep pattern that checks "$raw_out" in the
provider/transport error guard (the block using raw_out, agent_rc, SESSION_ID
and die) to match the canonical suite error tokens used elsewhere (e.g., include
ETIMEDOUT, ENETUNREACH, EHOSTUNREACH, ENOTFOUND, "No route to host", dns, etc.)
so the fail-fast behavior is consistent with test/e2e/test-inference-routing.sh;
modify the extended regex passed to grep -qiE to add these additional
keywords/phrases while preserving the existing terms and the die call that
reports the agent_rc and SESSION_ID.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: e43b9e1c-eb26-40f8-95bc-50dff449ef0f

📥 Commits

Reviewing files that changed from the base of the PR and between f439189 and 38b2b17.

📒 Files selected for processing (4)
  • test/e2e/e2e-cloud-experimental/features/skill/verify-sandbox-skill-via-agent.sh
  • test/e2e/test-full-e2e.sh
  • test/e2e/test-hermes-e2e.sh
  • test/e2e/test-sandbox-operations.sh

Comment on lines +291 to +294
log " Sending one-shot message to agent via SSH (openclaw agent --json)..."
local session_id raw
session_id="e2e-sbx-02-$(date +%s)-$$"
raw=$(sandbox_exec "openclaw agent --agent main --json --session-id '${session_id}' -m 'What is 6 multiplied by 7? Reply with only the integer, no extra words.'" 2>/dev/null) || true

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.

⚠️ Potential issue | 🟠 Major

Stderr pollution may break JSON parsing.

The sandbox_exec helper (lines 75-103) captures the remote command's stderr via 2>&1 into the result. This means raw will contain any stderr output from openclaw agent, which would corrupt the JSON.

In contrast, test-full-e2e.sh handles this correctly by placing 2>/dev/null inside the SSH command itself (line 393), ensuring stderr is discarded before capture.

🐛 Proposed fix

The cleanest fix is to invoke the remote command directly instead of using sandbox_exec, mirroring the pattern in test-full-e2e.sh:

-  raw=$(sandbox_exec "openclaw agent --agent main --json --session-id '${session_id}' -m 'What is 6 multiplied by 7? Reply with only the integer, no extra words.'" 2>/dev/null) || true
+  local ssh_cfg
+  ssh_cfg="$(mktemp)"
+  if openshell sandbox ssh-config "$SANDBOX_A" >"$ssh_cfg" 2>/dev/null; then
+    raw=$(run_with_timeout 120 ssh -F "$ssh_cfg" \
+      -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
+      -o ConnectTimeout=10 -o LogLevel=ERROR \
+      "openshell-${SANDBOX_A}" \
+      "openclaw agent --agent main --json --session-id '${session_id}' -m 'What is 6 multiplied by 7? Reply with only the integer, no extra words.'" \
+      2>/dev/null) || true
+  fi
+  rm -f "$ssh_cfg"

Alternatively, add a sandbox_exec_stdout_only variant that discards stderr from the remote command.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/e2e/test-sandbox-operations.sh` around lines 291 - 294, The captured
variable `raw` is polluted because `sandbox_exec` merges remote stderr into its
output; update the test to discard remote stderr like `test-full-e2e.sh` by
running the SSH command directly (instead of via `sandbox_exec`) so the remote
invocation of `openclaw agent --json --session-id '${session_id}' ...
2>/dev/null` is executed on the remote side, or alternatively implement a new
helper `sandbox_exec_stdout_only` that runs the remote command with stderr
redirected to /dev/null and use that when assigning `raw` (references:
sandbox_exec, raw, session_id, and the `openclaw agent` invocation).

@ericksoa

Copy link
Copy Markdown
Contributor Author

Folding into #2490. The fix and the tests that prove it are reciprocal — neither validates without the other — so a single PR is the cleaner unit of review and the cleaner unit of nightly-e2e validation. All four files from this PR (test-full-e2e.sh, test-hermes-e2e.sh, test-sandbox-operations.sh, verify-sandbox-skill-via-agent.sh) have been cherry-picked onto fix/openclaw-4-9-inference-ssrf as commit ca03324.

@ericksoa ericksoa closed this Apr 26, 2026
@wscurran wscurran added the chore Build, CI, dependency, or tooling maintenance label Jun 8, 2026
@cv
cv deleted the test/honest-live-inference-coverage branch June 28, 2026 00:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

chore Build, CI, dependency, or tooling maintenance

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants