Skip to content

test(e2e): migrate test-hermes-discord-e2e.sh to vitest - #5610

Merged
jyaunches merged 4 commits into
mainfrom
e2e-migrate-test-hermes-discord-vitest
Jun 23, 2026
Merged

test(e2e): migrate test-hermes-discord-e2e.sh to vitest#5610
jyaunches merged 4 commits into
mainfrom
e2e-migrate-test-hermes-discord-vitest

Conversation

@jyaunches

@jyaunches jyaunches commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Summary

Migrate test-hermes-discord-e2e.sh with equivalent live Vitest coverage in test/e2e-scenario/live/hermes-discord.test.ts.

Legacy shell deletion and nightly shell lane retirement are deferred to #5098 Phase 11.

Related Issues

Refs #5098
Refs #3032

Assertion parity

ID Legacy assertion/check Replacement Vitest assertion Boundary preserved Status
A1 Docker is running; NEMOCLAW_NON_INTERACTIVE=1; third-party software acceptance is set; hosted inference key is present. dockerInfo(...) exit zero plus env expectations and secrets.required("NVIDIA_INFERENCE_API_KEY"). Real Docker daemon + secret-gated live workflow env. covered
A2 Pre-cleanup destroys any stale NemoClaw/OpenShell sandbox and gateway before install. cleanupHermesDiscord(..., "preclean-hermes-discord") calls real nemoclaw destroy, openshell sandbox delete, and openshell gateway destroy. Real host CLI/OpenShell cleanup. covered
A3 bash install.sh --non-interactive succeeds with NEMOCLAW_AGENT=hermes, Discord env enabled, policy tier open, fresh/recreated sandbox, hosted CI inference. host.command("bash", ["install.sh", "--non-interactive"], ...) exit zero with Hermes Discord env. Real installer/onboard/Docker/OpenShell boundary. covered
A4 nemoclaw and openshell are on PATH after install. bash -lc "command -v nemoclaw && openshell --version" exit zero and stdout contains nemoclaw. Real login/path command boundary. covered
A5 nemoclaw list contains the Hermes Discord sandbox. host.command("nemoclaw", ["list"]) exit zero and output contains SANDBOX_NAME. Real NemoClaw CLI/registry boundary. covered
A6 OpenShell provider ${SANDBOX_NAME}-discord-bridge exists. openshell provider get ${SANDBOX_NAME}-discord-bridge exit zero. Real OpenShell gateway/provider boundary. covered
A7 Hermes health returns "ok" within 15 attempts. Loop over sandbox curl -sf http://localhost:8642/health, then assert exit zero and "ok". Real sandbox exec and Hermes runtime HTTP health. covered
A8 /sandbox/.hermes/config.yaml has top-level discord, expected booleans/defaults, platforms.discord.enabled=true, platforms.api_server, and no DISCORD_BOT_TOKEN literal. In-sandbox Python/YAML config probe asserts every field and fails if DISCORD_BOT_TOKEN appears. Real sandbox filesystem/config. covered
A9 /sandbox/.hermes/.env contains Discord placeholder, guild IDs, allowed users, and API_SERVER_PORT=18642. In-sandbox Python probe asserts exact .env lines with normalized IDs. Real sandbox filesystem/env file. covered
A10 Hermetic fake Discord Gateway starts on host. startHermesFakeDiscordGateway(...) starts fake-discord-gateway.cjs in Docker and returns a published port/capture file. Real Docker-hosted fake Gateway. covered
A11 OpenShell native WebSocket policy with credential rewrite is applied for Hermes fake Discord Gateway, including node/python/Hermes binaries. applyHermesFakeDiscordPolicy(...) runs openshell policy update with websocket rewrite, allowed methods/IPs, and node/python/Hermes binary allowlist; exit zero. Real OpenShell policy boundary. covered
A12 Hermes Python/discord.py native Gateway path reaches UPGRADE, HELLO, IDENTIFY_SENT_PLACEHOLDER, READY, HEARTBEAT_ACK; import failure is fatal. runHermesPythonDiscordGatewayProof(...) runs /opt/hermes/.venv/bin/python in sandbox and asserts all protocol markers plus absence of IMPORT_DISCORD_FAILED. Real Hermes Python env, discord.py, sandbox network policy, fake Gateway. covered
A13 Fake Gateway proves host-side Discord token rewrite while sandbox sent only placeholder. assertDiscordGatewayCapture(...) asserts tokenMatchesExpected=true, tokenLooksPlaceholder=false, and capture does not contain raw token. Real fake Gateway capture and OpenShell credential rewrite. covered
A14 Raw Discord token absent from /sandbox/.hermes/config.yaml and .env. assertRawTokenAbsentFromFiles(...) decodes token in sandbox and greps both files, expecting OK. Real sandbox filesystem negative check. covered
A15 Raw Discord token absent from sandbox environment and no DISCORD_PROXY env remains. rawTokenSurfaceProbe(..., "env") expects ABSENT; emits distinct failures for token or DISCORD_PROXY. Real sandbox env negative check. covered
A16 Raw Discord token absent from sandbox process list. rawTokenSurfaceProbe(..., "process") scans /proc/*/cmdline, expecting ABSENT. Real /proc process boundary. covered
A17 Raw Discord token absent from /sandbox, /home, /etc, /tmp, /var. rawTokenSurfaceProbe(..., "filesystem") recursive grep expects ABSENT. Real sandbox filesystem negative check. covered
A18 Discord REST /api/v10/users/@me reaches Discord with configured placeholder; 200/401 pass, timeout is explicitly skipped, other errors fail. Sandbox Node HTTPS probe reads placeholder from .hermes/.env, calls Discord, accepts 200/401, writes timeout skip artifact, fails other errors. Real sandbox HTTPS/Discord REST path. covered
A19 No local Discord facade/decode proxy/DISCORD_PROXY residue in env, files, /tmp, binaries, or process list. phase-7-no-local-discord-bridge shell probe reproduces legacy env/file/tmp/binary/process checks and expects empty stdout. Real sandbox env/files/process negative checks. covered
A20 Fake Gateway container/scratch are removed before rebuild so Docker build context is readable. Best-effort docker rm -f, fs.rmSync(fakeGateway.dir), and repo .tmp/fake-discord.* cleanup. Real Docker and repo scratch cleanup. covered
A21 nemoclaw <sandbox> rebuild --yes succeeds after NVIDIA_INFERENCE_API_KEY, NVIDIA_API_KEY, and COMPATIBLE_API_KEY are unset; output does not contain provider credential not found. phase-8-rebuild-without-inference-env deletes credential env keys, asserts exit zero and no provider-credential error. Real rebuild and gateway-stored credential reuse. covered
A22 Cleanup destroys sandbox/gateway and registry no longer contains the sandbox unless NEMOCLAW_E2E_KEEP_SANDBOX=1. nemoclaw destroy --yes, gateway destroy, and registry grep expecting ABSENT. Real cleanup/registry boundary. covered

All legacy assertions are covered or intentionally stronger in Vitest. No row is missing, partial, or candidate only.

Contract mapping

  • Legacy assertion family: Hermes Discord install/onboard, schema, provider, placeholder/token isolation, native WebSocket rewrite, REST egress, no local bridge residue, rebuild credential reuse, and cleanup.
    • Replacement: test/e2e-scenario/live/hermes-discord.test.ts assertions A1-A22.
    • Boundary preserved: real bash install.sh, Docker, OpenShell provider/policy, sandbox exec, Hermes Python runtime, fake Discord Gateway, /proc, filesystem scans, Discord REST, and nemoclaw rebuild.

Simplicity check

  • Test shape: simple live Vitest test.
  • Original runner/lane: .github/workflows/nightly-e2e.yaml job hermes-discord-e2e, reusable e2e-script.yaml, default ubuntu-latest, 60 minutes, Docker/OpenShell/Hermes sandbox, NVIDIA_INFERENCE_API_KEY, fake Discord token/env, github_token: true.
  • Replacement runner: .github/workflows/e2e-vitest-scenarios.yaml job hermes-discord-vitest, ubuntu-latest, 75 minutes, same Docker/OpenShell/Hermes/fake Discord boundaries and NVIDIA_INFERENCE_API_KEY.
  • New shared helpers: none; one-off probes stay local to the test and reuse existing phase6-messaging-helpers / fake Discord Docker helper.
  • New framework/registry/ledger: none.
  • Workflow changes: add dispatchable hermes-discord-vitest free-standing Vitest job and workflow-boundary selector validation.
  • Selective dispatch: gh workflow run e2e-vitest-scenarios.yaml --repo NVIDIA/NemoClaw --ref e2e-migrate-test-hermes-discord-vitest -f jobs=hermes-discord-vitest -f pr_number=<PR>.

Pre-push parity gate

  • Legacy script: test/e2e/test-hermes-discord-e2e.sh
  • Assertion rows inventoried: 22
  • Covered/stronger rows: 22
  • Missing/partial/candidate-only rows: 0
  • Direct reference only rows: 0
  • Runner/resource boundary matched: yes — nightly-e2e hermes-discord-e2e ubuntu-latest -> e2e-vitest-scenarios hermes-discord-vitest ubuntu-latest

Verification

  • NEMOCLAW_RUN_E2E_SCENARIOS=1 npx vitest run --project e2e-scenarios-live test/e2e-scenario/live/hermes-discord.test.ts --silent=false --reporter=default (local no-secret gate skips cleanly)
  • npx tsx -e "import {validateE2eVitestScenariosWorkflowBoundary,evaluateE2eVitestWorkflowDispatchSelectors} from './tools/e2e-scenarios/workflow-boundary.mts'; const errors=validateE2eVitestScenariosWorkflowBoundary(); if (errors.length) { console.error(JSON.stringify(errors,null,2)); process.exit(1); } const evalResult=evaluateE2eVitestWorkflowDispatchSelectors({scenarios:'hermes-discord'}); if (!evalResult.valid || evalResult.liveScenariosRuns || evalResult.selectedFreeStandingJobs[0] !== 'hermes-discord-vitest') { console.error(JSON.stringify(evalResult,null,2)); process.exit(1); } console.log('workflow boundary ok');"
  • npm run build:cli
  • git diff --check && git diff --cached --check
  • PR: test(e2e): migrate test-hermes-discord-e2e.sh to vitest #5610
  • Same-runner selective run: https://github.com/NVIDIA/NemoClaw/actions/runs/27983197863 (in_progress)

Summary by CodeRabbit

  • Tests
    • Added a new live end-to-end Vitest scenario for the Discord bridging integration, including gateway/websocket flow validation and strict token/credential safety checks across config, env, processes, and filesystem.
    • Replaced the legacy shell-based Discord scenario with the new Vitest flow.
  • New Features
    • Added a conditional workflow job to run the Hermes Discord scenario based on workflow inputs.
  • CI / Reporting
    • Included the new job in PR reporting and improved scenario selector validation for consistent execution.
    • Uploads scenario artifacts from the run.

@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 4453a9ad-2bf3-4db8-9052-fb2e294af32e

📥 Commits

Reviewing files that changed from the base of the PR and between 048a459 and 94ab960.

📒 Files selected for processing (2)
  • .github/workflows/e2e-vitest-scenarios.yaml
  • tools/e2e-scenarios/workflow-boundary.mts
💤 Files with no reviewable changes (1)
  • tools/e2e-scenarios/workflow-boundary.mts

📝 Walkthrough

Walkthrough

Adds a new live Vitest e2e scenario (hermes-discord.test.ts) that orchestrates a full Hermes Discord bridge sandbox test including fake gateway container lifecycle, token isolation probes, Python gateway proof, and Discord REST boundary checks. Wires a corresponding hermes-discord-vitest CI job into the workflow and registers it in boundary validation.

Changes

Hermes Discord Live E2E Vitest Scenario

Layer / File(s) Summary
Test constants, helpers, and fake gateway lifecycle
test/e2e-scenario/live/hermes-discord.test.ts
Defines sandbox name/token/URL constants, commandEnv/redactions/normalizedCsv helpers, cleanupHermesDiscord, startHermesFakeDiscordGateway, applyHermesFakeDiscordPolicy, and assertDiscordGatewayCapture.
Python gateway proof script and token surface probes
test/e2e-scenario/live/hermes-discord.test.ts
Embeds the HERMES_DISCORD_PYTHON_GATEWAY_PROOF raw script that records WebSocket protocol events; adds runHermesPythonDiscordGatewayProof, assertRawTokenAbsentFromFiles, and rawTokenSurfaceProbe for env/process/filesystem surface scanning.
Main live test scenario orchestration
test/e2e-scenario/live/hermes-discord.test.ts
Implements the main test.skipIf scenario: phased install/health-poll, config/env shape assertions, fake gateway + policy, Python proof, token isolation checks across all surfaces, Discord REST /users/@me with timeout-to-skip, residue probe, rebuild-without-inference assertions, optional destroy/registry-removal, and scenario-result.json write.
CI workflow job and boundary validation
.github/workflows/e2e-vitest-scenarios.yaml, tools/e2e-scenarios/workflow-boundary.mts
Adds hermes-discord-vitest free-standing job with isolated Docker auth, anonymous fallback login, live test execution, and artifact upload; appends it to report-to-pr needs; registers the hermes-discord-vitesthermes-discord selector in validateE2eVitestScenariosWorkflowBoundary.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • NVIDIA/NemoClaw#5605: Both PRs modify .github/workflows/e2e-vitest-scenarios.yaml by adding a new hermes-*-vitest free-standing job and wiring it into the shared report-to-pr needs: list (scenario-specific to Discord vs Slack), so the workflow/reporting changes are directly related.
  • NVIDIA/NemoClaw#5611: Both PRs extend the same "free-standing Vitest job" wiring in e2e-vitest-scenarios.yaml and the workflow-boundary/selector validation logic (adding a scenario→job mapping and including the job in PR reporting), albeit for different scenarios (hermes-discord-vitest vs overlayfs-autofix-vitest).

🐇 A fake gateway hops into place,
Token rewritten without a trace,
Python proof connects with grace,
WebSocket markers win the race—
No raw secret found in any space! 🎉

🚥 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 describes the primary change: migrating a legacy shell-based test to Vitest, which is the main objective of this 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 e2e-migrate-test-hermes-discord-vitest

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

@github-code-quality

github-code-quality Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Overview

Languages: TypeScript

TypeScript / code-coverage/plugin

The overall coverage in the e2e-migrate-test-her... branch is 96%. Coverage data for the main branch is not yet available.

Show a code coverage summary of the most covered files.
File main e2e-migrate-test-her... 94ab960 +/-
nemoclaw/src/se...cret-scanner.ts 100%
nemoclaw/src/commands/slash.ts 100%
nemoclaw/src/li...bprocess-env.ts 100%
nemoclaw/src/bl...eprint/state.ts 98%
nemoclaw/src/onboard/config.ts 98%
nemoclaw/src/bl...int/snapshot.ts 97%
nemoclaw/src/bl...print/runner.ts 95%
nemoclaw/src/co...ration-state.ts 94%
nemoclaw/src/bl...ate-networks.ts 94%
nemoclaw/src/index.ts 94%

TypeScript / code-coverage/cli

The overall coverage in the e2e-migrate-test-her... branch is 46%. Coverage data for the main branch is not yet available.

Show a code coverage summary of the most covered files.
File main e2e-migrate-test-her... 94ab960 +/-
src/lib/state/o...oard-session.ts 91%
src/lib/inference/local.ts 76%
src/lib/sandbox/config.ts 72%
src/lib/actions...dbox/rebuild.ts 67%
src/lib/onboard/preflight.ts 64%
src/lib/actions...licy-channel.ts 56%
src/lib/state/sandbox.ts 55%
src/lib/onboard...er-gpu-patch.ts 50%
src/lib/policy/index.ts 49%
src/lib/onboard.ts 18%

Updated June 23, 2026 01:37 UTC
Code Coverage is in Public Preview. Learn more and provide us with your feedback.

@github-actions

github-actions Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

E2E Advisor Recommendation

Required E2E: hermes-discord-vitest
Optional E2E: hermes-e2e-vitest, messaging-providers-vitest

Dispatch hint: hermes-discord-vitest

Workflow run

Full advisor summary

E2E Recommendation Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required E2E

  • hermes-discord-vitest (high): This PR adds and wires the Hermes Discord live E2E job itself. It should run to validate the new workflow selector, install/onboarding path, Discord credential rewrite boundary, sandbox probes, and rebuild behavior.

Optional E2E

  • hermes-e2e-vitest (high): Useful adjacent confidence for the baseline Hermes live install/onboarding/inference path, but not required because the PR is focused on the Discord-specific scenario and workflow wiring.
  • messaging-providers-vitest (medium): Optional because the new Hermes Discord test reuses messaging provider helper infrastructure and validates provider/gateway behavior; this broader messaging provider suite can catch helper regressions if reviewers want extra confidence.

New E2E recommendations

  • None.

Dispatch hint

  • Workflow: .github/workflows/e2e-vitest-scenarios.yaml
  • jobs input: hermes-discord-vitest

@github-actions

github-actions Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Vitest E2E Scenario Recommendation

Required Vitest E2E scenarios: hermes-discord-vitest
Optional Vitest E2E scenarios: None

Dispatch required Vitest E2E scenarios:

  • gh workflow run e2e-vitest-scenarios.yaml --ref <pr-head-ref> --field jobs=hermes-discord-vitest

Workflow run

Full Vitest E2E advisor summary

Vitest E2E Scenario Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required Vitest E2E scenarios

  • hermes-discord-vitest: Focused free-standing Vitest job wired for changed live test test/e2e-scenario/live/hermes-discord.test.ts.
    • Dispatch: gh workflow run e2e-vitest-scenarios.yaml --ref <pr-head-ref> --field jobs=hermes-discord-vitest

Optional Vitest E2E scenarios

  • None.

Relevant changed files

  • .github/workflows/e2e-vitest-scenarios.yaml
  • test/e2e-scenario/live/hermes-discord.test.ts
  • tools/e2e-scenarios/workflow-boundary.mts

@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

🧹 Nitpick comments (1)
test/e2e-scenario/live/hermes-discord.test.ts (1)

633-635: 🧹 Nitpick | 🔵 Trivial

Consider using a clearer assertion pattern for better readability.

The current code uses expect([200, 401], message).toContain(statusCode), which is valid Vitest syntax (the second argument is a custom error message). However, this pattern reads counterintuitively since it checks if the expected-values array contains the actual status code, rather than checking if the status code is in the allowed values.

For improved clarity, consider using .includes() with a boolean assertion:

💡 Suggested refactor
-      expect([200, 401], `Unexpected Discord users/@me response: ${discordApi.stdout}`).toContain(
-        discordApiResult.statusCode,
-      );
+      expect(
+        [200, 401].includes(discordApiResult.statusCode!),
+        `Unexpected Discord users/@me response (got ${discordApiResult.statusCode}): ${discordApi.stdout}`,
+      ).toBe(true);

This makes the intent more explicit: validating that the status code is one of the allowed values.

🤖 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 `@test/e2e-scenario/live/hermes-discord.test.ts` around lines 633 - 635, The
assertion for validating the Discord API response status code in the
discordApiResult check uses toContain() in a counterintuitive way. Replace the
current pattern where the array of expected status codes is passed to expect()
with toContain checking against the actual status code. Instead, call includes()
directly on the array of allowed status codes to check if
discordApiResult.statusCode is one of the permitted values, then use toBe(true)
to assert the result is truthy. This makes the validation logic more explicit
and easier to understand - it clearly shows you are checking if the status code
is in the allowed values list.
🤖 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.

Inline comments:
In @.github/workflows/e2e-vitest-scenarios.yaml:
- Around line 1663-1668: The "Clean up Docker auth" step uses
`"${DOCKER_CONFIG}"` in the rm -rf command which will fail under `set -u` if
DOCKER_CONFIG is unset. Replace the variable expansion with a defaulted
expansion syntax `"${DOCKER_CONFIG:-}"` to ensure the variable safely expands to
an empty string if unset, preventing the script from failing during cleanup.

In `@test/e2e-scenario/live/hermes-discord.test.ts`:
- Line 441: The codebase growth guardrail flagged 4 conditional statements in
the test file that exceeded acceptable limits. To resolve this, either extract
the conditional logic from the test body into helper functions outside the test
(such as a helper function for the health polling break condition at line 441, a
handleDiscordApiResult or similar function for the timeout/error differentiation
at lines 626-636, and a conditionalCleanup function for the
NEMOCLAW_E2E_KEEP_SANDBOX check at line 706), or alternatively add documentation
comments explaining why each conditional is necessary for the live E2E test
orchestration and request a guardrail exemption from the team for live E2E
scenario test files.

---

Nitpick comments:
In `@test/e2e-scenario/live/hermes-discord.test.ts`:
- Around line 633-635: The assertion for validating the Discord API response
status code in the discordApiResult check uses toContain() in a counterintuitive
way. Replace the current pattern where the array of expected status codes is
passed to expect() with toContain checking against the actual status code.
Instead, call includes() directly on the array of allowed status codes to check
if discordApiResult.statusCode is one of the permitted values, then use
toBe(true) to assert the result is truthy. This makes the validation logic more
explicit and easier to understand - it clearly shows you are checking if the
status code is in the allowed values list.
🪄 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: f340c8eb-eb33-427c-8a16-9cac2d8e2de1

📥 Commits

Reviewing files that changed from the base of the PR and between b241036 and 94c80ba.

📒 Files selected for processing (3)
  • .github/workflows/e2e-vitest-scenarios.yaml
  • test/e2e-scenario/live/hermes-discord.test.ts
  • tools/e2e-scenarios/workflow-boundary.mts

Comment on lines +1663 to +1668
- name: Clean up Docker auth
if: always()
run: |
set -euo pipefail
docker logout docker.io || true
rm -rf "${DOCKER_CONFIG}"

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 | 🟡 Minor | ⚡ Quick win

Guard DOCKER_CONFIG expansion in cleanup path.

Line 1668 can fail under set -u when DOCKER_CONFIG is unset (for example, if earlier steps didn’t export $GITHUB_ENV). Use a defaulted expansion before rm -rf to keep always() cleanup robust.

Suggested fix
       - name: Clean up Docker auth
         if: always()
         run: |
           set -euo pipefail
           docker logout docker.io || true
-          rm -rf "${DOCKER_CONFIG}"
+          if [[ -n "${DOCKER_CONFIG:-}" ]]; then
+            rm -rf "${DOCKER_CONFIG}"
+          fi
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Clean up Docker auth
if: always()
run: |
set -euo pipefail
docker logout docker.io || true
rm -rf "${DOCKER_CONFIG}"
- name: Clean up Docker auth
if: always()
run: |
set -euo pipefail
docker logout docker.io || true
if [[ -n "${DOCKER_CONFIG:-}" ]]; then
rm -rf "${DOCKER_CONFIG}"
fi
🤖 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 @.github/workflows/e2e-vitest-scenarios.yaml around lines 1663 - 1668, The
"Clean up Docker auth" step uses `"${DOCKER_CONFIG}"` in the rm -rf command
which will fail under `set -u` if DOCKER_CONFIG is unset. Replace the variable
expansion with a defaulted expansion syntax `"${DOCKER_CONFIG:-}"` to ensure the
variable safely expands to an empty string if unset, preventing the script from
failing during cleanup.

redactionValues,
timeoutMs: 20_000,
});
if (health.exitCode === 0 && /"ok"/i.test(resultText(health))) break;

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 | 🟡 Minor | ⚡ Quick win

Address pipeline failure: codebase growth guardrails flagged conditional logic.

The CI check test-conditionals:scan failed due to 4 if statements in this test file. The conditionals are:

  1. Line 441: Health polling break condition
  2. Lines 626-636: Discord API timeout/error differentiation
  3. Line 706: NEMOCLAW_E2E_KEEP_SANDBOX conditional cleanup

For a live E2E test with phased orchestration, some conditional logic is necessary. Consider either:

  • Option A: Extract conditionals into helper functions outside the test body (e.g., handleDiscordApiResult(...) and conditionalCleanup(...))
  • Option B: Document why these conditionals are necessary and request a guardrail exemption for live E2E scenario tests

The timeout-to-skip pattern at lines 626-630 explicitly matches legacy shell script behavior per the PR description, which is a valid justification.

Also applies to: 626-636, 706-737

🤖 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 `@test/e2e-scenario/live/hermes-discord.test.ts` at line 441, The codebase
growth guardrail flagged 4 conditional statements in the test file that exceeded
acceptable limits. To resolve this, either extract the conditional logic from
the test body into helper functions outside the test (such as a helper function
for the health polling break condition at line 441, a handleDiscordApiResult or
similar function for the timeout/error differentiation at lines 626-636, and a
conditionalCleanup function for the NEMOCLAW_E2E_KEEP_SANDBOX check at line
706), or alternatively add documentation comments explaining why each
conditional is necessary for the live E2E test orchestration and request a
guardrail exemption from the team for live E2E scenario test files.

Source: Pipeline failures

@github-actions

github-actions Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

PR Review Advisor — Changes requested

Merge posture: Do not merge yet
Primary next action: Resolve or justify PRA-1: New secrets-capable Hermes Discord job reuses a mutable fake Gateway Docker image.
Open items: 0 required · 1 warning · 0 suggestions · 7 test follow-ups
Since last review: 0 prior items resolved · 1 still applies · 0 new items found

Action checklist

  • PRA-1 Resolve or justify: New secrets-capable Hermes Discord job reuses a mutable fake Gateway Docker image in test/e2e-scenario/live/hermes-discord.test.ts:114
  • PRA-T1 Add or justify test follow-up: Runtime validation
  • PRA-T2 Add or justify test follow-up: Runtime validation
  • PRA-T3 Add or justify test follow-up: Runtime validation
  • PRA-T4 Add or justify test follow-up: Runtime validation
  • PRA-T5 Add or justify test follow-up: Runtime validation
  • PRA-T6 Add or justify test follow-up: Acceptance clause
  • PRA-T7 Add or justify test follow-up: Acceptance clause

Findings index

ID Severity Category Location Required action
PRA-1 Resolve/justify security test/e2e-scenario/live/hermes-discord.test.ts:114 Pin the fake Docker API runtime image used by startFakeDockerApi to a trusted digest, or route fake API tests through an already-pinned/local runtime image. If the helper is intentionally shared, update it once so this new test and existing fake API users inherit the pinned image.
Review findings by urgency: 0 required fixes, 1 item to resolve/justify, 0 in-scope improvements

⚠️ Resolve or justify before merge

Investigate these in the current review; either fix them, explain why they are not applicable, or document the accepted risk.

PRA-1 Resolve/justify — New secrets-capable Hermes Discord job reuses a mutable fake Gateway Docker image

  • Location: test/e2e-scenario/live/hermes-discord.test.ts:114
  • Category: security
  • Problem: The new Hermes Discord live test starts its fake Discord Gateway through startFakeDockerApi(...). That shared helper still runs the fake API container from node:22-bookworm-slim by tag rather than by immutable digest, while the new workflow job receives NVIDIA_INFERENCE_API_KEY and Docker Hub credentials and exercises Docker/OpenShell/sandbox lifecycle boundaries.
  • Impact: A compromised or unexpectedly changed node:22-bookworm-slim tag could execute in the CI host Docker context for this new live job and observe the fake service environment, mounted fake-server scripts, and host Docker/network context. This is test-only, but it is on a credential-bearing sandbox/workflow trusted-code boundary.
  • Recommended action: Pin the fake Docker API runtime image used by startFakeDockerApi to a trusted digest, or route fake API tests through an already-pinned/local runtime image. If the helper is intentionally shared, update it once so this new test and existing fake API users inherit the pinned image.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read test/e2e-scenario/live/hermes-discord.test.ts around startHermesFakeDiscordGateway(...) and test/e2e-scenario/live/messaging-providers-helpers.ts around the dockerArgs that append "node:22-bookworm-slim"; confirm the image reference includes an immutable @sha256 digest or an equivalent pinned local image source.
  • Missing regression test: Add or extend a static workflow-boundary/security guard that fails if startFakeDockerApi or the fake API runtime image reference uses a mutable Docker tag instead of an immutable digest.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read test/e2e-scenario/live/hermes-discord.test.ts around startHermesFakeDiscordGateway(...) and test/e2e-scenario/live/messaging-providers-helpers.ts around the dockerArgs that append "node:22-bookworm-slim"; confirm the image reference includes an immutable @sha256 digest or an equivalent pinned local image source.
  • Evidence: The PR adds startHermesFakeDiscordGateway(...) at test/e2e-scenario/live/hermes-discord.test.ts:114, which delegates to startFakeDockerApi. Nearby repository code still appends "node:22-bookworm-slim" in test/e2e-scenario/live/messaging-providers-helpers.ts:565.

💡 In-scope improvements

These are lower-risk, not throwaway. Prefer fixing them in this PR when they are local to changed code; defer only with rationale or a linked follow-up.

  • None.
Test follow-ups to resolve or justify

If these cover changed behavior, prefer adding them in this PR; otherwise state why existing coverage is enough or link the follow-up.

  • PRA-T1 Runtime validation — scenarios=hermes-discord routes only to hermes-discord-vitest and leaves the live-scenarios matrix path empty. The changed behavior spans workflow selection/reporting, installer/onboard behavior, Docker-hosted fake services, OpenShell policy, sandbox network credential rewrite, filesystem/process leak probes, and rebuild credential reuse. Static review confirms the wiring and assertions, but these are live infrastructure boundaries that need behavior-level validation.
  • PRA-T2 Runtime validation — hermes-discord native Gateway proof captures IDENTIFY with tokenMatchesExpected=true and tokenLooksPlaceholder=false while sandbox output includes IDENTIFY_SENT_PLACEHOLDER. The changed behavior spans workflow selection/reporting, installer/onboard behavior, Docker-hosted fake services, OpenShell policy, sandbox network credential rewrite, filesystem/process leak probes, and rebuild credential reuse. Static review confirms the wiring and assertions, but these are live infrastructure boundaries that need behavior-level validation.
  • PRA-T3 Runtime validation — hermes-discord raw token probes return ABSENT for env, process, and filesystem and do not emit FOUND_DISCORD_PROXY. The changed behavior spans workflow selection/reporting, installer/onboard behavior, Docker-hosted fake services, OpenShell policy, sandbox network credential rewrite, filesystem/process leak probes, and rebuild credential reuse. Static review confirms the wiring and assertions, but these are live infrastructure boundaries that need behavior-level validation.
  • PRA-T4 Runtime validation — hermes-discord rebuild succeeds after NVIDIA_INFERENCE_API_KEY, NVIDIA_API_KEY, and COMPATIBLE_API_KEY are removed and output lacks provider credential not found. The changed behavior spans workflow selection/reporting, installer/onboard behavior, Docker-hosted fake services, OpenShell policy, sandbox network credential rewrite, filesystem/process leak probes, and rebuild credential reuse. Static review confirms the wiring and assertions, but these are live infrastructure boundaries that need behavior-level validation.
  • PRA-T5 Runtime validation — fake API runtime image guard rejects mutable Docker tags in startFakeDockerApi. The changed behavior spans workflow selection/reporting, installer/onboard behavior, Docker-hosted fake services, OpenShell policy, sandbox network credential rewrite, filesystem/process leak probes, and rebuild credential reuse. Static review confirms the wiring and assertions, but these are live infrastructure boundaries that need behavior-level validation.
  • PRA-T6 Acceptance clause — Refs Epic: Migrate legacy bash E2E into the Vitest E2E system #5098 — add test evidence or identify existing coverage. The deterministic review context did not include trusted issue Epic: Migrate legacy bash E2E into the Vitest E2E system #5098 body text or comments, so literal linked-issue acceptance clauses could not be extracted. The PR body reference is untrusted evidence only.
  • PRA-T7 Acceptance clause — Refs nemoclaw onboard --agent hermes generates invalid discord configuration #3032 — add test evidence or identify existing coverage. The deterministic review context did not include trusted issue nemoclaw onboard --agent hermes generates invalid discord configuration #3032 body text or comments, so literal linked-issue acceptance clauses could not be extracted. The PR body reference is untrusted evidence only.
Since last review details

Current findings, using the urgency labels above:

PRA-1 Resolve/justify — New secrets-capable Hermes Discord job reuses a mutable fake Gateway Docker image

  • Location: test/e2e-scenario/live/hermes-discord.test.ts:114
  • Category: security
  • Problem: The new Hermes Discord live test starts its fake Discord Gateway through startFakeDockerApi(...). That shared helper still runs the fake API container from node:22-bookworm-slim by tag rather than by immutable digest, while the new workflow job receives NVIDIA_INFERENCE_API_KEY and Docker Hub credentials and exercises Docker/OpenShell/sandbox lifecycle boundaries.
  • Impact: A compromised or unexpectedly changed node:22-bookworm-slim tag could execute in the CI host Docker context for this new live job and observe the fake service environment, mounted fake-server scripts, and host Docker/network context. This is test-only, but it is on a credential-bearing sandbox/workflow trusted-code boundary.
  • Recommended action: Pin the fake Docker API runtime image used by startFakeDockerApi to a trusted digest, or route fake API tests through an already-pinned/local runtime image. If the helper is intentionally shared, update it once so this new test and existing fake API users inherit the pinned image.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read test/e2e-scenario/live/hermes-discord.test.ts around startHermesFakeDiscordGateway(...) and test/e2e-scenario/live/messaging-providers-helpers.ts around the dockerArgs that append "node:22-bookworm-slim"; confirm the image reference includes an immutable @sha256 digest or an equivalent pinned local image source.
  • Missing regression test: Add or extend a static workflow-boundary/security guard that fails if startFakeDockerApi or the fake API runtime image reference uses a mutable Docker tag instead of an immutable digest.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read test/e2e-scenario/live/hermes-discord.test.ts around startHermesFakeDiscordGateway(...) and test/e2e-scenario/live/messaging-providers-helpers.ts around the dockerArgs that append "node:22-bookworm-slim"; confirm the image reference includes an immutable @sha256 digest or an equivalent pinned local image source.
  • Evidence: The PR adds startHermesFakeDiscordGateway(...) at test/e2e-scenario/live/hermes-discord.test.ts:114, which delegates to startFakeDockerApi. Nearby repository code still appends "node:22-bookworm-slim" in test/e2e-scenario/live/messaging-providers-helpers.ts:565.

Workflow run details

This is an automated, non-binding review; it still expects maintainers and agents to respond to each required or warning item. Treat suggestions as current-PR improvements when they touch changed code; defer only with maintainer rationale or a linked follow-up. A human maintainer must make the final merge decision.

@github-actions

Copy link
Copy Markdown
Contributor

Vitest E2E Scenario Results — ✅ All requested jobs passed

Run: 27983197863
Workflow ref: e2e-migrate-test-hermes-discord-vitest
Requested scenarios: (default — all supported)
Requested jobs: hermes-discord-vitest
Summary: 1 passed, 0 failed, 0 cancelled, 0 skipped

Job Result
hermes-discord-vitest ✅ success

@github-actions

Copy link
Copy Markdown
Contributor

Vitest E2E Scenario Results — ⚠️ Run cancelled — no signal

Run: 27983342746
Workflow ref: e2e-migrate-test-hermes-discord-vitest
Requested scenarios: (default — all supported)
Requested jobs: (selector rejected by workflow validation)
Summary: 0 passed, 0 failed, 61 cancelled, 0 skipped

Job Result
agent-turn-latency-vitest ⚠️ cancelled
bedrock-runtime-compatible-anthropic-vitest ⚠️ cancelled
brave-search-vitest ⚠️ cancelled
channels-add-remove-vitest ⚠️ cancelled
channels-stop-start-vitest ⚠️ cancelled
cloud-inference-vitest ⚠️ cancelled
cloud-onboard-vitest ⚠️ cancelled
common-egress-agent-vitest ⚠️ cancelled
concurrent-gateway-ports-vitest ⚠️ cancelled
credential-migration-vitest ⚠️ cancelled
credential-sanitization-vitest ⚠️ cancelled
cron-preflight-inference-local-vitest ⚠️ cancelled
device-auth-health-vitest ⚠️ cancelled
diagnostics-vitest ⚠️ cancelled
double-onboard-vitest ⚠️ cancelled
full-e2e-vitest ⚠️ cancelled
gateway-drift-preflight-vitest ⚠️ cancelled
gateway-guard-recovery ⚠️ cancelled
gateway-health-honest-vitest ⚠️ cancelled
gpu-double-onboard-vitest ⚠️ cancelled
gpu-e2e-vitest ⚠️ cancelled
hermes-discord-vitest ⚠️ cancelled
hermes-e2e-vitest ⚠️ cancelled
hermes-inference-switch-vitest ⚠️ cancelled
hermes-root-entrypoint-smoke-vitest ⚠️ cancelled
inference-routing-vitest ⚠️ cancelled
issue-2478-crash-loop-recovery-vitest ⚠️ cancelled
issue-4434-tui-unreachable-inference-vitest ⚠️ cancelled
issue-4462-scope-upgrade-approval-vitest ⚠️ cancelled
kimi-inference-compat-vitest ⚠️ cancelled
launchable-smoke-vitest ⚠️ cancelled
live-scenarios ⚠️ cancelled
messaging-compatible-endpoint-vitest ⚠️ cancelled
messaging-providers-vitest ⚠️ cancelled
model-router-provider-routed-inference-vitest ⚠️ cancelled
network-policy-vitest ⚠️ cancelled
ollama-auth-proxy-vitest ⚠️ cancelled
onboard-negative-paths-vitest ⚠️ cancelled
onboard-repair-vitest ⚠️ cancelled
onboard-resume-vitest ⚠️ cancelled
openclaw-discord-pairing-vitest ⚠️ cancelled
openclaw-inference-switch-vitest ⚠️ cancelled
openclaw-skill-cli-vitest ⚠️ cancelled
openclaw-slack-pairing-vitest ⚠️ cancelled
openclaw-tui-chat-correlation-vitest ⚠️ cancelled
openshell-version-pin-vitest ⚠️ cancelled
rebuild-hermes-stale-base-vitest ⚠️ cancelled
rebuild-hermes-vitest ⚠️ cancelled
rebuild-openclaw-vitest ⚠️ cancelled
runtime-overrides-vitest ⚠️ cancelled
sandbox-rebuild-vitest ⚠️ cancelled
sandbox-survival-vitest ⚠️ cancelled
sessions-agents-cli-vitest ⚠️ cancelled
shields-config-vitest ⚠️ cancelled
skill-agent-vitest ⚠️ cancelled
snapshot-commands-vitest ⚠️ cancelled
state-backup-restore-vitest ⚠️ cancelled
telegram-injection-vitest ⚠️ cancelled
token-rotation-vitest ⚠️ cancelled
tunnel-lifecycle-vitest ⚠️ cancelled
upgrade-stale-sandbox-vitest ⚠️ cancelled

@github-actions

Copy link
Copy Markdown
Contributor

Vitest E2E Scenario Results — ✅ All requested jobs passed

Run: 27983713604
Workflow ref: e2e-migrate-test-hermes-discord-vitest
Requested scenarios: (default — all supported)
Requested jobs: hermes-discord-vitest
Summary: 1 passed, 0 failed, 0 cancelled, 0 skipped

Job Result
hermes-discord-vitest ✅ success

@github-actions

Copy link
Copy Markdown
Contributor

Vitest E2E Scenario Results — ✅ All requested jobs passed

Run: 27995992856
Workflow ref: e2e-migrate-test-hermes-discord-vitest
Requested scenarios: (default — all supported)
Requested jobs: hermes-discord-vitest
Summary: 1 passed, 0 failed, 0 cancelled, 0 skipped

Job Result
hermes-discord-vitest ✅ success

@jyaunches
jyaunches merged commit 81540e6 into main Jun 23, 2026
111 checks passed
@jyaunches
jyaunches deleted the e2e-migrate-test-hermes-discord-vitest branch June 23, 2026 01:46
@wscurran wscurran added area: e2e End-to-end tests, nightly failures, or validation infrastructure integration: discord Discord integration or channel behavior integration: hermes Hermes integration behavior labels Aug 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: e2e End-to-end tests, nightly failures, or validation infrastructure integration: discord Discord integration or channel behavior integration: hermes Hermes integration behavior

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants