Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .agents/skills/nemoclaw-maintainer-day/MERGE-GATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ The product-scope gate is a human decision and is not represented by `allPass`.
The script handles the deterministic checks. You handle judgment calls:

- **Product scope not established:** Stop before approval when the PR would create a new supported product surface and no accepted issue or design decision establishes ownership and lifecycle expectations. Technical correctness, successful tests, green CI, and positive advisor output do not substitute for product approval. Ask a maintainer for the product decision or route an independent solution through [Community Solutions](../../../docs/resources/community-contributions.mdx).
- **Missing required checks:** The checked-in script requires `checks`, `check-hash`, `changes`, `commit-lint`, `dco-check`, and `E2E / PR Gate` in the status rollup, including while the repository ruleset rollout is staged. First-time fork contributors may need "Approve and run" before the ordinary `pull_request` checks appear. The trusted E2E controller reserves its exact-head context for both internal and fork PRs without executing PR code. Never waive a missing, neutral, or skipped E2E gate, and never run untrusted fork code with privileged credentials to manufacture a result.
- **Fork no-secret exception:** Use this only when an exact-head gate has failed with `Maintainer fork exception required`. In Actions, open `E2E / PR Gate`, choose **Run workflow** on `main`, select `resolve-fork`, and provide the fork PR number, its current 40-character head SHA, a specific 10–500-character reason, and optionally an `NVIDIA/NemoClaw` Actions run URL as supporting evidence. Re-read the PR head immediately before dispatch. The controller rejects a changed head, an internal PR, an empty E2E plan, a non-failed gate, a stale controller commit that is no longer `main`, or an actor below maintainer role. It validates the optional URL's repository and run-ID shape but does not inspect that run's head, jobs, or conclusion; review the run yourself before citing it. A successful dispatch records that credential-bearing E2E was not run; it is an audited no-secret exception, not passing E2E evidence.
- **E2E control-plane no-secret exception:** Use this only when an internal exact-head gate has failed with `Maintainer control-plane exception required`. The deterministic `e2e-control-plane` family is a conservative path boundary: it covers E2E and PR-CI workflows, risk policy, dependency and test configuration, preparation and upload actions, and non-documentation files under `tools/e2e/` and `test/e2e/`, including shell and Python support files. Because a matching revision may influence job selection, credential-bearing execution, or the evidence used by the gate, the controller withholds the selected live jobs instead of trying to classify individual diffs as harmless. Independently review the change and its non-secret CI, then run `E2E / PR Gate` on `main` with `resolve-control-plane`, the PR number, current exact SHA, a specific reason, and optionally a same-repository Actions run URL. The controller rejects forks, stale heads, plans without that family, a mismatched failed gate, a stale controller commit that is no longer `main`, or an actor below maintainer role. It does not query an approval record or inspect optional run evidence; the privileged dispatch and reason are the maintainer's auditable assertion that the review occurred. The recorded success states that the credential-bearing jobs were waived; it never claims they passed.
- **Two-phase ruleset rollout and backfill:** First deploy the E2E check producer and its trusted fork handling. Re-run `CI / Pull Request` for every already-open exact PR head (approving a first-time fork run when necessary), then verify that `E2E / PR Gate` is attached to that same head SHA. The fail-closed maintainer checker identifies any head still needing backfill. Adding the workflow does not retroactively report the context, and enabling the ruleset first leaves existing PRs at "Waiting for status to be reported." Do not activate the context as a security boundary while it is scoped only to the shared GitHub Actions app: that app identity cannot distinguish this workflow from another workflow. First give the gate distinct provenance through a dedicated GitHub App or an organization required-workflow rule. When the context is finally activated, also enable strict/up-to-date required status checks; otherwise a successful head can remain mergeable after `main` advances and changes the effective merge diff. Preserve the control-plane review and deterministic floor even after those external protections are in place.
- **Missing required checks:** The checked-in script requires `checks`, `check-hash`, `changes`, `commit-lint`, `dco-check`, and `E2E / PR Gate` in the status rollup, including while the repository ruleset rollout is staged. First-time fork contributors may need "Approve and run" before the ordinary `pull_request` checks appear. The trusted E2E controller reserves its exact head/base context for both internal and fork PRs without executing PR code. Never waive a missing, neutral, or skipped E2E gate, and never run untrusted fork code with privileged credentials to manufacture a result.
- **Fork no-secret exception:** Use this only when an exact-diff gate has failed with `Maintainer fork exception required`. In Actions, open `E2E / PR Gate`, choose **Run workflow** on `main`, select `resolve-fork`, and provide the fork PR number, its current 40-character head SHA as `expected_head_sha`, its current 40-character base SHA as `expected_base_sha`, a specific 10–500-character reason, and optionally an `NVIDIA/NemoClaw` Actions run URL as supporting evidence. Re-read both PR SHAs immediately before dispatch. The controller rejects a closed PR, a changed head or base, an internal PR, an empty E2E plan, a non-failed gate, a controller commit that is neither current `main` nor a safely validated ancestor of it, or an actor below maintainer role. A safe `main` advance must preserve the controller commit as its merge base, contain fewer than 300 fully enumerated changed files, and avoid `e2e-control-plane` changes; other advances fail closed. The controller validates the optional URL's repository and run-ID shape but does not inspect that run's head, jobs, or conclusion; review the run yourself before citing it. It re-reads the open PR's exact head and base immediately before writing success. A successful dispatch records that credential-bearing E2E was not run; it is an audited no-secret exception, not passing E2E evidence.
- **E2E control-plane no-secret exception:** Use this only when an internal exact-diff gate has failed with `Maintainer control-plane exception required`. The deterministic `e2e-control-plane` family is a conservative path boundary: it covers E2E and PR-CI workflows, risk policy, dependency and test configuration, preparation and upload actions, and non-documentation files under `tools/e2e/` and `test/e2e/`, including shell and Python support files. Because a matching revision may influence job selection, credential-bearing execution, or the evidence used by the gate, the controller withholds the selected live jobs instead of trying to classify individual diffs as harmless. Independently review the change and its non-secret CI, then run `E2E / PR Gate` on `main` with `resolve-control-plane`, the PR number, current `expected_head_sha`, current `expected_base_sha`, a specific reason, and optionally a same-repository Actions run URL. The controller rejects closed PRs, forks, stale heads or bases, plans without that family, a mismatched failed gate, a controller commit that is neither current `main` nor a safely validated ancestor of it, or an actor below maintainer role. A safe `main` advance must preserve the controller commit as its merge base, contain fewer than 300 fully enumerated changed files, and avoid `e2e-control-plane` changes; other advances fail closed. It does not query an approval record or inspect optional run evidence; the privileged dispatch and reason are the maintainer's auditable assertion that the review occurred. It re-reads the open PR's exact head and base immediately before writing success. The recorded success states that the credential-bearing jobs were waived; it never claims they passed.
- **Two-phase ruleset rollout and backfill:** First deploy the E2E check producer and its trusted fork handling. Re-run `CI / Pull Request` for every already-open exact PR head/base pair (approving a first-time fork run when necessary), then verify that `E2E / PR Gate` is attached to that same head SHA for the current base. The fail-closed maintainer checker identifies any head still needing backfill. Adding the workflow does not retroactively report the context, and enabling the ruleset first leaves existing PRs at "Waiting for status to be reported." Do not activate the context as a security boundary while it is scoped only to the shared GitHub Actions app: that app identity cannot distinguish this workflow from another workflow. First give the gate distinct provenance through a dedicated GitHub App or an organization required-workflow rule. When the context is finally activated, also enable strict/up-to-date required status checks; otherwise a successful head can remain mergeable after `main` advances and changes the effective merge diff. Preserve the control-plane review and deterministic floor even after those external protections are in place.
- **Contributor compliance failed:** Reject the PR and ask the contributor to provide the PR-body DCO declaration or replace unverified commits with a clean verified history. Do not approve, merge, amend, sign, or force-push on the contributor's behalf.
- **Contributor/approver overlap:** Surface `advisories.contributorApprovalOverlap` when the same account not recognized as automated by the supported login conventions appears as the current PR opener, commit author, or co-author and its latest opinionated review is approved. The invalid state detected here is contributor and approver identity overlap in the current GitHub PR metadata; the source boundary is the current opener plus all commit-author and review pages fetched through GitHub's GraphQL API. The advisory includes contributors whose commits remain in the current PR head at check time; it does not retain original push actors or authors removed when history is rebased, squashed, or fixed up. A clear result is not proof of independent approval. Missing, invalid, or conflicting review timestamps, or failure to retrieve complete paginated history, produce a warning because the latest opinion cannot be selected reliably.

Expand Down
16 changes: 16 additions & 0 deletions .github/workflows/e2e.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,16 @@ on:
required: false
default: ""
type: string
base_sha:
description: PR base commit selected by the controller.
required: false
default: ""
type: string
workflow_sha:
description: Trusted E2E workflow commit selected by the controller.
required: false
default: ""
type: string
plan_hash:
description: SHA-256 of the selected E2E plan.
required: false
Expand Down Expand Up @@ -82,7 +92,9 @@ jobs:
- name: Validate controller dispatch
if: ${{ inputs.checkout_sha != '' }}
env:
BASE_SHA: ${{ inputs.base_sha }}
CHECKOUT_SHA: ${{ inputs.checkout_sha }}
EXPECTED_WORKFLOW_SHA: ${{ inputs.workflow_sha }}
GITHUB_TOKEN: ${{ github.token }}
JOBS: ${{ inputs.jobs }}
PLAN_HASH: ${{ inputs.plan_hash }}
Expand All @@ -91,10 +103,13 @@ jobs:
TARGETS: ${{ inputs.targets }}
WORKFLOW_EVENT: ${{ github.event_name }}
WORKFLOW_REF: ${{ github.ref }}
WORKFLOW_SHA: ${{ github.workflow_sha }}
run: |
set -euo pipefail
[[ "$WORKFLOW_EVENT" == "workflow_dispatch" && "$WORKFLOW_REF" == "refs/heads/main" ]] || { echo "::error::PR E2E runs must be dispatched from main"; exit 1; }
[[ "$CHECKOUT_SHA" =~ ^[a-f0-9]{40}$ ]] || { echo "::error::checkout_sha must be a lowercase 40-character SHA"; exit 1; }
[[ "$BASE_SHA" =~ ^[a-f0-9]{40}$ ]] || { echo "::error::base_sha must be a lowercase 40-character SHA"; exit 1; }
[[ "$EXPECTED_WORKFLOW_SHA" =~ ^[a-f0-9]{40}$ && "$WORKFLOW_SHA" == "$EXPECTED_WORKFLOW_SHA" ]] || { echo "::error::workflow_sha must match the trusted workflow commit"; exit 1; }
[[ "$(git rev-parse --verify HEAD)" == "$CHECKOUT_SHA" ]] || { echo "::error::checked-out commit does not match checkout_sha"; exit 1; }
[[ "$PLAN_HASH" =~ ^[a-f0-9]{64}$ ]] || { echo "::error::plan_hash must be a lowercase SHA-256"; exit 1; }
[[ "$CORRELATION_ID" =~ ^[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$ ]] || { echo "::error::correlation_id must be a lowercase UUIDv4"; exit 1; }
Expand All @@ -109,6 +124,7 @@ jobs:
[[ "$(jq -r '.state' <<< "$pull_json")" == "open" ]] || { echo "::error::pull request must still be open"; exit 1; }
[[ "$(jq -r '.head.repo.full_name // ""' <<< "$pull_json")" == "$GITHUB_REPOSITORY" ]] || { echo "::error::pull request must originate from this repository"; exit 1; }
[[ "$(jq -r '.head.sha' <<< "$pull_json")" == "$CHECKOUT_SHA" ]] || { echo "::error::checkout_sha must match the PR head commit"; exit 1; }
[[ "$(jq -r '.base.sha' <<< "$pull_json")" == "$BASE_SHA" ]] || { echo "::error::base_sha must match the PR base commit"; exit 1; }

- name: Prepare E2E workspace
uses: NVIDIA/NemoClaw/.github/actions/prepare-e2e@50281ee84c4a6fc759da95ea28fc0b7d9c378a28
Expand Down
25 changes: 18 additions & 7 deletions .github/workflows/pr-e2e-gate.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ on:
workflows: ["CI / Pull Request"]
types: [completed]
pull_request_target:
types: [opened, synchronize, reopened, ready_for_review, closed]
types: [opened, synchronize, reopened, ready_for_review, edited, closed]
workflow_dispatch:
inputs:
operation:
description: Exact-head exception type to record.
description: Exact-diff exception type to record.
required: true
default: resolve-fork
type: choice
Expand All @@ -27,6 +27,10 @@ on:
description: Exact 40-character PR head SHA reviewed by the maintainer.
required: true
type: string
expected_base_sha:
description: Exact 40-character PR base SHA reviewed by the maintainer.
required: true
type: string
waiver_reason:
description: Why credentialed E2E cannot be run safely for this revision.
required: true
Expand All @@ -41,14 +45,15 @@ permissions: {}

jobs:
initialize:
if: ${{ github.event_name == 'pull_request_target' && github.repository == 'NVIDIA/NemoClaw' && github.event.action != 'closed' }}
if: ${{ github.event_name == 'pull_request_target' && github.repository == 'NVIDIA/NemoClaw' && github.event.action != 'closed' && (github.event.action != 'edited' || github.event.changes.base != null) }}
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
checks: write
contents: read
pull-requests: read
concurrency:
group: pr-e2e-gate-seed-${{ github.event.pull_request.number }}-${{ github.event.pull_request.head.sha }}
group: pr-e2e-gate-${{ github.event.pull_request.head.repo.full_name }}-${{ github.event.pull_request.head.ref }}
cancel-in-progress: false
steps:
- name: Checkout controller
Expand All @@ -65,8 +70,9 @@ jobs:
- name: Install controller dependencies
run: npm ci --ignore-scripts

- name: Reserve exact-head gate
- name: Reserve exact-diff gate
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
GITHUB_TOKEN: ${{ github.token }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
PR_NUMBER: ${{ github.event.pull_request.number }}
Expand All @@ -75,9 +81,10 @@ jobs:
--mode seed
--pr "$PR_NUMBER"
--head "$HEAD_SHA"
--base "$BASE_SHA"

cancel-superseded:
if: ${{ github.event_name == 'pull_request_target' && github.repository == 'NVIDIA/NemoClaw' && github.event.pull_request.head.repo.full_name == github.repository }}
if: ${{ github.event_name == 'pull_request_target' && github.repository == 'NVIDIA/NemoClaw' && github.event.pull_request.head.repo.full_name == github.repository && (github.event.action != 'edited' || github.event.changes.base != null) }}
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
Expand Down Expand Up @@ -108,7 +115,7 @@ jobs:
--pr "$PR_NUMBER"

coordinate:
if: ${{ github.event_name == 'workflow_run' && github.repository == 'NVIDIA/NemoClaw' && github.event.workflow_run.event == 'pull_request' }}
if: ${{ github.event_name == 'workflow_run' && github.repository == 'NVIDIA/NemoClaw' && github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.path == '.github/workflows/pr.yaml' && endsWith(github.event.workflow_run.display_title, ' gate true') }}
runs-on: ubuntu-latest
timeout-minutes: 180
permissions:
Expand Down Expand Up @@ -148,6 +155,7 @@ jobs:
name: Start evaluation
env:
CI_CONCLUSION: ${{ github.event.workflow_run.conclusion }}
CI_DISPLAY_TITLE: ${{ github.event.workflow_run.display_title }}
CI_RUN_ATTEMPT: ${{ github.event.workflow_run.run_attempt }}
CI_RUN_ID: ${{ github.event.workflow_run.id }}
GITHUB_TOKEN: ${{ github.token }}
Expand All @@ -165,6 +173,7 @@ jobs:
--head-branch "$HEAD_BRANCH"
--workflow-sha "$WORKFLOW_SHA"
--ci-conclusion "$CI_CONCLUSION"
--ci-display-title "$CI_DISPLAY_TITLE"
--ci-run-attempt "$CI_RUN_ATTEMPT"
--ci-run-id "$CI_RUN_ID"
--pr "$PR_NUMBER"
Expand Down Expand Up @@ -324,6 +333,7 @@ jobs:
- name: Record E2E exception
env:
EVIDENCE_URL: ${{ inputs.evidence_url }}
EXPECTED_BASE_SHA: ${{ inputs.expected_base_sha }}
EXPECTED_HEAD_SHA: ${{ inputs.expected_head_sha }}
GITHUB_TOKEN: ${{ github.token }}
MAINTAINER: ${{ github.triggering_actor }}
Expand All @@ -336,6 +346,7 @@ jobs:
--mode "$OPERATION"
--pr "$PR_NUMBER"
--head "$EXPECTED_HEAD_SHA"
--base "$EXPECTED_BASE_SHA"
--workflow-sha "$WORKFLOW_SHA"
--maintainer "$MAINTAINER"
--reason "$WAIVER_REASON"
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/pr-review-advisor.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ on:
# advisor secrets available for both internal and fork PRs. The analysis job
# never executes PR-controlled content and has no write permission.
pull_request_target:
types: [opened, synchronize, reopened, ready_for_review]
types: [opened, synchronize, reopened, ready_for_review, edited]
workflow_dispatch:
inputs:
base_ref:
Expand Down Expand Up @@ -46,13 +46,13 @@ on:
permissions: {}

concurrency:
group: pr-review-advisor-${{ github.event_name }}-${{ github.event.pull_request.number || github.ref }}-${{ inputs.target_repo || github.repository }}-${{ inputs.target_pr || '' }}
group: pr-review-advisor-${{ github.event_name }}-${{ github.event.pull_request.number || github.ref }}-${{ inputs.target_repo || github.repository }}-${{ inputs.target_pr || '' }}-${{ github.event_name != 'pull_request_target' || github.event.action != 'edited' || github.event.changes.base != null }}
cancel-in-progress: true

jobs:
review:
name: PR review advisor (${{ matrix.advisor.label }})
if: ${{ github.repository == 'NVIDIA/NemoClaw' }}
if: ${{ github.repository == 'NVIDIA/NemoClaw' && (github.event_name != 'pull_request_target' || github.event.action != 'edited' || github.event.changes.base != null) }}
permissions:
actions: read
checks: read
Expand Down Expand Up @@ -369,7 +369,7 @@ jobs:
publish:
name: Publish PR review advisor
needs: review
if: ${{ always() && github.event_name == 'pull_request_target' && needs.review.result != 'cancelled' }}
if: ${{ always() && github.event_name == 'pull_request_target' && (github.event.action != 'edited' || github.event.changes.base != null) && needs.review.result != 'cancelled' }}
# Publication is best-effort and must never hide the primary analysis
# lane's required outcome in the review matrix above.
continue-on-error: true
Expand Down
Loading