Skip to content

Commit

Permalink
Add SLSA provenance generator to release; closes #222 (#223)
Browse files Browse the repository at this point in the history
* feat: split release workflows into different jobs with different permissions

Signed-off-by: Diogo Teles Sant'Anna <diogoteles08@gmail.com>

* feat: add workflow_dispatch trigger for release action

Signed-off-by: Diogo Teles Sant'Anna <diogoteles08@gmail.com>

* feat: add provenance generation to release workflow

Signed-off-by: Diogo Teles Sant'Anna <diogoteles08@gmail.com>

* fix: wrong line breaking on sign step of release

Signed-off-by: Diogo Teles Sant'Anna <diogoteles08@gmail.com>

* docs: update README to add SLSA 3 badge and instructions to verify build provenance

Signed-off-by: Diogo Teles Sant'Anna <diogoteles08@gmail.com>

* fix: issue downloading artifacts for release on pypi

Signed-off-by: Diogo Teles Sant'Anna <diogoteles08@gmail.com>

* Revert "feat: add workflow_dispatch trigger for release action"

This reverts commit 88583f0.

* fix: wrong URL being reffered on README

On the instructions on how to verify the provenance, we were reffering
to the instructions on how to do so, but linking to the wrong URL.

Signed-off-by: Diogo Teles Sant'Anna <diogoteles08@gmail.com>

* feat: change provenance name to have the version number

Signed-off-by: Diogo Teles Sant'Anna <diogoteles08@gmail.com>

* feat: remove unnecessary permission on job workflow

On release-pypi job on release workflow, the token-id permission was set
to "write", but it's not necessary and was removed.

Signed-off-by: Diogo Teles Sant'Anna <diogoteles08@gmail.com>

* Update README.md

Signed-off-by: William Woodruff <william@yossarian.net>

* Update README.md

Signed-off-by: William Woodruff <william@yossarian.net>

* docs: explain why not using hash pinning in a GHA

Because of a demand of SLSA Generator, their action cannot be used through pinned hashing. As using tags goes agains the best practices, I'm letting explicit the reason why we are using them.

Signed-off-by: Diogo Teles Sant'Anna <diogoteles08@gmail.com>

Signed-off-by: Diogo Teles Sant'Anna <diogoteles08@gmail.com>
Signed-off-by: William Woodruff <william@yossarian.net>
Co-authored-by: William Woodruff <william@trailofbits.com>
Co-authored-by: William Woodruff <william@yossarian.net>
  • Loading branch information
3 people authored Sep 29, 2022
1 parent 954c01a commit e5acd69
Show file tree
Hide file tree
Showing 2 changed files with 131 additions and 70 deletions.
193 changes: 123 additions & 70 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,78 +1,131 @@
name: Release

on:
release:
types:
- published

name: release

permissions:
# Needed to access the workflow's OIDC identity.
id-token: write

# Needed to upload release assets.
contents: write

jobs:
pypi:
name: Build, sign and publish release to PyPI
build:
name: Build and sign artifacts
runs-on: ubuntu-latest
permissions:
id-token: write
outputs:
hashes: ${{ steps.hash.outputs.hashes }}
steps:
- uses: actions/checkout@d171c3b028d844f2bf14e9fdec0c58114451e4bf

- uses: actions/setup-python@7f80679172b057fc5e90d70d197929d454754a5a

- name: deps
run: python -m pip install -U build

- name: build
run: python -m build

- name: sign
run: |
mkdir -p smoketest-artifacts
# we smoke-test sigstore by installing each of the distributions
# we've built in a fresh environment and using each to sign and
# verify for itself, using the ambient OIDC identity
for dist in dist/*; do
dist_base="$(basename "${dist}")"
python -m venv smoketest-env
./smoketest-env/bin/python -m pip install "${dist}"
# NOTE: signing artifacts currently go in a separate directory,
# to avoid confusing the package uploader (which otherwise tries
# to upload them to PyPI and fails). Future versions of twine
# and the gh-action-pypi-publish action should support these artifacts.
./smoketest-env/bin/python -m \
sigstore sign "${dist}" \
--output-signature smoketest-artifacts/"${dist_base}.sig" \
--output-certificate smoketest-artifacts/"${dist_base}.crt"
./smoketest-env/bin/python -m \
sigstore verify "${dist}" \
--cert "smoketest-artifacts/${dist_base}.crt" \
--signature "smoketest-artifacts/${dist_base}.sig" \
--cert-oidc-issuer https://token.actions.githubusercontent.com
rm -rf smoketest-env
done
- name: Generate hashes for provenance
shell: bash
id: hash
run: |
# sha256sum generates sha256 hash for all artifacts.
# base64 -w0 encodes to base64 and outputs on a single line.
# sha256sum artifact1 artifact2 ... | base64 -w0
echo "::set-output name=hashes::$(sha256sum ./dist/* | base64 -w0)"
- name: Upload built packages
uses: actions/upload-artifact@v3
with:
name: built-packages
path: ./dist/
if-no-files-found: warn

- name: Upload smoketest-artifacts
uses: actions/upload-artifact@v3
with:
name: smoketest-artifacts
path: smoketest-artifacts/
if-no-files-found: warn

generate-provenance:
needs: [build]
name: Generate build provenance
permissions:
actions: read # To read the workflow path.
id-token: write # To sign the provenance.
contents: write # To add assets to a release.
# Currently this action needs to be referred by tag. More details at:
# https://github.com/slsa-framework/slsa-github-generator#verification-of-provenance
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v1.2.0
with:
attestation-name: provenance-sigstore-${{ github.event.release.tag_name }}.intoto.jsonl
base64-subjects: "${{ needs.build.outputs.hashes }}"
upload-assets: true

release-pypi:
needs: [build, generate-provenance]
runs-on: ubuntu-latest
permissions: {}
steps:
- name: Download artifacts diretories # goes to current working directory
uses: actions/download-artifact@v3

- name: publish
uses: pypa/gh-action-pypi-publish@717ba43cfbb0387f6ce311b169a825772f54d295
with:
user: __token__
password: ${{ secrets.PYPI_TOKEN }}
packages_dir: built-packages/

release-github:
needs: [build, generate-provenance]
runs-on: ubuntu-latest
permissions:
# Needed to upload release assets.
contents: write
steps:
- uses: actions/checkout@d171c3b028d844f2bf14e9fdec0c58114451e4bf

- uses: actions/setup-python@7f80679172b057fc5e90d70d197929d454754a5a

- name: deps
run: python -m pip install -U build

- name: build
run: python -m build

- name: sign
run: |
mkdir -p smoketest-artifacts
# we smoke-test sigstore by installing each of the distributions
# we've built in a fresh environment and using each to sign and
# verify for itself, using the ambient OIDC identity
for dist in dist/*; do
dist_base="$(basename "${dist}")"
python -m venv smoketest-env
./smoketest-env/bin/python -m pip install "${dist}"
# NOTE: signing artifacts currently go in a separate directory,
# to avoid confusing the package uploader (which otherwise tries
# to upload them to PyPI and fails). Future versions of twine
# and the gh-action-pypi-publish action should support these artifacts.
./smoketest-env/bin/python -m \
sigstore sign "${dist}" \
--output-signature smoketest-artifacts/"${dist_base}.sig" \
--output-certificate smoketest-artifacts/"${dist_base}.crt"
./smoketest-env/bin/python -m \
sigstore verify "${dist}" \
--cert "smoketest-artifacts/${dist_base}.crt" \
--signature "smoketest-artifacts/${dist_base}.sig" \
--cert-oidc-issuer https://token.actions.githubusercontent.com \
rm -rf smoketest-env
done
- name: publish
uses: pypa/gh-action-pypi-publish@717ba43cfbb0387f6ce311b169a825772f54d295
with:
user: __token__
password: ${{ secrets.PYPI_TOKEN }}

- name: upload artifacts to github
# Confusingly, this action also supports updating releases, not
# just creating them. This is what we want here, since we've manually
# created the release that triggered the action.
uses: softprops/action-gh-release@v1
with:
# dist/ contains the built packages, which smoketest-artifacts/
# contains the signatures and certificates.
files: |
dist/*
smoketest-artifacts/*
- name: Download artifacts diretories # goes to current working directory
uses: actions/download-artifact@v3

- name: Upload artifacts to github
# Confusingly, this action also supports updating releases, not
# just creating them. This is what we want here, since we've manually
# created the release that triggered the action.
uses: softprops/action-gh-release@v1
with:
# smoketest-artifacts/ contains the signatures and certificates.
files: |
built-packages/*
smoketest-artifacts/*
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ sigstore-python
![CI](https://github.com/sigstore/sigstore-python/workflows/CI/badge.svg)
[![PyPI version](https://badge.fury.io/py/sigstore.svg)](https://pypi.org/project/sigstore)
[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/sigstore/sigstore-python/badge)](https://api.securityscorecards.dev/projects/github.com/sigstore/sigstore-python)
[![SLSA](https://slsa.dev/images/gh-badge-level3.svg)](https://slsa.dev/)
<!--- @end-badges@ --->

⚠️ This project is not ready for general-purpose use! ⚠️
Expand Down Expand Up @@ -305,6 +306,13 @@ Everyone interacting with this project is expected to follow the
Should you discover any security issues, please refer to sigstore's [security
process](https://github.com/sigstore/.github/blob/main/SECURITY.md).

### SLSA Provenance
This project emits a SLSA provenance on its release! This enables you to verify the integrity
of the downloaded artifacts and ensured that the binary's code really comes from this source code.

To do so, please follow the instructions [here](https://github.com/slsa-framework/slsa-github-generator#verification-of-provenance).


## Info

`sigstore-python` is developed as part of the [`sigstore`](https://sigstore.dev) project.
Expand Down

0 comments on commit e5acd69

Please sign in to comment.