From 6bc309baf2063a9b04d463f21e3d20dc6fc3c043 Mon Sep 17 00:00:00 2001 From: ethernet Date: Fri, 29 May 2026 10:47:47 -0400 Subject: [PATCH] ci: ensure required checks always report status Remove paths filters from contributor-check and supply-chain-audit workflows. When no matching files changed, the workflows never ran and the required checks (check-attribution, supply chain scan, dep bounds) stayed "pending" forever, blocking merge. Now both workflows always trigger. A path-check step/job determines whether the real work should run; gate jobs with matching names report success when the real job was skipped, so branch protection always gets a check status. Also fixes dep-bounds: the old condition if: contains(github.event.pull_request.changed_files_url, 'pyproject.toml') || true was always true (the || true made it unconditional). Now uses the proper changes.deps output from the shared filter job. --- .github/workflows/contributor-check.yml | 22 ++++++-- .github/workflows/supply-chain-audit.yml | 71 ++++++++++++++++++++---- 2 files changed, 78 insertions(+), 15 deletions(-) diff --git a/.github/workflows/contributor-check.yml b/.github/workflows/contributor-check.yml index 939215ed4..de38fcaae 100644 --- a/.github/workflows/contributor-check.yml +++ b/.github/workflows/contributor-check.yml @@ -3,11 +3,9 @@ name: Contributor Attribution Check on: pull_request: branches: [main] - paths: - # Only run when code files change (not docs-only PRs) - - '*.py' - - '**/*.py' - - '.github/workflows/contributor-check.yml' + # No paths filter — the job must always run so the required check + # reports a status (path-gated workflows leave checks "pending" forever + # when no matching files change, which blocks merge). permissions: contents: read @@ -20,7 +18,21 @@ jobs: with: fetch-depth: 0 # Full history needed for git log + - name: Check if relevant files changed + id: filter + run: | + BASE="${{ github.event.pull_request.base.sha }}" + HEAD="${{ github.event.pull_request.head.sha }}" + CHANGED=$(git diff --name-only "$BASE"..."$HEAD" -- '*.py' '**/*.py' '.github/workflows/contributor-check.yml' || true) + if [ -n "$CHANGED" ]; then + echo "run=true" >> "$GITHUB_OUTPUT" + else + echo "run=false" >> "$GITHUB_OUTPUT" + echo "No Python files changed, skipping attribution check." + fi + - name: Check for unmapped contributor emails + if: steps.filter.outputs.run == 'true' run: | # Get the merge base between this PR and main MERGE_BASE=$(git merge-base origin/main HEAD) diff --git a/.github/workflows/supply-chain-audit.yml b/.github/workflows/supply-chain-audit.yml index 2f727e8d2..324a2e142 100644 --- a/.github/workflows/supply-chain-audit.yml +++ b/.github/workflows/supply-chain-audit.yml @@ -3,15 +3,9 @@ name: Supply Chain Audit on: pull_request: types: [opened, synchronize, reopened] - paths: - - '**/*.py' - - '**/*.pth' - - '**/setup.py' - - '**/setup.cfg' - - '**/sitecustomize.py' - - '**/usercustomize.py' - - '**/__init__.pth' - - 'pyproject.toml' + # No paths filter — the jobs must always run so required checks + # report a status (path-gated workflows leave checks "pending" forever + # when no matching files change, which blocks merge). permissions: pull-requests: write @@ -27,8 +21,44 @@ permissions: # advisory-only workflow instead. jobs: + # ── Path filter (shared by both scan and dep-bounds) ─────────────── + changes: + runs-on: ubuntu-latest + outputs: + # True when any file the scanner cares about changed in this PR + scan: ${{ steps.filter.outputs.scan }} + # True when pyproject.toml changed in this PR + deps: ${{ steps.filter.outputs.deps }} + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + fetch-depth: 0 + - name: Check for relevant file changes + id: filter + run: | + BASE="${{ github.event.pull_request.base.sha }}" + HEAD="${{ github.event.pull_request.head.sha }}" + SCAN_FILES=$(git diff --name-only "$BASE"..."$HEAD" -- \ + '*.py' '**/*.py' '*.pth' '**/*.pth' \ + 'setup.py' 'setup.cfg' \ + 'sitecustomize.py' 'usercustomize.py' '__init__.pth' \ + 'pyproject.toml' || true) + if [ -n "$SCAN_FILES" ]; then + echo "scan=true" >> "$GITHUB_OUTPUT" + else + echo "scan=false" >> "$GITHUB_OUTPUT" + fi + DEPS_FILES=$(git diff --name-only "$BASE"..."$HEAD" -- 'pyproject.toml' || true) + if [ -n "$DEPS_FILES" ]; then + echo "deps=true" >> "$GITHUB_OUTPUT" + else + echo "deps=false" >> "$GITHUB_OUTPUT" + fi + scan: name: Scan PR for critical supply chain risks + needs: changes + if: needs.changes.outputs.scan == 'true' runs-on: ubuntu-latest steps: - name: Checkout @@ -147,10 +177,21 @@ jobs: echo "::error::CRITICAL supply chain risk patterns detected in this PR. See the PR comment for details." exit 1 + # Gate: reports success when scan was skipped (no relevant files changed). + # This ensures the required check always gets a status. + scan-gate: + name: Scan PR for critical supply chain risks + needs: changes + if: needs.changes.outputs.scan == 'false' + runs-on: ubuntu-latest + steps: + - run: echo "No supply-chain-relevant files changed, skipping scan." + dep-bounds: name: Check PyPI dependency upper bounds + needs: changes + if: needs.changes.outputs.deps == 'true' runs-on: ubuntu-latest - if: contains(github.event.pull_request.changed_files_url, 'pyproject.toml') || true steps: - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 @@ -211,3 +252,13 @@ jobs: run: | echo "::error::PyPI dependencies without upper bounds detected. Add