From c8488860d34e8dd4c92540fe19874093d38f588a Mon Sep 17 00:00:00 2001 From: Guillaume Fieni Date: Wed, 10 Jul 2024 13:22:47 +0200 Subject: [PATCH] ci(release): Rework python package build/publish steps Separate the python package build and publish steps in order to secure against arbitrary code that could be executed by a build dependency. Thanks to this, we can now generate SLSA provenance attestations for the generated build artifacts and upload them as release assets. --- .github/workflows/release.yml | 163 ++++++++++++++++++++++------------ 1 file changed, 104 insertions(+), 59 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e48d7a96..52f37a02 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -16,61 +16,99 @@ jobs: contents: read steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - - - name: Check if package version corresponds to git tag - shell: python - env: - PYTHONPATH: ${{ github.workspace }}/src - run: | - import os - import sys - from powerapi import __version__ - - git_tag = os.environ['GITHUB_REF_NAME'].removeprefix('v') - pkg_version = __version__ - - if git_tag != pkg_version: - title = 'Invalid version' - file = 'src/powerapi/__init__.py' - msg = f'Version mismatch between python package ({pkg_version}) and git tag ({git_tag})' - print(f'::error title={title},file={file}::{msg}') - sys.exit(1) - - pypi-package: - name: Publish Pypi package + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + + - name: Check if package version corresponds to git tag + shell: python + env: + PYTHONPATH: ${{ github.workspace }}/src + run: | + import os + import sys + from powerapi import __version__ + + git_tag = os.environ['GITHUB_REF_NAME'].removeprefix('v') + pkg_version = __version__ + + if git_tag != pkg_version: + title = 'Invalid version' + file = 'src/powerapi/__init__.py' + msg = f'Version mismatch between python package ({pkg_version}) and git tag ({git_tag})' + print(f'::error title={title},file={file}::{msg}') + sys.exit(1) + + build-python-package: + name: Build Python Package runs-on: ubuntu-latest - needs: pre-checks + needs: [pre-checks] + outputs: + dist-hashes: ${{ steps.dist-hashes.outputs.hash }} permissions: contents: read - id-token: write steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + + - name: Set up Python + uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0 + with: + python-version: "3.x" - - name: Set up Python - uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0 - with: - python-version: "3.x" + - name: Install uv + uses: astral-sh/setup-uv@f731690a1dacb2f6393acc910887b8cda1a97789 # v3.1.6 - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install build + - name: Build sdist and wheel + run: | + uv build --sdist --wheel --out-dir dist/ - - name: Build package - run: python -m build + - name: Compute SHA256 hashes of build artifacts + id: dist-hashes + shell: bash + run: | + cd ./dist && echo "hash=$(sha256sum -- * | base64 -w0)" >> $GITHUB_OUTPUT - - name: Publish package - uses: pypa/gh-action-pypi-publish@f7600683efdcb7656dec5b29656edb7bc586e597 # v1.10.3 - with: - print-hash: true - attestations: true + - name: Upload build artifacts + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 + with: + name: "python-build-dist" + path: ./dist + if-no-files-found: error + + slsa-provenance: + name: Generate artifacts provenance attestation + needs: [build-python-package] + permissions: + contents: read + actions: read + id-token: write + uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.0.0 + with: + base64-subjects: "${{ needs.build-python-package.outputs.dist-hashes }}" + + publish-python-package: + name: Publish Pypi Package + runs-on: ubuntu-latest + needs: [build-python-package, slsa-provenance] + permissions: + contents: read + id-token: write + + steps: + - name: Download build artifacts + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 + with: + name: "python-build-dist" + + - name: Publish package + uses: pypa/gh-action-pypi-publish@f7600683efdcb7656dec5b29656edb7bc586e597 # v1.10.3 + with: + print-hash: true + attestations: true docker-image: name: Publish Docker image runs-on: ubuntu-latest - needs: pre-checks + needs: [pre-checks] permissions: contents: read packages: write @@ -118,26 +156,33 @@ jobs: github-release: name: Publish GitHub release runs-on: ubuntu-latest - needs: [pre-checks, pypi-package, docker-image] + needs: [publish-python-package, docker-image] permissions: contents: write env: CHGLOG_VERSION: "0.15.4" steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - with: - fetch-depth: 0 - - - name: Generate version changelog - run: | - set -euo pipefail - export BASE_URL="https://github.com/git-chglog/git-chglog/releases/download" - export FILENAME="git-chglog_${CHGLOG_VERSION}_linux_amd64.tar.gz" - curl -fsSL "${BASE_URL}/v${CHGLOG_VERSION}/${FILENAME}" |sudo tar xz --no-same-owner -C /usr/local/bin git-chglog - git-chglog --config .github/chglog/config.yml --output CHANGELOG.md "${GITHUB_REF_NAME}" - - - name: Create GitHub release - uses: softprops/action-gh-release@c062e08bd532815e2082a85e87e3ef29c3e6d191 # v2.0.8 - with: - body_path: CHANGELOG.md + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + with: + fetch-depth: 0 + + - name: Generate version changelog + run: | + set -euo pipefail + export BASE_URL="https://github.com/git-chglog/git-chglog/releases/download" + export FILENAME="git-chglog_${CHGLOG_VERSION}_linux_amd64.tar.gz" + curl -fsSL "${BASE_URL}/v${CHGLOG_VERSION}/${FILENAME}" |sudo tar xz --no-same-owner -C /usr/local/bin git-chglog + git-chglog --config .github/chglog/config.yml --output CHANGELOG.md "${GITHUB_REF_NAME}" + + - name: Download build artifacts + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 + + - name: Create GitHub release + uses: softprops/action-gh-release@c062e08bd532815e2082a85e87e3ef29c3e6d191 # v2.0.8 + with: + body_path: CHANGELOG.md + files: | + dist/powerapi-*.whl + dist/powerapi-*.tar.gz + *.intoto.jsonl