Skip to content

Commit 22ccdce

Browse files
authored
ci: switch from SLSA provenance to actions/attest with subject-path (#46)
1 parent 5388a0c commit 22ccdce

File tree

5 files changed

+44
-64
lines changed

5 files changed

+44
-64
lines changed

.github/actions/build/action.yml

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,9 @@
11
name: Build distribution files
22
description: 'Build distribution files'
3-
outputs:
4-
package-hashes:
5-
description: "base64-encoded sha256 hashes of distribution files"
6-
value: ${{ steps.package-hashes.outputs.package-hashes }}
73

84
runs:
95
using: composite
106
steps:
117
- name: Build distribution files
128
shell: bash
139
run: poetry build
14-
- name: Hash build files for provenance
15-
id: package-hashes
16-
shell: bash
17-
working-directory: ./dist
18-
run: |
19-
echo "package-hashes=$(sha256sum * | base64 -w0)" >> "$GITHUB_OUTPUT"

.github/workflows/manual-publish.yml

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@ jobs:
1414
permissions:
1515
id-token: write
1616
contents: read
17-
outputs:
18-
package-hashes: ${{ steps.build.outputs.package-hashes}}
17+
attestations: write
1918
steps:
2019
- uses: actions/checkout@v4
2120

@@ -33,21 +32,15 @@ jobs:
3332
ssm_parameter_pairs: '/production/common/releasing/pypi/token = PYPI_AUTH_TOKEN'
3433

3534
- uses: ./.github/actions/build
36-
id: build
3735

3836
- name: Publish package distributions to PyPI
39-
if: ${{ inputs.dry_run == false }}
37+
if: ${{ format('{0}', inputs.dry_run) == 'false' }}
4038
uses: pypa/gh-action-pypi-publish@release/v1
4139
with:
4240
password: ${{env.PYPI_AUTH_TOKEN}}
4341

44-
release-provenance:
45-
needs: [ 'build-publish' ]
46-
permissions:
47-
actions: read
48-
id-token: write
49-
contents: write
50-
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.0.0
51-
with:
52-
base64-subjects: "${{ needs.build-publish.outputs.package-hashes }}"
53-
upload-assets: ${{ !inputs.dry_run }}
42+
- name: Attest build provenance
43+
if: ${{ format('{0}', inputs.dry_run) == 'false' }}
44+
uses: actions/attest@v4
45+
with:
46+
subject-path: 'dist/*'

.github/workflows/release-please.yml

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,9 @@ jobs:
99
runs-on: ubuntu-latest
1010
permissions:
1111
id-token: write # Needed if using OIDC to get release secrets.
12-
contents: write # Contents and pull-requests are for release-please to make releases.
12+
contents: write # Needed for release-please to create releases.
1313
pull-requests: write
14-
outputs:
15-
release-created: ${{ steps.release.outputs.release_created }}
16-
upload-tag-name: ${{ steps.release.outputs.tag_name }}
17-
package-hashes: ${{ steps.build.outputs.package-hashes}}
14+
attestations: write
1815
steps:
1916
- uses: googleapis/release-please-action@v4
2017
id: release
@@ -41,7 +38,6 @@ jobs:
4138
ssm_parameter_pairs: '/production/common/releasing/pypi/token = PYPI_AUTH_TOKEN'
4239

4340
- uses: ./.github/actions/build
44-
id: build
4541
if: ${{ steps.release.outputs.releases_created == 'true' }}
4642

4743
- uses: ./.github/actions/build-docs
@@ -53,15 +49,8 @@ jobs:
5349
with:
5450
password: ${{env.PYPI_AUTH_TOKEN}}
5551

56-
release-provenance:
57-
needs: [ 'release-package' ]
58-
if: ${{ needs.release-package.outputs.release-created == 'true' }}
59-
permissions:
60-
actions: read
61-
id-token: write
62-
contents: write
63-
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.0.0
64-
with:
65-
base64-subjects: "${{ needs.release-package.outputs.package-hashes }}"
66-
upload-assets: true
67-
upload-tag-name: ${{ needs.release-package.outputs.upload-tag-name }}
52+
- name: Attest build provenance
53+
if: ${{ steps.release.outputs.releases_created == 'true' }}
54+
uses: actions/attest@v4
55+
with:
56+
subject-path: 'dist/*'

PROVENANCE.md

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
## Verifying SDK build provenance with the SLSA framework
1+
## Verifying SDK build provenance with GitHub artifact attestations
22

3-
LaunchDarkly uses the [SLSA framework](https://slsa.dev/spec/v1.0/about) (Supply-chain Levels for Software Artifacts) to help developers make their supply chain more secure by ensuring the authenticity and build integrity of our published SDK packages.
3+
LaunchDarkly uses [GitHub artifact attestations](https://docs.github.com/en/actions/security-for-github-actions/using-artifact-attestations/using-artifact-attestations-to-establish-provenance-for-builds) to help developers make their supply chain more secure by ensuring the authenticity and build integrity of our published SDK packages.
44

5-
As part of [SLSA requirements for level 3 compliance](https://slsa.dev/spec/v1.0/requirements), LaunchDarkly publishes provenance about our SDK package builds using [GitHub's generic SLSA3 provenance generator](https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/generic/README.md#generation-of-slsa3-provenance-for-arbitrary-projects) for distribution alongside our packages. These attestations are available for download from the GitHub release page for the release version under Assets > `multiple.intoto.jsonl`.
5+
LaunchDarkly publishes provenance about our SDK package builds using [GitHub's `actions/attest` action](https://github.com/actions/attest). These attestations are stored in GitHub's attestation API and can be verified using the [GitHub CLI](https://cli.github.com/).
66

7-
To verify SLSA provenance attestations, we recommend using [slsa-verifier](https://github.com/slsa-framework/slsa-verifier). Example usage for verifying a package is included below:
7+
To verify build provenance attestations, we recommend using the [GitHub CLI `attestation verify` command](https://cli.github.com/manual/gh_attestation_verify). Example usage for verifying SDK packages is included below:
88

99
<!-- x-release-please-start-version -->
1010
```
@@ -13,32 +13,37 @@ VERSION=1.2.0
1313
```
1414
<!-- x-release-please-end -->
1515

16-
1716
```
18-
# Download package from PyPi
17+
# Download package from PyPI
1918
$ pip download --only-binary=:all: launchdarkly-server-sdk-otel==${VERSION}
2019
21-
# Download provenance from Github release into same directory
22-
$ curl --location -O \
23-
https://github.com/launchdarkly/python-server-sdk-otel/releases/download/${VERSION}/multiple.intoto.jsonl
24-
25-
# Run slsa-verifier to verify provenance against package artifacts
26-
$ slsa-verifier verify-artifact \
27-
--provenance-path multiple.intoto.jsonl \
28-
--source-uri github.com/launchdarkly/python-server-sdk-otel \
29-
launchdarkly_server_sdk_otel-${VERSION}-py3-none-any.whl
20+
# Verify provenance using the GitHub CLI
21+
$ gh attestation verify launchdarkly_server_sdk_otel-${VERSION}-py3-none-any.whl --owner launchdarkly
3022
```
3123

3224
Below is a sample of expected output.
3325

3426
```
35-
Verified signature against tlog entry index 89939519 at URL: https://rekor.sigstore.dev/api/v1/log/entries/24296fb24b8ad77abb8d2f681b007c76a4fe9f89cd9574918683ac8bc87cd6834c5baa479ae5cb98
36-
Verified build using builder "https://github.com/slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@refs/tags/v1.10.0" at commit 984fc268df29918b03f51f2507146f66d8668d03
37-
Verifying artifact launchdarkly_server_sdk_otel-1.0.0-py3-none-any.whl: PASSED
27+
Loaded digest sha256:... for file://launchdarkly_server_sdk_otel-1.2.0-py3-none-any.whl
28+
Loaded 1 attestation from GitHub API
29+
30+
The following policy criteria will be enforced:
31+
- Predicate type must match:................ https://slsa.dev/provenance/v1
32+
- Source Repository Owner URI must match:... https://github.com/launchdarkly
33+
- Subject Alternative Name must match regex: (?i)^https://github.com/launchdarkly/
34+
- OIDC Issuer must match:................... https://token.actions.githubusercontent.com
35+
36+
✓ Verification succeeded!
37+
38+
The following 1 attestation matched the policy criteria
3839
39-
PASSED: Verified SLSA provenance
40+
- Attestation #1
41+
- Build repo:..... launchdarkly/python-server-sdk-otel
42+
- Build workflow:. .github/workflows/release-please.yml
43+
- Signer repo:.... launchdarkly/python-server-sdk-otel
44+
- Signer workflow: .github/workflows/release-please.yml
4045
```
4146

42-
Alternatively, to verify the provenance manually, the SLSA framework specifies [recommendations for verifying build artifacts](https://slsa.dev/spec/v1.0/verifying-artifacts) in their documentation.
47+
For more information, see [GitHub's documentation on verifying artifact attestations](https://docs.github.com/en/actions/security-for-github-actions/using-artifact-attestations/using-artifact-attestations-to-establish-provenance-for-builds#verifying-artifact-attestations-with-the-github-cli).
4348

44-
**Note:** These instructions do not apply when building our libraries from source.
49+
**Note:** These instructions do not apply when building our libraries from source.

release-please-config.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@
44
"release-type": "python",
55
"versioning": "default",
66
"include-v-in-tag": false,
7-
"extra-files": ["ldotel/__init__.py", "PROVENANCE.md"],
7+
"extra-files": [
8+
"ldotel/__init__.py",
9+
"PROVENANCE.md"
10+
],
811
"include-component-in-tag": false
912
}
1013
}

0 commit comments

Comments
 (0)