Skip to content

test(e2e): reproduce Hermes shields cycle regression - #6398

Merged
jyaunches merged 3 commits into
mainfrom
codex/hermes-shields-live-e2e
Jul 7, 2026
Merged

test(e2e): reproduce Hermes shields cycle regression#6398
jyaunches merged 3 commits into
mainfrom
codex/hermes-shields-live-e2e

Conversation

@jyaunches

@jyaunches jyaunches commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a CPU-only live E2E that reproduces the fresh Hermes shields lifecycle regression from #6381. The test onboards a new non-root Hermes sandbox, runs shields down/up twice, and preserves the failure as a dedicated E2E lane until #6384 lands.

Related Issue

Relates to #6381.

Depends on #6384.

Changes

  • Add a fresh Hermes onboard and two-cycle shields down/up live regression test.
  • Assert the mutable and locked ownership/mode contracts after each transition.
  • Add a dedicated hermes-shields-config workflow job that requires no GPU or hosted inference secret.
  • Extend the E2E artifact workflow boundary for the new job.

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)

Quality Gates

  • Tests added or updated for changed behavior
  • Existing tests cover changed behavior — justification:
  • Tests not applicable — justification:
  • Docs updated for user-facing behavior changes
  • Docs not applicable — justification: test and CI coverage only; no user-facing behavior changes
  • Sensitive paths changed (security, policy, credentials, preflight, onboarding, inference, runner, sandbox, or messaging)
  • Sensitive-path review completed or maintainer-approved waiver recorded — reviewer/approval link/justification:
  • Non-success, skipped, or missing CI check accepted by maintainer — check name, approval link, and follow-up issue:

Verification

  • PR description includes the DCO sign-off declaration and every commit appears as Verified in GitHub
  • Normal pre-commit, commit-msg, and pre-push hooks passed, or npm run check:diff passed when hooks were skipped or unavailable
  • Targeted behavior tests pass for the current change set, or tests are marked not applicable above — command/result or justification: E2E workflow support tests passed (24/24), and the live target collects successfully; the live run is intentionally expected to reproduce [Ubuntu 24.04][Sandbox] nemohermes shields down fails on fresh Hermes sandbox — strict hash verification failed for Hermes restart seal #6381 on current main
  • Applicable broad gate passed — npm test for broad runtime/test-harness changes; npm run check for repo-wide validation/coverage changes — command/result:
  • Quality Gates section completed with required justifications or waivers
  • No secrets, API keys, or credentials committed
  • npm run 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: Julie Yaunches jyaunches@nvidia.com

Summary by CodeRabbit

  • New Features
    • Added a new Hermes live end-to-end check that runs repeated shields cycles in a fresh non-root sandbox.
    • Updated PR reporting so the new live job is included in the results summary.
  • Bug Fixes
    • Updated E2E artifact upload workflow boundary validations to match the current number of expected E2E execution jobs and default callers.

Signed-off-by: Julie Yaunches <jyaunches@nvidia.com>
@jyaunches jyaunches self-assigned this Jul 7, 2026
@copy-pr-bot

copy-pr-bot Bot commented Jul 7, 2026

Copy link
Copy Markdown

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

Contributors can view more details about this message here.

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a new hermes-shields-config live E2E test for Hermes shields cycles and config-hash stability, adds a matching CI job and PR reporting wiring, and updates workflow-boundary validation counts and assertions for the added job.

Changes

Hermes shields-config E2E test and CI wiring

Layer / File(s) Summary
Test helpers and posture checks
test/e2e/live/hermes-shields-config.test.ts
Adds test constants, environment setup, sandbox/shields helpers, and filesystem posture assertions for mutable and locked states.
End-to-end Hermes shields scenario
test/e2e/live/hermes-shields-config.test.ts
Implements the full Hermes sandbox test that starts the fake inference server, verifies Ready state and config-hash stability, runs two shields cycles, and registers cleanup.
Workflow job and validator updates
.github/workflows/e2e.yaml, tools/e2e/upload-e2e-artifacts-workflow-boundary.mts, test/e2e/support/upload-e2e-artifacts-workflow-boundary.test.ts
Adds the hermes-shields-config workflow job, includes it in report-to-pr, and updates the expected execution-job and default-caller counts in validation logic and tests.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Test as hermes-shields-config.test.ts
  participant FakeServer as fake OpenAI-compatible server
  participant Sandbox as Hermes sandbox
  participant Gateway as gateway

  Test->>FakeServer: start server
  Test->>Sandbox: install and onboard Hermes
  Test->>Sandbox: verify Phase: Ready
  Test->>Sandbox: capture initial config hash
  loop two shields cycles
    Test->>Sandbox: run shields down
    Sandbox-->>Test: DOWN state
    Test->>Sandbox: run shields up
    Sandbox-->>Test: UP state
  end
  Test->>Sandbox: re-read config hash and verify unchanged
  Test->>Gateway: destroy sandbox and gateway
Loading

Suggested labels: area: e2e, bug-fix, integration: hermes

Suggested reviewers: ericksoa, cv

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: a test(e2e) update to reproduce the Hermes shields cycle regression.
✨ 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 codex/hermes-shields-live-e2e

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

@github-code-quality

github-code-quality Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Overview

Languages: TypeScript

TypeScript / code-coverage/plugin

The overall coverage in the codex/hermes-shields... 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 codex/hermes-shields... 0076b5d +/-
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 codex/hermes-shields... branch is 75%. Coverage data for the main branch is not yet available.

Show a code coverage summary of the most covered files.
File main codex/hermes-shields... 0076b5d +/-
src/lib/shields...nsition-lock.ts 85%
src/lib/onboard/preflight.ts 83%
src/lib/actions...all/run-plan.ts 81%
src/lib/state/o...oard-session.ts 80%
src/lib/actions...licy-channel.ts 79%
src/lib/state/sandbox.ts 75%
src/lib/onboard...er-gpu-patch.ts 69%
src/lib/shields/index.ts 68%
src/lib/policy/index.ts 66%
src/lib/onboard.ts 28%

Updated July 07, 2026 14:57 UTC
Code Coverage is in Public Preview. Learn more and provide us with your feedback.

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

E2E Advisor Recommendation

Required E2E: hermes-shields-config, cloud-onboard
Optional E2E: shields-config

Dispatch hint: hermes-shields-config

Workflow run

Full advisor summary

E2E Recommendation Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required E2E

  • hermes-shields-config (medium): This PR introduces and wires the hermes-shields-config live job. Run it to prove the new workflow target, fresh Hermes onboard path, sandbox lifecycle, shields down/up transitions, fake inference endpoint routing, and default artifact upload integration all work in CI.
  • cloud-onboard (high): Changed onboard, trace timing, scorecard, or E2E workflow code can affect cloud onboard wall-clock behavior and should refresh the trusted cloud-onboard trace timing signal.

Optional E2E

  • shields-config (medium): Adjacent confidence check for the existing OpenClaw shields/config live path. Useful if reviewers want to compare the new Hermes-specific shields regression against the established shields-config target, but the PR does not modify shared runtime shields code.

New E2E recommendations

  • None.

Dispatch hint

  • Workflow: .github/workflows/e2e.yaml
  • jobs input: hermes-shields-config

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

E2E Target Recommendation

Required E2E targets: hermes-shields-config
Optional E2E targets: None

Dispatch required E2E targets:

  • gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=hermes-shields-config

Workflow run

Full E2E target advisor summary

E2E Target Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required E2E targets

  • hermes-shields-config: Focused free-standing E2E job wired for changed live test test/e2e/live/hermes-shields-config.test.ts.
    • Dispatch: gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=hermes-shields-config

Optional E2E targets

  • None.

Relevant changed files

  • .github/workflows/e2e.yaml
  • test/e2e/live/hermes-shields-config.test.ts
  • test/e2e/support/upload-e2e-artifacts-workflow-boundary.test.ts
  • tools/e2e/upload-e2e-artifacts-workflow-boundary.mts

@jyaunches

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

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.

@github-actions

github-actions Bot commented Jul 7, 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: Assert the auth-required fake inference endpoint is exercised.
Open items: 0 required · 1 warning · 0 suggestions · 5 test follow-ups
Since last review: 0 prior items resolved · 1 still applies · 0 new items found

Action checklist

  • PRA-1 Resolve or justify: Assert the auth-required fake inference endpoint is exercised in test/e2e/live/hermes-shields-config.test.ts:172
  • 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: Acceptance clause

Findings index

ID Severity Category Location Required action
PRA-1 Resolve/justify security test/e2e/live/hermes-shields-config.test.ts:172 After the fresh onboard/status checks, assert over fake.requests(): filter POSTs to /v1/chat/completions, /chat/completions, /v1/responses, or /responses; require at least one request with auth === "ok" and model === COMPATIBLE_MODEL when a model is recorded; and reject unauthenticated inference posts. Consider also asserting the serialized fake requests do not contain any known placeholder tokens if this test gains extra marker values.
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 — Assert the auth-required fake inference endpoint is exercised

  • Location: test/e2e/live/hermes-shields-config.test.ts:172
  • Category: security
  • Problem: The test starts a fake OpenAI-compatible endpoint with requireAuth enabled and passes fake.baseUrl into the fresh Hermes onboard, but it only writes fake.requests() during cleanup. There is no assertion that onboarding made an authenticated inference POST to the fake endpoint for hermes-shields-e2e-model.
  • Impact: A regression where Hermes skips provider validation, uses the wrong endpoint or model, falls back to another provider, or only performs unauthenticated/failed requests could still pass the shields-cycle and config-hash assertions. That creates false confidence in the new hermetic provider/auth boundary coverage.
  • Recommended action: After the fresh onboard/status checks, assert over fake.requests(): filter POSTs to /v1/chat/completions, /chat/completions, /v1/responses, or /responses; require at least one request with auth === "ok" and model === COMPATIBLE_MODEL when a model is recorded; and reject unauthenticated inference posts. Consider also asserting the serialized fake requests do not contain any known placeholder tokens if this test gains extra marker values.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read test/e2e/live/hermes-shields-config.test.ts after startFakeOpenAiCompatibleServer(...) and compare with test/e2e/live/hermes-gpu-startup.test.ts, which filters fake.requests() and asserts authenticated fake inference POSTs instead of only recording cleanup artifacts.
  • Missing regression test: Extend the existing test named "hermes-shields-config: fresh non-root Hermes sandbox completes two shields cycles ([Ubuntu 24.04][Sandbox] nemohermes shields down fails on fresh Hermes sandbox — strict hash verification failed for Hermes restart seal #6381)" so it fails when the fake endpoint receives zero authenticated inference POSTs for hermes-shields-e2e-model, or when any inference POST to the accepted completion/response paths has auth other than "ok".
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read test/e2e/live/hermes-shields-config.test.ts after startFakeOpenAiCompatibleServer(...) and compare with test/e2e/live/hermes-gpu-startup.test.ts, which filters fake.requests() and asserts authenticated fake inference POSTs instead of only recording cleanup artifacts.
  • Evidence: startFakeOpenAiCompatibleServer({ apiKey: COMPATIBLE_API_KEY, model: COMPATIBLE_MODEL, requireAuth: true }) is created, commandEnv(fake.baseUrl) is passed to install.sh, but fake.requests() is only consumed in the cleanup callback that writes fake-openai-compatible-requests.json.

💡 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 — Assert hermes-shields-config fresh onboard sends at least one authenticated fake inference POST for hermes-shields-e2e-model to an accepted OpenAI-compatible completion/response path.. The meaningful changed behavior crosses Docker, install.sh, OpenShell sandbox lifecycle, a sandbox-reachable fake OpenAI-compatible endpoint, Hermes startup, real nemohermes shields transitions, and workflow selector/reporting boundaries. Static review confirms the test and boundary coverage exist, but cannot prove runtime sandbox behavior.
  • PRA-T2 Runtime validation — Runtime validate that the first nemohermes shields down on a fresh non-root Hermes sandbox reconciles the hash anchor and that a second down/up preserves the original /sandbox/.hermes/config.yaml SHA-256.. The meaningful changed behavior crosses Docker, install.sh, OpenShell sandbox lifecycle, a sandbox-reachable fake OpenAI-compatible endpoint, Hermes startup, real nemohermes shields transitions, and workflow selector/reporting boundaries. Static review confirms the test and boundary coverage exist, but cannot prove runtime sandbox behavior.
  • PRA-T3 Runtime validation — Identify existing boundary coverage or add a direct selector test proving both jobs=hermes-shields-config and targets=hermes-shields-config select the new free-standing workflow job without falling through to the live matrix.. The meaningful changed behavior crosses Docker, install.sh, OpenShell sandbox lifecycle, a sandbox-reachable fake OpenAI-compatible endpoint, Hermes startup, real nemohermes shields transitions, and workflow selector/reporting boundaries. Static review confirms the test and boundary coverage exist, but cannot prove runtime sandbox behavior.
  • PRA-T4 Runtime validation — If deterministic linked issue clauses become available, map each [Ubuntu 24.04][Sandbox] nemohermes shields down fails on fresh Hermes sandbox — strict hash verification failed for Hermes restart seal #6381 clause/comment to the new live test assertions or add the missing behavior-specific coverage.. The meaningful changed behavior crosses Docker, install.sh, OpenShell sandbox lifecycle, a sandbox-reachable fake OpenAI-compatible endpoint, Hermes startup, real nemohermes shields transitions, and workflow selector/reporting boundaries. Static review confirms the test and boundary coverage exist, but cannot prove runtime sandbox behavior.
  • PRA-T5 Acceptance clause — No deterministic linked issue clauses or issue comments were available for this review. — add test evidence or identify existing coverage. The validation context reported linkedIssues: []. PR body references issue numbers, but PR-provided text is untrusted for literal acceptance extraction. Diff evidence still shows a fresh Hermes onboard, two shields down/up cycles, config hash preservation, a new workflow job, and updated artifact-upload boundary counts.
Since last review details

Current findings, using the urgency labels above:

PRA-1 Resolve/justify — Assert the auth-required fake inference endpoint is exercised

  • Location: test/e2e/live/hermes-shields-config.test.ts:172
  • Category: security
  • Problem: The test starts a fake OpenAI-compatible endpoint with requireAuth enabled and passes fake.baseUrl into the fresh Hermes onboard, but it only writes fake.requests() during cleanup. There is no assertion that onboarding made an authenticated inference POST to the fake endpoint for hermes-shields-e2e-model.
  • Impact: A regression where Hermes skips provider validation, uses the wrong endpoint or model, falls back to another provider, or only performs unauthenticated/failed requests could still pass the shields-cycle and config-hash assertions. That creates false confidence in the new hermetic provider/auth boundary coverage.
  • Recommended action: After the fresh onboard/status checks, assert over fake.requests(): filter POSTs to /v1/chat/completions, /chat/completions, /v1/responses, or /responses; require at least one request with auth === "ok" and model === COMPATIBLE_MODEL when a model is recorded; and reject unauthenticated inference posts. Consider also asserting the serialized fake requests do not contain any known placeholder tokens if this test gains extra marker values.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read test/e2e/live/hermes-shields-config.test.ts after startFakeOpenAiCompatibleServer(...) and compare with test/e2e/live/hermes-gpu-startup.test.ts, which filters fake.requests() and asserts authenticated fake inference POSTs instead of only recording cleanup artifacts.
  • Missing regression test: Extend the existing test named "hermes-shields-config: fresh non-root Hermes sandbox completes two shields cycles ([Ubuntu 24.04][Sandbox] nemohermes shields down fails on fresh Hermes sandbox — strict hash verification failed for Hermes restart seal #6381)" so it fails when the fake endpoint receives zero authenticated inference POSTs for hermes-shields-e2e-model, or when any inference POST to the accepted completion/response paths has auth other than "ok".
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read test/e2e/live/hermes-shields-config.test.ts after startFakeOpenAiCompatibleServer(...) and compare with test/e2e/live/hermes-gpu-startup.test.ts, which filters fake.requests() and asserts authenticated fake inference POSTs instead of only recording cleanup artifacts.
  • Evidence: startFakeOpenAiCompatibleServer({ apiKey: COMPATIBLE_API_KEY, model: COMPATIBLE_MODEL, requireAuth: true }) is created, commandEnv(fake.baseUrl) is passed to install.sh, but fake.requests() is only consumed in the cleanup callback that writes fake-openai-compatible-requests.json.

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

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

E2E Target Results — ❌ Some jobs failed

Run: 28874332234
Workflow ref: codex/hermes-shields-live-e2e
Requested targets: (default — all supported)
Requested jobs: hermes-shields-config
Summary: 0 passed, 1 failed, 0 cancelled, 0 skipped

Job Result
hermes-shields-config ❌ failure

Failed jobs: hermes-shields-config. Check run artifacts for logs.

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

PR Review Advisor (Nemotron Ultra) — Blocked

Merge posture: Do not merge until addressed
Primary next action: Fix PRA-3: Missing drift detection test — no host-root tamper parity with OpenClaw test; then add or justify PRA-T1.
Open items: 4 required · 5 warnings · 2 suggestions · 8 test follow-ups
Since last review: 1 prior item resolved · 8 still apply · 3 new items found

Action checklist

  • PRA-3 Fix: Missing drift detection test — no host-root tamper parity with OpenClaw test in test/e2e/live/hermes-shields-config.test.ts:148
  • PRA-4 Fix: cleanupGatewayRegistration silent catch swallows all errors in test/e2e/live/hermes-shields-config.test.ts:57
  • PRA-5 Fix: bestEffortCleanupSandbox silent catch swallows sandbox destroy errors in test/e2e/fixtures/clients/host.ts:154
  • PRA-6 Fix: No negative tests for invalid shields sequences in test/e2e/live/hermes-shields-config.test.ts:148
  • PRA-1 Resolve or justify: Source-of-truth review needed: test/e2e/live/hermes-shields-config.test.ts:57 — cleanupGatewayRegistration silent catch
  • PRA-2 Resolve or justify: Source-of-truth review needed: test/e2e/fixtures/clients/host.ts:154-161 — bestEffortCleanupSandbox empty catch
  • PRA-7 Resolve or justify: Fake OpenAI server binds to 0.0.0.0 instead of 127.0.0.1 in test/e2e/live/hermes-shields-config.test.ts:174
  • PRA-8 Resolve or justify: Hardcoded job counts conflict with 4 overlapping PRs in tools/e2e/upload-e2e-artifacts-workflow-boundary.mts:44
  • PRA-9 Resolve or justify: Missing audit trail and auto-restore timer coverage (OpenClaw parity) in test/e2e/live/hermes-shields-config.test.ts:218
  • 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: Missing drift detection test — no host-root tamper parity with OpenClaw test
  • PRA-T7 Add or justify test follow-up: No negative tests for invalid shields sequences
  • PRA-T8 Add or justify test follow-up: Missing audit trail and auto-restore timer coverage (OpenClaw parity)
  • PRA-10 In-scope improvement: Single-use env-config constants can be inlined in test/e2e/live/hermes-shields-config.test.ts:18
  • PRA-11 In-scope improvement: Redundant pre-cleanup call duplicates cleanupRegistry entry in test/e2e/live/hermes-shields-config.test.ts:101

Findings index

ID Severity Category Location Required action
PRA-1 Resolve/justify architecture Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
PRA-2 Resolve/justify architecture Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
PRA-3 Required tests test/e2e/live/hermes-shields-config.test.ts:148 Add a drift detection sub-test or phase that performs host-root tamper (docker exec -u 0 chmod/write/chmod on CONFIG_PATH) and verifies shields status detects content drift, matching OpenClaw test coverage.
PRA-4 Required security test/e2e/live/hermes-shields-config.test.ts:57 Replace silent catch with artifact logging: `.catch(err => { await artifacts.writeText('gateway-cleanup-error.txt', err.message); })` so failures are visible while test continues.
PRA-5 Required security test/e2e/fixtures/clients/host.ts:154 Modify bestEffortCleanupSandbox to accept an artifacts parameter and write failures to artifact, or return a Result type. At minimum, log the error at debug level.
PRA-6 Required tests test/e2e/live/hermes-shields-config.test.ts:148 Add negative test cases in same file covering the four scenarios above, mirroring OpenClaw test phases 10-11.
PRA-7 Resolve/justify security test/e2e/live/hermes-shields-config.test.ts:174 Change host parameter to '127.0.0.1' and update publicHost accordingly, or justify why 0.0.0.0 is required for OpenShell internal networking.
PRA-8 Resolve/justify workflow tools/e2e/upload-e2e-artifacts-workflow-boundary.mts:44 Refactor validateUploadE2eArtifactsInvocations to compute expected counts dynamically from workflow YAML structure instead of hardcoded constants.
PRA-9 Resolve/justify tests test/e2e/live/hermes-shields-config.test.ts:218 Add audit trail verification (JSONL entries, no secrets) and dead timer inline restore test phase mirroring OpenClaw phases 8-9.
PRA-10 Improvement scope test/e2e/live/hermes-shields-config.test.ts:18 Replace with constants: `const SANDBOX_NAME = 'e2e-hermes-shields'; const GATEWAY_NAME = 'nemoclaw';` and remove process.env reads.
PRA-11 Improvement scope test/e2e/live/hermes-shields-config.test.ts:101 Remove the explicit `await cleanup(host, "pre-cleanup")` line; rely solely on cleanupRegistry for both pre and post cleanup (or use test.before/after hooks).

🚨 Required before merge

Address these before merging unless a maintainer explicitly overrides the advisor with rationale.

PRA-3 Required — Missing drift detection test — no host-root tamper parity with OpenClaw test

  • Location: test/e2e/live/hermes-shields-config.test.ts:148
  • Category: tests
  • Problem: OpenClaw shields-config.test.ts (lines 350-400) tests host-root chmod-write-chmod tamper detection: after shields-up, docker exec -u 0 modifies config, refreshes hash, then shields status shows 'UP (DRIFTED)' and shields up refuses re-seal. Hermes test has zero equivalent coverage. A regression in Hermes drift detection would not be caught.
  • Impact: Hermes shields drift detection regression would go undetected; security posture parity not achieved. Host-root config tamper could silently persist.
  • Required action: Add a drift detection sub-test or phase that performs host-root tamper (docker exec -u 0 chmod/write/chmod on CONFIG_PATH) and verifies shields status detects content drift, matching OpenClaw test coverage.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: Compare test/e2e/live/shields-config.test.ts phase-5b-host-root-tamper through phase-5b-shields-up-refuses-tamper with hermes-shields-config.test.ts; verify equivalent tamper+detect+refuse sequence exists
  • Missing regression test: Hermes shields drift detection: host-root tamper to config.yaml detected as content drift after shields-up; shields status returns 'UP (DRIFTED)' and shields up refuses with 'Refusing to re-seal'
  • Done when: The required change is committed and verification passes: Compare test/e2e/live/shields-config.test.ts phase-5b-host-root-tamper through phase-5b-shields-up-refuses-tamper with hermes-shields-config.test.ts; verify equivalent tamper+detect+refuse sequence exists.
  • Evidence: shields-config.test.ts lines 350-400 test gateway write + hash refresh + shields-up drift detection; hermes-shields-config.test.ts has no equivalent tamper/detection/refusal phases

PRA-4 Required — cleanupGatewayRegistration silent catch swallows all errors

  • Location: test/e2e/live/hermes-shields-config.test.ts:57
  • Category: security
  • Problem: Line 57: `await host.cleanupGatewayRegistration(GATEWAY_NAME, {...}).catch(() => undefined);` — any failure in gateway cleanup (gateway not found, openshell command failure, legacy destroy fallback failure) is silently ignored. Gateway registration leakage can expose credentials, cause port conflicts, and leave stale OpenShell state.
  • Impact: Gateway cleanup failures invisible in CI artifacts; credential leakage risk; port conflicts on re-run; stale gateway state pollutes subsequent test runs.
  • Required action: Replace silent catch with artifact logging: `.catch(err => { await artifacts.writeText('gateway-cleanup-error.txt', err.message); })` so failures are visible while test continues.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: Read test/e2e/live/hermes-shields-config.test.ts line 57; verify .catch() logs error to artifact instead of swallowing
  • Missing regression test: Mock cleanupGatewayRegistration to fail; verify error artifact 'gateway-cleanup-error.txt' is written with error message
  • Done when: The required change is committed and verification passes: Read test/e2e/live/hermes-shields-config.test.ts line 57; verify .catch() logs error to artifact instead of swallowing.
  • Evidence: cleanup() function: await host.cleanupGatewayRegistration(...).catch(() => undefined);

PRA-5 Required — bestEffortCleanupSandbox silent catch swallows sandbox destroy errors

  • Location: test/e2e/fixtures/clients/host.ts:154
  • Category: security
  • Problem: host.ts lines 154-161: `bestEffortCleanupSandbox` wraps `cleanupSandbox` in try/catch with empty catch block. Sandbox destroy failures (not found, busy, Docker errors) are completely hidden. This is shared infrastructure used by multiple tests.
  • Impact: Sandbox leakage between test runs; resource exhaustion; state pollution; hidden sandbox escape vectors; credential files left in stale sandboxes.
  • Required action: Modify bestEffortCleanupSandbox to accept an artifacts parameter and write failures to artifact, or return a Result type. At minimum, log the error at debug level.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: Read test/e2e/fixtures/clients/host.ts lines 154-161; verify catch block logs error instead of empty
  • Missing regression test: Mock destroySandbox to throw; verify error artifact written (e.g., 'sandbox-cleanup-error.txt') and test continues
  • Done when: The required change is committed and verification passes: Read test/e2e/fixtures/clients/host.ts lines 154-161; verify catch block logs error instead of empty.
  • Evidence: async bestEffortCleanupSandbox(...) { try { await this.cleanupSandbox(...) } catch { } }

PRA-6 Required — No negative tests for invalid shields sequences

  • Location: test/e2e/live/hermes-shields-config.test.ts:148
  • Category: tests
  • Problem: No tests for: (1) run shields down twice, expect second to fail; (2) run shields up twice, expect second to fail; (3) run shields up when already UP, expect failure; (4) run shields down when already DOWN, expect failure. OpenClaw test has these (phases 10-11).
  • Impact: State machine transition bugs (double operations, wrong-state operations) would not be caught. Regression in Hermes shields state validation would go undetected.
  • Required action: Add negative test cases in same file covering the four scenarios above, mirroring OpenClaw test phases 10-11.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: Search hermes-shields-config.test.ts for double down/up, wrong-state tests — none exist
  • Missing regression test: Four negative tests: double shields-down rejected, double shields-up rejected, shields-up-when-UP rejected, shields-down-when-DOWN rejected
  • Done when: The required change is committed and verification passes: Search hermes-shields-config.test.ts for double down/up, wrong-state tests — none exist.
  • Evidence: hermes-shields-config.test.ts only tests happy path (two successful cycles); no error-path assertions
Review findings by urgency: 4 required fixes, 5 items to resolve/justify, 2 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 — Source-of-truth review needed: test/e2e/live/hermes-shields-config.test.ts:57 — cleanupGatewayRegistration silent catch

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as missing.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: Mock cleanupGatewayRegistration to fail; verify error artifact 'gateway-cleanup-error.txt' is written with error message
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: cleanup() function: await host.cleanupGatewayRegistration(...).catch(() => undefined); source method already handles expected errors properly

PRA-2 Resolve/justify — Source-of-truth review needed: test/e2e/fixtures/clients/host.ts:154-161 — bestEffortCleanupSandbox empty catch

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: Mock destroySandbox to throw; verify error artifact written (e.g., 'sandbox-cleanup-error.txt') and test continues
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: async bestEffortCleanupSandbox(...) { try { await this.cleanupSandbox(...) } catch { } }

PRA-7 Resolve/justify — Fake OpenAI server binds to 0.0.0.0 instead of 127.0.0.1

  • Location: test/e2e/live/hermes-shields-config.test.ts:174
  • Category: security
  • Problem: Line 174: `host: "0.0.0.0"` passed to startFakeOpenAiCompatibleServer. The server binds all interfaces. readinessProbeHost() converts to 127.0.0.1 for health checks but server still binds 0.0.0.0. Systemic pattern (15+ files), but PR adds new instance.
  • Impact: Network exposure in CI; potential SSRF vector if sandbox network policy misconfigured; violates least-privilege binding.
  • Recommended action: Change host parameter to '127.0.0.1' and update publicHost accordingly, or justify why 0.0.0.0 is required for OpenShell internal networking.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read test/e2e/live/hermes-shields-config.test.ts line 174; verify host: '0.0.0.0'; check fixtures/fake-openai-compatible.ts readinessProbeHost conversion
  • Missing regression test: Verify fake server binds only localhost: netstat -tlnp shows 127.0.0.1:PORT not 0.0.0.0:PORT
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read test/e2e/live/hermes-shields-config.test.ts line 174; verify host: '0.0.0.0'; check fixtures/fake-openai-compatible.ts readinessProbeHost conversion.
  • Evidence: startFakeOpenAiCompatibleServer called with host: "0.0.0.0"; readinessProbeHost converts but server binds original host

PRA-8 Resolve/justify — Hardcoded job counts conflict with 4 overlapping PRs

  • Location: tools/e2e/upload-e2e-artifacts-workflow-boundary.mts:44
  • Category: workflow
  • Problem: EXPECTED_UPLOAD_JOB_COUNT=74 and EXPECTED_DEFAULT_CALLER_COUNT=63 are hardcoded constants. Four overlapping PRs (fix(onboard): diagnose incomplete custom plugin images #6250, feat(gpu): prefer native OpenShell with compatibility fallback #6333, feat(performance): add progressive disclosure tests and compositional routing acceptance #6341, test(e2e): cover v0.0.55 gateway upgrades #6397) modify the same workflow + boundary files. Each PR increments counts independently — guaranteed merge conflicts and validation failures.
  • Impact: Merge conflicts on every PR; validation tool fails when counts drift; manual coordination required; fragile workflow boundary enforcement.
  • Recommended action: Refactor validateUploadE2eArtifactsInvocations to compute expected counts dynamically from workflow YAML structure instead of hardcoded constants.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Check EXPECTED_UPLOAD_JOB_COUNT=74 in tools/e2e/upload-e2e-artifacts-workflow-boundary.mts:44; verify 4 PRs modify same constants
  • Missing regression test: Validation tool computes correct job count from workflow YAML without hardcoded constants; adding/removing jobs updates count automatically
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Check EXPECTED_UPLOAD_JOB_COUNT=74 in tools/e2e/upload-e2e-artifacts-workflow-boundary.mts:44; verify 4 PRs modify same constants.
  • Evidence: Constants at lines 44-45; 4 overlapping PRs identified in drift context modifying same files

PRA-9 Resolve/justify — Missing audit trail and auto-restore timer coverage (OpenClaw parity)

  • Location: test/e2e/live/hermes-shields-config.test.ts:218
  • Category: tests
  • Problem: OpenClaw test has phase-8-audit-trail (JSONL, no secrets), phase-9-dead-timer-inline-restore (dead timer triggers inline recovery, config re-locked, .config-hash restored). Hermes test has neither.
  • Impact: Audit trail regression (secret leakage, missing entries) not caught. Auto-restore timer dead-path recovery not validated.
  • Recommended action: Add audit trail verification (JSONL entries, no secrets) and dead timer inline restore test phase mirroring OpenClaw phases 8-9.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Compare shields-config.test.ts phase-8-audit-summary through phase-9-config-hash-perms-after-dead-timer-inline-restore with hermes test
  • Missing regression test: Audit JSONL contains shields_up/shields_down entries with no API keys; dead timer kills process, inline restore re-locks config and .config-hash, state file has correct fileHashes
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Compare shields-config.test.ts phase-8-audit-summary through phase-9-config-hash-perms-after-dead-timer-inline-restore with hermes test.
  • Evidence: hermes-shields-config.test.ts has no audit file checks, no timer manipulation, no inline restore validation

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

PRA-10 Improvement — Single-use env-config constants can be inlined

  • Location: test/e2e/live/hermes-shields-config.test.ts:18
  • Category: scope
  • Problem: SANDBOX_NAME and GATEWAY_NAME read from process.env with fallbacks but are never overridden in CI or locally. They are effectively constants.
  • Impact: Unnecessary indirection; suggests configurability that doesn't exist; clutters test setup.
  • Suggested action: Replace with constants: `const SANDBOX_NAME = 'e2e-hermes-shields'; const GATEWAY_NAME = 'nemoclaw';` and remove process.env reads.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Read lines 18-19; verify no test or CI sets NEMOCLAW_SANDBOX_NAME or OPENSHELL_GATEWAY differently
  • Missing regression test: N/A — simplification, no behavior change
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: const SANDBOX_NAME = process.env.NEMOCLAW_SANDBOX_NAME ?? "e2e-hermes-shields"; const GATEWAY_NAME = process.env.OPENSHELL_GATEWAY ?? "nemoclaw";

PRA-11 Improvement — Redundant pre-cleanup call duplicates cleanupRegistry entry

  • Location: test/e2e/live/hermes-shields-config.test.ts:101
  • Category: scope
  • Problem: Line 101: `await cleanup(host, "pre-cleanup");` runs before test setup. cleanupRegistry already adds post-test cleanup for sandbox and gateway. Pre-cleanup duplicates effort and can mask setup failures.
  • Impact: Wasted time; pre-cleanup failure could obscure real setup issue; cleanupRegistry already guarantees post-test cleanup.
  • Suggested action: Remove the explicit `await cleanup(host, "pre-cleanup")` line; rely solely on cleanupRegistry for both pre and post cleanup (or use test.before/after hooks).
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Read line 101; verify cleanupRegistry.add for sandbox destroy already covers pre-cleanup need
  • Missing regression test: N/A — simplification, no behavior change
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: Line 101: await cleanup(host, "pre-cleanup"); cleanupRegistry.add already registers destroy for same sandbox/gateway
Simplification opportunities: 2 possible cuts, net -1 lines possible

These are safe simplification checks only. Do not remove validation, security controls, data-loss prevention, or required tests.

  • PRA-10 shrink (test/e2e/live/hermes-shields-config.test.ts:18): process.env.NEMOCLAW_SANDBOX_NAME ?? "e2e-hermes-shields" and process.env.OPENSHELL_GATEWAY ?? "nemoclaw"
    • Replacement: "e2e-hermes-shields" and "nemoclaw"
    • Net: 0 lines
    • Safety boundary: No behavior change; values are constant in all current and foreseeable executions
  • PRA-11 delete (test/e2e/live/hermes-shields-config.test.ts:101): await cleanup(host, "pre-cleanup");
    • Replacement: Use the simpler existing path.
    • Net: -1 lines
    • Safety boundary: cleanupRegistry already guarantees post-test cleanup; pre-cleanup is redundant
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 — hermes-shields-drift-detection-host-root-tamper: Host-root docker exec -u 0 chmod-write-chmod on config.yaml detected as content drift; shields status returns UP (DRIFTED); shields up refuses with Refusing to re-seal. Runtime/sandbox/infrastructure paths need behavioral runtime validation: .github/workflows/e2e.yaml, tools/e2e/upload-e2e-artifacts-workflow-boundary.mts. New live E2E test requires drift detection, negative paths, audit trail, and auto-restore parity with OpenClaw.
  • PRA-T2 Runtime validation — hermes-shields-double-down-rejected: Second shields down when already DOWN fails with already unlocked. Runtime/sandbox/infrastructure paths need behavioral runtime validation: .github/workflows/e2e.yaml, tools/e2e/upload-e2e-artifacts-workflow-boundary.mts. New live E2E test requires drift detection, negative paths, audit trail, and auto-restore parity with OpenClaw.
  • PRA-T3 Runtime validation — hermes-shields-double-up-rejected: Second shields up when already UP fails with already active. Runtime/sandbox/infrastructure paths need behavioral runtime validation: .github/workflows/e2e.yaml, tools/e2e/upload-e2e-artifacts-workflow-boundary.mts. New live E2E test requires drift detection, negative paths, audit trail, and auto-restore parity with OpenClaw.
  • PRA-T4 Runtime validation — hermes-shields-up-when-up-fails: shields up when already UP fails. Runtime/sandbox/infrastructure paths need behavioral runtime validation: .github/workflows/e2e.yaml, tools/e2e/upload-e2e-artifacts-workflow-boundary.mts. New live E2E test requires drift detection, negative paths, audit trail, and auto-restore parity with OpenClaw.
  • PRA-T5 Runtime validation — hermes-shields-down-when-down-fails: shields down when already DOWN fails. Runtime/sandbox/infrastructure paths need behavioral runtime validation: .github/workflows/e2e.yaml, tools/e2e/upload-e2e-artifacts-workflow-boundary.mts. New live E2E test requires drift detection, negative paths, audit trail, and auto-restore parity with OpenClaw.
  • PRA-T6 Missing drift detection test — no host-root tamper parity with OpenClaw test — Add a drift detection sub-test or phase that performs host-root tamper (docker exec -u 0 chmod/write/chmod on CONFIG_PATH) and verifies shields status detects content drift, matching OpenClaw test coverage.
  • PRA-T7 No negative tests for invalid shields sequences — Add negative test cases in same file covering the four scenarios above, mirroring OpenClaw test phases 10-11.
  • PRA-T8 Missing audit trail and auto-restore timer coverage (OpenClaw parity) — Add audit trail verification (JSONL entries, no secrets) and dead timer inline restore test phase mirroring OpenClaw phases 8-9.
Since last review details

Current findings, using the urgency labels above:

PRA-1 Resolve/justify — Source-of-truth review needed: test/e2e/live/hermes-shields-config.test.ts:57 — cleanupGatewayRegistration silent catch

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as missing.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: Mock cleanupGatewayRegistration to fail; verify error artifact 'gateway-cleanup-error.txt' is written with error message
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: cleanup() function: await host.cleanupGatewayRegistration(...).catch(() => undefined); source method already handles expected errors properly

PRA-2 Resolve/justify — Source-of-truth review needed: test/e2e/fixtures/clients/host.ts:154-161 — bestEffortCleanupSandbox empty catch

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: Mock destroySandbox to throw; verify error artifact written (e.g., 'sandbox-cleanup-error.txt') and test continues
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: async bestEffortCleanupSandbox(...) { try { await this.cleanupSandbox(...) } catch { } }

PRA-3 Required — Missing drift detection test — no host-root tamper parity with OpenClaw test

  • Location: test/e2e/live/hermes-shields-config.test.ts:148
  • Category: tests
  • Problem: OpenClaw shields-config.test.ts (lines 350-400) tests host-root chmod-write-chmod tamper detection: after shields-up, docker exec -u 0 modifies config, refreshes hash, then shields status shows 'UP (DRIFTED)' and shields up refuses re-seal. Hermes test has zero equivalent coverage. A regression in Hermes drift detection would not be caught.
  • Impact: Hermes shields drift detection regression would go undetected; security posture parity not achieved. Host-root config tamper could silently persist.
  • Required action: Add a drift detection sub-test or phase that performs host-root tamper (docker exec -u 0 chmod/write/chmod on CONFIG_PATH) and verifies shields status detects content drift, matching OpenClaw test coverage.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: Compare test/e2e/live/shields-config.test.ts phase-5b-host-root-tamper through phase-5b-shields-up-refuses-tamper with hermes-shields-config.test.ts; verify equivalent tamper+detect+refuse sequence exists
  • Missing regression test: Hermes shields drift detection: host-root tamper to config.yaml detected as content drift after shields-up; shields status returns 'UP (DRIFTED)' and shields up refuses with 'Refusing to re-seal'
  • Done when: The required change is committed and verification passes: Compare test/e2e/live/shields-config.test.ts phase-5b-host-root-tamper through phase-5b-shields-up-refuses-tamper with hermes-shields-config.test.ts; verify equivalent tamper+detect+refuse sequence exists.
  • Evidence: shields-config.test.ts lines 350-400 test gateway write + hash refresh + shields-up drift detection; hermes-shields-config.test.ts has no equivalent tamper/detection/refusal phases

PRA-4 Required — cleanupGatewayRegistration silent catch swallows all errors

  • Location: test/e2e/live/hermes-shields-config.test.ts:57
  • Category: security
  • Problem: Line 57: `await host.cleanupGatewayRegistration(GATEWAY_NAME, {...}).catch(() => undefined);` — any failure in gateway cleanup (gateway not found, openshell command failure, legacy destroy fallback failure) is silently ignored. Gateway registration leakage can expose credentials, cause port conflicts, and leave stale OpenShell state.
  • Impact: Gateway cleanup failures invisible in CI artifacts; credential leakage risk; port conflicts on re-run; stale gateway state pollutes subsequent test runs.
  • Required action: Replace silent catch with artifact logging: `.catch(err => { await artifacts.writeText('gateway-cleanup-error.txt', err.message); })` so failures are visible while test continues.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: Read test/e2e/live/hermes-shields-config.test.ts line 57; verify .catch() logs error to artifact instead of swallowing
  • Missing regression test: Mock cleanupGatewayRegistration to fail; verify error artifact 'gateway-cleanup-error.txt' is written with error message
  • Done when: The required change is committed and verification passes: Read test/e2e/live/hermes-shields-config.test.ts line 57; verify .catch() logs error to artifact instead of swallowing.
  • Evidence: cleanup() function: await host.cleanupGatewayRegistration(...).catch(() => undefined);

PRA-5 Required — bestEffortCleanupSandbox silent catch swallows sandbox destroy errors

  • Location: test/e2e/fixtures/clients/host.ts:154
  • Category: security
  • Problem: host.ts lines 154-161: `bestEffortCleanupSandbox` wraps `cleanupSandbox` in try/catch with empty catch block. Sandbox destroy failures (not found, busy, Docker errors) are completely hidden. This is shared infrastructure used by multiple tests.
  • Impact: Sandbox leakage between test runs; resource exhaustion; state pollution; hidden sandbox escape vectors; credential files left in stale sandboxes.
  • Required action: Modify bestEffortCleanupSandbox to accept an artifacts parameter and write failures to artifact, or return a Result type. At minimum, log the error at debug level.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: Read test/e2e/fixtures/clients/host.ts lines 154-161; verify catch block logs error instead of empty
  • Missing regression test: Mock destroySandbox to throw; verify error artifact written (e.g., 'sandbox-cleanup-error.txt') and test continues
  • Done when: The required change is committed and verification passes: Read test/e2e/fixtures/clients/host.ts lines 154-161; verify catch block logs error instead of empty.
  • Evidence: async bestEffortCleanupSandbox(...) { try { await this.cleanupSandbox(...) } catch { } }

PRA-6 Required — No negative tests for invalid shields sequences

  • Location: test/e2e/live/hermes-shields-config.test.ts:148
  • Category: tests
  • Problem: No tests for: (1) run shields down twice, expect second to fail; (2) run shields up twice, expect second to fail; (3) run shields up when already UP, expect failure; (4) run shields down when already DOWN, expect failure. OpenClaw test has these (phases 10-11).
  • Impact: State machine transition bugs (double operations, wrong-state operations) would not be caught. Regression in Hermes shields state validation would go undetected.
  • Required action: Add negative test cases in same file covering the four scenarios above, mirroring OpenClaw test phases 10-11.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: Search hermes-shields-config.test.ts for double down/up, wrong-state tests — none exist
  • Missing regression test: Four negative tests: double shields-down rejected, double shields-up rejected, shields-up-when-UP rejected, shields-down-when-DOWN rejected
  • Done when: The required change is committed and verification passes: Search hermes-shields-config.test.ts for double down/up, wrong-state tests — none exist.
  • Evidence: hermes-shields-config.test.ts only tests happy path (two successful cycles); no error-path assertions

PRA-7 Resolve/justify — Fake OpenAI server binds to 0.0.0.0 instead of 127.0.0.1

  • Location: test/e2e/live/hermes-shields-config.test.ts:174
  • Category: security
  • Problem: Line 174: `host: "0.0.0.0"` passed to startFakeOpenAiCompatibleServer. The server binds all interfaces. readinessProbeHost() converts to 127.0.0.1 for health checks but server still binds 0.0.0.0. Systemic pattern (15+ files), but PR adds new instance.
  • Impact: Network exposure in CI; potential SSRF vector if sandbox network policy misconfigured; violates least-privilege binding.
  • Recommended action: Change host parameter to '127.0.0.1' and update publicHost accordingly, or justify why 0.0.0.0 is required for OpenShell internal networking.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read test/e2e/live/hermes-shields-config.test.ts line 174; verify host: '0.0.0.0'; check fixtures/fake-openai-compatible.ts readinessProbeHost conversion
  • Missing regression test: Verify fake server binds only localhost: netstat -tlnp shows 127.0.0.1:PORT not 0.0.0.0:PORT
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read test/e2e/live/hermes-shields-config.test.ts line 174; verify host: '0.0.0.0'; check fixtures/fake-openai-compatible.ts readinessProbeHost conversion.
  • Evidence: startFakeOpenAiCompatibleServer called with host: "0.0.0.0"; readinessProbeHost converts but server binds original host

PRA-8 Resolve/justify — Hardcoded job counts conflict with 4 overlapping PRs

  • Location: tools/e2e/upload-e2e-artifacts-workflow-boundary.mts:44
  • Category: workflow
  • Problem: EXPECTED_UPLOAD_JOB_COUNT=74 and EXPECTED_DEFAULT_CALLER_COUNT=63 are hardcoded constants. Four overlapping PRs (fix(onboard): diagnose incomplete custom plugin images #6250, feat(gpu): prefer native OpenShell with compatibility fallback #6333, feat(performance): add progressive disclosure tests and compositional routing acceptance #6341, test(e2e): cover v0.0.55 gateway upgrades #6397) modify the same workflow + boundary files. Each PR increments counts independently — guaranteed merge conflicts and validation failures.
  • Impact: Merge conflicts on every PR; validation tool fails when counts drift; manual coordination required; fragile workflow boundary enforcement.
  • Recommended action: Refactor validateUploadE2eArtifactsInvocations to compute expected counts dynamically from workflow YAML structure instead of hardcoded constants.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Check EXPECTED_UPLOAD_JOB_COUNT=74 in tools/e2e/upload-e2e-artifacts-workflow-boundary.mts:44; verify 4 PRs modify same constants
  • Missing regression test: Validation tool computes correct job count from workflow YAML without hardcoded constants; adding/removing jobs updates count automatically
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Check EXPECTED_UPLOAD_JOB_COUNT=74 in tools/e2e/upload-e2e-artifacts-workflow-boundary.mts:44; verify 4 PRs modify same constants.
  • Evidence: Constants at lines 44-45; 4 overlapping PRs identified in drift context modifying same files

PRA-9 Resolve/justify — Missing audit trail and auto-restore timer coverage (OpenClaw parity)

  • Location: test/e2e/live/hermes-shields-config.test.ts:218
  • Category: tests
  • Problem: OpenClaw test has phase-8-audit-trail (JSONL, no secrets), phase-9-dead-timer-inline-restore (dead timer triggers inline recovery, config re-locked, .config-hash restored). Hermes test has neither.
  • Impact: Audit trail regression (secret leakage, missing entries) not caught. Auto-restore timer dead-path recovery not validated.
  • Recommended action: Add audit trail verification (JSONL entries, no secrets) and dead timer inline restore test phase mirroring OpenClaw phases 8-9.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Compare shields-config.test.ts phase-8-audit-summary through phase-9-config-hash-perms-after-dead-timer-inline-restore with hermes test
  • Missing regression test: Audit JSONL contains shields_up/shields_down entries with no API keys; dead timer kills process, inline restore re-locks config and .config-hash, state file has correct fileHashes
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Compare shields-config.test.ts phase-8-audit-summary through phase-9-config-hash-perms-after-dead-timer-inline-restore with hermes test.
  • Evidence: hermes-shields-config.test.ts has no audit file checks, no timer manipulation, no inline restore validation

PRA-10 Improvement — Single-use env-config constants can be inlined

  • Location: test/e2e/live/hermes-shields-config.test.ts:18
  • Category: scope
  • Problem: SANDBOX_NAME and GATEWAY_NAME read from process.env with fallbacks but are never overridden in CI or locally. They are effectively constants.
  • Impact: Unnecessary indirection; suggests configurability that doesn't exist; clutters test setup.
  • Suggested action: Replace with constants: `const SANDBOX_NAME = 'e2e-hermes-shields'; const GATEWAY_NAME = 'nemoclaw';` and remove process.env reads.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Read lines 18-19; verify no test or CI sets NEMOCLAW_SANDBOX_NAME or OPENSHELL_GATEWAY differently
  • Missing regression test: N/A — simplification, no behavior change
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: const SANDBOX_NAME = process.env.NEMOCLAW_SANDBOX_NAME ?? "e2e-hermes-shields"; const GATEWAY_NAME = process.env.OPENSHELL_GATEWAY ?? "nemoclaw";

PRA-11 Improvement — Redundant pre-cleanup call duplicates cleanupRegistry entry

  • Location: test/e2e/live/hermes-shields-config.test.ts:101
  • Category: scope
  • Problem: Line 101: `await cleanup(host, "pre-cleanup");` runs before test setup. cleanupRegistry already adds post-test cleanup for sandbox and gateway. Pre-cleanup duplicates effort and can mask setup failures.
  • Impact: Wasted time; pre-cleanup failure could obscure real setup issue; cleanupRegistry already guarantees post-test cleanup.
  • Suggested action: Remove the explicit `await cleanup(host, "pre-cleanup")` line; rely solely on cleanupRegistry for both pre and post cleanup (or use test.before/after hooks).
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Read line 101; verify cleanupRegistry.add for sandbox destroy already covers pre-cleanup need
  • Missing regression test: N/A — simplification, no behavior change
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: Line 101: await cleanup(host, "pre-cleanup"); cleanupRegistry.add already registers destroy for same sandbox/gateway

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.

Signed-off-by: Julie Yaunches <jyaunches@nvidia.com>
@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

E2E Target Results — ✅ All requested jobs passed

Run: 28874424031
Workflow ref: codex/hermes-shields-live-e2e
Requested targets: (default — all supported)
Requested jobs: cloud-onboard
Summary: 1 passed, 0 failed, 0 cancelled, 0 skipped

Job Result
cloud-onboard ✅ success

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

E2E Target Results — ❌ Some jobs failed

Run: 28874817718
Workflow ref: codex/hermes-shields-live-e2e
Requested targets: (default — all supported)
Requested jobs: hermes-shields-config
Summary: 0 passed, 1 failed, 0 cancelled, 0 skipped

Job Result
hermes-shields-config ❌ failure

Failed jobs: hermes-shields-config. Check run artifacts for logs.

@jyaunches

Copy link
Copy Markdown
Contributor Author

Validation update:

Expected next state: keep this PR draft/blocked on #6384, then rerun hermes-shields-config after #6384 lands; it should complete both down/up cycles.

Signed-off-by: Julie Yaunches <jyaunches@nvidia.com>
@jyaunches

Copy link
Copy Markdown
Contributor Author

Automated-review follow-up (latest SHA 0076b5d86):

Please treat the requested drift/negative-path additions as deferred scope for maintainer review; they are not needed to prove the specific #6381 lifecycle regression.

@jyaunches

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

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.

@jyaunches
jyaunches marked this pull request as ready for review July 7, 2026 15:24
@jyaunches
jyaunches merged commit 6fa6f4b into main Jul 7, 2026
51 checks passed
@jyaunches
jyaunches deleted the codex/hermes-shields-live-e2e branch July 7, 2026 16:51
Hadar301 pushed a commit to Hadar301/NemoClaw-OpenShift that referenced this pull request Jul 12, 2026
<!-- markdownlint-disable MD041 -->
## Summary
Adds a CPU-only live E2E that reproduces the fresh Hermes shields
lifecycle regression from NVIDIA#6381. The test onboards a new non-root Hermes
sandbox, runs shields down/up twice, and preserves the failure as a
dedicated E2E lane until NVIDIA#6384 lands.

## Related Issue
Relates to NVIDIA#6381.

Depends on NVIDIA#6384.

## Changes
- Add a fresh Hermes onboard and two-cycle shields down/up live
regression test.
- Assert the mutable and locked ownership/mode contracts after each
transition.
- Add a dedicated `hermes-shields-config` workflow job that requires no
GPU or hosted inference secret.
- Extend the E2E artifact workflow boundary for the new job.

## Type of Change

- [x] 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)

## Quality Gates
<!-- Check exactly one tests line and one docs line. Check other lines
when applicable. Add every requested justification or approval
reference. -->
- [x] Tests added or updated for changed behavior
- [ ] Existing tests cover changed behavior — justification:
- [ ] Tests not applicable — justification:
- [ ] Docs updated for user-facing behavior changes
- [x] Docs not applicable — justification: test and CI coverage only; no
user-facing behavior changes
- [ ] Sensitive paths changed (security, policy, credentials, preflight,
onboarding, inference, runner, sandbox, or messaging)
- [ ] Sensitive-path review completed or maintainer-approved waiver
recorded — reviewer/approval link/justification:
- [ ] Non-success, skipped, or missing CI check accepted by maintainer —
check name, approval link, and follow-up issue:

## Verification
<!-- Check each applicable item only when supported by the requested
evidence. Run targeted tests once per relevant change set and rerun
after later edits or hook autofixes that can affect the tested behavior.
Do not rerun hook-covered checks. -->
- [x] PR description includes the DCO sign-off declaration and every
commit appears as `Verified` in GitHub
- [x] Normal `pre-commit`, `commit-msg`, and `pre-push` hooks passed, or
`npm run check:diff` passed when hooks were skipped or unavailable
- [ ] Targeted behavior tests pass for the current change set, or tests
are marked not applicable above — command/result or justification: E2E
workflow support tests passed (24/24), and the live target collects
successfully; the live run is intentionally expected to reproduce NVIDIA#6381
on current `main`
- [ ] Applicable broad gate passed — `npm test` for broad
runtime/test-harness changes; `npm run check` for repo-wide
validation/coverage changes — command/result:
- [x] Quality Gates section completed with required justifications or
waivers
- [x] No secrets, API keys, or credentials committed
- [ ] `npm run docs` builds without warnings (doc changes only)
- [ ] Doc pages follow the [style
guide](https://github.com/NVIDIA/NemoClaw/blob/main/docs/CONTRIBUTING.md)
(doc changes only)
- [ ] New doc pages include SPDX header and frontmatter (new pages only)

---
<!-- DCO sign-off is required in this PR description, and every commit
must appear as Verified in GitHub. Run: git config user.name && git
config user.email -->
Signed-off-by: Julie Yaunches <jyaunches@nvidia.com>


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added a new Hermes live end-to-end check that runs repeated shields
cycles in a fresh non-root sandbox.
* Updated PR reporting so the new live job is included in the results
summary.
* **Bug Fixes**
* Updated E2E artifact upload workflow boundary validations to match the
current number of expected E2E execution jobs and default callers.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: Julie Yaunches <jyaunches@nvidia.com>
@wscurran wscurran added area: ci CI workflows, checks, release automation, or GitHub Actions area: e2e End-to-end tests, nightly failures, or validation infrastructure 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: ci CI workflows, checks, release automation, or GitHub Actions area: e2e End-to-end tests, nightly failures, or validation infrastructure integration: hermes Hermes integration behavior

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants