From 19768a05b5f1051b34c51c4aba775f9ea834f050 Mon Sep 17 00:00:00 2001 From: veit Date: Sun, 5 Apr 2026 20:25:44 +0200 Subject: [PATCH 1/3] =?UTF-8?q?:memo:=20Add=20=E2=80=98Securing=20the=20re?= =?UTF-8?q?lease=20workflow=E2=80=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Git tags replaced by commit SHA values --- .github/workflows/ci.yml | 16 +- docs/document/sphinx/test.rst | 4 +- docs/packs/.github/workflows/build_wheels.yml | 6 +- docs/packs/publish.rst | 144 +++++++++++++++--- docs/test/pytest/ci.yaml | 20 +-- docs/test/tox.rst | 14 +- 6 files changed, 154 insertions(+), 50 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 95a72cf2..a27c1e0c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,21 +9,21 @@ jobs: pre-commit: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 - - uses: actions/setup-python@v6 - - uses: actions/cache@v5 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + - uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: path: ~/.cache/pre-commit key: pre-commit|${{ env.pythonLocation }}|${{ hashFiles('.pre-commit-config.yaml') }} - - uses: pre-commit/action@v3.0.1 + - uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1 docs: name: Build docs and check links runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 - - uses: pandoc/actions/setup@v1 - - uses: actions/setup-python@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: pandoc/actions/setup@86321b6dd4675f5014c611e05088e10d4939e09e # v1.1.1 + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: # Keep in sync with .readthedocs.yaml python-version-file: .python-version @@ -31,7 +31,7 @@ jobs: run: | sudo apt install plantuml - name: Setup cached uv - uses: hynek/setup-cached-uv@v2 + uses: hynek/setup-cached-uv@4300ec2180bc77d705e626a34e381b81a4772c51 # v2.5.0 - name: Create venv and install docs dependencies run: | uv venv diff --git a/docs/document/sphinx/test.rst b/docs/document/sphinx/test.rst index dbbdf7ac..81bc5ac1 100644 --- a/docs/document/sphinx/test.rst +++ b/docs/document/sphinx/test.rst @@ -126,13 +126,13 @@ definieren: runs-on: ubuntu-latest steps: - name: Download pre-built packages - uses: actions/download-artifact@v4 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: Packages path: dist - run: tar xf dist/*.tar.gz --strip-components=1 - - uses: actions/setup-python@v5 + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: # Keep in sync with tox.ini/docs and .readthedocs.yaml python-version: "3.12" diff --git a/docs/packs/.github/workflows/build_wheels.yml b/docs/packs/.github/workflows/build_wheels.yml index 46552cd5..85cfe017 100644 --- a/docs/packs/.github/workflows/build_wheels.yml +++ b/docs/packs/.github/workflows/build_wheels.yml @@ -16,12 +16,12 @@ jobs: os: [ubuntu-latest, windows-latest, macos-13, macos-14] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Build wheels - uses: pypa/cibuildwheel@v2.21.3 + uses: pypa/cibuildwheel@8d2b08b68458a16aeb24b64e68a09ab1c8e82084 # v3.4.1 - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: cibw-wheels-${{ matrix.os }}-${{ strategy.job-index }} path: ./wheelhouse/*.whl diff --git a/docs/packs/publish.rst b/docs/packs/publish.rst index 016ee37e..041a47d4 100644 --- a/docs/packs/publish.rst +++ b/docs/packs/publish.rst @@ -111,7 +111,25 @@ PyPI Registriert euch nun beim :term:`Python Package Index` (:term:`PyPI`) und stellt sicher, dass die `Zwei-Faktor-Authentifizierung -`_. +`_ +aktiviert ist, indem ihr Folgendes in die Datei :file:`~/.pypirc` einfügt: + +.. code-block:: ini + + [distutils] + index-servers= + pypi + test + + [test] + repository = https://test.pypi.org/legacy/ + username = veit + + [pypi] + username = __token__ + +Bei dieser Konfiguration wird für das Hochladen nicht mehr die Kombination aus +Name und Passwort verwendet, sondern ein Upload-Token. .. seealso:: * `PyPI now supports uploading via API token @@ -169,16 +187,16 @@ folgendermaßen aussehen: needs: [test] steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 0 - name: Set up Python - uses: actions/setup-python@v5 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version-file: .python-version cache-dependency-path: '**/pyproject.toml' - name: Setup cached uv - uses: hynek/setup-cached-uv@v2 + uses: hynek/setup-cached-uv@4300ec2180bc77d705e626a34e381b81a4772c51 # v2.5.0 - name: Create venv run: | uv venv @@ -189,9 +207,9 @@ folgendermaßen aussehen: - name: Retrieve and publish steps: - name: Retrieve release distributions - uses: actions/download-artifact@v4 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 - name: Publish package distributions to PyPI - uses: pypa/gh-action-pypi-publish@release/v1 + uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0 with: username: __token__ password: ${{ secrets.PYPI_TOKEN }} @@ -215,17 +233,53 @@ Zeile 38–41 * `GitHub Actions `_ * :doc:`cibuildwheel` +Absichern des Release-Workflows +------------------------------- + +Continuous Deployment zur Veröffentlichung von Python-Paketen sind ein beliebtes +Ziel für Angriffe. Ihr könnt viele der Gefahren vermeiden, indem ihr einige +wenige Sicherheitsempfehlungen befolgt: + +Vermeidet unsichere Trigger + Workflows, die bei einem Angriff ausgelöst werden können, insbesondere + Eingaben, die dieser kontrolliert (wie :ref:`Pull Requests + `- oder :doc:`Branch + `-Titel), wurden in der + Vergangenheit genutzt, Befehle einzuschleusen. Insbesondere der Trigger + ``pull_request_target`` der :ref:`github-actions` sollte vermieden werden. +Säubert Parameter und Eingaben + Jeder Workflow-Parameter oder jede Eingabe, die sich zu einem ausführbaren + Befehl erweitern lässt, birgt das Potenzial, bei Angriffen ausgenutzt zu + werden. Säubert Werte, indem ihr sie als Umgebungsvariablen an Befehle + übergebt, um :abbr:`SSTI (Server Side Template Injection)`-Angriffe zu + vermeiden. +Vermeidet veränderbare Referenzen + fixiert eure Abhängigkeiten in Workflows. + + * Bevorzugt Git-Commit-`SHA + `_-Werte anstelle von + :doc:`Git-Tags `, da Tags änderbar + sind. + * Verwendet eine :ref:`uv_lock` für PyPI-Abhängigkeiten, die in Workflows + verwendet wird. + +Verwendet überprüfbare Deployments + Mit :ref:`trusted_publishers` könnt ihr überprüfbare GitHub-Umgebungen für + den Bau eurer Python-Pakete verwenden. Falls ihr GitHub Actions für die + kontinuierliche Bereitstellung nutzt, solltet ihr :ref:`zizmorcore` + verwenden um unsichere Workflows zu erkennen und zu beheben. + .. _trusted_publishers: Trusted Publishers ------------------- +~~~~~~~~~~~~~~~~~~ `Trusted Publishers `_ ist ein Verfahren zum Veröffentlichen von Paketen auf dem :term:`PyPI`. Es basiert auf OpenID Connect und erfordert weder Passwort noch Token. Dazu sind lediglich die folgenden Schritte erforderlich: -#. Fügt einen *Trusted Publishers* auf PyPI hinzu +#. Fügt einen *Trusted Publisher* auf PyPI hinzu Je nachdem, ob ihr ein neues Paket veröffentlichen oder ein bestehendes aktualisieren wollt, unterscheidet sich der Prozess geringfügig: @@ -281,7 +335,7 @@ folgenden Schritte erforderlich: Zeilen 13–14 Die ``write``-Berechtigung ist für *Trusted Publishing* erforderlich. - Zeilen 42–44 + Zeilen 40–44 ``username`` und ``password`` werden für die GitHub-Aktion ``pypa/gh-action-pypi-publish`` nicht mehr benötigt. @@ -290,16 +344,11 @@ folgenden Schritte erforderlich: :lineno-start: 40 :emphasize-lines: 3- - - name: Publish package distributions to PyPI - uses: pypa/gh-action-pypi-publish@release/v1 - - with: - - username: __token__ - - password: ${{ secrets.PYPI_TOKEN }} - -.. _digital-attestations: - -Digital Attestations --------------------- + - name: Publish package distributions to PyPI + uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0 + with: + username: __token__ + password: ${{ secrets.PYPI_TOKEN }} Seit 14. November 2024 unterstützt :term:`PyPI` auch :pep:`740` mit `Digital Attestations `_. PyPI verwendet das @@ -327,7 +376,7 @@ zum Veröffentlichen verwendet werden: id-token: write steps: - name: Publish package distributions to PyPI - uses: pypa/gh-action-pypi-publish@release/v1 + uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0 .. note:: Die Unterstützung für die automatische Erstellung von Digital Attestations @@ -337,3 +386,58 @@ zum Veröffentlichen verwendet werden: .. seealso:: `PyPI now supports digital attestations `_ + +.. _zizmorcore: + +zizmor +~~~~~~ + +`zizmor `_ kann viele Sicherheitsprobleme in typischen +CI/CD-Konfigurationen von GitHub Actions aufspüren und beheben. zizmor ist für +die Integration in GitHub Actions konzipiert. Eine typische GitHub Action von +uns für zizmor sieht so aus: + +.. code-block:: yaml + :caption: .github/workflows/zizmor.yml + + # https://github.com/woodruffw/zizmor + name: Zizmor + + on: + push: + branches: ["main"] + pull_request: + branches: ["**"] + + concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + + permissions: {} + + jobs: + zizmor: + name: Run zizmor + runs-on: ubuntu-latest + permissions: + security-events: write # Required for upload-sarif (used by zizmor-action) to upload SARIF files. + steps: + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + - name: Run zizmor + uses: zizmorcore/zizmor-action@71321a20a9ded102f6e9ce5718a2fcec2c4f70d8 # v0.5.2 + with: + persona: pedantic + +.. _add_2fa: + +2FA für alle Entwicklungskonten +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Ihr solltet Zwei-Faktor-Authentifizierung für alle eure Konten nutzen, die mit +der Entwicklung in Verbindung stehen – nicht nur für :term:`PyPI`. Denkt an eure +Konten für die Versionskontrolle (`GitHub `_, `GitLab +`_, `Codeberg `_, `Forgejo +`_) und E-Mail. diff --git a/docs/test/pytest/ci.yaml b/docs/test/pytest/ci.yaml index e9052764..94cc21e0 100644 --- a/docs/test/pytest/ci.yaml +++ b/docs/test/pytest/ci.yaml @@ -19,18 +19,18 @@ jobs: - macos-latest - windows-latest python-version: - - "3.8" - - "3.9" - "3.10" - "3.11" - "3.12" + - "3.13" + - "3.14" steps: - name: Check out the repo - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Set up Python - uses: actions/setup-python@v5 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: ${{ matrix.python-version }} @@ -43,7 +43,7 @@ jobs: python -m tox - name: Upload coverage data - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: coverage-data path: .coverage.* @@ -56,10 +56,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out the repo - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Set up Python - uses: actions/setup-python@v5 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: 3.12 @@ -68,7 +68,7 @@ jobs: python -m pip install --upgrade coverage[toml] - name: Download coverage data - uses: actions/download-artifact@v4 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: coverage-data @@ -84,14 +84,14 @@ jobs: python -Im coverage report --fail-under=100 - name: Upload HTML report if check failed - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: html-report path: htmlcov if: ${{ failure() }} - name: Create badge - uses: schneegans/dynamic-badges-action@v1.7.0 + uses: schneegans/dynamic-badges-action@0e50b8bad39e7e1afd3e4e9c2b7dd145fad07501 # v1.8.0 with: auth: ${{ secrets.GIST_TOKEN }} gistID: YOUR_GIST_ID diff --git a/docs/test/tox.rst b/docs/test/tox.rst index 341e218a..1baa1a0c 100644 --- a/docs/test/tox.rst +++ b/docs/test/tox.rst @@ -459,16 +459,16 @@ GitHub-Actions verfügbar: `github.com/actions/runner-images if: always() steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - - uses: actions/setup-python@v6 + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version-file: .python-version - - uses: hynek/setup-cached-uv@v2 + - uses: hynek/setup-cached-uv@4300ec2180bc77d705e626a34e381b81a4772c51 # v2.5.0 - name: Download coverage data - uses: actions/download-artifact@v7 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: pattern: coverage-data-* merge-multiple: true @@ -492,16 +492,16 @@ GitHub-Actions verfügbar: `github.com/actions/runner-images ``steps`` ist eine Liste von Schritten. Der Name eines jeden Schrittes kann beliebig sein und ist optional. - ``uses: actions/checkout@v4`` + ``uses: actions/checkout`` ist ein GitHub-Actions-Tool, das unser Repository auscheckt, damit der Rest des Workflows darauf zugreifen kann. - ``uses: actions/setup-python@v5`` + ``uses: actions/setup-python`` ist ein GitHub-Actions-Tool, das Python konfiguriert und in einer Build-Umgebung installiert. ``with: python-version: ${{ matrix.python }}`` sagt, dass eine Umgebung für jede der in ``matrix.python`` aufgeführten Python-Versionen erstellt werden soll. - ``uses: hynek/setup-cached-uv@v2`` + ``uses: hynek/setup-cached-uv`` uses :term:`uv` in GitHub Actions. .. seealso:: From e2050ce3d1fdb16c4609fe0a7907390ff45ecb8d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 6 Apr 2026 18:18:14 +0000 Subject: [PATCH 2/3] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/tox-dev/pyproject-fmt: v2.16.2 → v2.21.0](https://github.com/tox-dev/pyproject-fmt/compare/v2.16.2...v2.21.0) - [github.com/psf/black-pre-commit-mirror: 26.1.0 → 26.3.1](https://github.com/psf/black-pre-commit-mirror/compare/26.1.0...26.3.1) - [github.com/codespell-project/codespell: v2.4.1 → v2.4.2](https://github.com/codespell-project/codespell/compare/v2.4.1...v2.4.2) --- .pre-commit-config.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7c57fdaa..ec237981 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -15,7 +15,7 @@ repos: - id: check-added-large-files args: ['--maxkb=1024'] - repo: https://github.com/tox-dev/pyproject-fmt - rev: v2.16.2 + rev: v2.21.0 hooks: - id: pyproject-fmt - repo: https://github.com/abravalheri/validate-pyproject @@ -35,7 +35,7 @@ repos: entry: isort --profile=black name: isort (python) - repo: https://github.com/psf/black-pre-commit-mirror - rev: 26.1.0 + rev: 26.3.1 hooks: - id: black - repo: https://github.com/adamchainz/blacken-docs @@ -46,7 +46,7 @@ repos: additional_dependencies: - black - repo: https://github.com/codespell-project/codespell - rev: v2.4.1 + rev: v2.4.2 hooks: - id: codespell - repo: local From fb5f987f024ba437fa623b975b5613b823292bb2 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 6 Apr 2026 18:21:12 +0000 Subject: [PATCH 3/3] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- docs/packs/dataprep/pyproject.toml | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/packs/dataprep/pyproject.toml b/docs/packs/dataprep/pyproject.toml index 1a78ec2b..ebbdb014 100644 --- a/docs/packs/dataprep/pyproject.toml +++ b/docs/packs/dataprep/pyproject.toml @@ -26,7 +26,7 @@ dependencies = [ "pandas", ] urls."Bug Tracker" = "https://github.com/veit/dataprep/issues" -urls."Homepage" = "https://github.com/veit/dataprep" +urls.Homepage = "https://github.com/veit/dataprep" License-Expression = "BSD-3-Clause" License-File = [ "LICENSE" ] diff --git a/pyproject.toml b/pyproject.toml index 36aeef02..c463adb4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,7 +20,7 @@ classifiers = [ ] dependencies = [] urls."Bug Tracker" = "https://github.com/veit/python-basics-tutorial-de/issues" -urls."Homepage" = "https://github.com/veit/python-basics-tutorial-de/" +urls.Homepage = "https://github.com/veit/python-basics-tutorial-de/" [dependency-groups] dev = [