From 1154c0a46833720e42201d54e0e7cb9f20782a00 Mon Sep 17 00:00:00 2001 From: Jaya Venkatesh Date: Tue, 17 Mar 2026 17:37:25 -0700 Subject: [PATCH 1/7] add PR CI workflows Signed-off-by: Jaya Venkatesh --- .github/workflows/pr-limit.yaml | 36 ++++++++++++++++++++ .github/workflows/pr.yaml | 58 +++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 .github/workflows/pr-limit.yaml create mode 100644 .github/workflows/pr.yaml diff --git a/.github/workflows/pr-limit.yaml b/.github/workflows/pr-limit.yaml new file mode 100644 index 0000000000..05369cd1a6 --- /dev/null +++ b/.github/workflows/pr-limit.yaml @@ -0,0 +1,36 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +name: pr-limit + +on: + pull_request: + types: [opened] + +permissions: + pull-requests: write + +jobs: + check-pr-limit: + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - name: Check open PR count for author + env: + GH_TOKEN: ${{ github.token }} + run: | + AUTHOR="${{ github.event.pull_request.user.login }}" + PR_NUMBER="${{ github.event.pull_request.number }}" + REPO="${{ github.repository }}" + + OPEN_COUNT=$(gh pr list --repo "$REPO" --author "$AUTHOR" --state open --json number --jq 'length') + + echo "Author $AUTHOR has $OPEN_COUNT open PR(s)" + + if [ "$OPEN_COUNT" -gt 10 ]; then + gh pr comment "$PR_NUMBER" --repo "$REPO" --body \ + "This repository limits contributors to 10 open pull requests. Please close or merge existing PRs before opening new ones." + gh pr close "$PR_NUMBER" --repo "$REPO" + echo "::error::PR closed — author $AUTHOR exceeds the 10 open PR limit" + exit 1 + fi diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml new file mode 100644 index 0000000000..7bee17420b --- /dev/null +++ b/.github/workflows/pr.yaml @@ -0,0 +1,58 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +name: pr + +on: + pull_request: + types: [opened, synchronize, reopened] + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + test-unit: + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "22" + cache: npm + + - name: Install root dependencies + run: npm ci + + - name: Install and build TypeScript plugin + working-directory: nemoclaw + run: | + npm ci + npm run build + + - name: Run root unit tests + run: node --test test/*.test.js + + - name: Run TypeScript unit tests + working-directory: nemoclaw + run: npx vitest run + + test-e2e-sandbox: + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Build sandbox test image + run: docker build -f test/Dockerfile.sandbox -t nemoclaw-sandbox-test . + + - name: Run sandbox E2E tests + run: docker run --rm -v "${{ github.workspace }}/test:/opt/test" nemoclaw-sandbox-test /opt/test/e2e-test.sh From 6c843064d28d85b26674aec7bf6d5b81d4b998d6 Mon Sep 17 00:00:00 2001 From: Jaya Venkatesh Date: Tue, 17 Mar 2026 17:41:49 -0700 Subject: [PATCH 2/7] changed npm to install Signed-off-by: Jaya Venkatesh --- .github/workflows/pr.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index 7bee17420b..936b6ef91f 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -29,12 +29,12 @@ jobs: cache: npm - name: Install root dependencies - run: npm ci + run: npm install - name: Install and build TypeScript plugin working-directory: nemoclaw run: | - npm ci + npm install npm run build - name: Run root unit tests From 6ea7be17cd30f60c48738742850dd98a1769a0e0 Mon Sep 17 00:00:00 2001 From: Jaya Venkatesh Date: Tue, 17 Mar 2026 17:47:49 -0700 Subject: [PATCH 3/7] merged both PR checks into one Signed-off-by: Jaya Venkatesh --- .github/workflows/pr-limit.yaml | 36 --------------------------------- .github/workflows/pr.yaml | 30 +++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 36 deletions(-) delete mode 100644 .github/workflows/pr-limit.yaml diff --git a/.github/workflows/pr-limit.yaml b/.github/workflows/pr-limit.yaml deleted file mode 100644 index 05369cd1a6..0000000000 --- a/.github/workflows/pr-limit.yaml +++ /dev/null @@ -1,36 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -name: pr-limit - -on: - pull_request: - types: [opened] - -permissions: - pull-requests: write - -jobs: - check-pr-limit: - runs-on: ubuntu-latest - timeout-minutes: 5 - steps: - - name: Check open PR count for author - env: - GH_TOKEN: ${{ github.token }} - run: | - AUTHOR="${{ github.event.pull_request.user.login }}" - PR_NUMBER="${{ github.event.pull_request.number }}" - REPO="${{ github.repository }}" - - OPEN_COUNT=$(gh pr list --repo "$REPO" --author "$AUTHOR" --state open --json number --jq 'length') - - echo "Author $AUTHOR has $OPEN_COUNT open PR(s)" - - if [ "$OPEN_COUNT" -gt 10 ]; then - gh pr comment "$PR_NUMBER" --repo "$REPO" --body \ - "This repository limits contributors to 10 open pull requests. Please close or merge existing PRs before opening new ones." - gh pr close "$PR_NUMBER" --repo "$REPO" - echo "::error::PR closed — author $AUTHOR exceeds the 10 open PR limit" - exit 1 - fi diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index 936b6ef91f..87036ddebd 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -9,13 +9,41 @@ on: permissions: contents: read + pull-requests: write concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: + check-pr-limit: + if: github.event.action == 'opened' + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - name: Check open PR count for author + env: + GH_TOKEN: ${{ github.token }} + run: | + AUTHOR="${{ github.event.pull_request.user.login }}" + PR_NUMBER="${{ github.event.pull_request.number }}" + REPO="${{ github.repository }}" + + OPEN_COUNT=$(gh pr list --repo "$REPO" --author "$AUTHOR" --state open --json number --jq 'length') + + echo "Author $AUTHOR has $OPEN_COUNT open PR(s)" + + if [ "$OPEN_COUNT" -gt 10 ]; then + gh pr comment "$PR_NUMBER" --repo "$REPO" --body \ + "This repository limits contributors to 10 open pull requests. Please close or merge existing PRs before opening new ones." + gh pr close "$PR_NUMBER" --repo "$REPO" + echo "::error::PR closed — author $AUTHOR exceeds the 10 open PR limit" + exit 1 + fi + test-unit: + needs: check-pr-limit + if: ${{ !cancelled() && (needs.check-pr-limit.result == 'success' || needs.check-pr-limit.result == 'skipped') }} runs-on: ubuntu-latest timeout-minutes: 10 steps: @@ -45,6 +73,8 @@ jobs: run: npx vitest run test-e2e-sandbox: + needs: check-pr-limit + if: ${{ !cancelled() && (needs.check-pr-limit.result == 'success' || needs.check-pr-limit.result == 'skipped') }} runs-on: ubuntu-latest timeout-minutes: 15 steps: From 87f6046a8b92852e6aec2dd927f136f7fa92d682 Mon Sep 17 00:00:00 2001 From: Jaya Venkatesh Date: Tue, 17 Mar 2026 18:12:22 -0700 Subject: [PATCH 4/7] moved variables from run to env Signed-off-by: Jaya Venkatesh --- .github/workflows/pr.yaml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index 87036ddebd..b923147111 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -24,11 +24,10 @@ jobs: - name: Check open PR count for author env: GH_TOKEN: ${{ github.token }} + AUTHOR: ${{ github.event.pull_request.user.login }} + PR_NUMBER: ${{ github.event.pull_request.number }} + REPO: ${{ github.repository }} run: | - AUTHOR="${{ github.event.pull_request.user.login }}" - PR_NUMBER="${{ github.event.pull_request.number }}" - REPO="${{ github.repository }}" - OPEN_COUNT=$(gh pr list --repo "$REPO" --author "$AUTHOR" --state open --json number --jq 'length') echo "Author $AUTHOR has $OPEN_COUNT open PR(s)" From ab72e1c4992ec9677c64388635ab7734ec2eeee3 Mon Sep 17 00:00:00 2001 From: Jaya Venkatesh Date: Tue, 17 Mar 2026 18:24:41 -0700 Subject: [PATCH 5/7] scoping read permissions Signed-off-by: Jaya Venkatesh --- .github/workflows/pr.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index b923147111..8e47bb6e14 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -9,7 +9,6 @@ on: permissions: contents: read - pull-requests: write concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -17,8 +16,10 @@ concurrency: jobs: check-pr-limit: - if: github.event.action == 'opened' + if: github.event.action == 'opened' || github.event.action == 'reopened' runs-on: ubuntu-latest + permissions: + pull-requests: write timeout-minutes: 5 steps: - name: Check open PR count for author From 6fd1ffda1ea0252bfe1bdf7d8976b4a04b385f50 Mon Sep 17 00:00:00 2001 From: Jaya Venkatesh Date: Tue, 17 Mar 2026 18:38:29 -0700 Subject: [PATCH 6/7] split pr closer into a separate file Signed-off-by: Jaya Venkatesh --- .github/workflows/pr-limit.yaml | 35 +++++++++++++++++++++++++++++++++ .github/workflows/pr.yaml | 30 ---------------------------- 2 files changed, 35 insertions(+), 30 deletions(-) create mode 100644 .github/workflows/pr-limit.yaml diff --git a/.github/workflows/pr-limit.yaml b/.github/workflows/pr-limit.yaml new file mode 100644 index 0000000000..d94e8a4752 --- /dev/null +++ b/.github/workflows/pr-limit.yaml @@ -0,0 +1,35 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +name: pr-limit + +on: + pull_request: + types: [opened, reopened] + +permissions: + pull-requests: write + +jobs: + check-pr-limit: + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - name: Check open PR count for author + env: + GH_TOKEN: ${{ github.token }} + AUTHOR: ${{ github.event.pull_request.user.login }} + PR_NUMBER: ${{ github.event.pull_request.number }} + REPO: ${{ github.repository }} + run: | + OPEN_COUNT=$(gh pr list --repo "$REPO" --author "$AUTHOR" --state open --json number --jq 'length') + + echo "Author $AUTHOR has $OPEN_COUNT open PR(s)" + + if [ "$OPEN_COUNT" -gt 10 ]; then + gh pr comment "$PR_NUMBER" --repo "$REPO" --body \ + "This repository limits contributors to 10 open pull requests. Please close or merge existing PRs before opening new ones." + gh pr close "$PR_NUMBER" --repo "$REPO" + echo "::error::PR closed — author $AUTHOR exceeds the 10 open PR limit" + exit 1 + fi diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index 8e47bb6e14..936b6ef91f 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -15,35 +15,7 @@ concurrency: cancel-in-progress: true jobs: - check-pr-limit: - if: github.event.action == 'opened' || github.event.action == 'reopened' - runs-on: ubuntu-latest - permissions: - pull-requests: write - timeout-minutes: 5 - steps: - - name: Check open PR count for author - env: - GH_TOKEN: ${{ github.token }} - AUTHOR: ${{ github.event.pull_request.user.login }} - PR_NUMBER: ${{ github.event.pull_request.number }} - REPO: ${{ github.repository }} - run: | - OPEN_COUNT=$(gh pr list --repo "$REPO" --author "$AUTHOR" --state open --json number --jq 'length') - - echo "Author $AUTHOR has $OPEN_COUNT open PR(s)" - - if [ "$OPEN_COUNT" -gt 10 ]; then - gh pr comment "$PR_NUMBER" --repo "$REPO" --body \ - "This repository limits contributors to 10 open pull requests. Please close or merge existing PRs before opening new ones." - gh pr close "$PR_NUMBER" --repo "$REPO" - echo "::error::PR closed — author $AUTHOR exceeds the 10 open PR limit" - exit 1 - fi - test-unit: - needs: check-pr-limit - if: ${{ !cancelled() && (needs.check-pr-limit.result == 'success' || needs.check-pr-limit.result == 'skipped') }} runs-on: ubuntu-latest timeout-minutes: 10 steps: @@ -73,8 +45,6 @@ jobs: run: npx vitest run test-e2e-sandbox: - needs: check-pr-limit - if: ${{ !cancelled() && (needs.check-pr-limit.result == 'success' || needs.check-pr-limit.result == 'skipped') }} runs-on: ubuntu-latest timeout-minutes: 15 steps: From e22af2066b76dfcff3bbb03b658c40afdfb78147 Mon Sep 17 00:00:00 2001 From: Jaya Venkatesh Date: Tue, 17 Mar 2026 18:58:35 -0700 Subject: [PATCH 7/7] changed action to pull_request_target Signed-off-by: Jaya Venkatesh --- .github/workflows/pr-limit.yaml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pr-limit.yaml b/.github/workflows/pr-limit.yaml index d94e8a4752..ebf95d3499 100644 --- a/.github/workflows/pr-limit.yaml +++ b/.github/workflows/pr-limit.yaml @@ -3,8 +3,13 @@ name: pr-limit +# pull_request_target runs in the base repo context, giving the token write +# access even for fork PRs. This is safe here because this workflow never +# checks out or executes code from the PR — it only counts open PRs and +# closes excess ones. Do NOT add a checkout step or run PR-sourced code +# in this workflow to prevent injection attacks. on: - pull_request: + pull_request_target: types: [opened, reopened] permissions: