Skip to content

fix(ci): resolve macOS/bash 3.2 vitest failures on main#6140

Merged
apurvvkumaria merged 4 commits into
mainfrom
fix/macos-vitest-failures-clean
Jul 1, 2026
Merged

fix(ci): resolve macOS/bash 3.2 vitest failures on main#6140
apurvvkumaria merged 4 commits into
mainfrom
fix/macos-vitest-failures-clean

Conversation

@prekshivyas

@prekshivyas prekshivyas commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Summary

Five pre-existing test failures on the macos-vitest CI workflow (confirmed present before #6060) traced to bash 3.x incompatibilities, a macOS UTF-8 locale issue, and a missing fixture sync. This PR fixes all five root causes.

Supersedes #6137 (that PR's branch was accidentally cut from a security feature branch, pulling in unrelated files into the diff; this is a clean rebase onto main with the same two commits plus a CodeRabbit fix).

Related Issue

Investigation of CI run 28539883104; failures also present in run 28534214317 (before #6060), confirming #6060 is not the cause.

Changes

  • agents/hermes/start.sh — three bash 3.2 compatibility fixes:
    • Replace bash 4.1+ named-FD exec {var}<file with a { } < file grouped redirect; variables assigned inside {} remain in function scope
    • Replace mapfile -d '' -t (bash 4.x only) with while IFS= read -r -d "" elem; do arr+=("$elem"); done
    • Guard ${_HERMES_GUARD_TIMEOUT[@]} with ${arr[@]+"${arr[@]}"} so set -u does not abort the script when the array is empty (bash 3.2 treats empty [@] as unbound)
  • scripts/gateway-control.sh — add export LC_ALL=C so [a-f] character-class ranges in case patterns are byte-exact; macOS en_US.UTF-8 makes [a-f] case-insensitive, allowing uppercase hex nonces to pass the *[!0-9a-f]* check
  • scripts/lib/gateway-supervisor.sh — same LC_ALL=C fix for the sourced library's nonce validation path
  • test/gateway-supervisor-control.test.ts — pin NEMOCLAW_TEST_GATEWAY_CONTROL_CALLER_UID=0 in the nonce-rejection test so it does not depend on the CI runner's UID; tighten macOS bash 3.2 SIGTERM filter from broad word-match to exact Terminated: <digits> / Killed: <digits> format so unrelated stderr still fails the assertion
  • test/e2e/fixtures/redaction.ts — add tvly- Tavily token pattern missing since fix(policy): restore Tavily egress for managed Python #6134, fixing the e2e-redaction-parity Array(16) vs Array(17) mismatch

Type of Change

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

Quality Gates

  • Tests added or updated for changed behavior
  • Docs not applicable — justification: shell compatibility and test fixes, no user-facing behavior change
  • Sensitive paths changed (security, policy, credentials, preflight, onboarding, inference, runner, sandbox, or messaging) — gateway-control.sh and gateway-supervisor.sh handle nonce validation
  • Sensitive-path review completed or maintainer-approved waiver recorded — the LC_ALL=C fix tightens nonce validation (rejects uppercase hex on macOS that was previously accepted); gateway_control_stop_tracked_pid behavior is unchanged

Verification

  • Git hooks passed during commit and push
  • Targeted tests pass for changed behavior
    • test/gateway-supervisor-control.test.ts: 22/22 ✓
    • test/hermes-managed-exit-authorization.test.ts: all ✓ (was 8 failures before)
    • test/e2e/support/e2e-redaction-parity.test.ts: 3/3 ✓
    • test/hermes-gateway-supervisor-recovery.test.ts: 41/42 (1 local flake — PID 4242 alive on dev machine; unrelated to these changes, passes on CI fresh runners)
  • No secrets, API keys, or credentials committed

Remaining failures not addressed in this PR (different root class, need separate investigation):

  • install-preflight.test.ts — environment-specific
  • deepagents-code-tui-startup-check.test.ts — needs investigation
  • platform-parity-cloud-experimental.test.ts — needs investigation
  • WSL runtime-recovery-preload.test.ts, rebuild-config-hash.test.ts — different class of failure

Signed-off-by: Prekshi Vyas prekshiv@nvidia.com

Summary by CodeRabbit

  • Bug Fixes
    • Improved gateway nonce validation to reliably accept only lowercase hex characters, independent of locale and macOS environments.
    • Fixed managed gateway startup, recovery, and live-status monitoring to be compatible with older Bash versions.
    • Tightened controller/marker parsing to reduce incorrect authorization or status detection.
    • Expanded secret redaction to cover additional Tavily-shaped tokens, improving protection in logs and text output.

prekshivyas and others added 2 commits July 1, 2026 13:27
Five pre-existing failures on macos-vitest traced to bash 3.x
incompatibilities and a missing locale guard:

- agents/hermes/start.sh: replace bash 4.1+ named-FD exec ({var}<file)
  with a { } < file grouped redirect (bash 3.2 compatible); replace
  mapfile -d '' -t with while/read -r -d "" loop; guard
  ${_HERMES_GUARD_TIMEOUT[@]} with ${arr[@]+"${arr[@]}"} so set -u
  with an empty array does not abort the script
- scripts/gateway-control.sh, scripts/lib/gateway-supervisor.sh: export
  LC_ALL=C so [a-f] character-class ranges in case patterns are
  byte-exact — macOS en_US.UTF-8 treats [a-f] as case-insensitive,
  allowing uppercase hex nonces to bypass validation
- test/gateway-supervisor-control.test.ts: pin
  NEMOCLAW_TEST_GATEWAY_CONTROL_CALLER_UID=0 so the nonce-rejection test
  does not depend on the CI runner being root; suppress macOS bash 3.2
  SIGTERM job-notification lines in the stderr assertion
- test/e2e/fixtures/redaction.ts: add tvly- Tavily pattern missing since
  #6134, fixing e2e-redaction-parity Array(16) vs Array(17) mismatch

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The job-control noise emitted by macOS bash 3.2 is specifically
"Terminated: 15  <cmd>" — signal name, colon, signal number. Tighten
the replace() regex from a broad any-line-containing-the-word match to
/^(?:Terminated|Killed): \d+/ so unrelated stderr that happens to
contain those words still fails the assertion.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 1, 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: bdffa554-f8e5-42c9-8a9a-230ab5601fae

📥 Commits

Reviewing files that changed from the base of the PR and between a8568a2 and 88a7718.

📒 Files selected for processing (2)
  • scripts/gateway-control.sh
  • scripts/lib/gateway-supervisor.sh

📝 Walkthrough

Walkthrough

This PR updates Hermes shell compatibility for restart and managed-gateway checks, switches gateway nonce validation to explicit lowercase hex character sets, adds a Tavily token prefix to redaction fixtures, and adjusts supervisor control tests for macOS bash behavior.

Changes

Hermes shell portability

Layer / File(s) Summary
Guard timeout expansion
agents/hermes/start.sh
Restart sealing, unsealing, and startup recovery use guarded timeout array expansion when invoking the runtime-config guard.
Controller and marker parsing
agents/hermes/start.sh
Managed controller liveness parsing replaces mapfile -d '' with while IFS= read -r -d '', and gateway exit authorization reads marker contents through a grouped redirect instead of a named file descriptor.

Gateway nonce validation

Layer / File(s) Summary
Nonce character class
scripts/gateway-control.sh, scripts/lib/gateway-supervisor.sh
Both scripts switch nonce validation to explicit lowercase hex character sets and add comments describing the locale-independent checks.

Redaction and supervisor test updates

Layer / File(s) Summary
Redaction fixture and test hardening
test/e2e/fixtures/redaction.ts, test/gateway-supervisor-control.test.ts
The redaction fixture adds a Tavily token prefix, and the gateway supervisor control test disables job control, filters macOS job-control stderr output, and sets the caller UID environment for one rejection case.

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

Possibly related PRs

Suggested labels: platform: macos, bug-fix

Suggested reviewers: cv

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR does not restore /opt/venv/bin/python3* to the Tavily policy/provider allowlists or add the required Tavily regression coverage. Update the Tavily preset and provider profile to include /opt/venv/bin/python3*, keep system/project Python excluded, and add managed-vs-system Tavily tests.
Out of Scope Changes check ⚠️ Warning Most changes fix macOS/bash 3.2 CI issues and redaction fixtures, which are unrelated to the Tavily allowlist restoration requested in #6134. Split the macOS/bash/test fixture fixes into a separate PR, or retarget this PR to the Tavily policy/profile changes and tests required by #6134.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: fixing macOS/bash 3.2 Vitest failures.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ 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 fix/macos-vitest-failures-clean

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

@github-code-quality

github-code-quality Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Overview

Languages: TypeScript

TypeScript / code-coverage/plugin

The overall coverage in the branch is 96%. Coverage data for the branch is not yet available.

Show a code coverage summary of the most covered files.
File 88a7718 +/-
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 branch is 68%. Coverage data for the branch is not yet available.

Show a code coverage summary of the most covered files.
File 88a7718 +/-
src/lib/shields...nsition-lock.ts 86%
src/lib/actions...dbox/rebuild.ts 80%
src/lib/actions...all/run-plan.ts 80%
src/lib/state/o...oard-session.ts 80%
src/lib/state/sandbox.ts 72%
src/lib/shields/index.ts 69%
src/lib/onboard/preflight.ts 69%
src/lib/onboard...er-gpu-patch.ts 59%
src/lib/actions...licy-channel.ts 58%
src/lib/onboard.ts 20%

Updated July 01, 2026 20:46 UTC
Code Coverage is in Public Preview. Learn more and provide us with your feedback.

@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

E2E Advisor Recommendation

Required E2E: hermes-e2e, hermes-root-entrypoint-smoke, hermes-sandbox-secret-boundary, gateway-guard-recovery
Optional E2E: shields-config, security-posture, macos-e2e

Dispatch hint: hermes-e2e,hermes-root-entrypoint-smoke,hermes-sandbox-secret-boundary,gateway-guard-recovery

Workflow run

Full advisor summary

E2E Recommendation Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required E2E

  • hermes-e2e (high): Required because it exercises the real Hermes sandbox lifecycle through install/onboard, gateway restart, gateway recover, managed supervisor behavior, health checks, forwards recovery, raw-secret restart refusal, and shields-related runtime contracts that are implemented in agents/hermes/start.sh.
  • hermes-root-entrypoint-smoke (medium): Required as a focused image/entrypoint smoke for agents/hermes/start.sh. It catches shell syntax/runtime regressions in root startup and managed-entrypoint paths before the broader Hermes live flow reaches them.
  • hermes-sandbox-secret-boundary (medium): Required because the changed Hermes entrypoint code gates restart and startup behavior on secret-boundary/runtime-env validation. This job probes the Hermes image and startup secret-boundary contracts in a real Docker sandbox image.
  • gateway-guard-recovery (medium): Required because scripts/gateway-control.sh and scripts/lib/gateway-supervisor.sh are the privileged PID 1 request/status protocol used by real recovery. This job exercises the production recovery route through a live sandbox after guard-chain/gateway disruption.

Optional E2E

  • shields-config (medium): Useful adjacent confidence for live shields up/down drift detection and config locking. The primary shields-sensitive changes are in Hermes, so this is not merge-blocking if the required Hermes coverage passes.
  • security-posture (high): Useful defense-in-depth for security-boundary regressions across OpenClaw and Hermes after privileged control and secret-boundary script changes.
  • macos-e2e (medium): Optional platform signal for the bash 3.2 and locale-motivated changes. It may not exercise Hermes container entrypoint paths, but it can catch broader macOS build/install regressions from shell portability changes.

New E2E recommendations

  • Gateway control locale/portability (medium): Existing live E2E primarily runs the privileged gateway-control protocol in Linux CI. The PR specifically targets locale-sensitive nonce validation and bash 3.2-compatible shell behavior; current coverage appears mostly unit-level for those portability details.
    • Suggested test: Add a lightweight macOS or cross-shell E2E/support-boundary job that invokes the real gateway-control.sh and sourced gateway-supervisor.sh request parser under UTF-8 locales and verifies uppercase/non-hex nonce rejection plus valid lowercase nonce acceptance.
  • Hermes interrupted restart seal recovery (high): agents/hermes/start.sh changes seal/unseal guard execution and mutation-owner recovery, but existing live jobs mainly cover successful restart/recover and broad secret-boundary refusal. A deterministic interruption/orphaned-seal scenario would provide higher confidence for fail-closed restart recovery.
    • Suggested test: Add a Hermes live regression that interrupts a gateway restart after seal creation, restarts the sandbox, and asserts PID 1 either safely unseals/resumes the trusted transaction or fails closed with the expected diagnostic without adopting mutable config drift.

Dispatch hint

  • Workflow: .github/workflows/e2e.yaml
  • jobs input: hermes-e2e,hermes-root-entrypoint-smoke,hermes-sandbox-secret-boundary,gateway-guard-recovery

@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

E2E Target Recommendation

Required E2E targets: e2e-all
Optional E2E targets: None

Dispatch required E2E targets:

  • gh workflow run e2e.yaml --ref <pr-head-ref>

Workflow run

Full E2E target advisor summary

E2E Target Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required E2E targets

  • e2e-all: The PR changes shared E2E fixture redaction infrastructure under test/e2e/fixtures/redaction.ts. Shared fixture changes can affect every live E2E target, so the full E2E target fan-out is required. The Hermes gateway supervisor/runtime script changes are also directly exercised by live target runs and are covered by the full fan-out.
    • Dispatch: gh workflow run e2e.yaml --ref <pr-head-ref>

Optional E2E targets

  • None.

Relevant changed files

  • agents/hermes/start.sh
  • scripts/gateway-control.sh
  • scripts/lib/gateway-supervisor.sh
  • test/e2e/fixtures/redaction.ts

@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

PR Review Advisor (Nemotron Ultra) — Changes requested

Merge posture: Do not merge yet
Primary next action: Resolve or justify PRA-1: Source-of-truth review needed: agents/hermes/start.sh _HERMES_GUARD_TIMEOUT array guard.
Open items: 0 required · 4 warnings · 2 suggestions · 4 test follow-ups
Since last review: 1 prior item resolved · 0 still apply · 0 new items found

Action checklist

  • PRA-1 Resolve or justify: Source-of-truth review needed: agents/hermes/start.sh _HERMES_GUARD_TIMEOUT array guard
  • PRA-2 Resolve or justify: Add test for unset _HERMES_GUARD_TIMEOUT array guard (bash 3.2 compat) in test/hermes-gateway-supervisor-recovery.test.ts:393
  • PRA-3 Resolve or justify: Nonce validation hardened to explicit locale-independent character class in scripts/gateway-control.sh:42
  • PRA-4 Resolve or justify: Bash 3.2 array expansion guard for _HERMES_GUARD_TIMEOUT in agents/hermes/start.sh:1800
  • PRA-T1 Add or justify test follow-up: Runtime validation
  • PRA-T2 Add or justify test follow-up: Add test for unset _HERMES_GUARD_TIMEOUT array guard (bash 3.2 compat)
  • PRA-T3 Add or justify test follow-up: Acceptance clause
  • PRA-T4 Add or justify test follow-up: agents/hermes/start.sh _HERMES_GUARD_TIMEOUT array guard
  • PRA-5 In-scope improvement: Tavily API token pattern added to secret redaction fixtures in test/e2e/fixtures/redaction.ts:49
  • PRA-6 In-scope improvement: macOS bash 3.2 SIGTERM stderr filter tightened in test/gateway-supervisor-control.test.ts:107

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 tests test/hermes-gateway-supervisor-recovery.test.ts:393 Add a test case that does not assign _HERMES_GUARD_TIMEOUT at all before calling seal_hermes_restart_inputs, verifying the alternate expansion prevents 'unbound variable' error.
PRA-3 Resolve/justify security scripts/gateway-control.sh:42 Change is complete and correct. Same fix applied in scripts/lib/gateway-supervisor.sh:58. No further action needed.
PRA-4 Resolve/justify correctness agents/hermes/start.sh:1800 Fix is correct for bash 3.2 compatibility. Add test for truly unset variable (see PRA-T1).
PRA-5 Improvement security test/e2e/fixtures/redaction.ts:49 Good addition. Ensure parity test (test/e2e/support/e2e-redaction-parity.test.ts) validates this pattern stays in sync with canonical source.
PRA-6 Improvement correctness test/gateway-supervisor-control.test.ts:107 Fix is appropriate for cross-platform test stability. No production code change.
Review findings by urgency: 0 required fixes, 4 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: agents/hermes/start.sh _HERMES_GUARD_TIMEOUT array guard

  • 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: test/hermes-gateway-supervisor-recovery.test.ts line 393 tests empty array; need test with unset variable
  • 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: agents/hermes/start.sh lines 1800,1817,1860,1994 use ${_HERMES_GUARD_TIMEOUT[@]+\"${_HERMES_GUARD_TIMEOUT[@]}\"}

PRA-2 Resolve/justify — Add test for unset _HERMES_GUARD_TIMEOUT array guard (bash 3.2 compat)

  • Location: test/hermes-gateway-supervisor-recovery.test.ts:393
  • Category: tests
  • Problem: The array guard `${_HERMES_GUARD_TIMEOUT[@]+"${_HERMES_GUARD_TIMEOUT[@]}"}` prevents 'unbound variable' under `set -u` when the array is unset in bash 3.2. Current test at line 393 uses `_HERMES_GUARD_TIMEOUT=()` (empty array) which behaves differently from a truly unset variable in bash 3.2.
  • Impact: If the array is truly unset (e.g., sourced without line 235 executing), the guard may not be exercised by current tests, leaving a potential runtime crash on macOS/bash 3.2.
  • Recommended action: Add a test case that does not assign _HERMES_GUARD_TIMEOUT at all before calling seal_hermes_restart_inputs, verifying the alternate expansion prevents 'unbound variable' error.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Run test with `unset _HERMES_GUARD_TIMEOUT` before invoking seal_hermes_restart_inputs; verify no 'unbound variable' error and guard timeout is simply omitted from the command.
  • Missing regression test: New test in test/hermes-gateway-supervisor-recovery.test.ts: 'handles unset _HERMES_GUARD_TIMEOUT without unbound variable error (bash 3.2 compat)'
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Run test with `unset _HERMES_GUARD_TIMEOUT` before invoking seal_hermes_restart_inputs; verify no 'unbound variable' error and guard timeout is simply omitted from the command.
  • Evidence: test/hermes-gateway-supervisor-recovery.test.ts:393 sets `_HERMES_GUARD_TIMEOUT=()`; agents/hermes/start.sh:1800,1817,1860,1994 use `${_HERMES_GUARD_TIMEOUT[@]+"${_HERMES_GUARD_TIMEOUT[@]}"}` pattern

PRA-3 Resolve/justify — Nonce validation hardened to explicit locale-independent character class

  • Location: scripts/gateway-control.sh:42
  • Category: security
  • Problem: Changed nonce validation from locale-dependent `[a-f]` range to explicit `[0123456789abcdef]` character class. Previously, macOS UTF-8 locale folded `[a-f]` case-insensitively, allowing uppercase hex digits to pass validation. Now only lowercase hex is accepted on all platforms.
  • Impact: Prevents potential nonce validation bypass on macOS hosts where locale could accept uppercase hex, strengthening the cryptographic binding between host request and sandbox restart.
  • Recommended action: Change is complete and correct. Same fix applied in scripts/lib/gateway-supervisor.sh:58. No further action needed.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Check case statement at scripts/gateway-control.sh:42 and scripts/lib/gateway-supervisor.sh:58 for `*[!0123456789abcdef]*` pattern.
  • Missing regression test: test/gateway-supervisor-control.test.ts line 91 already has 'uppercase nonce' test case validating rejection of 64-char uppercase nonce.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Check case statement at scripts/gateway-control.sh:42 and scripts/lib/gateway-supervisor.sh:58 for `*[!0123456789abcdef]*` pattern.
  • Evidence: scripts/gateway-control.sh:42 and scripts/lib/gateway-supervisor.sh:58 use `*[!0123456789abcdef]*` pattern

PRA-4 Resolve/justify — Bash 3.2 array expansion guard for _HERMES_GUARD_TIMEOUT

  • Location: agents/hermes/start.sh:1800
  • Category: correctness
  • Problem: Four array expansions changed from `${_HERMES_GUARD_TIMEOUT[@]}` to `${_HERMES_GUARD_TIMEOUT[@]+"${_HERMES_GUARD_TIMEOUT[@]}"}` to prevent 'unbound variable' error under `set -u` in bash 3.2 when array is unset. Array is initialized at line 235 in production, but defensive guard handles sourcing edge cases.
  • Impact: Ensures Hermes startup/restart works on macOS default bash 3.2 without crashing on unset array access. No production behavioral change since array is always initialized.
  • Recommended action: Fix is correct for bash 3.2 compatibility. Add test for truly unset variable (see PRA-T1).
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Check lines 1800, 1817, 1860, 1994 in agents/hermes/start.sh for the `${_HERMES_GUARD_TIMEOUT[@]+"${_HERMES_GUARD_TIMEOUT[@]}"}` pattern.
  • Missing regression test: test/hermes-gateway-supervisor-recovery.test.ts line 393 tests empty array; need test with unset variable.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Check lines 1800, 1817, 1860, 1994 in agents/hermes/start.sh for the `${_HERMES_GUARD_TIMEOUT[@]+"${_HERMES_GUARD_TIMEOUT[@]}"}` pattern.
  • Evidence: agents/hermes/start.sh lines 1800, 1817, 1860, 1994

💡 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-5 Improvement — Tavily API token pattern added to secret redaction fixtures

  • Location: test/e2e/fixtures/redaction.ts:49
  • Category: security
  • Problem: Added `/tvly-[A-Za-z0-9_-]{10,}/g` to TOKEN_PREFIX_PATTERNS for secret redaction in test fixtures, improving secret hygiene for Tavily token format.
  • Impact: Prevents Tavily API tokens from leaking into test logs/artifacts. Pattern mirrors canonical source in src/lib/security/secret-patterns.ts.
  • Suggested action: Good addition. Ensure parity test (test/e2e/support/e2e-redaction-parity.test.ts) validates this pattern stays in sync with canonical source.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Run test/e2e/support/e2e-redaction-parity.test.ts to confirm regex mirrors canonical source.
  • Missing regression test: Parity test should cover this — verify test/e2e/support/e2e-redaction-parity.test.ts includes the new pattern.
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: test/e2e/fixtures/redaction.ts:49 adds Tavily pattern to TOKEN_PREFIX_PATTERNS

PRA-6 Improvement — macOS bash 3.2 SIGTERM stderr filter tightened

  • Location: test/gateway-supervisor-control.test.ts:107
  • Category: correctness
  • Problem: Added `set +m` and stderr regex `/^(?:Terminated|Killed): \d+[^\n]*\n?/gm` to filter macOS bash 3.2 job control notifications (e.g., 'Terminated: 15 sleep 30') that appear despite `set +m`. Prevents test flakiness on macOS runners.
  • Impact: Improves test stability on macOS CI without masking real stderr output. Filter is precise to bash 3.2 notification format.
  • Suggested action: Fix is appropriate for cross-platform test stability. No production code change.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Run tests on macOS bash 3.2 to confirm no flaky stderr output from job control notifications.
  • Missing regression test: The test itself serves as regression coverage for PID tracking behavior; the stderr filter is test infrastructure.
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: test/gateway-supervisor-control.test.ts:107 adds `set +m` and stderr filter regex
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 — Add test for seal_hermes_restart_inputs with truly unset _HERMES_GUARD_TIMEOUT to verify bash 3.2 unbound variable guard behavior. Runtime/sandbox/infrastructure paths need behavioral runtime validation: agents/hermes/start.sh, scripts/gateway-control.sh, scripts/lib/gateway-supervisor.sh. The array guard fix is defensive but untested for truly unset variable in bash 3.2.
  • PRA-T2 Add test for unset _HERMES_GUARD_TIMEOUT array guard (bash 3.2 compat) — Add a test case that does not assign _HERMES_GUARD_TIMEOUT at all before calling seal_hermes_restart_inputs, verifying the alternate expansion prevents 'unbound variable' error.
  • PRA-T3 Acceptance clause — Add export LC_ALL=C for byte-exact [a-f] ranges — add test evidence or identify existing coverage. PR body claimed LC_ALL=C export, but actual fix is better: explicit character class [0123456789abcdef] at scripts/gateway-control.sh:42 and scripts/lib/gateway-supervisor.sh:58 — no locale side effects
  • PRA-T4 agents/hermes/start.sh _HERMES_GUARD_TIMEOUT array guard — test/hermes-gateway-supervisor-recovery.test.ts line 393 tests empty array; need test with unset variable. agents/hermes/start.sh lines 1800,1817,1860,1994 use ${_HERMES_GUARD_TIMEOUT[@]+\"${_HERMES_GUARD_TIMEOUT[@]}\"}
Since last review details

Current findings, using the urgency labels above:

PRA-1 Resolve/justify — Source-of-truth review needed: agents/hermes/start.sh _HERMES_GUARD_TIMEOUT array guard

  • 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: test/hermes-gateway-supervisor-recovery.test.ts line 393 tests empty array; need test with unset variable
  • 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: agents/hermes/start.sh lines 1800,1817,1860,1994 use ${_HERMES_GUARD_TIMEOUT[@]+\"${_HERMES_GUARD_TIMEOUT[@]}\"}

PRA-2 Resolve/justify — Add test for unset _HERMES_GUARD_TIMEOUT array guard (bash 3.2 compat)

  • Location: test/hermes-gateway-supervisor-recovery.test.ts:393
  • Category: tests
  • Problem: The array guard `${_HERMES_GUARD_TIMEOUT[@]+"${_HERMES_GUARD_TIMEOUT[@]}"}` prevents 'unbound variable' under `set -u` when the array is unset in bash 3.2. Current test at line 393 uses `_HERMES_GUARD_TIMEOUT=()` (empty array) which behaves differently from a truly unset variable in bash 3.2.
  • Impact: If the array is truly unset (e.g., sourced without line 235 executing), the guard may not be exercised by current tests, leaving a potential runtime crash on macOS/bash 3.2.
  • Recommended action: Add a test case that does not assign _HERMES_GUARD_TIMEOUT at all before calling seal_hermes_restart_inputs, verifying the alternate expansion prevents 'unbound variable' error.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Run test with `unset _HERMES_GUARD_TIMEOUT` before invoking seal_hermes_restart_inputs; verify no 'unbound variable' error and guard timeout is simply omitted from the command.
  • Missing regression test: New test in test/hermes-gateway-supervisor-recovery.test.ts: 'handles unset _HERMES_GUARD_TIMEOUT without unbound variable error (bash 3.2 compat)'
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Run test with `unset _HERMES_GUARD_TIMEOUT` before invoking seal_hermes_restart_inputs; verify no 'unbound variable' error and guard timeout is simply omitted from the command.
  • Evidence: test/hermes-gateway-supervisor-recovery.test.ts:393 sets `_HERMES_GUARD_TIMEOUT=()`; agents/hermes/start.sh:1800,1817,1860,1994 use `${_HERMES_GUARD_TIMEOUT[@]+"${_HERMES_GUARD_TIMEOUT[@]}"}` pattern

PRA-3 Resolve/justify — Nonce validation hardened to explicit locale-independent character class

  • Location: scripts/gateway-control.sh:42
  • Category: security
  • Problem: Changed nonce validation from locale-dependent `[a-f]` range to explicit `[0123456789abcdef]` character class. Previously, macOS UTF-8 locale folded `[a-f]` case-insensitively, allowing uppercase hex digits to pass validation. Now only lowercase hex is accepted on all platforms.
  • Impact: Prevents potential nonce validation bypass on macOS hosts where locale could accept uppercase hex, strengthening the cryptographic binding between host request and sandbox restart.
  • Recommended action: Change is complete and correct. Same fix applied in scripts/lib/gateway-supervisor.sh:58. No further action needed.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Check case statement at scripts/gateway-control.sh:42 and scripts/lib/gateway-supervisor.sh:58 for `*[!0123456789abcdef]*` pattern.
  • Missing regression test: test/gateway-supervisor-control.test.ts line 91 already has 'uppercase nonce' test case validating rejection of 64-char uppercase nonce.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Check case statement at scripts/gateway-control.sh:42 and scripts/lib/gateway-supervisor.sh:58 for `*[!0123456789abcdef]*` pattern.
  • Evidence: scripts/gateway-control.sh:42 and scripts/lib/gateway-supervisor.sh:58 use `*[!0123456789abcdef]*` pattern

PRA-4 Resolve/justify — Bash 3.2 array expansion guard for _HERMES_GUARD_TIMEOUT

  • Location: agents/hermes/start.sh:1800
  • Category: correctness
  • Problem: Four array expansions changed from `${_HERMES_GUARD_TIMEOUT[@]}` to `${_HERMES_GUARD_TIMEOUT[@]+"${_HERMES_GUARD_TIMEOUT[@]}"}` to prevent 'unbound variable' error under `set -u` in bash 3.2 when array is unset. Array is initialized at line 235 in production, but defensive guard handles sourcing edge cases.
  • Impact: Ensures Hermes startup/restart works on macOS default bash 3.2 without crashing on unset array access. No production behavioral change since array is always initialized.
  • Recommended action: Fix is correct for bash 3.2 compatibility. Add test for truly unset variable (see PRA-T1).
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Check lines 1800, 1817, 1860, 1994 in agents/hermes/start.sh for the `${_HERMES_GUARD_TIMEOUT[@]+"${_HERMES_GUARD_TIMEOUT[@]}"}` pattern.
  • Missing regression test: test/hermes-gateway-supervisor-recovery.test.ts line 393 tests empty array; need test with unset variable.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Check lines 1800, 1817, 1860, 1994 in agents/hermes/start.sh for the `${_HERMES_GUARD_TIMEOUT[@]+"${_HERMES_GUARD_TIMEOUT[@]}"}` pattern.
  • Evidence: agents/hermes/start.sh lines 1800, 1817, 1860, 1994

PRA-5 Improvement — Tavily API token pattern added to secret redaction fixtures

  • Location: test/e2e/fixtures/redaction.ts:49
  • Category: security
  • Problem: Added `/tvly-[A-Za-z0-9_-]{10,}/g` to TOKEN_PREFIX_PATTERNS for secret redaction in test fixtures, improving secret hygiene for Tavily token format.
  • Impact: Prevents Tavily API tokens from leaking into test logs/artifacts. Pattern mirrors canonical source in src/lib/security/secret-patterns.ts.
  • Suggested action: Good addition. Ensure parity test (test/e2e/support/e2e-redaction-parity.test.ts) validates this pattern stays in sync with canonical source.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Run test/e2e/support/e2e-redaction-parity.test.ts to confirm regex mirrors canonical source.
  • Missing regression test: Parity test should cover this — verify test/e2e/support/e2e-redaction-parity.test.ts includes the new pattern.
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: test/e2e/fixtures/redaction.ts:49 adds Tavily pattern to TOKEN_PREFIX_PATTERNS

PRA-6 Improvement — macOS bash 3.2 SIGTERM stderr filter tightened

  • Location: test/gateway-supervisor-control.test.ts:107
  • Category: correctness
  • Problem: Added `set +m` and stderr regex `/^(?:Terminated|Killed): \d+[^\n]*\n?/gm` to filter macOS bash 3.2 job control notifications (e.g., 'Terminated: 15 sleep 30') that appear despite `set +m`. Prevents test flakiness on macOS runners.
  • Impact: Improves test stability on macOS CI without masking real stderr output. Filter is precise to bash 3.2 notification format.
  • Suggested action: Fix is appropriate for cross-platform test stability. No production code change.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Run tests on macOS bash 3.2 to confirm no flaky stderr output from job control notifications.
  • Missing regression test: The test itself serves as regression coverage for PID tracking behavior; the stderr filter is test infrastructure.
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: test/gateway-supervisor-control.test.ts:107 adds `set +m` and stderr filter regex

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 1, 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: Source-of-truth review needed: Remaining Hermes lifecycle hex validation in `agents/hermes/start.sh`.
Open items: 0 required · 2 warnings · 0 suggestions · 6 test follow-ups
Since last review: 2 prior items resolved · 0 still apply · 1 new item found

Action checklist

  • PRA-1 Resolve or justify: Source-of-truth review needed: Remaining Hermes lifecycle hex validation in `agents/hermes/start.sh`
  • PRA-2 Resolve or justify: Finish locale-independent hex validation in touched Hermes lifecycle checks in agents/hermes/start.sh:2453
  • 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
  • PRA-T6 Add or justify test follow-up: Remaining Hermes lifecycle hex validation in `agents/hermes/start.sh`

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 security agents/hermes/start.sh:2453 Use the same explicit character class in the touched `start.sh` validators, e.g. replace `*[!0-9a-f]*` with `*[!0123456789abcdef]*` for the managed controller nonce and startup shields token checks. Preserve the existing length checks and lowercase-only rejection semantics.
Review findings by urgency: 0 required fixes, 2 items 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 — Source-of-truth review needed: Remaining Hermes lifecycle hex validation in `agents/hermes/start.sh`

  • 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: Nearby tests exercise managed-exit authorization negative cases, but none make an otherwise exact controller argv with an uppercase 64-byte nonce under a UTF-8 locale.
  • 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: `agents/hermes/start.sh:2453` and `agents/hermes/start.sh:1963` still use `*[!0-9a-f]*`.

PRA-2 Resolve/justify — Finish locale-independent hex validation in touched Hermes lifecycle checks

  • Location: agents/hermes/start.sh:2453
  • Category: security
  • Problem: `scripts/gateway-control.sh` and `scripts/lib/gateway-supervisor.sh` now avoid locale-sensitive `[a-f]` ranges by using `[0123456789abcdef]`, but `agents/hermes/start.sh` still validates the managed controller nonce with `*[!0-9a-f]*`. This function is part of the changed managed-exit authorization path, and the same macOS UTF-8 collation behavior can make uppercase hex bytes pass this lowercase-only check. A nearby startup shields token check at `agents/hermes/start.sh:1963` has the same range pattern.
  • Impact: The helper/supervisor request boundary rejects uppercase nonces deterministically, while the managed-exit authorization validator can still accept an uppercase 64-byte controller nonce under affected locales. That leaves a security-sensitive lifecycle parser with behavior that depends on the host shell locale and can undermine the PR's byte-exact validation invariant.
  • Recommended action: Use the same explicit character class in the touched `start.sh` validators, e.g. replace `*[!0-9a-f]*` with `*[!0123456789abcdef]*` for the managed controller nonce and startup shields token checks. Preserve the existing length checks and lowercase-only rejection semantics.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read-only check: inspect `agents/hermes/start.sh:2451-2454` and `agents/hermes/start.sh:1961-1965` and compare them with the explicit classes now used in `scripts/gateway-control.sh` and `scripts/lib/gateway-supervisor.sh`.
  • Missing regression test: Add a managed-exit authorization test where the controller argv is otherwise exact but its nonce is `B`.repeat(64) under a UTF-8 locale; it should be counted/rejected. If the shields resume token check is changed too, add a shell harness that feeds an uppercase 64-byte `lock_token` from the fake guard and expects `resume_startup_hermes_shields_lock` to fail.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read-only check: inspect `agents/hermes/start.sh:2451-2454` and `agents/hermes/start.sh:1961-1965` and compare them with the explicit classes now used in `scripts/gateway-control.sh` and `scripts/lib/gateway-supervisor.sh`.
  • Evidence: `scripts/gateway-control.sh` and `scripts/lib/gateway-supervisor.sh` changed their nonce checks to `*[!0123456789abcdef]*`, but `agents/hermes/start.sh` still contains `'' | *[!0-9a-f]*) return 1 ;;` in `hermes_managed_controller_argv_is_expected` and `*[!0-9a-f]*)` in `resume_startup_hermes_shields_lock`.

💡 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 — Source `scripts/lib/gateway-supervisor.sh` with `LC_ALL` or `LANG` set to a UTF-8 locale, reject an uppercase 64-byte request nonce, and assert the sourced shell's locale variables remain unchanged afterward.. The PR touches privileged gateway-control and PID 1 sandbox lifecycle shell. Static and nearby tests cover most changed behavior, but locale-sensitive shell parsing is runtime-dependent and should be proven under an explicit UTF-8 locale.
  • PRA-T2 Runtime validation — Run `scripts/gateway-control.sh` with an explicit UTF-8 locale and the root test seam, pass an uppercase 64-byte nonce, and assert it returns `SUPERVISOR_INVALID_NONCE` before control-directory access.. The PR touches privileged gateway-control and PID 1 sandbox lifecycle shell. Static and nearby tests cover most changed behavior, but locale-sensitive shell parsing is runtime-dependent and should be proven under an explicit UTF-8 locale.
  • PRA-T3 Runtime validation — In `test/hermes-managed-exit-authorization.test.ts`, make the controller argv otherwise exact but set its nonce to `B`.repeat(64) under a UTF-8 locale; the exit should be counted/rejected.. The PR touches privileged gateway-control and PID 1 sandbox lifecycle shell. Static and nearby tests cover most changed behavior, but locale-sensitive shell parsing is runtime-dependent and should be proven under an explicit UTF-8 locale.
  • PRA-T4 Runtime validation — Add or identify direct bash harness coverage for each changed guarded `_HERMES_GUARD_TIMEOUT` call path with the array unset and empty so bash 3.2 does not abort under `set -u`.. The PR touches privileged gateway-control and PID 1 sandbox lifecycle shell. Static and nearby tests cover most changed behavior, but locale-sensitive shell parsing is runtime-dependent and should be proven under an explicit UTF-8 locale.
  • PRA-T5 Acceptance clause — No linked issue clauses were available in the deterministic context for this PR. — add test evidence or identify existing coverage. `linkedIssues` was empty, so acceptance review is based on the changed files and nearby tests rather than issue-clause mapping.
  • PRA-T6 Remaining Hermes lifecycle hex validation in `agents/hermes/start.sh` — Nearby tests exercise managed-exit authorization negative cases, but none make an otherwise exact controller argv with an uppercase 64-byte nonce under a UTF-8 locale.. `agents/hermes/start.sh:2453` and `agents/hermes/start.sh:1963` still use `*[!0-9a-f]*`.
Since last review details

Current findings, using the urgency labels above:

PRA-1 Resolve/justify — Source-of-truth review needed: Remaining Hermes lifecycle hex validation in `agents/hermes/start.sh`

  • 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: Nearby tests exercise managed-exit authorization negative cases, but none make an otherwise exact controller argv with an uppercase 64-byte nonce under a UTF-8 locale.
  • 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: `agents/hermes/start.sh:2453` and `agents/hermes/start.sh:1963` still use `*[!0-9a-f]*`.

PRA-2 Resolve/justify — Finish locale-independent hex validation in touched Hermes lifecycle checks

  • Location: agents/hermes/start.sh:2453
  • Category: security
  • Problem: `scripts/gateway-control.sh` and `scripts/lib/gateway-supervisor.sh` now avoid locale-sensitive `[a-f]` ranges by using `[0123456789abcdef]`, but `agents/hermes/start.sh` still validates the managed controller nonce with `*[!0-9a-f]*`. This function is part of the changed managed-exit authorization path, and the same macOS UTF-8 collation behavior can make uppercase hex bytes pass this lowercase-only check. A nearby startup shields token check at `agents/hermes/start.sh:1963` has the same range pattern.
  • Impact: The helper/supervisor request boundary rejects uppercase nonces deterministically, while the managed-exit authorization validator can still accept an uppercase 64-byte controller nonce under affected locales. That leaves a security-sensitive lifecycle parser with behavior that depends on the host shell locale and can undermine the PR's byte-exact validation invariant.
  • Recommended action: Use the same explicit character class in the touched `start.sh` validators, e.g. replace `*[!0-9a-f]*` with `*[!0123456789abcdef]*` for the managed controller nonce and startup shields token checks. Preserve the existing length checks and lowercase-only rejection semantics.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read-only check: inspect `agents/hermes/start.sh:2451-2454` and `agents/hermes/start.sh:1961-1965` and compare them with the explicit classes now used in `scripts/gateway-control.sh` and `scripts/lib/gateway-supervisor.sh`.
  • Missing regression test: Add a managed-exit authorization test where the controller argv is otherwise exact but its nonce is `B`.repeat(64) under a UTF-8 locale; it should be counted/rejected. If the shields resume token check is changed too, add a shell harness that feeds an uppercase 64-byte `lock_token` from the fake guard and expects `resume_startup_hermes_shields_lock` to fail.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read-only check: inspect `agents/hermes/start.sh:2451-2454` and `agents/hermes/start.sh:1961-1965` and compare them with the explicit classes now used in `scripts/gateway-control.sh` and `scripts/lib/gateway-supervisor.sh`.
  • Evidence: `scripts/gateway-control.sh` and `scripts/lib/gateway-supervisor.sh` changed their nonce checks to `*[!0123456789abcdef]*`, but `agents/hermes/start.sh` still contains `'' | *[!0-9a-f]*) return 1 ;;` in `hermes_managed_controller_argv_is_expected` and `*[!0-9a-f]*)` in `resume_startup_hermes_shields_lock`.

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
scripts/lib/gateway-supervisor.sh (1)

9-11: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Scope LC_ALL=C to the nonce check, not the whole sourced library.

export LC_ALL=C at file scope mutates the caller’s shell and every child process. Since this library is sourced by scripts/nemoclaw-start.sh and agents/hermes/start.sh, the locale override should be limited to the nonce validation itself, e.g. by prefixing just that check or running it in a subshell.

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

In `@scripts/lib/gateway-supervisor.sh` around lines 9 - 11, The locale override
in gateway-supervisor.sh is too broad because export LC_ALL=C changes the caller
shell and all child processes. Limit the C locale to the nonce validation logic
in the nonce check path instead of setting it at file scope, using the
nonce-related comparison code in this sourced library so only the byte-exact
match is affected.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@scripts/lib/gateway-supervisor.sh`:
- Around line 9-11: The locale override in gateway-supervisor.sh is too broad
because export LC_ALL=C changes the caller shell and all child processes. Limit
the C locale to the nonce validation logic in the nonce check path instead of
setting it at file scope, using the nonce-related comparison code in this
sourced library so only the byte-exact match is affected.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 6d78bdab-83b1-4274-9b59-51152cef1556

📥 Commits

Reviewing files that changed from the base of the PR and between 4543f05 and a8568a2.

📒 Files selected for processing (5)
  • agents/hermes/start.sh
  • scripts/gateway-control.sh
  • scripts/lib/gateway-supervisor.sh
  • test/e2e/fixtures/redaction.ts
  • test/gateway-supervisor-control.test.ts

…ng LC_ALL

Addresses PR review advisor PRA-1/PRA-2 on #6140. The sourced supervisor
library set a top-level `export LC_ALL=C` so the `[!0-9a-f]` nonce glob would
match byte-exact (macOS UTF-8 folds [a-f] case-insensitively) — but exporting
LC_ALL from a sourced library leaks the C locale into the Hermes runtime.

Replace the locale-dependent range `[!0-9a-f]` with an explicit
locale-independent class `[!0123456789abcdef]` in both nonce checks
(scripts/lib/gateway-supervisor.sh and scripts/gateway-control.sh) and drop
the LC_ALL exports. Lowercase-only rejection is preserved (uppercase A-F are
not in the class) with no global locale side-effect.

Signed-off-by: Prekshi Vyas <prekshiv@nvidia.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@prekshivyas

Copy link
Copy Markdown
Contributor Author

Addressed the PR review advisor's two resolve/justify items in 88a7718f:

  • PRA-2 (LC_ALL leak, scripts/lib/gateway-supervisor.sh) — took the advisor's preferred fix: replaced the locale-dependent range [!0-9a-f] with an explicit locale-independent class [!0123456789abcdef] in both nonce checks (supervisor + gateway-control.sh) and dropped the top-level export LC_ALL=C. The sourced library no longer leaks the C locale into the Hermes runtime.
  • PRA-1 (source-of-truth for the localized behavior) — resolved by construction: with the explicit class there is no longer any locale-dependent workaround to document. The comments now explain the locale-independent class instead of an LC_ALL hack.

Lowercase-only rejection is preserved (uppercase AF aren't in the class), now without any global locale side-effect — the uppercase nonce rejection tests still pass, and it's byte-exact on macOS without relying on LC_ALL.

Also dispatched the E2E advisor's Required jobs against this branch (they don't run on PRs automatically): hermes-e2e, hermes-root-entrypoint-smoke, sandbox-operations.

@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Vitest E2E Target Results — ✅ All requested jobs passed

Run: 28546233046
Workflow ref: fix/macos-vitest-failures-clean
Requested targets: (default — all supported)
Requested jobs: hermes-e2e,hermes-root-entrypoint-smoke,sandbox-operations
Summary: 3 passed, 0 failed, 0 cancelled, 0 skipped

Job Result
hermes-e2e ✅ success
hermes-root-entrypoint-smoke ✅ success
sandbox-operations ✅ success

@apurvvkumaria apurvvkumaria merged commit 0127726 into main Jul 1, 2026
45 checks passed
@apurvvkumaria apurvvkumaria deleted the fix/macos-vitest-failures-clean branch July 1, 2026 20:51
prekshivyas added a commit that referenced this pull request Jul 6, 2026
…se64

Address the required PR-advisor findings on #6210:

- PRA-3: the corporate-CA bundle merged into a predictable /tmp path
  (/tmp/nemoclaw-ca-bundle.pem). Before the rename, drop any pre-planted
  symlink at the target so we rename into a fresh regular file we own rather
  than through an attacker-controlled link. Applied to both
  scripts/nemoclaw-start.sh and agents/hermes/start.sh.
- PRA-4: the Dockerfile decoded NEMOCLAW_CORPORATE_CA_B64 with `base64
  --decode` without checking the tool exists; add a build-time
  `command -v base64` guard that fails the build with a clear message.
- PRA-5 (justify, no change): GIT_SSL_CAINFO is already propagated to connect
  sessions by the pre-existing #2270 block whenever set (the merge exports it
  to the same bundle), so the corporate-CA propagation loop intentionally
  omits it to avoid a duplicate export; documented inline.

corporate-ca-runtime-merge + corporate-ca-tls-e2e suites pass; shell syntax
verified.

SKIP=test-cli: shell/Dockerfile-only change; the full vitest hook can trip on
pre-existing macOS bash 3.2 noise if this branch predates #6140. CI runs
bash 5.x green.

Signed-off-by: Prekshi Vyas <prekshiv@nvidia.com>
prekshivyas added a commit that referenced this pull request Jul 6, 2026
…x test titles

Follow-up to the #6293 SSRF hardening — two CI breakages:
- The isPrivateHostname block in probeOpenAiLikeEndpoint over-blocked
  host.docker.internal, a trusted sandbox->host bridge already gated by the
  allowHostDockerInternal check at the top of the function (Windows-host Ollama
  validation). Exempt the already-permitted hijacked-docker-internal alias.
- Three new test titles put the issue ref mid-parens ("(SSRF, #6293)") which
  fails test-title-style; move to a clean final "(#6293)".

cli project (635 tests) + npm run checks pass locally.

SKIP=test-cli: full hook may trip on pre-existing macOS bash 3.2 noise if this
branch predates #6140; CI runs bash 5.x green.

Signed-off-by: Prekshi Vyas <prekshiv@nvidia.com>
Hadar301 pushed a commit to Hadar301/NemoClaw-OpenShift that referenced this pull request Jul 12, 2026
## Summary

Five pre-existing test failures on the `macos-vitest` CI workflow
(confirmed present before NVIDIA#6060) traced to bash 3.x incompatibilities, a
macOS UTF-8 locale issue, and a missing fixture sync. This PR fixes all
five root causes.

Supersedes NVIDIA#6137 (that PR's branch was accidentally cut from a security
feature branch, pulling in unrelated files into the diff; this is a
clean rebase onto main with the same two commits plus a CodeRabbit fix).

## Related Issue

Investigation of CI run
[28539883104](https://github.com/NVIDIA/NemoClaw/actions/runs/28539883104);
failures also present in run
[28534214317](https://github.com/NVIDIA/NemoClaw/actions/runs/28534214317)
(before NVIDIA#6060), confirming NVIDIA#6060 is not the cause.

## Changes

- **`agents/hermes/start.sh`** — three bash 3.2 compatibility fixes:
- Replace bash 4.1+ named-FD `exec {var}<file` with a `{ } < file`
grouped redirect; variables assigned inside `{}` remain in function
scope
- Replace `mapfile -d '' -t` (bash 4.x only) with `while IFS= read -r -d
"" elem; do arr+=("$elem"); done`
- Guard `${_HERMES_GUARD_TIMEOUT[@]}` with `${arr[@]+"${arr[@]}"}` so
`set -u` does not abort the script when the array is empty (bash 3.2
treats empty `[@]` as unbound)
- **`scripts/gateway-control.sh`** — add `export LC_ALL=C` so `[a-f]`
character-class ranges in `case` patterns are byte-exact; macOS
`en_US.UTF-8` makes `[a-f]` case-insensitive, allowing uppercase hex
nonces to pass the `*[!0-9a-f]*` check
- **`scripts/lib/gateway-supervisor.sh`** — same `LC_ALL=C` fix for the
sourced library's nonce validation path
- **`test/gateway-supervisor-control.test.ts`** — pin
`NEMOCLAW_TEST_GATEWAY_CONTROL_CALLER_UID=0` in the nonce-rejection test
so it does not depend on the CI runner's UID; tighten macOS bash 3.2
SIGTERM filter from broad word-match to exact `Terminated: <digits>` /
`Killed: <digits>` format so unrelated stderr still fails the assertion
- **`test/e2e/fixtures/redaction.ts`** — add `tvly-` Tavily token
pattern missing since NVIDIA#6134, fixing the `e2e-redaction-parity`
`Array(16)` vs `Array(17)` mismatch

## Type of Change

- [x] Code change (feature, bug fix, or refactor)

## Quality Gates

- [x] Tests added or updated for changed behavior
- [x] Docs not applicable — justification: shell compatibility and test
fixes, no user-facing behavior change
- [x] Sensitive paths changed (security, policy, credentials, preflight,
onboarding, inference, runner, sandbox, or messaging) —
`gateway-control.sh` and `gateway-supervisor.sh` handle nonce validation
- [x] Sensitive-path review completed or maintainer-approved waiver
recorded — the `LC_ALL=C` fix tightens nonce validation (rejects
uppercase hex on macOS that was previously accepted);
`gateway_control_stop_tracked_pid` behavior is unchanged

## Verification

- [x] Git hooks passed during commit and push
- [x] Targeted tests pass for changed behavior
  - `test/gateway-supervisor-control.test.ts`: 22/22 ✓
- `test/hermes-managed-exit-authorization.test.ts`: all ✓ (was 8
failures before)
  - `test/e2e/support/e2e-redaction-parity.test.ts`: 3/3 ✓
- `test/hermes-gateway-supervisor-recovery.test.ts`: 41/42 (1 local
flake — PID 4242 alive on dev machine; unrelated to these changes,
passes on CI fresh runners)
- [x] No secrets, API keys, or credentials committed

**Remaining failures not addressed in this PR** (different root class,
need separate investigation):
- `install-preflight.test.ts` — environment-specific
- `deepagents-code-tui-startup-check.test.ts` — needs investigation
- `platform-parity-cloud-experimental.test.ts` — needs investigation
- WSL `runtime-recovery-preload.test.ts`, `rebuild-config-hash.test.ts`
— different class of failure

---
Signed-off-by: Prekshi Vyas <prekshiv@nvidia.com>

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

* **Bug Fixes**
* Improved gateway nonce validation to reliably accept only lowercase
hex characters, independent of locale and macOS environments.
* Fixed managed gateway startup, recovery, and live-status monitoring to
be compatible with older Bash versions.
* Tightened controller/marker parsing to reduce incorrect authorization
or status detection.
* Expanded secret redaction to cover additional Tavily-shaped tokens,
improving protection in logs and text output.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: Prekshi Vyas <prekshiv@nvidia.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants