From c0f0db2e7502bb795e198bac6cf1aba3d3780630 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Fri, 28 Aug 2026 14:44:14 +0100 Subject: [PATCH 01/16] Pin GitHub Actions to full commit hashes --- .github/renovate.json5 | 2 +- .github/workflows/daily.yml | 16 ++++---- .github/workflows/meta_tests.yml | 16 ++++---- .github/workflows/mypy_primer.yml | 10 ++--- .github/workflows/mypy_primer_comment.yml | 7 ++-- .github/workflows/stubsabot.yml | 6 +-- .github/workflows/stubtest_stdlib.yml | 4 +- .github/workflows/stubtest_third_party.yml | 4 +- .github/workflows/tests.yml | 44 +++++++++++----------- 9 files changed, 54 insertions(+), 55 deletions(-) diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 4fcaa043d3cb..68e6272a0922 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -2,7 +2,7 @@ "$schema": "https://docs.renovatebot.com/renovate-schema.json", "dependencyDashboard": true, "suppressNotifications": ["prEditedNotification"], - "extends": ["config:recommended"], + "extends": ["config:recommended", "helpers:pinGitHubActionDigests"], "labels": ["bot: dependencies"], "rebaseLabel": ["bot: rebase"], "semanticCommits": "disabled", diff --git a/.github/workflows/daily.yml b/.github/workflows/daily.yml index bda568659b9f..971051437762 100644 --- a/.github/workflows/daily.yml +++ b/.github/workflows/daily.yml @@ -43,9 +43,9 @@ jobs: fail-fast: false steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - name: Set up Python ${{ matrix.python-version }} on ${{ matrix.os }} - uses: actions/setup-python@v6 + uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6 with: python-version: ${{ matrix.python-version }} cache: pip @@ -67,8 +67,8 @@ jobs: shard-index: [0, 1, 2, 3] fail-fast: false steps: - - uses: actions/checkout@v7 - - uses: actions/setup-python@v6 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6 with: python-version: "3.13" cache: pip @@ -115,15 +115,15 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout typeshed - uses: actions/checkout@v7 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: path: typeshed - name: Checkout stub_uploader - uses: actions/checkout@v7 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: repository: typeshed-internal/stub_uploader path: stub_uploader - - uses: astral-sh/setup-uv@v8.2.0 + - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 with: version-file: "typeshed/requirements-tests.txt" - name: Run tests @@ -141,7 +141,7 @@ jobs: permissions: issues: write steps: - - uses: actions/github-script@v9 + - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | diff --git a/.github/workflows/meta_tests.yml b/.github/workflows/meta_tests.yml index 2c1dbc8f9a13..5dfd2b261284 100644 --- a/.github/workflows/meta_tests.yml +++ b/.github/workflows/meta_tests.yml @@ -35,8 +35,8 @@ jobs: platform: ["linux", "win32"] fail-fast: false steps: - - uses: actions/checkout@v7 - - uses: astral-sh/setup-uv@v8.2.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 with: version-file: "requirements-tests.txt" - name: Run check_typeshed_structure.py @@ -56,16 +56,16 @@ jobs: python-platform: ["Linux", "Windows"] fail-fast: false steps: - - uses: actions/checkout@v7 - - uses: actions/setup-python@v6 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6 with: python-version: "3.13" - - uses: astral-sh/setup-uv@v8.2.0 + - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 with: version-file: "requirements-tests.txt" - run: uv pip install -r requirements-tests.txt --system - name: Run pyright on typeshed - uses: jakebailey/pyright-action@v3 + uses: jakebailey/pyright-action@8ec14b5cfe41f26e5f41686a31eb6012758217ef # v3 with: version: PATH python-platform: ${{ matrix.python-platform }} @@ -76,8 +76,8 @@ jobs: name: "stubsabot: dry run" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v7 - - uses: astral-sh/setup-uv@v8.2.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 with: version-file: "requirements-tests.txt" - name: Git config diff --git a/.github/workflows/mypy_primer.yml b/.github/workflows/mypy_primer.yml index 43b42076ed41..ad9dc3d45a20 100644 --- a/.github/workflows/mypy_primer.yml +++ b/.github/workflows/mypy_primer.yml @@ -25,11 +25,11 @@ jobs: shard-index: [0, 1, 2, 3, 4, 5] fail-fast: false steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: path: typeshed_to_test fetch-depth: 0 - - uses: actions/setup-python@v6 + - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6 with: python-version: "3.13" - name: Install dependencies @@ -62,7 +62,7 @@ jobs: run: | echo ${{ github.event.pull_request.number }} | tee pr_number.txt - name: Upload mypy_primer diff + PR number - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 if: ${{ matrix.shard-index == 0 }} with: name: mypy_primer_diffs-${{ matrix.shard-index }} @@ -70,7 +70,7 @@ jobs: diff_${{ matrix.shard-index }}.txt pr_number.txt - name: Upload mypy_primer diff - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 if: ${{ matrix.shard-index != 0 }} with: name: mypy_primer_diffs-${{ matrix.shard-index }} @@ -84,7 +84,7 @@ jobs: contents: read steps: - name: Merge artifacts - uses: actions/upload-artifact/merge@v7 + uses: actions/upload-artifact/merge@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: mypy_primer_diffs pattern: mypy_primer_diffs-* diff --git a/.github/workflows/mypy_primer_comment.yml b/.github/workflows/mypy_primer_comment.yml index 4442d69111b9..57aedb865c3c 100644 --- a/.github/workflows/mypy_primer_comment.yml +++ b/.github/workflows/mypy_primer_comment.yml @@ -18,7 +18,7 @@ jobs: if: ${{ github.event.workflow_run.conclusion == 'success' }} steps: - name: Download diffs - uses: actions/github-script@v9 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 with: script: | const fs = require('fs'); @@ -44,7 +44,7 @@ jobs: - name: Post comment id: post-comment - uses: actions/github-script@v9 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | @@ -79,8 +79,7 @@ jobs: return prNumber - name: Hide old comments - # v0.4.0 - uses: kanga333/comment-hider@c12bb20b48aeb8fc098e35967de8d4f8018fffdf + uses: kanga333/comment-hider@c12bb20b48aeb8fc098e35967de8d4f8018fffdf # v0.4.0 with: github_token: ${{ secrets.GITHUB_TOKEN }} leave_visible: 1 diff --git a/.github/workflows/stubsabot.yml b/.github/workflows/stubsabot.yml index 527fd8899310..3935eee29ed6 100644 --- a/.github/workflows/stubsabot.yml +++ b/.github/workflows/stubsabot.yml @@ -19,12 +19,12 @@ jobs: if: github.repository == 'python/typeshed' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: # use an ssh key so that checks automatically run on stubsabot PRs ssh-key: ${{ secrets.STUBSABOT_SSH_PRIVATE_KEY }} fetch-depth: 0 - - uses: astral-sh/setup-uv@v8.2.0 + - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 with: version-file: "requirements-tests.txt" - name: Git config @@ -48,7 +48,7 @@ jobs: needs: [stubsabot] if: ${{ github.repository == 'python/typeshed' && always() && (needs.stubsabot.result == 'failure') }} steps: - - uses: actions/github-script@v9 + - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | diff --git a/.github/workflows/stubtest_stdlib.yml b/.github/workflows/stubtest_stdlib.yml index 5a4ad30473f6..5587e4e67bde 100644 --- a/.github/workflows/stubtest_stdlib.yml +++ b/.github/workflows/stubtest_stdlib.yml @@ -39,9 +39,9 @@ jobs: fail-fast: false steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - name: Set up Python ${{ matrix.python-version }} on ${{ matrix.os }} - uses: actions/setup-python@v6 + uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6 with: python-version: ${{ matrix.python-version }} cache: pip diff --git a/.github/workflows/stubtest_third_party.yml b/.github/workflows/stubtest_third_party.yml index 540a609ca1c2..e7d626572c79 100644 --- a/.github/workflows/stubtest_third_party.yml +++ b/.github/workflows/stubtest_third_party.yml @@ -36,10 +36,10 @@ jobs: fail-fast: false steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: fetch-depth: 0 - - uses: actions/setup-python@v6 + - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6 with: python-version: "3.13" cache: pip diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index ba4ce98734ee..14d4fc0c6b8b 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -26,8 +26,8 @@ jobs: name: Check typeshed structure runs-on: ubuntu-latest steps: - - uses: actions/checkout@v7 - - uses: astral-sh/setup-uv@v8.2.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 with: version-file: "requirements-tests.txt" - name: Run check_typeshed_structure.py @@ -47,12 +47,12 @@ jobs: python-version: ["3.10", "3.11", "3.12", "3.13", "3.14", "3.15"] fail-fast: false steps: - - uses: actions/checkout@v7 - - uses: actions/setup-python@v6 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6 with: python-version: ${{ matrix.python-version }} allow-prereleases: true - - uses: astral-sh/setup-uv@v8.2.0 + - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 with: version-file: "requirements-tests.txt" - run: uv pip install -r requirements-tests.txt --system @@ -70,8 +70,8 @@ jobs: name: "mypy: regression tests" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v7 - - uses: astral-sh/setup-uv@v8.2.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 with: version-file: "requirements-tests.txt" - name: Run regr_test.py @@ -94,11 +94,11 @@ jobs: python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"] fail-fast: false steps: - - uses: actions/checkout@v7 - - uses: actions/setup-python@v6 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6 with: python-version: "3.14" - - uses: astral-sh/setup-uv@v8.2.0 + - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 with: version-file: "requirements-tests.txt" - name: Install typeshed test-suite requirements @@ -127,11 +127,11 @@ jobs: python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"] fail-fast: false steps: - - uses: actions/checkout@v7 - - uses: actions/setup-python@v6 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6 with: python-version: "3.14" - - uses: astral-sh/setup-uv@v8.2.0 + - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 with: version-file: "requirements-tests.txt" - name: Install typeshed test-suite requirements @@ -161,11 +161,11 @@ jobs: python-version: ["3.11", "3.12", "3.13", "3.14"] fail-fast: false steps: - - uses: actions/checkout@v7 - - uses: actions/setup-python@v6 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6 with: python-version: "3.13" - - uses: astral-sh/setup-uv@v8.2.0 + - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 with: version-file: "requirements-tests.txt" - name: Install typeshed test-suite requirements @@ -192,14 +192,14 @@ jobs: - name: List 3rd-party stub dependencies installed run: uv pip freeze - name: Run pyright with basic settings on all the stubs - uses: jakebailey/pyright-action@v3 + uses: jakebailey/pyright-action@8ec14b5cfe41f26e5f41686a31eb6012758217ef # v3 with: version: PATH python-platform: ${{ matrix.python-platform }} python-version: ${{ matrix.python-version }} annotate: ${{ matrix.python-version == '3.13' && matrix.python-platform == 'Linux' }} # Having each job create the same comment is too noisy. - name: Run pyright with stricter settings on some of the stubs - uses: jakebailey/pyright-action@v3 + uses: jakebailey/pyright-action@8ec14b5cfe41f26e5f41686a31eb6012758217ef # v3 with: version: PATH python-platform: ${{ matrix.python-platform }} @@ -207,7 +207,7 @@ jobs: annotate: ${{ matrix.python-version == '3.13' && matrix.python-platform == 'Linux' }} # Having each job create the same comment is too noisy. project: ./pyrightconfig.stricter.json - name: Run pyright on the test cases - uses: jakebailey/pyright-action@v3 + uses: jakebailey/pyright-action@8ec14b5cfe41f26e5f41686a31eb6012758217ef # v3 with: version: PATH python-platform: ${{ matrix.python-platform }} @@ -220,15 +220,15 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout typeshed - uses: actions/checkout@v7 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: path: typeshed - name: Checkout stub_uploader - uses: actions/checkout@v7 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: repository: typeshed-internal/stub_uploader path: stub_uploader - - uses: astral-sh/setup-uv@v8.2.0 + - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 with: version-file: "typeshed/requirements-tests.txt" - name: Run tests From aacbf3fd875d46566132c35311c415480b496e24 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Fri, 28 Aug 2026 15:11:03 +0100 Subject: [PATCH 02/16] Add zizmor checks for GitHub Actions --- .github/workflows/daily.yml | 6 ++++++ .github/workflows/meta_tests.yml | 6 ++++++ .github/workflows/mypy_primer.yml | 1 + .github/workflows/mypy_primer_comment.yml | 4 +++- .github/workflows/stubsabot.yml | 11 +++++++---- .github/workflows/stubtest_stdlib.yml | 2 ++ .github/workflows/stubtest_third_party.yml | 3 ++- .github/workflows/tests.yml | 14 ++++++++++++++ .pre-commit-config.yaml | 6 ++++++ 9 files changed, 47 insertions(+), 6 deletions(-) diff --git a/.github/workflows/daily.yml b/.github/workflows/daily.yml index 971051437762..ed097604d989 100644 --- a/.github/workflows/daily.yml +++ b/.github/workflows/daily.yml @@ -44,6 +44,8 @@ jobs: steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + with: + persist-credentials: false - name: Set up Python ${{ matrix.python-version }} on ${{ matrix.os }} uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6 with: @@ -68,6 +70,8 @@ jobs: fail-fast: false steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + with: + persist-credentials: false - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6 with: python-version: "3.13" @@ -118,11 +122,13 @@ jobs: uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: path: typeshed + persist-credentials: false - name: Checkout stub_uploader uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: repository: typeshed-internal/stub_uploader path: stub_uploader + persist-credentials: false - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 with: version-file: "typeshed/requirements-tests.txt" diff --git a/.github/workflows/meta_tests.yml b/.github/workflows/meta_tests.yml index 5dfd2b261284..486a584b6211 100644 --- a/.github/workflows/meta_tests.yml +++ b/.github/workflows/meta_tests.yml @@ -36,6 +36,8 @@ jobs: fail-fast: false steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + with: + persist-credentials: false - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 with: version-file: "requirements-tests.txt" @@ -57,6 +59,8 @@ jobs: fail-fast: false steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + with: + persist-credentials: false - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6 with: python-version: "3.13" @@ -77,6 +81,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + with: + persist-credentials: false - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 with: version-file: "requirements-tests.txt" diff --git a/.github/workflows/mypy_primer.yml b/.github/workflows/mypy_primer.yml index ad9dc3d45a20..4f7cdfac587c 100644 --- a/.github/workflows/mypy_primer.yml +++ b/.github/workflows/mypy_primer.yml @@ -29,6 +29,7 @@ jobs: with: path: typeshed_to_test fetch-depth: 0 + persist-credentials: false - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6 with: python-version: "3.13" diff --git a/.github/workflows/mypy_primer_comment.yml b/.github/workflows/mypy_primer_comment.yml index 57aedb865c3c..a0b964c748f2 100644 --- a/.github/workflows/mypy_primer_comment.yml +++ b/.github/workflows/mypy_primer_comment.yml @@ -1,6 +1,8 @@ name: mypy_primer (comment) -on: +# workflow_run is needed to comment on PRs from forks. This workflow only reads +# artifacts as data; it never checks out or executes PR code. +on: # zizmor: ignore[dangerous-triggers] workflow_run: workflows: - mypy_primer diff --git a/.github/workflows/stubsabot.yml b/.github/workflows/stubsabot.yml index 3935eee29ed6..9996d6cab635 100644 --- a/.github/workflows/stubsabot.yml +++ b/.github/workflows/stubsabot.yml @@ -5,10 +5,7 @@ on: schedule: - cron: "0 0 * * *" -permissions: - contents: write - issues: write - pull-requests: write +permissions: {} env: FORCE_COLOR: 1 @@ -18,12 +15,16 @@ jobs: name: Upgrade stubs with stubsabot if: github.repository == 'python/typeshed' runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write # Create, update, and label PRs. steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: # use an ssh key so that checks automatically run on stubsabot PRs ssh-key: ${{ secrets.STUBSABOT_SSH_PRIVATE_KEY }} fetch-depth: 0 + persist-credentials: true # stubsabot needs the SSH key to push branches. - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 with: version-file: "requirements-tests.txt" @@ -47,6 +48,8 @@ jobs: runs-on: ubuntu-latest needs: [stubsabot] if: ${{ github.repository == 'python/typeshed' && always() && (needs.stubsabot.result == 'failure') }} + permissions: + issues: write steps: - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 with: diff --git a/.github/workflows/stubtest_stdlib.yml b/.github/workflows/stubtest_stdlib.yml index 5587e4e67bde..cb6624a4bc4a 100644 --- a/.github/workflows/stubtest_stdlib.yml +++ b/.github/workflows/stubtest_stdlib.yml @@ -40,6 +40,8 @@ jobs: steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + with: + persist-credentials: false - name: Set up Python ${{ matrix.python-version }} on ${{ matrix.os }} uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6 with: diff --git a/.github/workflows/stubtest_third_party.yml b/.github/workflows/stubtest_third_party.yml index e7d626572c79..e3763ae5de03 100644 --- a/.github/workflows/stubtest_third_party.yml +++ b/.github/workflows/stubtest_third_party.yml @@ -39,6 +39,7 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: fetch-depth: 0 + persist-credentials: false - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6 with: python-version: "3.13" @@ -54,7 +55,7 @@ jobs: # This only runs stubtest on changed stubs, because it is much faster. # Use the daily.yml workflow to run stubtest on all third party stubs. function find_stubs { - git diff --name-only origin/${{ github.base_ref }} HEAD | \ + git diff --name-only "origin/${GITHUB_BASE_REF}" HEAD | \ egrep ^stubs/ | cut -d "/" -f 2 | sort -u | \ (while read stub; do [ -d "stubs/$stub" ] && echo -n "$stub " || true; done) } diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 14d4fc0c6b8b..3f08dea1dc61 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -27,6 +27,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + with: + persist-credentials: false - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 with: version-file: "requirements-tests.txt" @@ -48,6 +50,8 @@ jobs: fail-fast: false steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + with: + persist-credentials: false - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6 with: python-version: ${{ matrix.python-version }} @@ -71,6 +75,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + with: + persist-credentials: false - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 with: version-file: "requirements-tests.txt" @@ -95,6 +101,8 @@ jobs: fail-fast: false steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + with: + persist-credentials: false - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6 with: python-version: "3.14" @@ -128,6 +136,8 @@ jobs: fail-fast: false steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + with: + persist-credentials: false - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6 with: python-version: "3.14" @@ -162,6 +172,8 @@ jobs: fail-fast: false steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + with: + persist-credentials: false - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6 with: python-version: "3.13" @@ -223,11 +235,13 @@ jobs: uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: path: typeshed + persist-credentials: false - name: Checkout stub_uploader uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: repository: typeshed-internal/stub_uploader path: stub_uploader + persist-credentials: false - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 with: version-file: "typeshed/requirements-tests.txt" diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3444cf8bd4db..8a0d88fab958 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -43,6 +43,12 @@ repos: - repo: meta hooks: - id: check-hooks-apply + # zizmor detects security vulnerabilities in GitHub Actions workflows. + - repo: https://github.com/zizmorcore/zizmor-pre-commit + rev: 451b56af716f9f0d0c2b816503a3fd0cf8b036fa # frozen: v1.29.0 + hooks: + - id: zizmor + priority: 0 ci: autofix_commit_msg: "[pre-commit.ci] auto fixes from pre-commit.com hooks" From 3138e91dd0b22be775b8b8bb168722fe8607f87c Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Fri, 28 Aug 2026 17:49:52 +0100 Subject: [PATCH 03/16] Update .pre-commit-config.yaml --- .pre-commit-config.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8a0d88fab958..47dac83f561b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -48,7 +48,6 @@ repos: rev: 451b56af716f9f0d0c2b816503a3fd0cf8b036fa # frozen: v1.29.0 hooks: - id: zizmor - priority: 0 ci: autofix_commit_msg: "[pre-commit.ci] auto fixes from pre-commit.com hooks" From 95acecb9d7db7939f03e666e55d66cb768cb6009 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Fri, 28 Aug 2026 17:57:56 +0100 Subject: [PATCH 04/16] Add actionlint checks for GitHub Actions --- .github/workflows/daily.yml | 19 ++++++---- .github/workflows/mypy_primer.yml | 6 ++-- .github/workflows/stubtest_third_party.yml | 31 ++++++++++------ .github/workflows/tests.yml | 41 +++++++++++++++++----- .pre-commit-config.yaml | 12 +++++++ 5 files changed, 80 insertions(+), 29 deletions(-) diff --git a/.github/workflows/daily.yml b/.github/workflows/daily.yml index ed097604d989..066aa70c1845 100644 --- a/.github/workflows/daily.yml +++ b/.github/workflows/daily.yml @@ -85,21 +85,28 @@ jobs: shell: bash run: | PACKAGES=$(python tests/get_stubtest_system_requirements.py) + PACKAGE_ARGS=() + while IFS= read -r package; do + PACKAGE_ARGS+=("$package") + done <<< "$PACKAGES" if [ "${{ runner.os }}" = "Linux" ]; then if [ -n "$PACKAGES" ]; then - printf "Installing APT packages:\n $(echo $PACKAGES | sed 's/ /\n /g')\n" - sudo apt-get update -q && sudo apt-get install -qy $PACKAGES + printf 'Installing APT packages:\n' + printf ' %s\n' "${PACKAGE_ARGS[@]}" + sudo apt-get update -q && sudo apt-get install -qy "${PACKAGE_ARGS[@]}" fi else if [ "${{ runner.os }}" = "macOS" ] && [ -n "$PACKAGES" ]; then - printf "Installing Homebrew packages:\n $(echo $PACKAGES | sed 's/ /\n /g')\n" - brew install -q $PACKAGES + printf 'Installing Homebrew packages:\n' + printf ' %s\n' "${PACKAGE_ARGS[@]}" + brew install -q "${PACKAGE_ARGS[@]}" fi if [ "${{ runner.os }}" = "Windows" ] && [ -n "$PACKAGES" ]; then - printf "Installing Chocolatey packages:\n $(echo $PACKAGES | sed 's/ /\n /g')\n" - choco install -y $PACKAGES + printf 'Installing Chocolatey packages:\n' + printf ' %s\n' "${PACKAGE_ARGS[@]}" + choco install -y "${PACKAGE_ARGS[@]}" fi fi - name: Run stubtest diff --git a/.github/workflows/mypy_primer.yml b/.github/workflows/mypy_primer.yml index 4f7cdfac587c..41f0ca2abd8d 100644 --- a/.github/workflows/mypy_primer.yml +++ b/.github/workflows/mypy_primer.yml @@ -41,7 +41,7 @@ jobs: cd typeshed_to_test MYPY_VERSION=$(grep mypy== requirements-tests.txt | cut -d = -f 3) echo "new commit" - git rev-list --format=%s --max-count=1 $GITHUB_SHA + git rev-list --format=%s --max-count=1 "$GITHUB_SHA" git checkout -b upstream_main origin/main echo "base commit" git rev-list --format=%s --max-count=1 upstream_main @@ -50,9 +50,9 @@ jobs: # fail action if exit code isn't zero or one ( mypy_primer \ - --new v${MYPY_VERSION} --old v${MYPY_VERSION} \ + --new "v${MYPY_VERSION}" --old "v${MYPY_VERSION}" \ --custom-typeshed-repo typeshed_to_test \ - --new-typeshed $GITHUB_SHA --old-typeshed upstream_main \ + --new-typeshed "$GITHUB_SHA" --old-typeshed upstream_main \ --num-shards 6 --shard-index ${{ matrix.shard-index }} \ --debug \ --output concise \ diff --git a/.github/workflows/stubtest_third_party.yml b/.github/workflows/stubtest_third_party.yml index e3763ae5de03..13602e169ea7 100644 --- a/.github/workflows/stubtest_third_party.yml +++ b/.github/workflows/stubtest_third_party.yml @@ -56,31 +56,39 @@ jobs: # Use the daily.yml workflow to run stubtest on all third party stubs. function find_stubs { git diff --name-only "origin/${GITHUB_BASE_REF}" HEAD | \ - egrep ^stubs/ | cut -d "/" -f 2 | sort -u | \ - (while read stub; do [ -d "stubs/$stub" ] && echo -n "$stub " || true; done) + grep -E ^stubs/ | cut -d "/" -f 2 | sort -u | \ + (while IFS= read -r stub; do [ -d "stubs/$stub" ] && echo -n "$stub " || true; done) } STUBS=$(find_stubs || echo '') echo "Changed stubs: $STUBS" - echo "STUBS=$STUBS" >> $GITHUB_ENV + echo "STUBS=$STUBS" >> "$GITHUB_ENV" - name: Install required system packages shell: bash run: | if [ -n "$STUBS" ]; then - PACKAGES=$(python tests/get_stubtest_system_requirements.py $STUBS) + read -r -a STUB_ARGS <<< "$STUBS" + PACKAGES=$(python tests/get_stubtest_system_requirements.py "${STUB_ARGS[@]}") + PACKAGE_ARGS=() + while IFS= read -r package; do + PACKAGE_ARGS+=("$package") + done <<< "$PACKAGES" if [ "${{ runner.os }}" = "Linux" ]; then if [ -n "$PACKAGES" ]; then - printf "Installing APT packages:\n $(echo $PACKAGES | sed 's/ /\n /g')\n" - sudo apt-get update -q && sudo apt-get install -qy $PACKAGES + printf 'Installing APT packages:\n' + printf ' %s\n' "${PACKAGE_ARGS[@]}" + sudo apt-get update -q && sudo apt-get install -qy "${PACKAGE_ARGS[@]}" fi else if [ "${{ runner.os }}" = "macOS" ] && [ -n "$PACKAGES" ]; then - printf "Installing Homebrew packages:\n $(echo $PACKAGES | sed 's/ /\n /g')\n" - brew install -q $PACKAGES + printf 'Installing Homebrew packages:\n' + printf ' %s\n' "${PACKAGE_ARGS[@]}" + brew install -q "${PACKAGE_ARGS[@]}" fi if [ "${{ runner.os }}" = "Windows" ] && [ -n "$PACKAGES" ]; then - printf "Installing Chocolatey packages:\n $(echo $PACKAGES | sed 's/ /\n /g')\n" - choco install -y $PACKAGES + printf 'Installing Chocolatey packages:\n' + printf ' %s\n' "${PACKAGE_ARGS[@]}" + choco install -y "${PACKAGE_ARGS[@]}" fi fi fi @@ -89,6 +97,7 @@ jobs: run: | if [ -n "$STUBS" ]; then echo "Testing $STUBS..." + read -r -a STUB_ARGS <<< "$STUBS" if [ "${{ runner.os }}" = "Linux" ]; then PYTHON_EXECUTABLE="xvfb-run python" @@ -96,7 +105,7 @@ jobs: PYTHON_EXECUTABLE="python" fi - $PYTHON_EXECUTABLE tests/stubtest_third_party.py --ci-platforms-only $STUBS + $PYTHON_EXECUTABLE tests/stubtest_third_party.py --ci-platforms-only "${STUB_ARGS[@]}" else echo "Nothing to test" fi diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 3f08dea1dc61..756f29bf621d 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -64,8 +64,13 @@ jobs: run: | PACKAGES=$(python tests/get_stubtest_system_requirements.py) if [ -n "$PACKAGES" ]; then - printf "Installing APT packages:\n $(echo $PACKAGES | sed 's/ /\n /g')\n" - sudo apt-get update -q && sudo apt-get install -qy $PACKAGES + PACKAGE_ARGS=() + while IFS= read -r package; do + PACKAGE_ARGS+=("$package") + done <<< "$PACKAGES" + printf 'Installing APT packages:\n' + printf ' %s\n' "${PACKAGE_ARGS[@]}" + sudo apt-get update -q && sudo apt-get install -qy "${PACKAGE_ARGS[@]}" fi - name: Run mypy_test.py run: python ./tests/mypy_test.py --platform=${{ matrix.platform }} --python-version=${{ matrix.python-version }} @@ -117,7 +122,11 @@ jobs: run: | PACKAGES=$(python tests/get_external_stub_requirements.py) if [ -n "$PACKAGES" ]; then - uv pip install --python-version ${{ matrix.python-version }} $PACKAGES + PACKAGE_ARGS=() + while IFS= read -r package; do + PACKAGE_ARGS+=("$package") + done <<< "$PACKAGES" + uv pip install --python-version ${{ matrix.python-version }} "${PACKAGE_ARGS[@]}" fi # Published stub packages can shadow the checked-in stubs when ty # resolves their relative imports. @@ -152,7 +161,11 @@ jobs: run: | PACKAGES=$(python tests/get_external_stub_requirements.py) if [ -n "$PACKAGES" ]; then - uv pip install --python-version ${{ matrix.python-version }} $PACKAGES + PACKAGE_ARGS=() + while IFS= read -r package; do + PACKAGE_ARGS+=("$package") + done <<< "$PACKAGES" + uv pip install --python-version ${{ matrix.python-version }} "${PACKAGE_ARGS[@]}" fi # Published stub packages can shadow the checked-in stubs when pyrefly # resolves their relative imports. @@ -187,8 +200,13 @@ jobs: run: | PACKAGES=$(python tests/get_stubtest_system_requirements.py) if [ -n "$PACKAGES" ]; then - printf "Installing APT packages:\n $(echo $PACKAGES | sed 's/ /\n /g')\n" - sudo apt-get update -q && sudo apt-get install -qy $PACKAGES + PACKAGE_ARGS=() + while IFS= read -r package; do + PACKAGE_ARGS+=("$package") + done <<< "$PACKAGES" + printf 'Installing APT packages:\n' + printf ' %s\n' "${PACKAGE_ARGS[@]}" + sudo apt-get update -q && sudo apt-get install -qy "${PACKAGE_ARGS[@]}" fi - name: Create an isolated venv for testing run: uv venv .venv @@ -196,11 +214,16 @@ jobs: run: | PACKAGES=$(python tests/get_external_stub_requirements.py) if [ -n "$PACKAGES" ]; then - printf "Installing python packages:\n $(echo $PACKAGES | sed 's/ /\n /g')\n" - uv pip install --python-version ${{ matrix.python-version }} $PACKAGES + PACKAGE_ARGS=() + while IFS= read -r package; do + PACKAGE_ARGS+=("$package") + done <<< "$PACKAGES" + printf 'Installing python packages:\n' + printf ' %s\n' "${PACKAGE_ARGS[@]}" + uv pip install --python-version ${{ matrix.python-version }} "${PACKAGE_ARGS[@]}" fi - name: Activate the isolated venv for the rest of the job - run: echo "$PWD/.venv/bin" >> $GITHUB_PATH + run: echo "$PWD/.venv/bin" >> "$GITHUB_PATH" - name: List 3rd-party stub dependencies installed run: uv pip freeze - name: Run pyright with basic settings on all the stubs diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 47dac83f561b..43bc9fcaebb6 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -48,6 +48,18 @@ repos: rev: 451b56af716f9f0d0c2b816503a3fd0cf8b036fa # frozen: v1.29.0 hooks: - id: zizmor + # `actionlint` hook, for verifying correct syntax in GitHub Actions workflows. + - repo: https://github.com/rhysd/actionlint + rev: 914e7df21a07ef503a81201c76d2b11c789d3fca # frozen: v1.7.12 + hooks: + - id: actionlint + # specifying this means renovate will also update `additional_dependencies` + language: golang + additional_dependencies: + # actionlint has a shellcheck integration which extracts shell scripts in `run:` steps from GitHub Actions + # and checks these with shellcheck. This is arguably its most useful feature, + # but the integration only works if shellcheck is installed + - "github.com/wasilibs/go-shellcheck/cmd/shellcheck@v0.11.1" ci: autofix_commit_msg: "[pre-commit.ci] auto fixes from pre-commit.com hooks" From d33800d8d3168d2da92bd6e39b24aa9148f6a65c Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Fri, 28 Aug 2026 18:23:53 +0100 Subject: [PATCH 05/16] Run actionlint in GitHub Actions instead of pre-commit.ci --- .github/workflows/actionlint.yml | 32 ++++++++++++++++++++++++++++++++ .pre-commit-config.yaml | 12 ------------ 2 files changed, 32 insertions(+), 12 deletions(-) create mode 100644 .github/workflows/actionlint.yml diff --git a/.github/workflows/actionlint.yml b/.github/workflows/actionlint.yml new file mode 100644 index 000000000000..ebb944b59daf --- /dev/null +++ b/.github/workflows/actionlint.yml @@ -0,0 +1,32 @@ +name: Lint GitHub Actions workflows + +on: + workflow_dispatch: + push: + branches: + - main + paths: + - ".github/workflows/**" + pull_request: + paths: + - ".github/workflows/**" + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + actionlint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + with: + persist-credentials: false + - name: Run actionlint + # The official image includes ShellCheck and Pyflakes. + uses: docker://rhysd/actionlint:1.7.12@sha256:b1934ee5f1c509618f2508e6eb47ee0d3520686341fec936f3b79331f9315667 + with: + args: -color diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 43bc9fcaebb6..47dac83f561b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -48,18 +48,6 @@ repos: rev: 451b56af716f9f0d0c2b816503a3fd0cf8b036fa # frozen: v1.29.0 hooks: - id: zizmor - # `actionlint` hook, for verifying correct syntax in GitHub Actions workflows. - - repo: https://github.com/rhysd/actionlint - rev: 914e7df21a07ef503a81201c76d2b11c789d3fca # frozen: v1.7.12 - hooks: - - id: actionlint - # specifying this means renovate will also update `additional_dependencies` - language: golang - additional_dependencies: - # actionlint has a shellcheck integration which extracts shell scripts in `run:` steps from GitHub Actions - # and checks these with shellcheck. This is arguably its most useful feature, - # but the integration only works if shellcheck is installed - - "github.com/wasilibs/go-shellcheck/cmd/shellcheck@v0.11.1" ci: autofix_commit_msg: "[pre-commit.ci] auto fixes from pre-commit.com hooks" From d7ac441d25868e1215b1dd471055cfc79e47fe59 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Fri, 28 Aug 2026 18:33:36 +0100 Subject: [PATCH 06/16] Show actionlint progress in CI --- .github/workflows/actionlint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/actionlint.yml b/.github/workflows/actionlint.yml index ebb944b59daf..e53a98041065 100644 --- a/.github/workflows/actionlint.yml +++ b/.github/workflows/actionlint.yml @@ -29,4 +29,4 @@ jobs: # The official image includes ShellCheck and Pyflakes. uses: docker://rhysd/actionlint:1.7.12@sha256:b1934ee5f1c509618f2508e6eb47ee0d3520686341fec936f3b79331f9315667 with: - args: -color + args: -color -verbose From 0a36c867b8bbec0e5f4f81290d94c6e0003c1677 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Fri, 28 Aug 2026 18:34:02 +0100 Subject: [PATCH 07/16] Demonstrate actionlint failure with an unquoted variable --- .github/workflows/actionlint.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/actionlint.yml b/.github/workflows/actionlint.yml index e53a98041065..987ef581463c 100644 --- a/.github/workflows/actionlint.yml +++ b/.github/workflows/actionlint.yml @@ -25,6 +25,8 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: persist-credentials: false + - name: Demonstrate a ShellCheck violation + run: echo $GITHUB_WORKSPACE - name: Run actionlint # The official image includes ShellCheck and Pyflakes. uses: docker://rhysd/actionlint:1.7.12@sha256:b1934ee5f1c509618f2508e6eb47ee0d3520686341fec936f3b79331f9315667 From 6611c6c06b1c69e9b26349e1c306c8833efd3c13 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Fri, 28 Aug 2026 18:41:17 +0100 Subject: [PATCH 08/16] Revert "Demonstrate actionlint failure with an unquoted variable" This reverts commit 0a36c867b8bbec0e5f4f81290d94c6e0003c1677. --- .github/workflows/actionlint.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/actionlint.yml b/.github/workflows/actionlint.yml index 987ef581463c..e53a98041065 100644 --- a/.github/workflows/actionlint.yml +++ b/.github/workflows/actionlint.yml @@ -25,8 +25,6 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: persist-credentials: false - - name: Demonstrate a ShellCheck violation - run: echo $GITHUB_WORKSPACE - name: Run actionlint # The official image includes ShellCheck and Pyflakes. uses: docker://rhysd/actionlint:1.7.12@sha256:b1934ee5f1c509618f2508e6eb47ee0d3520686341fec936f3b79331f9315667 From 7851964c8b5b33389cc34f2dd669de99dbcaaf5d Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Fri, 28 Aug 2026 17:57:56 +0100 Subject: [PATCH 09/16] Add actionlint checks for GitHub Actions --- .github/workflows/daily.yml | 19 ++++++---- .github/workflows/mypy_primer.yml | 6 ++-- .github/workflows/stubtest_third_party.yml | 31 ++++++++++------ .github/workflows/tests.yml | 41 +++++++++++++++++----- .pre-commit-config.yaml | 12 +++++++ 5 files changed, 80 insertions(+), 29 deletions(-) diff --git a/.github/workflows/daily.yml b/.github/workflows/daily.yml index ed097604d989..066aa70c1845 100644 --- a/.github/workflows/daily.yml +++ b/.github/workflows/daily.yml @@ -85,21 +85,28 @@ jobs: shell: bash run: | PACKAGES=$(python tests/get_stubtest_system_requirements.py) + PACKAGE_ARGS=() + while IFS= read -r package; do + PACKAGE_ARGS+=("$package") + done <<< "$PACKAGES" if [ "${{ runner.os }}" = "Linux" ]; then if [ -n "$PACKAGES" ]; then - printf "Installing APT packages:\n $(echo $PACKAGES | sed 's/ /\n /g')\n" - sudo apt-get update -q && sudo apt-get install -qy $PACKAGES + printf 'Installing APT packages:\n' + printf ' %s\n' "${PACKAGE_ARGS[@]}" + sudo apt-get update -q && sudo apt-get install -qy "${PACKAGE_ARGS[@]}" fi else if [ "${{ runner.os }}" = "macOS" ] && [ -n "$PACKAGES" ]; then - printf "Installing Homebrew packages:\n $(echo $PACKAGES | sed 's/ /\n /g')\n" - brew install -q $PACKAGES + printf 'Installing Homebrew packages:\n' + printf ' %s\n' "${PACKAGE_ARGS[@]}" + brew install -q "${PACKAGE_ARGS[@]}" fi if [ "${{ runner.os }}" = "Windows" ] && [ -n "$PACKAGES" ]; then - printf "Installing Chocolatey packages:\n $(echo $PACKAGES | sed 's/ /\n /g')\n" - choco install -y $PACKAGES + printf 'Installing Chocolatey packages:\n' + printf ' %s\n' "${PACKAGE_ARGS[@]}" + choco install -y "${PACKAGE_ARGS[@]}" fi fi - name: Run stubtest diff --git a/.github/workflows/mypy_primer.yml b/.github/workflows/mypy_primer.yml index 4f7cdfac587c..41f0ca2abd8d 100644 --- a/.github/workflows/mypy_primer.yml +++ b/.github/workflows/mypy_primer.yml @@ -41,7 +41,7 @@ jobs: cd typeshed_to_test MYPY_VERSION=$(grep mypy== requirements-tests.txt | cut -d = -f 3) echo "new commit" - git rev-list --format=%s --max-count=1 $GITHUB_SHA + git rev-list --format=%s --max-count=1 "$GITHUB_SHA" git checkout -b upstream_main origin/main echo "base commit" git rev-list --format=%s --max-count=1 upstream_main @@ -50,9 +50,9 @@ jobs: # fail action if exit code isn't zero or one ( mypy_primer \ - --new v${MYPY_VERSION} --old v${MYPY_VERSION} \ + --new "v${MYPY_VERSION}" --old "v${MYPY_VERSION}" \ --custom-typeshed-repo typeshed_to_test \ - --new-typeshed $GITHUB_SHA --old-typeshed upstream_main \ + --new-typeshed "$GITHUB_SHA" --old-typeshed upstream_main \ --num-shards 6 --shard-index ${{ matrix.shard-index }} \ --debug \ --output concise \ diff --git a/.github/workflows/stubtest_third_party.yml b/.github/workflows/stubtest_third_party.yml index e3763ae5de03..13602e169ea7 100644 --- a/.github/workflows/stubtest_third_party.yml +++ b/.github/workflows/stubtest_third_party.yml @@ -56,31 +56,39 @@ jobs: # Use the daily.yml workflow to run stubtest on all third party stubs. function find_stubs { git diff --name-only "origin/${GITHUB_BASE_REF}" HEAD | \ - egrep ^stubs/ | cut -d "/" -f 2 | sort -u | \ - (while read stub; do [ -d "stubs/$stub" ] && echo -n "$stub " || true; done) + grep -E ^stubs/ | cut -d "/" -f 2 | sort -u | \ + (while IFS= read -r stub; do [ -d "stubs/$stub" ] && echo -n "$stub " || true; done) } STUBS=$(find_stubs || echo '') echo "Changed stubs: $STUBS" - echo "STUBS=$STUBS" >> $GITHUB_ENV + echo "STUBS=$STUBS" >> "$GITHUB_ENV" - name: Install required system packages shell: bash run: | if [ -n "$STUBS" ]; then - PACKAGES=$(python tests/get_stubtest_system_requirements.py $STUBS) + read -r -a STUB_ARGS <<< "$STUBS" + PACKAGES=$(python tests/get_stubtest_system_requirements.py "${STUB_ARGS[@]}") + PACKAGE_ARGS=() + while IFS= read -r package; do + PACKAGE_ARGS+=("$package") + done <<< "$PACKAGES" if [ "${{ runner.os }}" = "Linux" ]; then if [ -n "$PACKAGES" ]; then - printf "Installing APT packages:\n $(echo $PACKAGES | sed 's/ /\n /g')\n" - sudo apt-get update -q && sudo apt-get install -qy $PACKAGES + printf 'Installing APT packages:\n' + printf ' %s\n' "${PACKAGE_ARGS[@]}" + sudo apt-get update -q && sudo apt-get install -qy "${PACKAGE_ARGS[@]}" fi else if [ "${{ runner.os }}" = "macOS" ] && [ -n "$PACKAGES" ]; then - printf "Installing Homebrew packages:\n $(echo $PACKAGES | sed 's/ /\n /g')\n" - brew install -q $PACKAGES + printf 'Installing Homebrew packages:\n' + printf ' %s\n' "${PACKAGE_ARGS[@]}" + brew install -q "${PACKAGE_ARGS[@]}" fi if [ "${{ runner.os }}" = "Windows" ] && [ -n "$PACKAGES" ]; then - printf "Installing Chocolatey packages:\n $(echo $PACKAGES | sed 's/ /\n /g')\n" - choco install -y $PACKAGES + printf 'Installing Chocolatey packages:\n' + printf ' %s\n' "${PACKAGE_ARGS[@]}" + choco install -y "${PACKAGE_ARGS[@]}" fi fi fi @@ -89,6 +97,7 @@ jobs: run: | if [ -n "$STUBS" ]; then echo "Testing $STUBS..." + read -r -a STUB_ARGS <<< "$STUBS" if [ "${{ runner.os }}" = "Linux" ]; then PYTHON_EXECUTABLE="xvfb-run python" @@ -96,7 +105,7 @@ jobs: PYTHON_EXECUTABLE="python" fi - $PYTHON_EXECUTABLE tests/stubtest_third_party.py --ci-platforms-only $STUBS + $PYTHON_EXECUTABLE tests/stubtest_third_party.py --ci-platforms-only "${STUB_ARGS[@]}" else echo "Nothing to test" fi diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 3f08dea1dc61..756f29bf621d 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -64,8 +64,13 @@ jobs: run: | PACKAGES=$(python tests/get_stubtest_system_requirements.py) if [ -n "$PACKAGES" ]; then - printf "Installing APT packages:\n $(echo $PACKAGES | sed 's/ /\n /g')\n" - sudo apt-get update -q && sudo apt-get install -qy $PACKAGES + PACKAGE_ARGS=() + while IFS= read -r package; do + PACKAGE_ARGS+=("$package") + done <<< "$PACKAGES" + printf 'Installing APT packages:\n' + printf ' %s\n' "${PACKAGE_ARGS[@]}" + sudo apt-get update -q && sudo apt-get install -qy "${PACKAGE_ARGS[@]}" fi - name: Run mypy_test.py run: python ./tests/mypy_test.py --platform=${{ matrix.platform }} --python-version=${{ matrix.python-version }} @@ -117,7 +122,11 @@ jobs: run: | PACKAGES=$(python tests/get_external_stub_requirements.py) if [ -n "$PACKAGES" ]; then - uv pip install --python-version ${{ matrix.python-version }} $PACKAGES + PACKAGE_ARGS=() + while IFS= read -r package; do + PACKAGE_ARGS+=("$package") + done <<< "$PACKAGES" + uv pip install --python-version ${{ matrix.python-version }} "${PACKAGE_ARGS[@]}" fi # Published stub packages can shadow the checked-in stubs when ty # resolves their relative imports. @@ -152,7 +161,11 @@ jobs: run: | PACKAGES=$(python tests/get_external_stub_requirements.py) if [ -n "$PACKAGES" ]; then - uv pip install --python-version ${{ matrix.python-version }} $PACKAGES + PACKAGE_ARGS=() + while IFS= read -r package; do + PACKAGE_ARGS+=("$package") + done <<< "$PACKAGES" + uv pip install --python-version ${{ matrix.python-version }} "${PACKAGE_ARGS[@]}" fi # Published stub packages can shadow the checked-in stubs when pyrefly # resolves their relative imports. @@ -187,8 +200,13 @@ jobs: run: | PACKAGES=$(python tests/get_stubtest_system_requirements.py) if [ -n "$PACKAGES" ]; then - printf "Installing APT packages:\n $(echo $PACKAGES | sed 's/ /\n /g')\n" - sudo apt-get update -q && sudo apt-get install -qy $PACKAGES + PACKAGE_ARGS=() + while IFS= read -r package; do + PACKAGE_ARGS+=("$package") + done <<< "$PACKAGES" + printf 'Installing APT packages:\n' + printf ' %s\n' "${PACKAGE_ARGS[@]}" + sudo apt-get update -q && sudo apt-get install -qy "${PACKAGE_ARGS[@]}" fi - name: Create an isolated venv for testing run: uv venv .venv @@ -196,11 +214,16 @@ jobs: run: | PACKAGES=$(python tests/get_external_stub_requirements.py) if [ -n "$PACKAGES" ]; then - printf "Installing python packages:\n $(echo $PACKAGES | sed 's/ /\n /g')\n" - uv pip install --python-version ${{ matrix.python-version }} $PACKAGES + PACKAGE_ARGS=() + while IFS= read -r package; do + PACKAGE_ARGS+=("$package") + done <<< "$PACKAGES" + printf 'Installing python packages:\n' + printf ' %s\n' "${PACKAGE_ARGS[@]}" + uv pip install --python-version ${{ matrix.python-version }} "${PACKAGE_ARGS[@]}" fi - name: Activate the isolated venv for the rest of the job - run: echo "$PWD/.venv/bin" >> $GITHUB_PATH + run: echo "$PWD/.venv/bin" >> "$GITHUB_PATH" - name: List 3rd-party stub dependencies installed run: uv pip freeze - name: Run pyright with basic settings on all the stubs diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 47dac83f561b..43bc9fcaebb6 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -48,6 +48,18 @@ repos: rev: 451b56af716f9f0d0c2b816503a3fd0cf8b036fa # frozen: v1.29.0 hooks: - id: zizmor + # `actionlint` hook, for verifying correct syntax in GitHub Actions workflows. + - repo: https://github.com/rhysd/actionlint + rev: 914e7df21a07ef503a81201c76d2b11c789d3fca # frozen: v1.7.12 + hooks: + - id: actionlint + # specifying this means renovate will also update `additional_dependencies` + language: golang + additional_dependencies: + # actionlint has a shellcheck integration which extracts shell scripts in `run:` steps from GitHub Actions + # and checks these with shellcheck. This is arguably its most useful feature, + # but the integration only works if shellcheck is installed + - "github.com/wasilibs/go-shellcheck/cmd/shellcheck@v0.11.1" ci: autofix_commit_msg: "[pre-commit.ci] auto fixes from pre-commit.com hooks" From 5281dc2d97b13131834c05902d49fdbe8ffca52f Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Fri, 28 Aug 2026 18:23:53 +0100 Subject: [PATCH 10/16] Run actionlint in GitHub Actions instead of pre-commit.ci --- .github/workflows/actionlint.yml | 32 ++++++++++++++++++++++++++++++++ .pre-commit-config.yaml | 12 ------------ 2 files changed, 32 insertions(+), 12 deletions(-) create mode 100644 .github/workflows/actionlint.yml diff --git a/.github/workflows/actionlint.yml b/.github/workflows/actionlint.yml new file mode 100644 index 000000000000..ebb944b59daf --- /dev/null +++ b/.github/workflows/actionlint.yml @@ -0,0 +1,32 @@ +name: Lint GitHub Actions workflows + +on: + workflow_dispatch: + push: + branches: + - main + paths: + - ".github/workflows/**" + pull_request: + paths: + - ".github/workflows/**" + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + actionlint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + with: + persist-credentials: false + - name: Run actionlint + # The official image includes ShellCheck and Pyflakes. + uses: docker://rhysd/actionlint:1.7.12@sha256:b1934ee5f1c509618f2508e6eb47ee0d3520686341fec936f3b79331f9315667 + with: + args: -color diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 43bc9fcaebb6..47dac83f561b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -48,18 +48,6 @@ repos: rev: 451b56af716f9f0d0c2b816503a3fd0cf8b036fa # frozen: v1.29.0 hooks: - id: zizmor - # `actionlint` hook, for verifying correct syntax in GitHub Actions workflows. - - repo: https://github.com/rhysd/actionlint - rev: 914e7df21a07ef503a81201c76d2b11c789d3fca # frozen: v1.7.12 - hooks: - - id: actionlint - # specifying this means renovate will also update `additional_dependencies` - language: golang - additional_dependencies: - # actionlint has a shellcheck integration which extracts shell scripts in `run:` steps from GitHub Actions - # and checks these with shellcheck. This is arguably its most useful feature, - # but the integration only works if shellcheck is installed - - "github.com/wasilibs/go-shellcheck/cmd/shellcheck@v0.11.1" ci: autofix_commit_msg: "[pre-commit.ci] auto fixes from pre-commit.com hooks" From 483509147942f14764fc405d53bc81d3eeaa83c1 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Fri, 28 Aug 2026 18:33:36 +0100 Subject: [PATCH 11/16] Show actionlint progress in CI --- .github/workflows/actionlint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/actionlint.yml b/.github/workflows/actionlint.yml index ebb944b59daf..e53a98041065 100644 --- a/.github/workflows/actionlint.yml +++ b/.github/workflows/actionlint.yml @@ -29,4 +29,4 @@ jobs: # The official image includes ShellCheck and Pyflakes. uses: docker://rhysd/actionlint:1.7.12@sha256:b1934ee5f1c509618f2508e6eb47ee0d3520686341fec936f3b79331f9315667 with: - args: -color + args: -color -verbose From b52f6e011c001afa57de27446496abd095e4cc5e Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Fri, 28 Aug 2026 18:34:02 +0100 Subject: [PATCH 12/16] Demonstrate actionlint failure with an unquoted variable --- .github/workflows/actionlint.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/actionlint.yml b/.github/workflows/actionlint.yml index e53a98041065..987ef581463c 100644 --- a/.github/workflows/actionlint.yml +++ b/.github/workflows/actionlint.yml @@ -25,6 +25,8 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: persist-credentials: false + - name: Demonstrate a ShellCheck violation + run: echo $GITHUB_WORKSPACE - name: Run actionlint # The official image includes ShellCheck and Pyflakes. uses: docker://rhysd/actionlint:1.7.12@sha256:b1934ee5f1c509618f2508e6eb47ee0d3520686341fec936f3b79331f9315667 From fc05e21e80d96045e1918a5d6a58de7980168cbb Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Fri, 28 Aug 2026 18:41:17 +0100 Subject: [PATCH 13/16] Revert "Demonstrate actionlint failure with an unquoted variable" This reverts commit 0a36c867b8bbec0e5f4f81290d94c6e0003c1677. --- .github/workflows/actionlint.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/actionlint.yml b/.github/workflows/actionlint.yml index 987ef581463c..e53a98041065 100644 --- a/.github/workflows/actionlint.yml +++ b/.github/workflows/actionlint.yml @@ -25,8 +25,6 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: persist-credentials: false - - name: Demonstrate a ShellCheck violation - run: echo $GITHUB_WORKSPACE - name: Run actionlint # The official image includes ShellCheck and Pyflakes. uses: docker://rhysd/actionlint:1.7.12@sha256:b1934ee5f1c509618f2508e6eb47ee0d3520686341fec936f3b79331f9315667 From fca65d4e28d06af6ba37b4dcc80c2310aee3f9d2 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Sat, 29 Aug 2026 14:05:22 +0100 Subject: [PATCH 14/16] Update .github/workflows/actionlint.yml --- .github/workflows/actionlint.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/actionlint.yml b/.github/workflows/actionlint.yml index e53a98041065..ab2bfccf1822 100644 --- a/.github/workflows/actionlint.yml +++ b/.github/workflows/actionlint.yml @@ -26,7 +26,11 @@ jobs: with: persist-credentials: false - name: Run actionlint - # The official image includes ShellCheck and Pyflakes. + # This is the recommended way to run actionlint in CI: + # https://github.com/rhysd/actionlint/blob/main/docs/usage.md#use-actionlint-on-github-actions. + # The actionlint pre-commit hook would be an alternative, + # but it causes our pre-commit CI jobs to time out. + # The Docker image includes ShellCheck and Pyflakes. uses: docker://rhysd/actionlint:1.7.12@sha256:b1934ee5f1c509618f2508e6eb47ee0d3520686341fec936f3b79331f9315667 with: args: -color -verbose From c7f6710d2fd2ea44fcb725fd4f2068f8c513aa19 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Mon, 31 Aug 2026 20:08:38 +0100 Subject: [PATCH 15/16] Update .github/workflows/actionlint.yml Co-authored-by: Sebastian Rittau --- .github/workflows/actionlint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/actionlint.yml b/.github/workflows/actionlint.yml index ab2bfccf1822..712bc610cce5 100644 --- a/.github/workflows/actionlint.yml +++ b/.github/workflows/actionlint.yml @@ -22,7 +22,7 @@ jobs: actionlint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - name: Run actionlint From 1f823925e8606ff6e179c0de0b1c1a3587787040 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Mon, 31 Aug 2026 20:57:06 +0100 Subject: [PATCH 16/16] Simplify intentional word splitting in workflows --- .github/workflows/daily.yml | 18 +++++++-------- .github/workflows/stubtest_third_party.yml | 26 ++++++++++------------ .github/workflows/tests.yml | 20 +++++++---------- 3 files changed, 28 insertions(+), 36 deletions(-) diff --git a/.github/workflows/daily.yml b/.github/workflows/daily.yml index 066aa70c1845..4342058a1f2e 100644 --- a/.github/workflows/daily.yml +++ b/.github/workflows/daily.yml @@ -85,28 +85,26 @@ jobs: shell: bash run: | PACKAGES=$(python tests/get_stubtest_system_requirements.py) - PACKAGE_ARGS=() - while IFS= read -r package; do - PACKAGE_ARGS+=("$package") - done <<< "$PACKAGES" + # System package names contain no whitespace or glob characters, so word splitting is intentional. + # shellcheck disable=SC2086 if [ "${{ runner.os }}" = "Linux" ]; then if [ -n "$PACKAGES" ]; then printf 'Installing APT packages:\n' - printf ' %s\n' "${PACKAGE_ARGS[@]}" - sudo apt-get update -q && sudo apt-get install -qy "${PACKAGE_ARGS[@]}" + printf ' %s\n' $PACKAGES + sudo apt-get update -q && sudo apt-get install -qy $PACKAGES fi else if [ "${{ runner.os }}" = "macOS" ] && [ -n "$PACKAGES" ]; then printf 'Installing Homebrew packages:\n' - printf ' %s\n' "${PACKAGE_ARGS[@]}" - brew install -q "${PACKAGE_ARGS[@]}" + printf ' %s\n' $PACKAGES + brew install -q $PACKAGES fi if [ "${{ runner.os }}" = "Windows" ] && [ -n "$PACKAGES" ]; then printf 'Installing Chocolatey packages:\n' - printf ' %s\n' "${PACKAGE_ARGS[@]}" - choco install -y "${PACKAGE_ARGS[@]}" + printf ' %s\n' $PACKAGES + choco install -y $PACKAGES fi fi - name: Run stubtest diff --git a/.github/workflows/stubtest_third_party.yml b/.github/workflows/stubtest_third_party.yml index 13602e169ea7..0b7337d08cc5 100644 --- a/.github/workflows/stubtest_third_party.yml +++ b/.github/workflows/stubtest_third_party.yml @@ -65,30 +65,27 @@ jobs: - name: Install required system packages shell: bash run: | + # System package and stub directory names contain no whitespace or glob characters; split both lists into arguments. + # shellcheck disable=SC2086 if [ -n "$STUBS" ]; then - read -r -a STUB_ARGS <<< "$STUBS" - PACKAGES=$(python tests/get_stubtest_system_requirements.py "${STUB_ARGS[@]}") - PACKAGE_ARGS=() - while IFS= read -r package; do - PACKAGE_ARGS+=("$package") - done <<< "$PACKAGES" + PACKAGES=$(python tests/get_stubtest_system_requirements.py $STUBS) if [ "${{ runner.os }}" = "Linux" ]; then if [ -n "$PACKAGES" ]; then printf 'Installing APT packages:\n' - printf ' %s\n' "${PACKAGE_ARGS[@]}" - sudo apt-get update -q && sudo apt-get install -qy "${PACKAGE_ARGS[@]}" + printf ' %s\n' $PACKAGES + sudo apt-get update -q && sudo apt-get install -qy $PACKAGES fi else if [ "${{ runner.os }}" = "macOS" ] && [ -n "$PACKAGES" ]; then printf 'Installing Homebrew packages:\n' - printf ' %s\n' "${PACKAGE_ARGS[@]}" - brew install -q "${PACKAGE_ARGS[@]}" + printf ' %s\n' $PACKAGES + brew install -q $PACKAGES fi if [ "${{ runner.os }}" = "Windows" ] && [ -n "$PACKAGES" ]; then printf 'Installing Chocolatey packages:\n' - printf ' %s\n' "${PACKAGE_ARGS[@]}" - choco install -y "${PACKAGE_ARGS[@]}" + printf ' %s\n' $PACKAGES + choco install -y $PACKAGES fi fi fi @@ -97,7 +94,6 @@ jobs: run: | if [ -n "$STUBS" ]; then echo "Testing $STUBS..." - read -r -a STUB_ARGS <<< "$STUBS" if [ "${{ runner.os }}" = "Linux" ]; then PYTHON_EXECUTABLE="xvfb-run python" @@ -105,7 +101,9 @@ jobs: PYTHON_EXECUTABLE="python" fi - $PYTHON_EXECUTABLE tests/stubtest_third_party.py --ci-platforms-only "${STUB_ARGS[@]}" + # Stub directory names contain no whitespace or glob characters, so word splitting is intentional. + # shellcheck disable=SC2086 + $PYTHON_EXECUTABLE tests/stubtest_third_party.py --ci-platforms-only $STUBS else echo "Nothing to test" fi diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 756f29bf621d..17bc258497e8 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -63,14 +63,12 @@ jobs: - name: Install required APT packages run: | PACKAGES=$(python tests/get_stubtest_system_requirements.py) + # System package names contain no whitespace or glob characters, so word splitting is intentional. + # shellcheck disable=SC2086 if [ -n "$PACKAGES" ]; then - PACKAGE_ARGS=() - while IFS= read -r package; do - PACKAGE_ARGS+=("$package") - done <<< "$PACKAGES" printf 'Installing APT packages:\n' - printf ' %s\n' "${PACKAGE_ARGS[@]}" - sudo apt-get update -q && sudo apt-get install -qy "${PACKAGE_ARGS[@]}" + printf ' %s\n' $PACKAGES + sudo apt-get update -q && sudo apt-get install -qy $PACKAGES fi - name: Run mypy_test.py run: python ./tests/mypy_test.py --platform=${{ matrix.platform }} --python-version=${{ matrix.python-version }} @@ -199,14 +197,12 @@ jobs: - name: Install required APT packages run: | PACKAGES=$(python tests/get_stubtest_system_requirements.py) + # System package names contain no whitespace or glob characters, so word splitting is intentional. + # shellcheck disable=SC2086 if [ -n "$PACKAGES" ]; then - PACKAGE_ARGS=() - while IFS= read -r package; do - PACKAGE_ARGS+=("$package") - done <<< "$PACKAGES" printf 'Installing APT packages:\n' - printf ' %s\n' "${PACKAGE_ARGS[@]}" - sudo apt-get update -q && sudo apt-get install -qy "${PACKAGE_ARGS[@]}" + printf ' %s\n' $PACKAGES + sudo apt-get update -q && sudo apt-get install -qy $PACKAGES fi - name: Create an isolated venv for testing run: uv venv .venv