From f382c302e94e3b548b5a06fe497cd43fce70cdb2 Mon Sep 17 00:00:00 2001 From: Shivam Raj Date: Thu, 26 Mar 2026 15:50:51 +0530 Subject: [PATCH 1/2] ci: harden workflows with SHA-pinned actions, permissions, and DCO rewrite MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Pin all 18 GitHub Action references to full commit SHAs (was 0/18) - Upgrade actions/checkout v3→v4, actions/cache v3→v4 (Node 16 EOL) - Upgrade actions/setup-node v1→v4 in release workflow (v1 EOL) - Upgrade release Node.js version from 16 to 20 - Add least-privilege `permissions: contents: read` to all workflows - Replace untrusted tisonkun/actions-dco@v1.1 (individual account, 7 stars) with inline git-based DCO check — eliminates third-party dependency - Add `permissions: pull-requests: write` to DCO check for failure comments All SHAs verified via GitHub API on 2026-03-26. Co-authored-by: Isaac --- .github/workflows/dco-check.yml | 25 ++++++++++++++++++++++--- .github/workflows/main.yml | 31 +++++++++++++++++-------------- .github/workflows/release.yml | 9 ++++++--- 3 files changed, 45 insertions(+), 20 deletions(-) diff --git a/.github/workflows/dco-check.yml b/.github/workflows/dco-check.yml index 1c0ca6ec..ba78e737 100644 --- a/.github/workflows/dco-check.yml +++ b/.github/workflows/dco-check.yml @@ -2,15 +2,34 @@ name: DCO Check on: [pull_request] +permissions: + contents: read + pull-requests: write + jobs: check: runs-on: ubuntu-latest steps: - - name: Check for DCO + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + with: + fetch-depth: 0 + - name: Check for DCO sign-off id: dco-check - uses: tisonkun/actions-dco@v1.1 + run: | + base_sha="${{ github.event.pull_request.base.sha }}" + head_sha="${{ github.event.pull_request.head.sha }}" + failed=0 + for sha in $(git rev-list "$base_sha".."$head_sha"); do + if ! git log -1 --format='%B' "$sha" | grep -qiE '^Signed-off-by: .+ <.+>'; then + echo "::error::Commit $sha is missing a DCO sign-off" + failed=1 + fi + done + if [ "$failed" -eq 1 ]; then + exit 1 + fi - name: Comment about DCO status - uses: actions/github-script@v6 + uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6 if: ${{ failure() }} with: script: | diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e854e459..6e501703 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -8,13 +8,16 @@ on: branches: - main +permissions: + contents: read + jobs: lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - name: Cache node modules - uses: actions/cache@v3 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 env: cache-name: cache-node-modules with: @@ -41,17 +44,17 @@ jobs: NYC_REPORT_DIR: coverage_unit_node${{ matrix.node-version }} steps: - - uses: actions/setup-node@v4 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: ${{ matrix.node-version }} - - uses: actions/checkout@v3 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - name: Set up Python 3.10 for Node 14 if: ${{ matrix.node-version == '14' }} - uses: actions/setup-python@v4 + uses: actions/setup-python@7f4fc3e22c37d6ff65e88745f38bd3157c663f7c # v4 with: python-version: '3.10' - name: Cache node modules - uses: actions/cache@v3 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 with: path: ~/.npm key: ${{ runner.os }}-${{ matrix.node-version }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} @@ -65,7 +68,7 @@ jobs: npm run test - run: tar -cvf ${{ env.NYC_REPORT_DIR }}.tar ${{ env.NYC_REPORT_DIR }} - name: Store coverage report - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: ${{ env.NYC_REPORT_DIR }} path: ${{ env.NYC_REPORT_DIR }}.tar @@ -86,9 +89,9 @@ jobs: NYC_REPORT_DIR: coverage_e2e steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - name: Cache node modules - uses: actions/cache@v3 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 with: path: ~/.npm key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} @@ -102,7 +105,7 @@ jobs: NODE_OPTIONS="--max-old-space-size=4096" npm run e2e - run: tar -cvf ${{ env.NYC_REPORT_DIR }}.tar ${{ env.NYC_REPORT_DIR }} - name: Store coverage report - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: ${{ env.NYC_REPORT_DIR }} path: ${{ env.NYC_REPORT_DIR }}.tar @@ -115,9 +118,9 @@ jobs: cache-name: cache-node-modules steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - name: Cache node modules - uses: actions/cache@v3 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 with: path: ~/.npm key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} @@ -125,7 +128,7 @@ jobs: ${{ runner.os }}-build-${{ env.cache-name }}- ${{ runner.os }}-build- ${{ runner.os }}- - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 with: pattern: coverage_* merge-multiple: true @@ -135,7 +138,7 @@ jobs: rm coverage_*.tar - run: ls -la - name: Coverage - uses: codecov/codecov-action@v3 + uses: codecov/codecov-action@ab904c41d6ece82784817410c45d8b8c02684457 # v3 with: token: ${{ secrets.CODECOV_TOKEN }} fail_ci_if_error: true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0504b21c..9153048b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -4,14 +4,17 @@ on: release: types: [published] +permissions: + contents: read + jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v1 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: - node-version: 16 + node-version: 20 registry-url: https://registry.npmjs.org/ - run: npm ci - run: npm publish --access public From 75898c77b7f3117c954dc9f110bac6f0a19f32db Mon Sep 17 00:00:00 2001 From: Shivam Raj Date: Thu, 26 Mar 2026 15:51:19 +0530 Subject: [PATCH 2/2] ci: migrate release pipeline to OIDC with build/publish separation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Split release workflow into build job (read-only) + publish job - Build job produces tarball artifact; publish job only has artifact access - Add `id-token: write` permission (scoped to publish job only) for npm provenance attestation via `npm publish --provenance` - Add `environment: npm-publish` for reviewer-gated deployments - Upgrade Node.js to 22 for npm provenance support - Keep NPM_TOKEN for auth (keyless OIDC requires npm >= 11.5.1; Node 22 ships npm 10.x — remove token after upgrading npm CLI) Prerequisites (manual steps before merging): - Create `npm-publish` GitHub environment with required reviewers and `main`-only branch restriction - Test with a pre-release to verify provenance works Co-authored-by: Isaac --- .github/workflows/release.yml | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9153048b..50fe2935 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -4,19 +4,39 @@ on: release: types: [published] -permissions: - contents: read - jobs: build: runs-on: ubuntu-latest + permissions: + contents: read steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: - node-version: 20 - registry-url: https://registry.npmjs.org/ + node-version: 22 - run: npm ci - - run: npm publish --access public + - run: npm pack + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 + with: + name: package-tarball + path: "*.tgz" + retention-days: 1 + + publish: + needs: [build] + runs-on: ubuntu-latest + environment: npm-publish + permissions: + contents: read + id-token: write + steps: + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 + with: + node-version: 22 + registry-url: https://registry.npmjs.org/ + - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 + with: + name: package-tarball + - run: npm publish --provenance --access public *.tgz env: - NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}