Skip to content

fix(ci): publish PR E2E gate as native job - #6909

Merged
cv merged 4 commits into
mainfrom
codex/native-pr-e2e-gate
Jul 15, 2026
Merged

fix(ci): publish PR E2E gate as native job#6909
cv merged 4 commits into
mainfrom
codex/native-pr-e2e-gate

Conversation

@cv

@cv cv commented Jul 15, 2026

Copy link
Copy Markdown
Collaborator

Summary

Replace the synthetic required-check identity with a native E2E / PR Gate job in the base-trusted pull_request_target workflow. The Checks API result becomes E2E / PR Gate Coordination, so suite-association ambiguity like the behavior observed on #6887 cannot leave the required native job unreported while exact-head/base validation and credentialed E2E authorization remain unchanged.

Changes

  • Add a read-only native E2E / PR Gate job that executes from github.workflow_sha, waits for the trusted exact-diff coordination result, publishes the terminal verdict as its native job result, logs the validated trusted run link, and keeps the job summary static.
  • Rename the controller-created custom check to E2E / PR Gate Coordination; authenticate it by exact external identity and GitHub Actions app, retain the old name only as a rollout bridge, and keep maintainer-authorization states pending.
  • Classify the observer as trusted E2E controller code and add behavior, workflow-boundary, watch-trigger, risk-plan, lifecycle, and contributor documentation coverage.

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: Required before merge; the new job is base-trusted, checks out github.workflow_sha, executes no PR code, and has only checks: read, contents: read, and pull-requests: read.
  • 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 test/pr-e2e-required.test.ts test/pr-e2e-gate-workflow.test.ts (27 passed); npm run typecheck:cli; npm run test:projects:check
  • Applicable broad gate passed — npm test (1,510 files passed, 3 skipped; 17,207 tests passed, 40 skipped)
  • Quality Gates section completed with required justifications or waivers — pending sensitive-path review above
  • No secrets, API keys, or credentials committed
  • npm run docs builds without warnings (doc changes only) — build passed with two pre-existing hidden Fern warnings
  • Doc pages follow the style guide (doc changes only)
  • New doc pages include SPDX header and frontmatter (new pages only)

Signed-off-by: Carlos Villela cvillela@nvidia.com

Summary by CodeRabbit

  • New Features

    • Added a native required E2E / PR Gate workflow job that mirrors a trusted exact-diff E2E coordination verdict.
    • Introduced required-gate polling that passes only for the current base/head and fails closed if revisions change.
    • Updated the coordination check display name to “E2E / PR Gate Coordination”.
  • Documentation

    • Refined E2E/PR gate architecture docs, including evidence, authorization, cancellation, and rollout/migration behavior.
  • Tests

    • Added required-gate end-to-end coverage and expanded workflow/config and gate lifecycle assertions.

Signed-off-by: Carlos Villela <cvillela@nvidia.com>
@cv cv self-assigned this Jul 15, 2026
@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The PR adds a native required E2E observer job, introduces exact-diff verdict polling and validation, renames the controller check to a coordination check, updates risk/watch coverage, and documents revised coordination, authorization, evidence, and cancellation behavior.

Changes

PR E2E required gate

Layer / File(s) Summary
Coordination check identity
tools/e2e/pr-e2e-gate.mts, test/pr-e2e-gate*.test.ts
The controller and fixtures use E2E / PR Gate Coordination for exact-diff coordination checks.
Required observer implementation
tools/e2e/pr-e2e-required.mts, test/pr-e2e-required.test.ts
The observer validates PR identity and check-run ownership, supports legacy-name lookup, polls coordination verdicts, revalidates revisions, writes summaries, and exits on non-success results.
Workflow and risk-plan wiring
.github/workflows/pr-e2e-gate.yaml, tools/advisors/risk-plan.mts, test/*watch*, test/pr-risk-plan.test.ts
A read-only, PR-scoped required job runs the observer; risk classification and targeted test triggers include the new workflow and script.
Gate architecture documentation
test/e2e/README.md, test/e2e/docs/README.md
Documentation describes the coordination/required-job split, exact-revision checks, authorization and fork handling, evidence rules, and cancellation behavior.

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

Sequence Diagram(s)

sequenceDiagram
  participant PullRequest
  participant RequiredJob
  participant RequiredObserver
  participant GitHubChecks
  PullRequest->>RequiredJob: trigger pull_request_target observer
  RequiredJob->>RequiredObserver: pass PR number and exact head/base SHAs
  RequiredObserver->>GitHubChecks: validate PR and poll coordination check
  GitHubChecks-->>RequiredObserver: return trusted terminal verdict
  RequiredObserver-->>RequiredJob: write summary and set job result
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
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 (4 passed)
Check name Status Explanation
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: publishing the PR E2E gate as a native CI job.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/native-pr-e2e-gate

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

@github-code-quality

github-code-quality Bot commented Jul 15, 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/native-pr-e2e-... branch remains at 79%, unchanged from the main branch.

Show a code coverage summary of the most impacted files.
File main 3cccebf codex/native-pr-e2e-... a83a401 +/-
src/lib/core/pr...mpt-activity.ts 92% 67% -25%
src/lib/actions...ge-preflight.ts 89% 74% -15%
src/lib/adapter...shell/client.ts 88% 83% -5%
src/lib/shields/audit.ts 97% 92% -5%
src/lib/messagi...n-validation.ts 100% 96% -4%
src/lib/messagi.../persistence.ts 89% 86% -3%
src/lib/securit...ntial-filter.ts 98% 99% +1%
src/lib/agent/m...fest-readers.ts 95% 97% +2%
src/lib/state/config-io.ts 92% 95% +3%
src/lib/agent/dashboard-ui.ts 85% 91% +6%

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

Signed-off-by: Carlos Villela <cvillela@nvidia.com>
Comment thread tools/e2e/pr-e2e-required.mts Fixed
@github-actions

github-actions Bot commented Jul 15, 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): Completed · high confidence · 0 blockers · 3 warnings · 0 suggestions
  • Model comparison: normalized findings differ; normalized E2E selections differ; Nemotron reported 1 fewer blocker, 3 more warnings, the same number of suggestions.

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: cloud-onboard, credential-sanitization, security-posture

Blockers

PRA-1 Blocker — Keep the native required job alive through the coordinator's terminal budget

  • Location: .github/workflows/pr-e2e-gate.yaml:90
  • Category: workflow
  • Problem: The `required` observer starts on the pull-request event but has a 170-minute job limit and polls for only 9,900 seconds (165 minutes). The separately triggered `coordinate` job is permitted to run for 180 minutes after upstream PR CI completes. A valid slow CI plus a coordinator that consumes its allowed budget therefore causes the observer to time out and fail before coordination can publish a successful terminal verdict.
  • Impact: The required `E2E / PR Gate` job can report a false non-passing result for an exact revision whose trusted coordination ultimately succeeds, preventing the native check from mirroring its intended terminal verdict.
  • Fix: Make the observer's timeout/job budget cover the maximum upstream-CI and coordination lifecycle from the PR event with scheduling margin, or reduce/restructure coordination so its maximum terminal verdict is guaranteed before the observer deadline.
  • Verification: Compare the `required` `timeout-minutes` and `--timeout-seconds` values with the `coordinate` job timeout and its workflow_run trigger timing in `.github/workflows/pr-e2e-gate.yaml`.
  • Test coverage: Add a workflow-contract test that asserts the observer's polling and job budgets cannot expire before the maximum supported coordination lifecycle from the pull-request event.
  • Evidence: `.github/workflows/pr-e2e-gate.yaml` sets `required.timeout-minutes: 170` and passes `--timeout-seconds 9900` (165 minutes). The same workflow permits `coordinate` to run for 180 minutes, and `coordinate` starts only after `CI / Pull Request` completes via `workflow_run`. `tools/e2e/pr-e2e-required.mts` throws on observer timeout, making the native job non-passing rather than continuing to await coordination.

Workflow run details

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

Signed-off-by: Carlos Villela <cvillela@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 (1)
tools/advisors/risk-plan.mts (1)

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

Constant name no longer matches its contents.

CONTROLLER_ONLY_E2E_FILES now also contains the observer/required-gate script (tools/e2e/pr-e2e-required.mts), not just controller files. Since this set gates the trusted-boundary/auto-dispatch decision (per test/e2e/README.md), a misleading name increases the risk that a future edit to this security-relevant list misclassifies a file. Consider renaming to something like TRUSTED_CONTROL_PLANE_ONLY_FILES to reflect that it now spans both controller and observer scripts.

As per path instructions, "Derive inventories and limits from a canonical source where possible; flag duplicated lists that can silently drift."

🤖 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/advisors/risk-plan.mts` around lines 74 - 78, Rename
CONTROLLER_ONLY_E2E_FILES to a name that reflects its trusted control-plane
scope, such as TRUSTED_CONTROL_PLANE_ONLY_FILES, and update every reference to
the set consistently. Preserve the existing file inventory and gating behavior
without introducing a separate duplicate list.

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.

Inline comments:
In `@test/pr-e2e-required.test.ts`:
- Around line 149-167: Rewrite the fetch mock in the test “waits through
authorization and revalidates the exact PR before passing” to remove both if
statements, using the file’s existing ternary-based dispatch pattern. Preserve
the current routing for the PR URL, Coordination listing, and legacy query
responses, including the first-query failure and subsequent success behavior.

---

Nitpick comments:
In `@tools/advisors/risk-plan.mts`:
- Around line 74-78: Rename CONTROLLER_ONLY_E2E_FILES to a name that reflects
its trusted control-plane scope, such as TRUSTED_CONTROL_PLANE_ONLY_FILES, and
update every reference to the set consistently. Preserve the existing file
inventory and gating behavior without introducing a separate duplicate list.
🪄 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: 98c8fc01-c7cc-42b0-88ee-688be1f34906

📥 Commits

Reviewing files that changed from the base of the PR and between 3cccebf and 532d7fd.

📒 Files selected for processing (14)
  • .github/workflows/pr-e2e-gate.yaml
  • test/e2e/README.md
  • test/e2e/docs/README.md
  • test/helpers/vitest-watch-triggers.ts
  • test/pr-e2e-gate-fork-skip.test.ts
  • test/pr-e2e-gate-lifecycle.test.ts
  • test/pr-e2e-gate-workflow.test.ts
  • test/pr-e2e-gate.test.ts
  • test/pr-e2e-required.test.ts
  • test/pr-risk-plan.test.ts
  • test/vitest-watch-triggers.test.ts
  • tools/advisors/risk-plan.mts
  • tools/e2e/pr-e2e-gate.mts
  • tools/e2e/pr-e2e-required.mts

Comment thread test/pr-e2e-required.test.ts Outdated

@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)
tools/e2e/pr-e2e-required.mts (1)

258-273: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Include the terminal verdict and trusted run link in the job summary.

appendJobSummary() now writes only static text, while result.conclusion and result.detailsUrl are logged separately. This breaks the stated PR contract that the native required job’s summary publishes both values; failures currently produce the same summary as successes.

Pass the validated result into appendJobSummary, render only the validated conclusion and URL, and add regression coverage in test/pr-e2e-required.test.ts.

Suggested direction
-function appendJobSummary(): void {
+function appendJobSummary(result: RequiredGateResult): void {
...
-      "## E2E / PR Gate\n\nThis native job mirrors the trusted exact-diff E2E coordination result. See the job log for the validated controller run.\n",
+      `## E2E / PR Gate\n\nVerdict: \`${result.conclusion}\`\n\nTrusted E2E coordination run: ${result.detailsUrl ?? "unavailable"}\n`,
...
-  appendJobSummary();
+  appendJobSummary(result);

As per coding guidelines, add a test or diagnostic for QA-escaped defects.

Also applies to: 291-292

🤖 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/pr-e2e-required.mts` around lines 258 - 273, Update
appendJobSummary to accept the validated result object and render its terminal
conclusion and trusted detailsUrl in the GitHub step summary instead of
static-only text. Update its call site to pass that validated result while
preserving the existing file validation behavior, and add regression coverage in
test/pr-e2e-required.test.ts verifying both values appear for success and
failure outcomes.

Source: Coding guidelines

🤖 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 `@tools/e2e/pr-e2e-required.mts`:
- Around line 258-273: Update appendJobSummary to accept the validated result
object and render its terminal conclusion and trusted detailsUrl in the GitHub
step summary instead of static-only text. Update its call site to pass that
validated result while preserving the existing file validation behavior, and add
regression coverage in test/pr-e2e-required.test.ts verifying both values appear
for success and failure outcomes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: d5b5d487-27a7-4730-bcb1-d512e1d64de9

📥 Commits

Reviewing files that changed from the base of the PR and between 532d7fd and 125144a.

📒 Files selected for processing (4)
  • test/e2e/README.md
  • test/e2e/docs/README.md
  • test/pr-e2e-required.test.ts
  • tools/e2e/pr-e2e-required.mts
🚧 Files skipped from review as they are similar to previous changes (3)
  • test/e2e/docs/README.md
  • test/e2e/README.md
  • test/pr-e2e-required.test.ts

Signed-off-by: Carlos Villela <cvillela@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

Caution

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

⚠️ Outside diff range comments (1)
tools/advisors/risk-plan.mts (1)

74-78: 🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

Derive the trusted inventory from one canonical source.

E2E_CONTROL_PLANE_FILES already defines the control-plane paths, while this set duplicates entries and can silently drift. Because the set controls credentialed E2E authorization, model trust metadata in a canonical inventory or enforce the subset relationship with an invariant test.

As per path instructions: derive inventories from a canonical source where possible and flag duplicated lists that can silently drift.

🤖 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/advisors/risk-plan.mts` around lines 74 - 78, Update
TRUSTED_CONTROL_PLANE_ONLY_FILES to derive its entries from the canonical
E2E_CONTROL_PLANE_FILES inventory instead of duplicating path literals, while
preserving the trusted subset used for credentialed E2E authorization. If direct
derivation is not supported, add an invariant that verifies the trusted set
remains a subset of E2E_CONTROL_PLANE_FILES.

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.

Inline comments:
In `@tools/advisors/risk-plan.mts`:
- Around line 411-413: Add focused regression tests for the authorization
predicate around the control-plane matched-file check: verify an untrusted file
returns true, a trusted-only set returns false, and a mixed trusted/untrusted
set still returns true. Use the existing test structure and
TRUSTED_CONTROL_PLANE_ONLY_FILES symbols without changing the predicate itself.

---

Outside diff comments:
In `@tools/advisors/risk-plan.mts`:
- Around line 74-78: Update TRUSTED_CONTROL_PLANE_ONLY_FILES to derive its
entries from the canonical E2E_CONTROL_PLANE_FILES inventory instead of
duplicating path literals, while preserving the trusted subset used for
credentialed E2E authorization. If direct derivation is not supported, add an
invariant that verifies the trusted set remains a subset of
E2E_CONTROL_PLANE_FILES.
🪄 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: c865da3d-535c-4aaf-96ea-03aff81f8653

📥 Commits

Reviewing files that changed from the base of the PR and between 125144a and a83a401.

📒 Files selected for processing (1)
  • tools/advisors/risk-plan.mts

Comment thread tools/advisors/risk-plan.mts
@cv

cv commented Jul 15, 2026

Copy link
Copy Markdown
Collaborator Author

Review follow-up: the static job summary is intentional after CodeQL flagged network-derived check data being written to a file. The native job conclusion remains the terminal verdict, and the strictly validated controller URL is available in the job log; the PR description and operator docs now state that boundary. The suggested trusted-set subset derivation was not applied because E2E_CONTROL_PLANE_FILES is only one supplement to the broader prefix-based e2e-control-plane matcher, not a canonical full inventory; forcing a subset would omit the two trusted tools/e2e/ scripts. Existing focused tests cover trusted-only, untrusted-only, and mixed authorization decisions.

@cv
cv merged commit 55fdc3f into main Jul 15, 2026
110 checks passed
@cv
cv deleted the codex/native-pr-e2e-gate branch July 15, 2026 09:19
@wscurran wscurran added area: ci CI workflows, checks, release automation, or GitHub Actions area: e2e End-to-end tests, nightly failures, or validation infrastructure bug-fix PR fixes a bug or regression labels Jul 29, 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 bug-fix PR fixes a bug or regression

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants