Skip to content

ci(deps): add candidate compatibility workflow#6738

Open
HOYALIM wants to merge 1 commit into
NVIDIA:mainfrom
HOYALIM:codex/issue-6691-candidate-compat
Open

ci(deps): add candidate compatibility workflow#6738
HOYALIM wants to merge 1 commit into
NVIDIA:mainfrom
HOYALIM:codex/issue-6691-candidate-compat

Conversation

@HOYALIM

@HOYALIM HOYALIM commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Summary

  • add a maintainer-dispatched compatibility controller for exact NemoClaw refs and official OpenShell, OpenClaw, Hermes, or DCode candidates
  • bind each run to a full source SHA, immutable artifact digest, resolution identity, and observed runtime version
  • execute component-appropriate deterministic lanes without editing pin authorities or granting write permissions
  • publish selected/skipped lane reasons and durable evidence; credentialed live E2E remains explicitly skipped until its separate approval boundary is connected

Validation

  • npx vitest run test/candidate-compat.test.ts (9 passed)
  • npm run check
  • npm run typecheck:cli
  • npm run check:diff
  • resolved real metadata for all four supported components
  • materialized OpenClaw, Hermes, and DCode candidates and verified OpenShell release checksum provenance

Refs #6691

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

Summary by CodeRabbit

  • New Features
    • Added a “Dependencies / Candidate Compatibility” workflow to deterministically resolve candidates, run compatibility lanes in parallel, and publish auditable compatibility evidence.
    • Added a candidate-compatibility CLI/library (resolve, plan, materialize, finalize) supporting OpenShell, OpenClaw, Hermes, and DCode.
  • Bug Fixes
    • Improved fail-closed validation for unsafe inputs, missing provenance, untrusted hosts, artifact digest/version mismatches, and incomplete lane results.
  • Tests
    • Added a new automated test suite covering workflow hardening, deterministic outputs, digest verification, and evidence finalization rules.
    • Updated the security test budget exceptions for the new suite.

Copilot AI review requested due to automatic review settings July 13, 2026 02:34
@copy-pr-bot

copy-pr-bot Bot commented Jul 13, 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 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds candidate compatibility resolution and verification tooling, deterministic lane planning, artifact materialization, evidence finalization, a GitHub Actions workflow, and tests covering provenance, security boundaries, runtime observations, and complete evidence aggregation.

Changes

Candidate Compatibility

Layer / File(s) Summary
Candidate resolution and provenance
tools/candidate-compat.mts, test/candidate-compat.test.ts
Validates candidate inputs and official sources, resolves component artifacts, verifies provenance and digests, and generates stable receipts.
Lane planning and evidence validation
tools/candidate-compat.mts, test/candidate-compat.test.ts
Builds deterministic and live lanes, verifies observed candidates, and requires complete, consistent lane results before finalizing evidence.
Candidate materialization and CLI commands
tools/candidate-compat.mts, test/candidate-compat.test.ts
Downloads and verifies artifacts, installs component runtimes, captures observed versions, and implements the resolve, plan, materialize, and finalize commands.
Compatibility workflow orchestration
.github/workflows/candidate-compatibility.yaml, test/candidate-compat.test.ts, ci/source-shape-test-budget.json
Dispatches compatibility runs, executes planned lanes against the resolved NemoClaw commit, uploads evidence, and enforces workflow security contracts.

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

Sequence Diagram(s)

sequenceDiagram
  participant GitHubActions
  participant CandidateCLI
  participant NemoClawCheckout
  participant LaneRuntime
  GitHubActions->>CandidateCLI: resolve candidate and generate plan
  CandidateCLI-->>GitHubActions: receipt and lane matrix
  GitHubActions->>NemoClawCheckout: checkout resolved NemoClaw SHA
  GitHubActions->>LaneRuntime: materialize candidate and run lane
  LaneRuntime-->>GitHubActions: observed output and lane result
  GitHubActions->>CandidateCLI: finalize lane evidence
  CandidateCLI-->>GitHubActions: auditable compatibility evidence
Loading

Possibly related issues

  • NVIDIA/NemoClaw#6691 — The workflow, resolver, artifact verification, deterministic/live lanes, and evidence finalization implement the issue’s candidate-compatibility objectives.

Suggested labels: area: cli, chore

Suggested reviewers: cv, jyaunches

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately describes the main change: adding a candidate compatibility workflow.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ 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 13, 2026

Copy link
Copy Markdown
Contributor

E2E Advisor Recommendation

Required E2E: None
Optional E2E: None

Workflow run

Full advisor summary

E2E Recommendation Advisor

Base: target/main
Head: HEAD
Confidence: high

Required E2E

  • None.

Optional E2E

  • None.

New E2E recommendations

  • dependency compatibility (high): The workflow records live E2E selectors but explicitly skips them because candidate injection is not wired into the credential-bearing E2E boundary. Current E2E jobs therefore cannot prove that a verified candidate runtime is consumed during real onboarding and assistant flows.
    • Suggested test: Add a trusted candidate-compatibility live lane that dispatches an existing component-specific E2E selector with a known official candidate artifact injected into the E2E environment, then asserts the observed candidate version and the relevant real user flow succeed.

@HOYALIM HOYALIM force-pushed the codex/issue-6691-candidate-compat branch from 4fe9f8c to 05fedce Compare July 13, 2026 02:43

@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)
tools/candidate-compat.mts (1)

552-564: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Validate the initial artifact URL host before issuing the request.

download uses redirect: "follow" and only checks the host of the final response.url. The initial request to artifactValue.url is issued before any host check, so a tampered receipt URL would still trigger an outbound fetch to an arbitrary host. The receipt is produced by the trusted resolve job, so this is defense-in-depth rather than an active exploit, but re-asserting the host on the initial URL is cheap and closes the gap.

🛡️ Proposed defense-in-depth check
 async function download(artifactValue: Artifact, directory: string): Promise<string> {
+  const requestUrl = new URL(artifactValue.url);
+  if (requestUrl.protocol !== "https:" || !DOWNLOAD_HOSTS.has(requestUrl.hostname)) {
+    throw new Error(`candidate artifact is not on an approved download host: ${artifactValue.url}`);
+  }
   const response = await fetch(artifactValue.url, { redirect: "follow" });
   if (!response.ok) throw new Error(`candidate download failed (${response.status})`);
🤖 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/candidate-compat.mts` around lines 552 - 564, Update download to parse
and validate artifactValue.url against the approved HTTPS protocol and
DOWNLOAD_HOSTS before calling fetch, rejecting unapproved initial hosts while
preserving the existing final response URL validation.
🤖 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 `@tools/candidate-compat.mts`:
- Around line 552-564: Update download to parse and validate artifactValue.url
against the approved HTTPS protocol and DOWNLOAD_HOSTS before calling fetch,
rejecting unapproved initial hosts while preserving the existing final response
URL validation.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 6b2028c0-76d0-4737-9143-32cb81fc4ff1

📥 Commits

Reviewing files that changed from the base of the PR and between deed1aa and 4fe9f8c.

📒 Files selected for processing (4)
  • .github/workflows/candidate-compatibility.yaml
  • ci/source-shape-test-budget.json
  • test/candidate-compat.test.ts
  • tools/candidate-compat.mts

@cv cv added the v0.0.82 Release target label Jul 13, 2026
Comment thread tools/candidate-compat.mts Fixed
Comment thread tools/candidate-compat.mts Fixed
Signed-off-by: Ho Lim <subhoya@gmail.com>
@HOYALIM HOYALIM force-pushed the codex/issue-6691-candidate-compat branch from 05fedce to ae774d4 Compare July 13, 2026 06:22

@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 (2)
tools/candidate-compat.mts (1)

111-121: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Use code-point ordering in stableJson resolutionId and the equality checks built from this helper should not depend on locale/ICU collation.

♻️ Use deterministic code-point ordering
-      .sort(([left], [right]) => left.localeCompare(right))
+      .sort(([left], [right]) => (left < right ? -1 : left > right ? 1 : 0))
🤖 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/candidate-compat.mts` around lines 111 - 121, Update stableJson’s
object-key sort to use deterministic code-point ordering rather than
localeCompare. Preserve the existing filtering, serialization, and recursive
traversal behavior while ensuring generated strings are independent of locale or
ICU collation.
.github/workflows/candidate-compatibility.yaml (1)

162-175: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Pass resolution_id via env: instead of interpolating into the shell body.

Line 172 expands ${{ needs.resolve.outputs.resolution_id }} directly into the run script, unlike every other step here which passes values through env: (e.g. LANE). The value is validated to ^[a-f0-9]{64}$ at line 85 so actual injection risk is nil, but keeping it as an env reference silences the scanner and honors the untrusted-as-data convention.

🔒 Proposed change to pass the value as data
         env:
           LANE: ${{ matrix.lane }}
+          RESOLUTION_ID: ${{ needs.resolve.outputs.resolution_id }}
         shell: bash
         run: |
           set -euo pipefail
           node --experimental-strip-types controller/tools/candidate-compat.mts materialize \
             --receipt candidate-input/candidate-receipt.json \
-            --resolution-id "${{ needs.resolve.outputs.resolution_id }}" \
+            --resolution-id "$RESOLUTION_ID" \
             --directory "${RUNNER_TEMP}/candidate-runtime" \
             --output "candidate-observed-${LANE}.json" \
             --github-env "$GITHUB_ENV" 2>&1 | tee "candidate-materialize-${LANE}.log"

As per path instructions: "pass untrusted values as data rather than interpolating them into shell programs."

🤖 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/workflows/candidate-compatibility.yaml around lines 162 - 175,
Update the “Materialize and verify candidate runtime” step to add
needs.resolve.outputs.resolution_id to its env mapping, then reference that
environment variable in the candidate-compat materialize command instead of
interpolating the GitHub expression directly in the shell script. Preserve the
existing resolution ID value and command behavior.

Sources: Path instructions, Linters/SAST tools

🤖 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/workflows/candidate-compatibility.yaml:
- Around line 162-175: Update the “Materialize and verify candidate runtime”
step to add needs.resolve.outputs.resolution_id to its env mapping, then
reference that environment variable in the candidate-compat materialize command
instead of interpolating the GitHub expression directly in the shell script.
Preserve the existing resolution ID value and command behavior.

In `@tools/candidate-compat.mts`:
- Around line 111-121: Update stableJson’s object-key sort to use deterministic
code-point ordering rather than localeCompare. Preserve the existing filtering,
serialization, and recursive traversal behavior while ensuring generated strings
are independent of locale or ICU collation.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: d87636d0-b189-4b6a-8730-8c380b6a5681

📥 Commits

Reviewing files that changed from the base of the PR and between 05fedce and ae774d4.

📒 Files selected for processing (4)
  • .github/workflows/candidate-compatibility.yaml
  • ci/source-shape-test-budget.json
  • test/candidate-compat.test.ts
  • tools/candidate-compat.mts
🚧 Files skipped from review as they are similar to previous changes (2)
  • ci/source-shape-test-budget.json
  • test/candidate-compat.test.ts

@wscurran wscurran added area: ci CI workflows, checks, release automation, or GitHub Actions chore Build, CI, dependency, or tooling maintenance integration: dcode LangChain Deep Code integration behavior labels Jul 13, 2026
@wscurran

Copy link
Copy Markdown
Contributor

✨ Thanks for the CI infrastructure work, @HOYALIM. Adding a maintainer-dispatched compatibility controller for candidate versions will improve our validation coverage. Ready for maintainer review.


Related open issues:

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

Reviewed exact head ae774d4. Both manually dispatched Advisors analyzed this head and recommend merge_as_is, but the direct supply-chain review found three blockers their broad checks miss:

  1. High — .github/workflows/candidate-compatibility.yaml:162-248 and tools/candidate-compat.mts:744-812,857-877 can mark a lane successful after standalone materialization plus ordinary tests without proving the lane consumed the candidate. NEMOCLAW_CANDIDATE_* has no repository consumer; the recorded version is a pre-lane probe. Require trusted, receipt-bound evidence that each selected install/build/runtime path actually invoked the candidate, and fail if that proof is absent.

  2. Medium — tools/candidate-compat.mts:347-356,530-536,748-787 admits npm hermes-agent as an official Hermes artifact using only version equality. The package's own registry metadata identifies it as an unofficial bridge from wyrtensi/hermes-agent-npm, while the receipt labels NousResearch. A digest authenticates those bytes, not official provenance. Remove it or replace it with an artifact verifiably controlled by the official upstream.

  3. Medium — tools/candidate-compat.mts:249-269,432-440,789-798 materializes OpenClaw with npm install from only a verified top-level tarball. The transitive closure is neither policy-checked nor bound into resolutionId/evidence; current caret dependencies make identical resolution IDs capable of executing different bytes. Resolve and bind a complete lock/integrity closure in the trusted resolve job, install from it, and preserve it in evidence.

Terra's process-boundary test warning is therefore blocking, not cosmetic. Add a fixture-based materialize CLI regression that validates observed JSON, PATH/candidate env output, actual candidate invocation, and fail-closed version mismatch.

@cjagwani cjagwani self-assigned this Jul 13, 2026
@cjagwani cjagwani added v0.0.83 Release target and removed v0.0.82 Release target labels Jul 13, 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 chore Build, CI, dependency, or tooling maintenance integration: dcode LangChain Deep Code integration behavior v0.0.83 Release target

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants