Skip to content

ci(e2e): reuse exact-commit CLI artifact - #7943

Open
cjagwani wants to merge 10 commits into
mainfrom
codex/7915-exact-commit-artifacts
Open

ci(e2e): reuse exact-commit CLI artifact#7943
cjagwani wants to merge 10 commits into
mainfrom
codex/7915-exact-commit-artifacts

Conversation

@cjagwani

@cjagwani cjagwani commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

Summary

Build the candidate CLI once in generate-matrix, publish a content-addressed artifact, and restore it in 63 live E2E consumers. The restore contract is pinned to an immutable commit and fails closed on provenance, digest, archive, candidate-SHA, compiled build-identity, or activation mismatch.

This branch is current with main; the retired sandbox-rebuild and upgrade-stale-sandbox jobs remain retired.

Related Issue

Advances #7915.

The before/after wall-time and runner-minute acceptance criterion remains open. Trusted PR E2E executes .github/workflows/e2e.yaml from main, so an honest post-change comparison requires a passing post-merge main run.

Changes

  • Make generate-matrix the single default CLI producer and pass one closed-schema nemoclaw-e2e-cli-provenance-v1 object to 63 restore consumers.
  • Pin every consumer to hardened restore action commit e5a55a8be89d4a3dfd44b743c7190544ef2f5246.
  • Require the manifest and staged dist/build-identity.json to bind the compiled CLI to the candidate commit before activation.
  • Extract into a private staging directory and reject digest mismatch, non-dist members, traversal, links, special files, or a preexisting workspace dist/.
  • Add executable restore fixtures for the valid path and each fail-closed boundary.
  • Cover valid-schema repository, workflow SHA, run ID, and run-attempt provenance mismatches before download.
  • Update the E2E maintainer documentation with the corrected inventory: 63 prior builds become one producer build, eliminating 62 duplicates.
  • Keep the measured-runtime procedure explicit without claiming theoretical runner-time savings as observed results.

Type of Change

  • Code change (feature, bug fix, or refactor)
  • Code change with doc updates
  • Doc only (prose changes, no code sample modifications)
  • Doc only (includes code sample changes)

Quality Gates

  • Tests added or updated for changed behavior
  • Existing tests cover changed behavior — justification:
  • Tests not applicable — justification:
  • Docs updated for user-facing behavior changes
  • Docs not applicable — justification:
  • Sensitive paths changed (security, policy, credentials, preflight, onboarding, inference, runner, sandbox, or messaging)
  • Sensitive-path review completed or maintainer-approved waiver recorded — reviewer/approval link/justification: Maintainer review completed in this task. Executable fixtures cover provenance, digest, archive-member, link, preexisting-output, and compiled-identity rejection.
  • Non-success, skipped, or missing CI check accepted by maintainer — check name, approval link, and follow-up issue:

Documentation Writer Review

  • Documentation writer subagent reviewed the completed changes
  • Result: docs-updated
  • Evidence: test/e2e/README.md; focused artifact suite 27/27; full E2E-support suite 1,871 passed and 17 skipped; test-conditionals scan, Biome, Markdown lint, and git diff --check passed
  • Agent: Codex Desktop

DGX Station Hardware Evidence

  • Tested on DGX Station
  • Tested commit:
  • Station profile/scenario:
  • Result:
  • Supporting evidence:

Verification

  • PR description includes a Signed-off-by: line and every commit appears as Verified in GitHub
  • Normal pre-commit, commit-msg, and pre-push hooks passed, or npm run validate:pr passed after refreshing origin/main when hooks were skipped or unavailable
  • Targeted behavior tests pass for the current change set, or tests are marked not applicable above — exact-commit artifact suite: 27/27 passed
  • Applicable broad gate passed — E2E-support: 1,871 passed and 17 skipped
  • Quality Gates section completed with required justifications or waivers
  • No secrets, API keys, or credentials committed
  • npm run docs builds without warnings (doc changes only)
  • Doc pages follow the style guide (doc changes only)
  • New doc pages include SPDX header and frontmatter (new pages only)

Signed-off-by: Charan Jagwani cjagwani@nvidia.com

Summary by CodeRabbit

  • New Features

    • Added verified exact-commit CLI artifact generation and restoration for end-to-end workflows.
    • Added integrity, provenance, safe extraction, build identity, and CLI version checks.
    • Centralized CLI building to produce consistent artifacts for all E2E jobs.
  • Documentation

    • Documented the artifact workflow, validation requirements, and build measurement process.
  • Tests

    • Added comprehensive coverage for valid, tampered, unsafe, and misconfigured artifact workflows.
    • Updated workflow boundary checks to enforce artifact restoration and ordering.

cjagwani added 2 commits July 30, 2026 13:31
Signed-off-by: Charan Jagwani <cjagwani@nvidia.com>
Signed-off-by: Charan Jagwani <cjagwani@nvidia.com>
@copy-pr-bot

copy-pr-bot Bot commented Jul 30, 2026

Copy link
Copy Markdown

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

Contributors can view more details about this message here.

@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The E2E workflow now builds one exact-commit CLI artifact, records provenance, and restores it across consumer jobs. A composite action validates identity, integrity, archive safety, and build metadata. Workflow validators and tests enforce producer, consumer, and ordering contracts.

Changes

CLI artifact reuse

Layer / File(s) Summary
Artifact packaging and restore contract
.github/actions/restore-e2e-cli-artifact/action.yaml, .github/workflows/e2e.yaml
The producer builds and publishes a content-addressed CLI artifact with provenance. The restore action validates provenance, digests, manifests, archive members, build identity, and CLI version.
Consumer workflow integration
.github/workflows/e2e.yaml, tools/e2e/prepare-e2e-workflow-boundary.mts, tools/e2e/*workflow-boundary.mts
E2E jobs disable local CLI builds, depend on generate-matrix, and restore the artifact after workspace preparation.
Workflow boundary validation
tools/e2e/*workflow-boundary.mts
Validators enforce producer configuration, immutable restoration, consumer dependencies, upload rules, and bootstrap ordering.
Boundary regression coverage
test/e2e/support/*, test/e2e/README.md
Tests cover provenance, payload and archive validation, workflow drift, ordering, excluded jobs, and retained fixture constraints. Documentation records the artifact flow and measurement requirements.

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

Sequence Diagram(s)

sequenceDiagram
  participant GenerateMatrix as generate-matrix
  participant ArtifactStore as GitHub artifact store
  participant RestoreAction as restore-e2e-cli-artifact
  participant E2EJob as E2E consumer job
  GenerateMatrix->>GenerateMatrix: build and record provenance
  GenerateMatrix->>ArtifactStore: upload CLI artifact
  E2EJob->>RestoreAction: pass cli_artifact_provenance
  RestoreAction->>ArtifactStore: download and verify artifact
  RestoreAction->>E2EJob: restore dist and verify CLI version
  E2EJob->>E2EJob: run E2E tests
Loading

Possibly related PRs

Suggested labels: area: ci, area: e2e, area: packaging, area: security

Suggested reviewers: cv, apurvvkumaria

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes reusing an exact-commit CLI artifact in E2E workflows, which is the pull request's primary change.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 2
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/7915-exact-commit-artifacts

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

@github-code-quality

github-code-quality Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Overview

Languages: TypeScript

TypeScript / code-coverage/plugin

The overall coverage in commit 6057eab in the codex/7915-exact-com... branch remains at 96%, unchanged from commit 0de2789 in the main branch.


Updated August 01, 2026 08:09 UTC

Comment thread test/e2e/support/cli-artifact-workflow-boundary.test.ts Fixed
Comment thread test/e2e/support/cli-artifact-workflow-boundary.test.ts Fixed
@github-actions

github-actions Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

PR Review Advisor — No blocking findings reported

Advisor assessment: No blocking advisor findings reported
Next action: No advisor follow-up needed.
Findings: 0 blockers · 0 warnings · 0 suggestions

Model lanes

  • GPT-5.6 Terra (primary): Completed · high confidence · 0 blockers · 0 warnings · 0 suggestions
  • Nemotron 3 Ultra (second opinion): Failed

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

E2E guidance

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

Recommended E2E: cloud-inference, cloud-onboard, security-posture

Workflow run details

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

cv added 6 commits July 31, 2026 16:38
Signed-off-by: Carlos Villela <cvillela@nvidia.com>
Signed-off-by: Carlos Villela <cvillela@nvidia.com>
Signed-off-by: Carlos Villela <cvillela@nvidia.com>
Signed-off-by: Carlos Villela <cvillela@nvidia.com>
Signed-off-by: Carlos Villela <cvillela@nvidia.com>
Signed-off-by: Carlos Villela <cvillela@nvidia.com>
@cv
cv marked this pull request as ready for review August 1, 2026 08:05

@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: 3

🧹 Nitpick comments (5)
tools/e2e/runner-comparison-workflow-boundary.mts (1)

197-198: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Record why the prepare fallback stays.

bootstrapEnd falls back to prepare when no restore step exists. That fallback is load-bearing, not defensive: security-posture is a comparison job and also a member of PREPARE_E2E_NO_BUILD_JOBS, so it never restores the artifact. Without a comment, a later cleanup can remove the fallback and break that job's validation. Add one line that names the case.

📝 Proposed comment
+    // Comparison jobs that never build or restore the CLI (for example
+    // security-posture, a PREPARE_E2E_NO_BUILD_JOBS member) end bootstrap at
+    // prepare-e2e, so the restore step is optional here.
     const restore = jobSteps.findIndex((step) => step.name === CLI_ARTIFACT_RESTORE_STEP);
     const bootstrapEnd = restore >= 0 ? restore : prepare;
🤖 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 `@tools/e2e/runner-comparison-workflow-boundary.mts` around lines 197 - 198,
Add a concise inline comment immediately above the `bootstrapEnd` assignment
explaining that comparison jobs such as `security-posture` skip artifact
restoration because they belong to `PREPARE_E2E_NO_BUILD_JOBS`, so the `prepare`
fallback must be preserved.
test/e2e/support/rebuild-hermes-workflow-boundary.test.ts (1)

60-78: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a case that removes only the restore step.

The suite never asserts the missing-restore-step error. validateRebuildHermesBootstrapBoundary guards its ordering check with restoreCli &&, so the ordering check short-circuits when the restore step is absent. If the requireJobStep call for CLI_ARTIFACT_RESTORE_STEP is removed later, a job that never restores the artifact produces no error and this suite still passes.

The existing negative case mutates the environment, the with block, and the step order together, so it cannot cover this path. Add one focused case that drops only the restore step.

As per path instructions: "Migration tests must prove the superseded path is unreachable or removed, not merely prove that the new path also works."

💚 Proposed additional case
it.each(JOB_NAMES)("%s must require the exact-commit CLI restore step", (jobName) => {
  const job = bootstrapJob(jobName);
  job.steps = job.steps.filter((step) => step.name !== "Restore exact-commit CLI artifact");

  expect(validateRebuildHermesBootstrapBoundary(jobName, job)).toContain(
    `${jobName} job is missing step 'Restore exact-commit CLI artifact'`,
  );
});

Match the expected string to the exact text that requireJobStep produces.

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

In `@test/e2e/support/rebuild-hermes-workflow-boundary.test.ts` around lines 60 -
78, Add a focused parameterized test alongside the existing rebuild Hermes
boundary cases that removes only the step named “Restore exact-commit CLI
artifact” from the job returned by bootstrapJob. Assert
validateRebuildHermesBootstrapBoundary reports the missing
CLI_ARTIFACT_RESTORE_STEP using the exact error text produced by requireJobStep,
without changing environment, preparation, installation, or ordering fields.

Source: Path instructions

test/e2e/support/cli-artifact-workflow-boundary.test.ts (2)

418-424: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove the temporary directory after the assertion.

Line 419 creates a directory under os.tmpdir() and the test never removes it. Every run leaks one directory. The other fixtures in this file clean up through cleanup() in a finally block. Apply the same pattern here.

♻️ Proposed fix
   it("rejects action implementation drift that weakens extraction or payload verification", () => {
     const directory = fs.mkdtempSync(path.join(os.tmpdir(), "cli-artifact-action-"));
-    const actionPath = path.join(directory, "action.yaml");
-    const source = readRepoText(".github/actions/restore-e2e-cli-artifact/action.yaml")
-      .replace("tar --no-same-owner --no-same-permissions", "tar")
-      .replace('[[ "$actual_payload_sha256" == "$PAYLOAD_SHA256" ]]', '[[ -s "$payload" ]]');
-    fs.writeFileSync(actionPath, source);
-
-    expect(validateCliArtifactRestoreAction(actionPath)).toEqual(
-      expect.arrayContaining([
-        "CLI artifact restore action must match its immutable workflow pin",
-        'CLI artifact payload verification must contain tar --no-same-owner --no-same-permissions -xf "$payload" -C "$restore_dir"',
-        'CLI artifact payload verification must contain [[ "$actual_payload_sha256" == "$PAYLOAD_SHA256" ]]',
-      ]),
-    );
+    try {
+      const actionPath = path.join(directory, "action.yaml");
+      const source = readRepoText(".github/actions/restore-e2e-cli-artifact/action.yaml")
+        .replace("tar --no-same-owner --no-same-permissions", "tar")
+        .replace('[[ "$actual_payload_sha256" == "$PAYLOAD_SHA256" ]]', '[[ -s "$payload" ]]');
+      fs.writeFileSync(actionPath, source);
+
+      expect(validateCliArtifactRestoreAction(actionPath)).toEqual(
+        expect.arrayContaining([
+          "CLI artifact restore action must match its immutable workflow pin",
+          'CLI artifact payload verification must contain tar --no-same-owner --no-same-permissions -xf "$payload" -C "$restore_dir"',
+          'CLI artifact payload verification must contain [[ "$actual_payload_sha256" == "$PAYLOAD_SHA256" ]]',
+        ]),
+      );
+    } finally {
+      fs.rmSync(directory, { force: true, recursive: true });
+    }
   });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/e2e/support/cli-artifact-workflow-boundary.test.ts` around lines 418 -
424, Update the test case around “rejects action implementation drift that
weakens extraction or payload verification” to remove its temporary directory
after the assertion, following the file’s existing cleanup() pattern in a
finally block and ensuring cleanup runs on both success and failure.

287-298: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert the rejection reason for each malformed provenance case.

This table asserts only a non-zero exit status. A bash syntax error or an unrelated failure in the identity script satisfies every row. The neighbouring table on lines 300-313 already pairs each case with its expected message. Apply the same shape here so each row proves the specific guard it names.

As per path instructions: "Flag copied production algorithms, broad mocks that bypass the behavior under test, and conditionals that make a test pass without exercising its claim."

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

In `@test/e2e/support/cli-artifact-workflow-boundary.test.ts` around lines 287 -
298, Update the malformed provenance cases in the it.each table to include each
case’s expected rejection message, then assert both non-zero status and the
corresponding message from runIdentityValidation. Match the neighboring table’s
assertion shape so failures prove the specific validation guard rather than an
unrelated script error.

Source: Path instructions

tools/e2e/cli-artifact-workflow-boundary.mts (1)

76-105: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Make the validator fail with an error message instead of throwing.

Line 76 reads the action file without a guard. If .github/actions/restore-e2e-cli-artifact/action.yaml is missing or renamed, validateCliArtifactRestoreAction throws. validateE2eWorkflow in tools/e2e/workflow-boundary.mts then aborts before it collects the remaining boundary errors.

Line 97 also mixes access styles. Line 96 uses identity?.name, then line 97 uses identity.id. A YAML list entry that parses to null makes line 97 throw a TypeError. The same pattern applies to download.uses on line 123.

♻️ Proposed fix
   const errors: string[] = [];
-  const actionSource = readFileSync(actionPath, "utf8");
+  let actionSource: string;
+  try {
+    actionSource = readFileSync(actionPath, "utf8");
+  } catch {
+    return ["CLI artifact restore action file is missing or unreadable"];
+  }
   if (
     identity?.name !== "Validate exact-commit CLI artifact identity" ||
-    identity.id !== "identity" ||
-    identity.shell !== "bash" ||
+    identity?.id !== "identity" ||
+    identity?.shell !== "bash" ||
   if (
     download?.name !== CLI_ARTIFACT_DOWNLOAD_STEP ||
-    download.uses !== CLI_ARTIFACT_DOWNLOAD_ACTION ||
+    download?.uses !== CLI_ARTIFACT_DOWNLOAD_ACTION ||
🤖 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 `@tools/e2e/cli-artifact-workflow-boundary.mts` around lines 76 - 105, Update
validateCliArtifactRestoreAction to catch missing or unreadable action files and
append a validation error instead of throwing, allowing validateE2eWorkflow to
continue collecting other boundary errors. Also make all destructured
action-step property checks null-safe, including identity.id and download.uses,
while preserving the existing validation messages and behavior for valid
entries.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/actions/restore-e2e-cli-artifact/action.yaml:
- Around line 159-173: Update the preexisting-dist guard before restore_dir in
the restore action to reject any existing $GITHUB_WORKSPACE/dist entry,
including dangling symlinks, by checking both existence and symlink status
rather than relying on -e alone. Preserve the current error-and-exit behavior,
and update any matching pinned fragments in
tools/e2e/cli-artifact-workflow-boundary.mts.

In `@test/e2e/README.md`:
- Around line 34-35: Clarify the README wording by replacing the ambiguous “It”
in the sentence following “Each consumer” with the explicit consumer job
subject, or combine both sentences so the setting clearly applies to each
consumer. Preserve the existing build-cli value and preparation-action details.

In `@tools/e2e/cli-artifact-workflow-boundary.mts`:
- Around line 332-334: Update the missing-producer branch in the workflow
validation logic to append its message to the existing errors collection instead
of returning a new array. Preserve the restore-action drift errors gathered
before the Object.keys(producer) check, then return errors after adding the
missing CLI artifact producer message.

---

Nitpick comments:
In `@test/e2e/support/cli-artifact-workflow-boundary.test.ts`:
- Around line 418-424: Update the test case around “rejects action
implementation drift that weakens extraction or payload verification” to remove
its temporary directory after the assertion, following the file’s existing
cleanup() pattern in a finally block and ensuring cleanup runs on both success
and failure.
- Around line 287-298: Update the malformed provenance cases in the it.each
table to include each case’s expected rejection message, then assert both
non-zero status and the corresponding message from runIdentityValidation. Match
the neighboring table’s assertion shape so failures prove the specific
validation guard rather than an unrelated script error.

In `@test/e2e/support/rebuild-hermes-workflow-boundary.test.ts`:
- Around line 60-78: Add a focused parameterized test alongside the existing
rebuild Hermes boundary cases that removes only the step named “Restore
exact-commit CLI artifact” from the job returned by bootstrapJob. Assert
validateRebuildHermesBootstrapBoundary reports the missing
CLI_ARTIFACT_RESTORE_STEP using the exact error text produced by requireJobStep,
without changing environment, preparation, installation, or ordering fields.

In `@tools/e2e/cli-artifact-workflow-boundary.mts`:
- Around line 76-105: Update validateCliArtifactRestoreAction to catch missing
or unreadable action files and append a validation error instead of throwing,
allowing validateE2eWorkflow to continue collecting other boundary errors. Also
make all destructured action-step property checks null-safe, including
identity.id and download.uses, while preserving the existing validation messages
and behavior for valid entries.

In `@tools/e2e/runner-comparison-workflow-boundary.mts`:
- Around line 197-198: Add a concise inline comment immediately above the
`bootstrapEnd` assignment explaining that comparison jobs such as
`security-posture` skip artifact restoration because they belong to
`PREPARE_E2E_NO_BUILD_JOBS`, so the `prepare` fallback must be preserved.
🪄 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: 9f3938a2-7881-46df-8265-819d238da987

📥 Commits

Reviewing files that changed from the base of the PR and between 0de2789 and 6057eab.

📒 Files selected for processing (13)
  • .github/actions/restore-e2e-cli-artifact/action.yaml
  • .github/workflows/e2e.yaml
  • test/e2e/README.md
  • test/e2e/support/cli-artifact-workflow-boundary.test.ts
  • test/e2e/support/prepare-e2e-workflow-boundary.test.ts
  • test/e2e/support/rebuild-hermes-workflow-boundary.test.ts
  • test/e2e/support/runner-comparison-workflow-boundary.test.ts
  • tools/e2e/cli-artifact-workflow-boundary.mts
  • tools/e2e/hermes-gpu-startup-workflow-boundary.mts
  • tools/e2e/prepare-e2e-workflow-boundary.mts
  • tools/e2e/runner-comparison-workflow-boundary.mts
  • tools/e2e/upload-e2e-artifacts-workflow-boundary.mts
  • tools/e2e/workflow-boundary.mts

Comment thread .github/actions/restore-e2e-cli-artifact/action.yaml
Comment thread test/e2e/README.md
Comment on lines +34 to +35
Each consumer still runs the pinned preparation action for Node.js and dependency installation.
It sets `build-cli: "false"`.

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

Remove the ambiguous pronoun.

Line 35 starts with "It". The nearest noun on line 34 is "the pinned preparation action", but the intended subject is the consumer job. Name the subject explicitly, or join the two sentences.

📝 Proposed wording
-Each consumer still runs the pinned preparation action for Node.js and dependency installation.
-It sets `build-cli: "false"`.
+Each consumer still runs the pinned preparation action for Node.js and dependency installation.
+Each consumer sets `build-cli: "false"` on that action.
📝 Committable suggestion

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

Suggested change
Each consumer still runs the pinned preparation action for Node.js and dependency installation.
It sets `build-cli: "false"`.
Each consumer still runs the pinned preparation action for Node.js and dependency installation.
Each consumer sets `build-cli: "false"` on that action.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/e2e/README.md` around lines 34 - 35, Clarify the README wording by
replacing the ambiguous “It” in the sentence following “Each consumer” with the
explicit consumer job subject, or combine both sentences so the setting clearly
applies to each consumer. Preserve the existing build-cli value and
preparation-action details.

Comment on lines +332 to +334
if (Object.keys(producer).length === 0) {
return [`workflow is missing CLI artifact producer ${CLI_ARTIFACT_PRODUCER_JOB}`];
}

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Preserve the restore-action errors when the producer job is missing.

Line 329 collects restore-action drift errors. Line 333 returns a new array and discards them. If a contributor removes generate-matrix and also weakens the composite action, the report names only the missing producer. Push the message onto errors and return errors.

🐛 Proposed fix
   if (Object.keys(producer).length === 0) {
-    return [`workflow is missing CLI artifact producer ${CLI_ARTIFACT_PRODUCER_JOB}`];
+    errors.push(`workflow is missing CLI artifact producer ${CLI_ARTIFACT_PRODUCER_JOB}`);
+    return errors;
   }
📝 Committable suggestion

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

Suggested change
if (Object.keys(producer).length === 0) {
return [`workflow is missing CLI artifact producer ${CLI_ARTIFACT_PRODUCER_JOB}`];
}
if (Object.keys(producer).length === 0) {
errors.push(`workflow is missing CLI artifact producer ${CLI_ARTIFACT_PRODUCER_JOB}`);
return errors;
}
🤖 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 `@tools/e2e/cli-artifact-workflow-boundary.mts` around lines 332 - 334, Update
the missing-producer branch in the workflow validation logic to append its
message to the existing errors collection instead of returning a new array.
Preserve the restore-action drift errors gathered before the
Object.keys(producer) check, then return errors after adding the missing CLI
artifact producer message.

@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 (4)
.github/actions/restore-e2e-cli-artifact/action.yaml (2)

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

Compare the CLI version with the build identity

bin/nemoclaw.js delegates to ../dist/nemoclaw, so this check exercises the restored artifact. Compare the reported version with .nemoclawVersion from dist/build-identity.json.

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

In @.github/actions/restore-e2e-cli-artifact/action.yaml at line 174, Update the
CLI validation around bin/nemoclaw.js to capture its reported version and
compare it against the .nemoclawVersion value from dist/build-identity.json,
failing the action when they differ; retain the restored-artifact check while
suppressing only the normal version output.

74-91: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Bind artifactDigest to the download, or remove the dead output.

artifact_digest is written at line 75, but no later step reads it. digest-mismatch: error compares the downloaded artifact with the digest reported by the GitHub API, not with the provenance artifactDigest. Compare both digests, or remove artifact_digest from GITHUB_OUTPUT. Update the full-content SHA and action commit pin if the action changes.

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

In @.github/actions/restore-e2e-cli-artifact/action.yaml around lines 74 - 91,
Update the artifact download flow after the provenance parsing to use
steps.identity.outputs.artifact_digest in an explicit comparison with the
downloaded artifact’s digest, while retaining the existing GitHub API digest
validation; alternatively remove the artifact_digest output if no comparison is
implemented. If changing the download action, update its full-content SHA and
version comment.
test/e2e/support/cli-artifact-workflow-boundary.test.ts (2)

32-59: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Temporary directories are created without a matching removal. Two helpers call fs.mkdtempSync and never remove the directory. runRestoreValidation already returns a cleanup handle for this purpose. Apply the same pattern to both sites so a full test run leaves no directories in the temporary directory.

  • test/e2e/support/cli-artifact-workflow-boundary.test.ts#L32-L59: remove the outputDirectory created at line 35 in a finally block. This helper runs in 13 test cases.
  • test/e2e/support/cli-artifact-workflow-boundary.test.ts#L418-L433: remove the directory created at line 419 in a finally block around the expect call.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/e2e/support/cli-artifact-workflow-boundary.test.ts` around lines 32 -
59, Update runIdentityValidation in
test/e2e/support/cli-artifact-workflow-boundary.test.ts lines 32-59 to return or
use a cleanup handle and remove outputDirectory in a finally block for every
invocation; also update the helper/test at
test/e2e/support/cli-artifact-workflow-boundary.test.ts lines 418-433 to remove
directory in a finally block around the expect call, following the existing
runRestoreValidation cleanup pattern.

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

Select action steps by identity, not array position.

runIdentityValidation uses steps[0], while runRestoreValidation uses steps[2]. Select the first step by id and the restore step by its unique name, then assert that each step exists.

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

In `@test/e2e/support/cli-artifact-workflow-boundary.test.ts` at line 36, Update
runIdentityValidation and runRestoreValidation to locate action steps by
identity rather than array position: find the first step by its id and the
restore step by its unique name, then assert each lookup succeeds before
accessing its run command.

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.

Nitpick comments:
In @.github/actions/restore-e2e-cli-artifact/action.yaml:
- Line 174: Update the CLI validation around bin/nemoclaw.js to capture its
reported version and compare it against the .nemoclawVersion value from
dist/build-identity.json, failing the action when they differ; retain the
restored-artifact check while suppressing only the normal version output.
- Around line 74-91: Update the artifact download flow after the provenance
parsing to use steps.identity.outputs.artifact_digest in an explicit comparison
with the downloaded artifact’s digest, while retaining the existing GitHub API
digest validation; alternatively remove the artifact_digest output if no
comparison is implemented. If changing the download action, update its
full-content SHA and version comment.

In `@test/e2e/support/cli-artifact-workflow-boundary.test.ts`:
- Around line 32-59: Update runIdentityValidation in
test/e2e/support/cli-artifact-workflow-boundary.test.ts lines 32-59 to return or
use a cleanup handle and remove outputDirectory in a finally block for every
invocation; also update the helper/test at
test/e2e/support/cli-artifact-workflow-boundary.test.ts lines 418-433 to remove
directory in a finally block around the expect call, following the existing
runRestoreValidation cleanup pattern.
- Line 36: Update runIdentityValidation and runRestoreValidation to locate
action steps by identity rather than array position: find the first step by its
id and the restore step by its unique name, then assert each lookup succeeds
before accessing its run command.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 9bc88616-b973-41d5-9feb-771a216430da

📥 Commits

Reviewing files that changed from the base of the PR and between 0de2789 and 6057eab.

📒 Files selected for processing (13)
  • .github/actions/restore-e2e-cli-artifact/action.yaml
  • .github/workflows/e2e.yaml
  • test/e2e/README.md
  • test/e2e/support/cli-artifact-workflow-boundary.test.ts
  • test/e2e/support/prepare-e2e-workflow-boundary.test.ts
  • test/e2e/support/rebuild-hermes-workflow-boundary.test.ts
  • test/e2e/support/runner-comparison-workflow-boundary.test.ts
  • tools/e2e/cli-artifact-workflow-boundary.mts
  • tools/e2e/hermes-gpu-startup-workflow-boundary.mts
  • tools/e2e/prepare-e2e-workflow-boundary.mts
  • tools/e2e/runner-comparison-workflow-boundary.mts
  • tools/e2e/upload-e2e-artifacts-workflow-boundary.mts
  • tools/e2e/workflow-boundary.mts
🚧 Files skipped from review as they are similar to previous changes (10)
  • test/e2e/support/runner-comparison-workflow-boundary.test.ts
  • tools/e2e/upload-e2e-artifacts-workflow-boundary.mts
  • test/e2e/support/prepare-e2e-workflow-boundary.test.ts
  • tools/e2e/runner-comparison-workflow-boundary.mts
  • tools/e2e/workflow-boundary.mts
  • tools/e2e/prepare-e2e-workflow-boundary.mts
  • .github/workflows/e2e.yaml
  • tools/e2e/cli-artifact-workflow-boundary.mts
  • test/e2e/support/rebuild-hermes-workflow-boundary.test.ts
  • tools/e2e/hermes-gpu-startup-workflow-boundary.mts

@wscurran wscurran added area: ci CI workflows, checks, release automation, or GitHub Actions area: e2e End-to-end tests, nightly failures, or validation infrastructure chore Build, CI, dependency, or tooling maintenance labels Aug 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: ci CI workflows, checks, release automation, or GitHub Actions area: e2e End-to-end tests, nightly failures, or validation infrastructure chore Build, CI, dependency, or tooling maintenance

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants