diff --git a/.github/workflows/32bit.yml b/.github/workflows/32bit.yml index 7462392dea..6d5da2e743 100644 --- a/.github/workflows/32bit.yml +++ b/.github/workflows/32bit.yml @@ -90,14 +90,15 @@ jobs: borg.testsuite.helpers.time_test steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: # Just fetching one commit is not enough for setuptools-scm, so we fetch all. fetch-depth: 0 fetch-tags: true + persist-credentials: false - name: Set up Python - uses: actions/setup-python@v7 + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: # same python version as in the container, so both sides are comparable python-version: '3.13' @@ -106,7 +107,7 @@ jobs: # (msgpack, PyYAML, backports-zstd, borghash, borgstore) are the expensive # part of the container setup, so keep them from run to run. - name: Cache pip-built wheels (armv7) - uses: actions/cache@v6 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: .pip-cache-armv7 key: armv7-pip-${{ hashFiles('pyproject.toml') }} @@ -136,7 +137,7 @@ jobs: echo "BORG_VERSION=$("$RUNNER_TEMP/venv-native/bin/borg" --version | cut -d' ' -f2)" >> $GITHUB_ENV - name: Set up QEMU - uses: docker/setup-qemu-action@v4 + uses: docker/setup-qemu-action@96fe6ef7f33517b61c61be40b68a1882f3264fb8 # v4.2.0 with: platforms: arm diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml index 4d6775b6ae..bf60ee93af 100644 --- a/.github/workflows/backport.yml +++ b/.github/workflows/backport.yml @@ -1,5 +1,11 @@ name: Backport pull request +# pull_request_target is needed because the backport has to run with a token +# that may write to this repository - a pull_request run from a fork does not +# get one. It is safe here because nothing from the pull request is checked +# out or executed: the checkout below takes the base branch (no `ref:`), and +# the only thing that touches pull request content is backport-action, which +# just cherry-picks commits. on: pull_request_target: types: [closed] @@ -7,8 +13,7 @@ on: types: [created] permissions: - contents: write # so it can comment - pull-requests: write # so it can create pull requests + contents: read jobs: backport: @@ -16,6 +21,10 @@ jobs: runs-on: ubuntu-26.04 timeout-minutes: 5 + permissions: + contents: write # backport-action pushes the backport branch + pull-requests: write # ... and opens the pull request and comments on it + # Only run when pull request is merged # or when a comment starting with `/backport` is created by someone other than the # https://github.com/backport-action bot user (user id: 97796249). Note that if you use your @@ -31,6 +40,9 @@ jobs: startsWith(github.event.comment.body, '/backport') ) steps: + # No persist-credentials: false here (unlike the other workflows): + # backport-action pushes the backport branch with a plain `git push`, + # so it needs the credentials that actions/checkout leaves behind. - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Create backport pull requests uses: korthout/backport-action@2e830a1d0b8269505846ddd407a70876913ad1f8 # v4.6.0 diff --git a/.github/workflows/bigendian.yml b/.github/workflows/bigendian.yml index 166fceedd5..4100f4cc00 100644 --- a/.github/workflows/bigendian.yml +++ b/.github/workflows/bigendian.yml @@ -74,14 +74,15 @@ jobs: borg.testsuite.helpers.msgpack_test steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: # Just fetching one commit is not enough for setuptools-scm, so we fetch all. fetch-depth: 0 fetch-tags: true + persist-credentials: false - name: Set up Python - uses: actions/setup-python@v7 + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: # same python version as in the container, so both sides are comparable python-version: '3.13' @@ -90,7 +91,7 @@ jobs: # (msgpack, borghash, borgstore) are the expensive # part of the container setup, so keep them from run to run. - name: Cache pip-built wheels (s390x) - uses: actions/cache@v6 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: .pip-cache-s390x key: s390x-pip-${{ hashFiles('pyproject.toml') }} @@ -120,7 +121,7 @@ jobs: echo "BORG_VERSION=$("$RUNNER_TEMP/venv-native/bin/borg" --version | cut -d' ' -f2)" >> $GITHUB_ENV - name: Set up QEMU - uses: docker/setup-qemu-action@v4 + uses: docker/setup-qemu-action@96fe6ef7f33517b61c61be40b68a1882f3264fb8 # v4.2.0 with: platforms: s390x diff --git a/.github/workflows/black.yaml b/.github/workflows/black.yaml index ae24faf502..b5d8efdc35 100644 --- a/.github/workflows/black.yaml +++ b/.github/workflows/black.yaml @@ -28,6 +28,8 @@ jobs: timeout-minutes: 5 steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - uses: psf/black@87928e6d6761a4a6d22250e1fee5601b3998086e # 26.5.1 with: version: "~= 24.0" diff --git a/.github/workflows/canary.yml b/.github/workflows/canary.yml index ea8ba0244f..fabc8057e5 100644 --- a/.github/workflows/canary.yml +++ b/.github/workflows/canary.yml @@ -48,6 +48,7 @@ jobs: with: fetch-depth: 0 fetch-tags: true + persist-credentials: false - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 @@ -131,6 +132,7 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 + persist-credentials: false # Same as the "Cache pip-built wheels" step in ci.yml (MSYS2's mingw # Python cannot use PyPI's win_amd64 wheels). Own key, because the diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2d18ec53dc..be2052b8d0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,6 +43,8 @@ jobs: steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - uses: astral-sh/ruff-action@278981a28ce3188b1e39527901f38254bf3aac89 # v4.1.0 security: @@ -52,6 +54,8 @@ jobs: steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Set up Python uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: @@ -76,6 +80,7 @@ jobs: # Just fetching one commit is not enough for setuptools-scm, so we fetch all. fetch-depth: 0 fetch-tags: true + persist-credentials: false - name: Set up Python uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 @@ -190,6 +195,7 @@ jobs: # Just fetching one commit is not enough for setuptools-scm, so we fetch all. fetch-depth: 0 fetch-tags: true + persist-credentials: false - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 @@ -197,15 +203,20 @@ jobs: python-version: ${{ matrix.python-version }} - name: Cache pip + # Not on tags: that is when the release binaries are built and attested, + # and they should not be able to pick up a poisoned cache entry. + if: ${{ !startsWith(github.ref, 'refs/tags/') }} uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: ~/.cache/pip key: ${{ runner.os }}-${{ runner.arch }}-pip-${{ hashFiles('requirements.d/development.lock.txt') }} restore-keys: | ${{ runner.os }}-${{ runner.arch }}-pip- - ${{ runner.os }}-${{ runner.arch }}- - name: Cache tox environments + # Not on tags: that is when the release binaries are built and attested, + # and they should not be able to pick up a poisoned cache entry. + if: ${{ !startsWith(github.ref, 'refs/tags/') }} uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: .tox @@ -347,13 +358,15 @@ jobs: - name: Prepare binaries (${{ matrix.binary }}) if: ${{ matrix.binary && startsWith(github.ref, 'refs/tags/') }} + env: + BINARY: ${{ matrix.binary }} run: | mkdir -p artifacts if [ -f dist/binary/borg.exe ]; then - cp dist/binary/borg.exe artifacts/${{ matrix.binary }} + cp dist/binary/borg.exe "artifacts/$BINARY" fi if [ -f dist/binary/borg.tgz ]; then - cp dist/binary/borg.tgz artifacts/${{ matrix.binary }}.tgz + cp dist/binary/borg.tgz "artifacts/$BINARY.tgz" fi echo "binary files" ls -l artifacts/ @@ -457,11 +470,15 @@ jobs: with: fetch-depth: 0 fetch-tags: true + persist-credentials: false # .pip-cache lives inside the workspace, which cross-platform-actions # rsyncs into the VM and back, so wheels built from sdists in one run # (most of the VM setup time) are reused by the next one. - name: Cache pip-built wheels + # Not on tags: that is when the release binaries are built and attested, + # and they should not be able to pick up a poisoned cache entry. + if: ${{ !startsWith(github.ref, 'refs/tags/') }} uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: .pip-cache @@ -737,11 +754,15 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 + persist-credentials: false # MSYS2's mingw Python cannot use PyPI's win_amd64 wheels, so pip builds # all compiled deps from source - incl. building maturin via cargo, just # to build the blake3 wheel. Persist the wheels pip builds. - name: Cache pip-built wheels + # Not on tags: that is when the release binaries are built and attested, + # and they should not be able to pick up a poisoned cache entry. + if: ${{ !startsWith(github.ref, 'refs/tags/') }} uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: .pip-cache diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 9985c05f54..c3009520c0 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -27,6 +27,10 @@ concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} cancel-in-progress: ${{ github.event_name == 'pull_request' }} +# The analyze job below raises this to what CodeQL needs. +permissions: + contents: read + jobs: analyze: name: Analyze @@ -50,6 +54,7 @@ jobs: with: # Just fetching one commit is not enough for setuptools-scm, so we fetch all. fetch-depth: 0 + persist-credentials: false - name: Set up Python uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: diff --git a/.github/workflows/fame.yml b/.github/workflows/fame.yml index 1baf34394c..9586003c9b 100644 --- a/.github/workflows/fame.yml +++ b/.github/workflows/fame.yml @@ -46,6 +46,7 @@ jobs: with: ref: master fetch-depth: 0 # git blame needs the whole history + persist-credentials: false - name: Set up Python uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 diff --git a/.github/workflows/pypy.yml b/.github/workflows/pypy.yml index 8d027811ea..efdd743f97 100644 --- a/.github/workflows/pypy.yml +++ b/.github/workflows/pypy.yml @@ -44,6 +44,7 @@ jobs: with: fetch-depth: 0 fetch-tags: true + persist-credentials: false - name: Set up PyPy 3.11 (nightly) uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a79b740182..f8850626a6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -62,6 +62,7 @@ jobs: # Just fetching one commit is not enough for setuptools-scm, so we fetch all. fetch-depth: 0 fetch-tags: true + persist-credentials: false - name: Set up Python uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 diff --git a/.github/zizmor.yml b/.github/zizmor.yml new file mode 100644 index 0000000000..f69f0d0d0a --- /dev/null +++ b/.github/zizmor.yml @@ -0,0 +1,33 @@ +# Configuration for zizmor (https://docs.zizmor.sh/), the GitHub Actions +# static analyser. Run it over this repository with: +# +# zizmor . +# +# The findings listed here are the ones that were looked at and accepted. The +# reasoning lives next to the code it is about, in the workflow files - this +# file only says "yes, we know". Ignores are deliberately kept as whole-file +# entries rather than file:line, so that they do not silently stop matching +# whenever the surrounding workflow shifts by a line. + +rules: + artipacked: + ignore: + # backport.yml is the one workflow that must keep the credentials + # actions/checkout leaves behind: korthout/backport-action pushes the + # backport branch with a plain `git push`. + - backport.yml + + dangerous-triggers: + ignore: + # backport.yml needs pull_request_target for a writable token, and never + # checks out or runs pull request code. See the comment in the workflow. + - backport.yml + + cache-poisoning: + ignore: + # The cache steps in ci.yml are skipped on tag pushes, which is when the + # release binaries are built and attested - see the `if:` on each of them. + # zizmor flags any actions/cache in a tag-triggered workflow regardless. + # A new cache step in ci.yml needs that same `if:`; this ignore will not + # tell you about it. + - ci.yml