diff --git a/.github/workflows/actions-pinned-check.yml b/.github/workflows/actions-pinned-check.yml new file mode 100644 index 0000000..70c3aa5 --- /dev/null +++ b/.github/workflows/actions-pinned-check.yml @@ -0,0 +1,41 @@ +--- +# SEC-254: every `uses:` must reference an immutable 40-char commit SHA. +# Mutable tags/branches do not pin — a compromised maintainer token can repoint +# them at a malicious commit (CVE-2025-30066 hit 23k+ repos via tj-actions). +# Deliberately implemented with shell only: the gate itself must not add a +# third-party action dependency. +name: actions-pinned-check +on: + pull_request: + paths: + - ".github/workflows/**" + - ".github/actions/**" + workflow_dispatch: + +permissions: + contents: read # actions/checkout needs this to fetch a private repo + +jobs: + check: + runs-on: opus-runner-standard + steps: + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 + with: + persist-credentials: false + - name: Fail on unpinned action refs + run: | + set -euo pipefail + bad=$(grep -rnE '^[[:space:]]*(-[[:space:]]+)?uses:' .github \ + --include='*.yml' --include='*.yaml' \ + | sed 's/#.*//' \ + | grep 'uses:' \ + | grep -vE "uses:[[:space:]]*[\"']?\./" \ + | grep -vE 'docker://[^[:space:]]+@sha256:' \ + | grep -vE "@[0-9a-f]{40}[\"']?[[:space:]]*$" \ + || true) + if [ -n "$bad" ]; then + echo "Unpinned action references (must be 40-char commit SHAs):" + echo "$bad" + exit 1 + fi + echo "All action references are SHA-pinned." diff --git a/.github/workflows/check-pr-basic.yml b/.github/workflows/check-pr-basic.yml index 758c8ab..0ef97af 100644 --- a/.github/workflows/check-pr-basic.yml +++ b/.github/workflows/check-pr-basic.yml @@ -13,13 +13,13 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 with: fetch-depth: 0 - name: Skip check for dependabot if: ${{ github.actor == 'dependabot[bot]' || github.actor == 'dependabot-preview[bot]' }} run: echo "Skipping PR basics check for dependabot." && exit 0 - - uses: thehanimo/pr-title-checker@v1.4.2 + - uses: thehanimo/pr-title-checker@1d8cd483a2b73118406a187f54dca8a9415f1375 # v1.4.2 with: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} configuration_path: pull_request_title.json \ No newline at end of file diff --git a/.github/workflows/test-pr-title.yml b/.github/workflows/test-pr-title.yml index 675df82..e7fc5a9 100644 --- a/.github/workflows/test-pr-title.yml +++ b/.github/workflows/test-pr-title.yml @@ -15,10 +15,10 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@7f4fc3e22c37d6ff65e88745f38bd3157c663f7c # v4.9.1 with: python-version: '3.10'