88# The GitHub release is created as a *draft* on purpose: the release notes want
99# a human. Publishing the draft is a single click in the GitHub UI.
1010#
11+ # The sdist gets a build provenance attestation, which says that this workflow
12+ # built it from this repository at this commit. GitHub serves it via the
13+ # attestations API, and the attestation bundle is attached to the release as a
14+ # .jsonl file as well, so that the sdist can also be verified against a file.
15+ #
1116# The upload to PyPI is a separate job only so that the "pypi" environment gate
1217# applies to the upload alone - that is the last chance to stop a release before
1318# the irreversible step.
4247 timeout-minutes : 30
4348
4449 permissions :
45- contents : write # to create the release
50+ contents : write # to create the release
51+ id-token : write # to attest the sdist
52+ attestations : write
4653
4754 steps :
4855 - uses : actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
@@ -97,6 +104,27 @@ jobs:
97104 "$RUNNER_TEMP/venv-sdist/bin/pytest" -v -rs tests/
98105 "$RUNNER_TEMP/venv-sdist/bin/borghash-demo"
99106
107+ - name : Attest the sdist provenance
108+ # Only after the checks above: an attestation for a sdist that does not
109+ # install would be a signed statement about a broken release.
110+ id : attest
111+ uses : actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2
112+ with :
113+ subject-path : ' dist/*.tar.gz'
114+
115+ - name : Keep the attestation bundle as a release asset
116+ # "gh attestation verify" fetches the attestation from the GitHub API by
117+ # default, but the bundle is tiny, so attach it to the release, too: then
118+ # the sdist can also be verified against that file, via "--bundle".
119+ env :
120+ BUNDLE : ${{ steps.attest.outputs.bundle-path }}
121+ TAG : ${{ github.ref_name }}
122+ run : |
123+ set -euxo pipefail
124+ # ".jsonl" is how "gh attestation download" names such a file.
125+ cp "$BUNDLE" "dist/borghash-$TAG.tar.gz.jsonl"
126+ ls -l dist/
127+
100128 - name : Create the draft release
101129 env :
102130 GH_TOKEN : ${{ github.token }}
@@ -115,17 +143,28 @@ jobs:
115143
116144 borghash is a Cython extension: installing the source distribution below
117145 needs a C compiler, but no Cython - the generated C files are included.
146+
147+ ### Verification
148+
149+ The sdist has a [build provenance attestation](https://github.com/borgbackup/borghash/attestations):
150+
151+ \`gh attestation verify --owner borgbackup borghash-$TAG.tar.gz\`
152+
153+ The attestation bundle is attached as \`borghash-$TAG.tar.gz.jsonl\`, too, for
154+ verifying against that file instead of the GitHub API:
155+
156+ \`gh attestation verify --owner borgbackup --bundle borghash-$TAG.tar.gz.jsonl borghash-$TAG.tar.gz\`
118157 EOF
119158 if gh release view "$TAG" > /dev/null 2>&1; then
120159 # a re-run of this job: keep the (possibly already edited) release and
121160 # just replace its assets.
122- gh release upload "$TAG" --clobber dist/*.tar.gz
161+ gh release upload "$TAG" --clobber dist/*.tar.gz dist/*.jsonl
123162 else
124163 gh release create "$TAG" \
125164 --draft $prerelease \
126165 --title "borghash $TAG" \
127166 --notes-file release-notes.md \
128- dist/*.tar.gz
167+ dist/*.tar.gz dist/*.jsonl
129168 fi
130169 gh release view "$TAG" --json isDraft,isPrerelease,assets
131170
0 commit comments