Skip to content

fix(hermes): prevent cron dispatch during rebuild restore - #7871

Open
HOYALIM wants to merge 10 commits into
NVIDIA:mainfrom
HOYALIM:codex/issue-7806-hermes-cron-activation
Open

fix(hermes): prevent cron dispatch during rebuild restore#7871
HOYALIM wants to merge 10 commits into
NVIDIA:mainfrom
HOYALIM:codex/issue-7806-hermes-cron-activation

Conversation

@HOYALIM

@HOYALIM HOYALIM commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Summary

Make Hermes cron restoration fail closed across sandbox rebuilds. Script-backed jobs now remain undispatchable until the backed-up cron tree and profile-local scripts are restored, validated, and acknowledged against the same gateway process identity.

Related Issue

Closes #7806.

Changes

  • include user-authored Hermes cron scripts in the durable rebuild state contract
  • reject incomplete or escaping active script references before sandbox deletion
  • reuse Hermes' external drain contract to quiesce dispatch, validate restored state, and release only after the same gateway returns to running
  • preserve the drain marker and backup when restore or activation proof is incomplete

Verification

  • PR description includes the DCO sign-off declaration and the commit is SSH-signed
  • npx vitest run --project cli --project integration src/lib/actions/sandbox/rebuild-hermes-cron-restore.test.ts test/hermes-cron-restore-control.test.ts
  • npx vitest run --project cli --project integration src/lib/actions/sandbox/rebuild-flow.test.ts src/lib/actions/sandbox/rebuild-hermes-post-restore.test.ts test/hermes-final-image-layout.test.ts
  • npm run typecheck:cli -- --incremental
  • npm run check:diff

Signed-off-by: Ho Lim subhoya@gmail.com

Summary by CodeRabbit

  • New Features
    • Added safe Hermes cron job backup and restore handling during sandbox rebuilds, including a multi-step drain, validation, and release lifecycle.
    • Preserves user-authored cron scripts and validates job definitions, script paths, and permissions before reactivating dispatch.
  • Bug Fixes
    • Fail-closed behavior prevents cron dispatch from being restored when safety cannot be confirmed.
    • Blocks missing, unreadable, symlinked, or out-of-scope cron scripts from being restored or executed.
    • Added integrity verification for the cron restore components.

Signed-off-by: Ho Lim <subhoya@gmail.com>
Copilot AI review requested due to automatic review settings July 30, 2026 03:02
@copy-pr-bot

copy-pr-bot Bot commented Jul 30, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Hermes cron rebuilds now validate restored job scripts, drain the gateway during state restoration, verify gateway identity and cron readiness, and release dispatch only after successful validation. The controller is packaged in the Hermes image, and cron scripts are preserved in rebuild backups.

Changes

Hermes cron restore

Layer / File(s) Summary
Backup validation
src/lib/state/rebuild/hermes-cron-restore-backup.ts, src/lib/actions/sandbox/rebuild-preflight-phase.ts, src/lib/actions/sandbox/rebuild-hermes-cron-restore.test.ts
Validates profile job stores, script paths, file metadata, readability, active-job counts, and dispatch-gate requirements before restore.
Gateway drain control
agents/hermes/cron-restore-control.py, test/hermes-cron-restore-control.test.ts
Adds fail-closed cron-tree validation and begin, validate, and release commands with gateway state, identity, receipt, and recovery handling.
Rebuild transaction integration
src/lib/actions/sandbox/rebuild-hermes-post-restore.ts, src/lib/actions/sandbox/rebuild-pipeline.ts, src/lib/actions/sandbox/rebuild-post-restore-phase.ts, src/lib/actions/sandbox/rebuild-hermes-cron-restore.test.ts
Runs Hermes restores inside an identity-bound drain transaction, handles incomplete or failed reactivation, revalidates the delete edge, and updates the post-restore export surface.
Runtime state and packaging
agents/hermes/manifest.yaml, agents/hermes/Dockerfile, test/hermes-final-image-layout.test.ts
Preserves Hermes scripts state and packages the cron restore controller with executable permissions, ownership, and SHA-256 integrity checks.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant RebuildPipeline
  participant BackupValidator
  participant HermesCronControl
  participant HermesGateway
  RebuildPipeline->>BackupValidator: validate cron backup
  RebuildPipeline->>HermesCronControl: begin restore gate
  HermesCronControl->>HermesGateway: request draining
  HermesGateway-->>HermesCronControl: draining with zero active agents
  RebuildPipeline->>RebuildPipeline: restore durable state
  RebuildPipeline->>HermesCronControl: validate restore
  HermesCronControl->>HermesGateway: verify identity and drain
  HermesCronControl-->>RebuildPipeline: validation receipt
  RebuildPipeline->>HermesCronControl: release restore gate
  HermesCronControl->>HermesGateway: clear drain request
  HermesGateway-->>HermesCronControl: running
Loading

Possibly related PRs

  • NVIDIA/NemoClaw#7168: Exercises the Hermes cron-restore lifecycle through rebuild E2E workflow instrumentation and progress tests.
  • NVIDIA/NemoClaw#7788: Modifies the same rebuild pipeline’s sandbox replacement journaling and delete/recreate lifecycle.
  • NVIDIA/NemoClaw#7880: Also changes Hermes cron state restoration and manifest scripts handling.

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

Suggested reviewers: cv, ericksoa

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The PR also wires route validation before deletion, which is unrelated to the Hermes cron restore requirements in [#7806]. Move the route validation changes to a separate PR or link an issue establishing them as part of this change.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes preventing Hermes cron dispatch during rebuild restoration, the PR's primary change.
Linked Issues check ✅ Passed The implementation adds durable script backup, fail-closed validation, gateway drain identity binding, and transactional release behavior required by [#7806].
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@github-actions

github-actions Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

PR Review Advisor — Blocking findings reported

Advisor assessment: Blockers require maintainer review
Next action: Review the blockers below.
Findings: 1 blocker · 0 warnings · 0 suggestions

Model lanes

  • GPT-5.6 Terra (primary): Completed · high confidence · 1 blocker · 0 warnings · 0 suggestions
  • Nemotron 3 Ultra (second opinion): Failed after a partial review · low confidence · 0 blockers · 2 warnings · 1 suggestion

Second-opinion terminology and E2E selections are advisory. They do not change the primary assessment or E2E / PR Gate.

1 semantic terminology decision

Terminology decisions are advisory. They affect the assessment only when a separate finding identifies concrete semantic impact.

  • define — cron restore controller at agents/hermes/Dockerfile:504: Define this term at first explanatory use when readers need to distinguish the controller from restore logic.

E2E guidance

Advisory only. E2E / PR Gate selects and runs jobs independently.

Recommended E2E: cloud-onboard, full-e2e, hermes-e2e, hermes-inference-switch, security-posture, onboard-repair, onboard-resume, rebuild-openclaw, state-backup-restore

2 optional E2E recommendations
  • rebuild-hermes
  • rebuild-hermes-stale-base

Blockers

PRA-1 Blocker — Quote the drain token before invoking the controller

  • Location: src/lib/actions/sandbox/rebuild-hermes-post-restore.ts:132
  • Category: security
  • Problem: The host accepts any nonempty string as a sandbox-produced drain token, then interpolates it into the `sh -c` command for validate and release. Shell metacharacters in a forged receipt token can alter the command that runs inside the sandbox.
  • Impact: A sandbox-controlled receipt can execute additional shell syntax during the host-initiated control operation, crossing the intended host-to-sandbox command boundary.
  • Fix: Shell-quote the drain token, or pass controller arguments through an argv-based execution path, before constructing the command.
  • Verification: Inspect the constructed validate and release command with a token containing spaces, quotes, and command substitution syntax; it must contain one literal --drain-token argument.
  • Test coverage: Add a rebuild-hermes-cron-restore test whose receipt has shell metacharacters in drain_token and asserts validate and release preserve it as one literal argument without extra command syntax.
  • Evidence: src/lib/actions/sandbox/rebuild-hermes-post-restore.ts:104-135 validates drain_token only as a nonempty string and interpolates it in `identityArgs`. src/lib/actions/sandbox/process-recovery.ts:219-229 executes the supplied command through `sh -c` inside the sandbox.

Workflow run details

This automated review informs maintainers. Warnings and suggestions do not require a response. A maintainer decides whether to merge.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (3)
src/lib/actions/sandbox/rebuild-pipeline.ts (1)

360-379: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract the gated-restore IIFE into a named helper.

The inline (() => { try {...} catch {...} })() embedded in a ternary is hard to scan at a glance and mixes two concerns (transaction execution + error reporting) inline with the main rebuild flow.

♻️ Suggested refactor
-      const restored = hermesCronRestorePlan?.requiresDispatchGate
-        ? (() => {
-            try {
-              return runHermesCronRestoreTransaction(sandboxName, restore, (state, identity) => {
-                log(
-                  `Hermes cron restore gate ${state}: pid=${String(identity.pid)}, startTime=${String(identity.start_time)}`,
-                );
-              });
-            } catch (error) {
-              console.error("");
-              console.error(
-                error instanceof HermesCronRestoreIncompleteError
-                  ? "  Hermes cron dispatch remains drained because state restore was incomplete."
-                  : `  Hermes cron restore could not prove safe reactivation: ${rebuildFailureDetail(error)}`,
-              );
-              console.error(`  Backup is preserved at: ${backup.backupManifest?.backupPath}`);
-              return bail("Hermes cron restore validation failed; dispatch was not re-enabled.");
-            }
-          })()
-        : restore();
+      const runGatedHermesCronRestore = (): typeof restore extends () => infer T ? T : never => {
+        try {
+          return runHermesCronRestoreTransaction(sandboxName, restore, (state, identity) => {
+            log(
+              `Hermes cron restore gate ${state}: pid=${String(identity.pid)}, startTime=${String(identity.start_time)}`,
+            );
+          });
+        } catch (error) {
+          console.error("");
+          console.error(
+            error instanceof HermesCronRestoreIncompleteError
+              ? "  Hermes cron dispatch remains drained because state restore was incomplete."
+              : `  Hermes cron restore could not prove safe reactivation: ${rebuildFailureDetail(error)}`,
+          );
+          console.error(`  Backup is preserved at: ${backup.backupManifest?.backupPath}`);
+          return bail("Hermes cron restore validation failed; dispatch was not re-enabled.");
+        }
+      };
+      const restored = hermesCronRestorePlan?.requiresDispatchGate
+        ? runGatedHermesCronRestore()
+        : restore();
🤖 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 `@src/lib/actions/sandbox/rebuild-pipeline.ts` around lines 360 - 379, Extract
the inline gated-restore IIFE from the `restored` assignment into a named helper
near the rebuild flow. Have the helper execute
`runHermesCronRestoreTransaction`, preserve the existing gate-state logging and
error-reporting behavior, and return `bail(...)` on failure; then call the
helper from the `hermesCronRestorePlan?.requiresDispatchGate` branch while
leaving the `restore()` branch unchanged.
src/lib/actions/sandbox/rebuild-hermes-cron-restore/backup.ts (1)

4-13: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoff

Direct filesystem I/O inside an actions-layer module.

This file performs raw fs syscalls (lstatSync, readdirSync, readFileSync, realpathSync) directly inside src/lib/actions/**, interleaved with the validity decisions (symlink checks, script-escape rules, size limits). Per the repo's layering rules, host-boundary work belongs in an adapter (injectable for tests) while the pure accept/reject decisions belong in a domain module; this file currently owns both.

♻️ Suggested direction

Split into: an adapter that exposes lstat/readdir/readFile/realpath primitives (mockable in tests), and a domain module that takes the resulting metadata and returns accept/reject decisions — with this file reduced to orchestrating the two.

As per path instructions for src/lib/{actions,domain,adapters,state}/**: "actions orchestrate, domain modules make pure decisions, adapters own host/process/network boundaries" (src/lib/README.md).

Also applies to: 182-212

🤖 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 `@src/lib/actions/sandbox/rebuild-hermes-cron-restore/backup.ts` around lines 4
- 13, Split the filesystem and validation responsibilities currently combined in
the backup flow: move lstat/readdir/readFile/realpath calls behind an injectable
adapter, move symlink, script-escape, and size-limit accept/reject logic into a
pure domain module, and reduce the action entrypoint to orchestrating those
components while preserving existing behavior. Use the existing backup-related
functions and module symbols to identify the orchestration, adapter, and domain
boundaries.

Source: Path instructions

test/hermes-final-image-layout.test.ts (1)

239-239: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Add the matching permission assertions
The test only covers the new COPY entry; add the chmod 755 and chown root:root expectations for hermes-cron-restore-control.py too so the new script’s ownership and mode changes stay covered.

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

In `@test/hermes-final-image-layout.test.ts` at line 239, Add assertions in the
Hermes final image layout test for the copied hermes-cron-restore-control.py
entry, verifying it receives chmod 755 and chown root:root alongside the
existing COPY expectation. Keep the assertions scoped to this script’s
permission and ownership configuration.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/lib/actions/sandbox/rebuild-hermes-cron-restore/backup.ts`:
- Around line 131-133: Replace the permission-bit-only check in the rebuild
preflight with an `isReadableSync` helper that calls `accessSync(path,
constants.R_OK)` and returns false on errors. Use this helper when validating
the resolved script path so the preflight matches the Python `_validate_script`
readability gate and throws the existing unreadable-script error before deleting
the old sandbox.

In `@test/hermes-cron-restore-control.test.ts`:
- Around line 17-71: Extend the Hermes cron restore control tests beyond
validateTree to directly cover begin_drain, validate_restore, and release_drain
in cron-restore-control.py. Add successful lifecycle coverage plus failure cases
for invalid gateway identity and missing or incorrect drain markers, asserting
each command’s status and relevant output while preserving the existing
temporary-home setup and cleanup.

---

Nitpick comments:
In `@src/lib/actions/sandbox/rebuild-hermes-cron-restore/backup.ts`:
- Around line 4-13: Split the filesystem and validation responsibilities
currently combined in the backup flow: move lstat/readdir/readFile/realpath
calls behind an injectable adapter, move symlink, script-escape, and size-limit
accept/reject logic into a pure domain module, and reduce the action entrypoint
to orchestrating those components while preserving existing behavior. Use the
existing backup-related functions and module symbols to identify the
orchestration, adapter, and domain boundaries.

In `@src/lib/actions/sandbox/rebuild-pipeline.ts`:
- Around line 360-379: Extract the inline gated-restore IIFE from the `restored`
assignment into a named helper near the rebuild flow. Have the helper execute
`runHermesCronRestoreTransaction`, preserve the existing gate-state logging and
error-reporting behavior, and return `bail(...)` on failure; then call the
helper from the `hermesCronRestorePlan?.requiresDispatchGate` branch while
leaving the `restore()` branch unchanged.

In `@test/hermes-final-image-layout.test.ts`:
- Line 239: Add assertions in the Hermes final image layout test for the copied
hermes-cron-restore-control.py entry, verifying it receives chmod 755 and chown
root:root alongside the existing COPY expectation. Keep the assertions scoped to
this script’s permission and ownership configuration.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 9637835a-e6fe-4b49-b92b-c42d404fc276

📥 Commits

Reviewing files that changed from the base of the PR and between 376beb5 and 5f5c085.

📒 Files selected for processing (10)
  • agents/hermes/Dockerfile
  • agents/hermes/cron-restore-control.py
  • agents/hermes/manifest.yaml
  • src/lib/actions/sandbox/rebuild-hermes-cron-restore.test.ts
  • src/lib/actions/sandbox/rebuild-hermes-cron-restore/backup.ts
  • src/lib/actions/sandbox/rebuild-hermes-post-restore.ts
  • src/lib/actions/sandbox/rebuild-pipeline.ts
  • src/lib/actions/sandbox/rebuild-post-restore-phase.ts
  • test/hermes-cron-restore-control.test.ts
  • test/hermes-final-image-layout.test.ts

Comment thread src/lib/state/rebuild/hermes-cron-restore-backup.ts
Comment thread test/hermes-cron-restore-control.test.ts
Signed-off-by: Ho Lim <subhoya@gmail.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

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

Inline comments:
In `@src/lib/actions/sandbox/rebuild-hermes-cron-restore/backup.ts`:
- Around line 5-6: Remove the direct filesystem and JSON persistence handling
from the backup restore action, including the accessSync/constants imports, and
move backup-tree traversal and persisted-state reads into the appropriate
state-layer API under state modules. Update the restore-validation orchestration
in the action to call that API directly, without retaining a forwarding
duplicate.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 749e83f4-60cf-4834-82f5-6440c656de8a

📥 Commits

Reviewing files that changed from the base of the PR and between 5f5c085 and fd7b3b9.

📒 Files selected for processing (2)
  • src/lib/actions/sandbox/rebuild-hermes-cron-restore/backup.ts
  • test/hermes-cron-restore-control.test.ts

Comment on lines +5 to +6
accessSync,
constants,

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.

📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift

Move persisted backup-tree I/O into the state layer.

These imports support direct metadata and JSON reads in an action module. Keep this action as the restore-validation orchestrator, but move backup filesystem traversal and persisted-state reads to src/lib/state/** and call that API here—without retaining a forwarding duplicate.

As per path instructions, “state modules own persisted files and state I/O.”

🤖 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 `@src/lib/actions/sandbox/rebuild-hermes-cron-restore/backup.ts` around lines 5
- 6, Remove the direct filesystem and JSON persistence handling from the backup
restore action, including the accessSync/constants imports, and move backup-tree
traversal and persisted-state reads into the appropriate state-layer API under
state modules. Update the restore-validation orchestration in the action to call
that API directly, without retaining a forwarding duplicate.

Source: Path instructions

Signed-off-by: Ho Lim <subhoya@gmail.com>
Signed-off-by: Ho Lim <subhoya@gmail.com>

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
agents/hermes/Dockerfile (1)

62-62: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Include the cron restore controller in the image integrity gate.

This security-critical controller is copied into the image and hardened, but it is not covered by the Dockerfile’s SHA-256 verification block. A modified build-context script could therefore change the fail-closed restore policy while the existing integrity checks still pass. Add a committed hash argument and sha256sum -c verification for /usr/local/lib/nemoclaw/hermes-cron-restore-control.py.

As per path instructions, agents/** is a security boundary requiring fail-closed handling and least privilege.

Also applies to: 216-217

🤖 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 `@agents/hermes/Dockerfile` at line 62, Add the committed SHA-256 hash argument
for hermes-cron-restore-control.py alongside the existing integrity values, and
extend the Dockerfile’s verification block to run sha256sum -c against
/usr/local/lib/nemoclaw/hermes-cron-restore-control.py. Ensure the check fails
the build on any mismatch and retains the existing fail-closed behavior.

Source: Path instructions

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

Outside diff comments:
In `@agents/hermes/Dockerfile`:
- Line 62: Add the committed SHA-256 hash argument for
hermes-cron-restore-control.py alongside the existing integrity values, and
extend the Dockerfile’s verification block to run sha256sum -c against
/usr/local/lib/nemoclaw/hermes-cron-restore-control.py. Ensure the check fails
the build on any mismatch and retains the existing fail-closed behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: a57dcd5f-7d50-4fb5-8f17-6b8d30514c7f

📥 Commits

Reviewing files that changed from the base of the PR and between c4dde20 and d0c19ff.

📒 Files selected for processing (3)
  • agents/hermes/Dockerfile
  • src/lib/actions/sandbox/rebuild-pipeline.ts
  • src/lib/actions/sandbox/rebuild-preflight-phase.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/lib/actions/sandbox/rebuild-preflight-phase.ts

Signed-off-by: Ho Lim <subhoya@gmail.com>
@wscurran

wscurran commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

✨ Thanks for the PR. This fixes the cron dispatch regression by making Hermes restoration fail closed until scripts are validated against the same gateway identity. Maintainers will review the drain contract reuse, backup preservation, and test coverage for both restore paths.


Related open issues:


Related open issues:

Signed-off-by: Ho Lim <subhoya@gmail.com>
@github-actions github-actions Bot added v0.0.102 Release target and removed v0.0.101 labels Aug 3, 2026

@apurvvkumaria apurvvkumaria left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Blocking: the new Hermes restore controller can erase a pre-existing drain owned by another workflow. begin_drain unconditionally writes the nemoclaw-cron-restore marker over any active current-epoch marker, and release_drain later clears that marker without proving this operation acquired it. Reproduction: seed a current-epoch drain marker with principal operator, run begin followed by release, and observe that the operator drain is gone and cron dispatch can resume even though the operator still requires it. The focused tests pass because they model drain state as a boolean and do not cover pre-existing ownership.\n\nPlease preserve an already-active drain, record an ownership receipt or token only when this controller acquires the marker, and clear only when the current marker still matches that ownership. Add success and failure-path tests showing an operator-owned marker survives begin, release, and rollback. This is required because the current behavior breaks the supported scheduling-safety contract.

Signed-off-by: Ho Lim <subhoya@gmail.com>

@apurvvkumaria apurvvkumaria left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Re-reviewed the current revision after the requested drain-ownership fix. Begin now preserves a pre-existing external drain and records a random ownership token only when this controller acquires the marker. Validation and release require the current marker to match that token; release without an acquired token preserves the external marker, and rollback will not overwrite a replacement operator marker. The new tests reproduce pre-existing, replacement, and failed-release cases and confirm the operator marker survives. The prior scheduling-safety blocker is resolved, and I found no new blocking correctness, security, compatibility, or regression defect.

@apurvvkumaria

Copy link
Copy Markdown
Collaborator

Non-blocking fast-follow recommendation: make drain marker acquisition and release compare-and-set operations. The pinned Hermes helpers currently implement unconditional replace/unlink, so an operator marker written in the narrow gaps between the controller's ownership check and its write, clear, or rollback write can still be overwritten or removed. The sequential supported-path blocker is fixed and this does not change the approval outcome. A narrowly scoped follow-up should add create-only and token-matched-clear primitives (or equivalent serialization) in Hermes, then cover concurrent operator replacement at begin, release, and rollback.

HOYALIM added 2 commits August 3, 2026 17:09
Signed-off-by: Ho Lim <subhoya@gmail.com>
Signed-off-by: Ho Lim <subhoya@gmail.com>
@HOYALIM
HOYALIM force-pushed the codex/issue-7806-hermes-cron-activation branch from 4817a2f to 06a6b6e Compare August 4, 2026 00:18

@apurvvkumaria apurvvkumaria left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Approve — re-reviewed exact head 06a6b6e after the main refresh. The previously approved external-drain ownership fix is unchanged. The conflict resolution correctly composes the cron restore controller into the current Hermes runtime payload and integrity gate, including copy, root ownership and mode, committed SHA-256 verification, and layout assertions. Exact-head focused suites passed 20 of 20 tests. I also reviewed the timed-out second-opinion artifact: its duplicate-PR coordination concern and optional content-hash hardening do not demonstrate PR-attributable breakage, while live script existence and permission validation runs after restore with dispatch still drained. No blocking defect found.

@cjagwani

cjagwani commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator

Release-queue follow-up: approved head 06a6b6e is now DIRTY against main. Its E2E controller timed out waiting for the trusted verdict rather than reporting a branch-owned test failure. Please update from current main, resolve the conflict with a signed/verified commit, and let the required CI, advisor, and E2E evidence regenerate on the new exact head.

Signed-off-by: Ho Lim <subhoya@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: sandbox OpenShell sandbox lifecycle, runtime, config, or recovery bug-fix PR fixes a bug or regression integration: hermes Hermes integration behavior v0.0.102 Release target

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Ubuntu 24.04][Upgrade] rebuild enables restored cron jobs before their scripts are available

6 participants