Skip to content

fix(ci): enforce trusted createRequire ratchet - #7057

Merged
cv merged 12 commits into
mainfrom
codex/7056-trusted-create-require-ratchet
Jul 18, 2026
Merged

fix(ci): enforce trusted createRequire ratchet#7057
cv merged 12 commits into
mainfrom
codex/7056-trusted-create-require-ratchet

Conversation

@apurvvkumaria

@apurvvkumaria apurvvkumaria commented Jul 16, 2026

Copy link
Copy Markdown
Collaborator

Summary

Run the createRequire allowlist ratchet from the immutable base-trusted static-check action. Pull requests now compare their reviewed allowlists with the validated base commit even from a shallow checkout, rejecting additions while permitting removals.

Related Issue

Closes #7056

Changes

  • Bundle a trusted ratchet with the shared static-check action and run it immediately after dependency installation.
  • Read both the current .ts checker and the pending .mts form, validate literal allowlists, and compare them with the pull request base revision.
  • Validate the base SHA from the GitHub event and fetch that exact public commit only when a shallow checkout does not already contain it.
  • Add focused behavior and trusted-action wiring coverage.
  • Preserve credit for Tinson Lai, who originally authored this prerequisite in refactor(checks): migrate repository check suite to .mts #7047; the commit retains Tinson as co-author.

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: internal CI enforcement only; no user-facing behavior changes
  • 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:
  • Non-success, skipped, or missing CI check accepted by maintainer — check name, approval link, and follow-up issue:

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 check:diff passed when hooks were skipped or unavailable
  • Targeted behavior tests pass for the current change set, or tests are marked not applicable above — npx vitest run --project integration test/create-require-ratchet.test.ts test/pr-workflow-contract.test.ts (2 files, 23 tests passed)
  • Applicable broad gate passed — npm test for broad runtime/test-harness changes; npm run check for repo-wide validation/coverage changes — hosted CI pending
  • 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: Apurv Kumaria akumaria@nvidia.com

Summary by CodeRabbit

  • New Features

    • Added a “createRequire allowlist ratchet” static check that verifies observed createRequire usage against trusted allowlists from the base revision.
    • Extended the CI static-check composite action to install required verifier tooling and enforce the ratchet check before other validations.
    • Pin verifier dependencies (TypeScript) to a fixed version for consistent results.
  • Bug Fixes

    • Hardened verification to fail closed on malformed/ambiguous checker state and to reject unsupported inventory inputs (e.g., symlinks).
  • Tests

    • Added end-to-end and contract coverage for allowlist extraction, boundary detection, base revision resolution behavior, and dependency pinning/integrity.

Co-authored-by: Tinson Lai <tinsonl@nvidia.com>
Signed-off-by: Apurv Kumaria <akumaria@nvidia.com>
@apurvvkumaria apurvvkumaria added area: ci CI workflows, checks, release automation, or GitHub Actions bug-fix PR fixes a bug or regression v0.0.85 labels Jul 16, 2026
@apurvvkumaria apurvvkumaria self-assigned this Jul 16, 2026
@cjagwani cjagwani added v0.0.86 and removed v0.0.85 labels Jul 16, 2026
Co-authored-by: Tinson Lai <tinsonl@nvidia.com>
Signed-off-by: Apurv Kumaria <akumaria@nvidia.com>
@coderabbitai

coderabbitai Bot commented Jul 17, 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

Adds a base-trusted createRequire allowlist ratchet. It parses checker allowlists, inventories TypeScript usage, compares current and base revisions, wires verification into CI, and adds focused unit and workflow contract tests.

Changes

CreateRequire allowlist ratchet

Layer / File(s) Summary
Trusted checker parsing and base resolution
.github/actions/ci-static-checks/create-require-ratchet-core.mts
Validates exported literal allowlists, locates exactly one checker in current and base revisions, and resolves pull-request base commits.
CreateRequire source inventory
.github/actions/ci-static-checks/create-require-ratchet-core.mts
Scans src/ and test/ TypeScript files, rejects symbolic links and malformed sources, detects executable createRequire references, and partitions inventory paths.
Ratchet verification and CI wiring
.github/actions/ci-static-checks/create-require-ratchet-core.mts, .github/actions/ci-static-checks/create-require-ratchet.mts, .github/actions/ci-static-checks/action.yaml, .github/actions/ci-static-checks/package.json
Compares current and trusted allowlists, rejects production usage and expansions, installs TypeScript dependencies, and runs the verifier in the composite action.
Ratchet behavior validation
test/create-require-ratchet.test.ts, test/pr-workflow-contract.test.ts
Tests parsing, scanning, failures, base resolution, checker migration, dependency pinning, runtime execution, and action command ordering.

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

Sequence Diagram(s)

sequenceDiagram
  participant CI as ci-static-checks action
  participant Runtime as create-require-ratchet.mts
  participant Verifier as verifyTrustedCreateRequireRatchet
  participant Git as createGitRunner
  CI->>CI: Install verifier dependencies
  CI->>Runtime: Run ratchet script
  Runtime->>Verifier: Verify repository
  Verifier->>Git: Resolve trusted base
  Git-->>Verifier: Return base checker
  Verifier-->>Runtime: Return failure or success
  Runtime-->>CI: Set exit status
Loading

Possibly related issues

  • Issue 6918: The executable .mts repository tool and direct-invocation runtime align with the issue’s repository-tool migration objective.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The ratchet, tests, and wiring are added, but allowlist comparison uses the PR base SHA instead of the merge-base version required by #7056. Compute the actual merge-base before loading the trusted checker, and add divergent-history coverage proving additions are rejected there too.
✅ 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 is concise and matches the main change: enforcing the trusted createRequire ratchet in CI.
Out of Scope Changes check ✅ Passed The changes stay focused on the ci-static-checks action, ratchet core, entrypoint, package manifest, and targeted tests.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/7056-trusted-create-require-ratchet

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

@github-code-quality

github-code-quality Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Overview

Languages: TypeScript

TypeScript / code-coverage/plugin

The overall coverage remains at 96%, unchanged from the main branch.

TypeScript / code-coverage/cli

The overall coverage in the codex/7056-trusted-c... branch remains at 80%, unchanged from the main branch.

Show a code coverage summary of the most impacted files.
File main 0339d88 codex/7056-trusted-c... 5b69f0c +/-
src/lib/core/pr...mpt-activity.ts 92% 67% -25%
src/lib/credentials/store.ts 64% 59% -5%
src/lib/adapter...hell/resolve.ts 100% 100% 0%
src/lib/agent/defs.ts 81% 81% 0%
src/lib/sandbox...rce-identity.ts 91% 91% 0%
src/lib/securit...p-url-target.ts 100% 100% 0%
src/lib/state/config-io.ts 93% 93% 0%
src/lib/state/registry-mcp.ts 100% 100% 0%
src/lib/state/registry.ts 83% 86% +3%

Updated July 18, 2026 09:35 UTC
Code Coverage is in Public Preview. Learn more and provide us with your feedback.

@github-actions

github-actions Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

PR Review Advisor — Informational

Advisor assessment: Informational / high confidence
Next action: No advisor follow-up needed.
Findings: 0 blockers · 0 warnings · 0 suggestions
Status: No actionable findings remain in the canonical review ledger.

Model lanes

  • GPT-5.6 Terra (primary): Completed · high confidence · 0 blockers · 0 warnings · 0 suggestions
  • Nemotron 3 Ultra (second opinion): Completed · high confidence · 0 blockers · 0 warnings · 0 suggestions
  • Model comparison: normalized findings match; normalized E2E selections match; severity counts match.

Nemotron output stays in workflow artifacts and does not change the assessment above.

E2E guidance

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

Recommended E2E: None

Workflow run details

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

Co-authored-by: Tinson Lai <tinsonl@nvidia.com>
Signed-off-by: Apurv Kumaria <akumaria@nvidia.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

🧹 Nitpick comments (2)
.github/actions/ci-static-checks/create-require-ratchet-core.mts (2)

145-178: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

Base-checker lookup discards git failure detail.

When git show fails for a reason other than "path missing at that revision" (auth, network, corrupt object, etc.), requireSingleBaseChecker (Lines 168-171) silently treats it as a non-match and, if both candidate paths fail, only ever reports found 0, hiding the real cause from CI logs.

🩹 Proposed fix to surface stderr on unexpected failures
   const matches = ALLOWLIST_PATHS.flatMap((relativePath) => {
     const result = runGit(["show", `${revision}:${relativePath}`]);
-    return result.status === 0 ? [{ path: relativePath, source: result.stdout }] : [];
+    if (result.status === 0) return [{ path: relativePath, source: result.stdout }];
+    if (!/^fatal: path .* does not exist/.test(result.stderr)) {
+      throw new Error(`git show ${revision}:${relativePath} failed: ${result.stderr}`);
+    }
+    return [];
   });
🤖 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/ci-static-checks/create-require-ratchet-core.mts around
lines 145 - 178, Update requireSingleBaseChecker so runGit failures are treated
as missing paths only when git explicitly indicates the candidate path does not
exist at the revision; for other nonzero statuses, surface the command’s stderr
in an error instead of adding no match. Preserve the existing exactly-one-match
validation and return behavior for valid paths.

60-82: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoff

Avoid relying on parseDiagnostics
parseDiagnostics is internal and not part of the public ts.SourceFile API. Use a supported path like ts.createProgram(...).getSyntacticDiagnostics() instead so this check doesn't depend on compiler internals.

🤖 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/ci-static-checks/create-require-ratchet-core.mts around
lines 60 - 82, Update parseSourceFile to stop casting sourceFile to access the
internal parseDiagnostics property. Use the public TypeScript API by creating a
program and retrieving syntactic diagnostics with getSyntacticDiagnostics(),
preserving the existing diagnostic formatting and error behavior.
🤖 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/ci-static-checks/create-require-ratchet-core.mts:
- Around line 290-328: Update collectCreateRequireInventory so testSupport also
scans test/**/*.test.ts files, either by adding a dedicated test bucket to
CreateRequireInventory or by including them in the existing testSupport
collection. Ensure root-level test files such as test/package-contract/*.test.ts
are included in the createRequire ratchet without removing coverage for non-test
support files.

---

Nitpick comments:
In @.github/actions/ci-static-checks/create-require-ratchet-core.mts:
- Around line 145-178: Update requireSingleBaseChecker so runGit failures are
treated as missing paths only when git explicitly indicates the candidate path
does not exist at the revision; for other nonzero statuses, surface the
command’s stderr in an error instead of adding no match. Preserve the existing
exactly-one-match validation and return behavior for valid paths.
- Around line 60-82: Update parseSourceFile to stop casting sourceFile to access
the internal parseDiagnostics property. Use the public TypeScript API by
creating a program and retrieving syntactic diagnostics with
getSyntacticDiagnostics(), preserving the existing diagnostic formatting and
error behavior.
🪄 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: 0fbcd278-6318-447a-b405-6249061c4959

📥 Commits

Reviewing files that changed from the base of the PR and between 50d5e83 and 9207083.

⛔ Files ignored due to path filters (1)
  • .github/actions/ci-static-checks/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (6)
  • .github/actions/ci-static-checks/action.yaml
  • .github/actions/ci-static-checks/create-require-ratchet-core.mts
  • .github/actions/ci-static-checks/create-require-ratchet.mts
  • .github/actions/ci-static-checks/package.json
  • test/create-require-ratchet.test.ts
  • test/pr-workflow-contract.test.ts

Comment thread .github/actions/ci-static-checks/create-require-ratchet-core.mts
@apurvvkumaria

Copy link
Copy Markdown
Collaborator Author

One trusted-scanner bypass blocks this revision. staticStringValue folds string literals, binary +, wrappers, and no-substitution template literals, but not a statically resolvable interpolated TemplateExpression. For example:

nodeModule[`create${"Require"}`](import.meta.url)

This expression contains no createRequire identifier, currently resolves to null, and is omitted from the observed inventory without requiring an allowlist update. That defeats the ratchet's claimed invariant.

Please add conservative static folding for template heads/spans whose expressions already resolve to static strings, and add focused plus spawned end-to-end regressions proving the interpolated form is inventoried. Do not broaden this into flagging every unresolved element access: nodeModule[`createRequire`] is already detected because TypeScript classifies a no-substitution template as StringLiteralLike.

The current DCO/signature, ordinary CI, CodeRabbit thread, and no-E2E-selection evidence are otherwise clean. The failed secondary advisor and its separate event-provenance checker mismatch still need policy reconciliation, but the concrete code blocker above is independently reproducible.

Co-authored-by: Tinson Lai <tinsonl@nvidia.com>
Signed-off-by: Apurv Kumaria <akumaria@nvidia.com>
@apurvvkumaria

Copy link
Copy Markdown
Collaborator Author

Pushed signed follow-up 655c7d8900e461b470b6100b06acba678121c8de to address the trusted-scanner blocker.

The fix conservatively folds TemplateExpression heads and spans only when every substitution already resolves through the existing static-string rules. nodeModule[create${"Require"}] is now inventoried, while unresolved dynamic substitutions remain unflagged. The focused unit regression covers both cases, and the spawned real-entrypoint regression now exercises the interpolated expansion.

Local verification:

  • npx vitest run --project integration test/create-require-ratchet.test.ts test/pr-workflow-contract.test.ts — 38 passed
  • npm run source-shape:check
  • npm run test-size:check
  • npm run test:projects:check
  • npm run test:titles:check
  • npm run typecheck:cli (after clean CLI/plugin builds)
  • changed-file prek hooks — passed
  • normal pre-push TypeScript/tag-sync hooks — passed

GitHub reports the commit signature as Verified (reason: valid), with Signed-off-by: Apurv Kumaria <akumaria@nvidia.com> and Co-authored-by: Tinson Lai <tinsonl@nvidia.com>. Exact post-push head/base: 655c7d8900e461b470b6100b06acba678121c8de / 50d5e836493e7b210ab7713184cfbfba1f9c8fa4. Hosted CI and automated review are running.

Separately, the maintainer advisor provenance checker currently accepts only pull_request, while the advisor workflow run uses pull_request_target; this follow-up intentionally does not broaden into that policy/tooling mismatch.

Co-authored-by: Tinson Lai <tinsonl@nvidia.com>
Signed-off-by: Apurv Kumaria <akumaria@nvidia.com>
@apurvvkumaria

Copy link
Copy Markdown
Collaborator Author

Blocking exact head 96148d0d124f0f8d01ab062786d1579be9201ccd on two exact-head gaps.

  1. The trusted scanner still misses ordinary one-hop aliases of the node:module object. This production-shaped case returns false from containsCreateRequireIdentifier:

    const moduleObject = await import("node:module");
    const { "createRequire": load } = moduleObject;
    export const requireFromHere = load(import.meta.url);

    collectNodeModuleObjectBindings records direct imports/import-equals, while isNodeModuleStringBinding trusts an identifier initializer only when that identifier is already in the set. Please resolve safe one-hop module-object aliases and add both focused and spawned-entrypoint regressions for dynamic-import and namespace-import aliases. The direct destructuring tests do not cover this bypass.

  2. Issue ci: enforce createRequire allowlist ratchet from base-trusted code #7056 requires comparison with merge-base versions, but resolveBaseRevision returns pull_request.base.sha; the current tests do not construct divergent histories. Please either compute and test the actual merge base, or record an explicit maintainer decision changing that acceptance contract and obtain a fresh advisor result. The current exact-head advisor remains merge_after_fixes on this point.

Please rerun the exact-head trusted scanner, ordinary CI, advisor, and protected E2E gate after both are resolved.

Co-authored-by: Tinson Lai <tinsonl@nvidia.com>
Signed-off-by: Apurv Kumaria <akumaria@nvidia.com>
apurvvkumaria and others added 2 commits July 17, 2026 05:27
Co-authored-by: Tinson Lai <tinsonl@nvidia.com>
Signed-off-by: Apurv Kumaria <akumaria@nvidia.com>
Co-authored-by: Tinson Lai <tinsonl@nvidia.com>
Signed-off-by: Apurv Kumaria <akumaria@nvidia.com>
@jyaunches jyaunches added v0.0.88 and removed v0.0.86 labels Jul 17, 2026
apurvvkumaria and others added 4 commits July 17, 2026 16:20
Read the checker and TypeScript inventory from the exact pull-request head while comparing against the verified merge base. Fail closed on ambiguous or unreadable Git objects and escape untrusted paths in diagnostics.

Co-authored-by: Tinson Lai <tinsonl@nvidia.com>
Signed-off-by: Apurv Kumaria <akumaria@nvidia.com>
Keep the fail-closed Git object coverage within the enforced test conditional budget.

Co-authored-by: Tinson Lai <tinsonl@nvidia.com>
Signed-off-by: Apurv Kumaria <akumaria@nvidia.com>
Run the trusted entrypoint across a real TypeScript-to-MTS checker migration.

Co-authored-by: Tinson Lai <tinsonl@nvidia.com>
Signed-off-by: Apurv Kumaria <akumaria@nvidia.com>

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

Approved on the refreshed exact head after the deterministic gate passed: 51 current checks green, mergeable/current base, no unresolved major/critical findings, DCO present, and all 12 commits verified. The ratchet validates exact event SHAs and a unique merge base, reads PR files as data without executing them, rejects non-regular entries, and uses the base-trusted locked TypeScript parser before candidate installation. Focused ratchet/workflow contracts passed 47 tests; the nine-category security review is clean.

@cv
cv merged commit fce1272 into main Jul 18, 2026
52 checks passed
@cv
cv deleted the codex/7056-trusted-create-require-ratchet branch July 18, 2026 15:57
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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ci: enforce createRequire allowlist ratchet from base-trusted code

6 participants