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

apurvvkumaria merged 4 commits into
mainfrom
fix/macos-vitest-failures-clean

Conversation

@prekshivyas

@prekshivyas prekshivyas commented Jul 1, 2026 •

Copy link
Copy Markdown
Collaborator

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 fix/macos-vitest-fai... 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 fix/macos-vitest-fai... 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 fix/macos-vitest-fai... branch is 68%. Coverage data for the main branch is not yet available.

Show a code coverage summary of the most covered files.
File main fix/macos-vitest-fai... 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
Collaborator 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 A–F 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>
@wscurran wscurran added area: ci CI workflows, checks, release automation, or GitHub Actions bug-fix PR fixes a bug or regression integration: hermes Hermes integration behavior platform: macos Affects macOS, including Apple Silicon 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 bug-fix PR fixes a bug or regression integration: hermes Hermes integration behavior platform: macos Affects macOS, including Apple Silicon

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants