Skip to content

Commit ade9f9d

Browse files
claudespoorcc
authored andcommitted
Add SLSA source provenance workflow and VSA integration
New source-provenance.yml workflow runs on push to main, creates a deterministic git archive, and attests it with SLSA build provenance.
1 parent 08cdf37 commit ade9f9d

4 files changed

Lines changed: 162 additions & 2 deletions

File tree

.github/workflows/build.yml

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,25 @@ jobs:
105105
restore-keys: |
106106
${{ github.job }}-${{ matrix.platform }}-${{ github.ref_name }}-
107107
108+
- name: Download canonical source archive
109+
id: download-source
110+
if: github.event_name != 'pull_request'
111+
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v5
112+
with:
113+
name: source-archive
114+
- name: Verify source provenance
115+
id: verify-source
116+
if: steps.download-source.outcome == 'success'
117+
shell: bash
118+
env:
119+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
120+
run: |
121+
gh attestation verify source.tar.gz \
122+
--repo "${{ github.repository }}" \
123+
--predicate-type https://slsa.dev/provenance/v1 \
124+
--cert-identity-regex "^https://github\.com/${{ github.repository }}/\.github/workflows/source-provenance\.yml@refs/(heads/main|tags/[0-9]+\.[0-9]+\.[0-9]+)$" \
125+
--cert-oidc-issuer https://token.actions.githubusercontent.com
126+
108127
- name: Create sbom, binary & package
109128
env:
110129
CCACHE_BASEDIR: ${{ github.workspace }}
@@ -175,6 +194,35 @@ jobs:
175194
--cert-identity "https://github.com/${{ github.repository }}/.github/workflows/build.yml@${{ github.ref }}" \
176195
--cert-oidc-issuer https://token.actions.githubusercontent.com
177196
done
197+
- name: Generate VSA predicate
198+
if: steps.verify-source.outcome == 'success'
199+
shell: bash
200+
run: |
201+
jq -n \
202+
--arg verifier "https://github.com/${{ github.repository }}/.github/workflows/build.yml@${{ github.ref }}" \
203+
--arg time "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
204+
--arg resource "pkg:github/${{ github.repository }}@${{ github.sha }}" \
205+
--arg policy "https://github.com/${{ github.repository }}/.github/workflows/source-provenance.yml@refs/heads/main" \
206+
'{
207+
verifier: { id: $verifier },
208+
timeVerified: $time,
209+
resourceUri: $resource,
210+
policy: { uri: $policy },
211+
inputAttestations: [],
212+
verificationResult: "PASSED",
213+
verifiedLevels: ["SLSA_SOURCE_LEVEL_3"]
214+
}' > vsa-predicate.json
215+
- name: Attest build artifacts with VSA
216+
if: steps.verify-source.outcome == 'success'
217+
uses: actions/attest@59d89421af93a897026c735860bf21b6eb4f7b26 # v4.1.0
218+
with:
219+
subject-path: |
220+
build/dfetch-package/*.deb
221+
build/dfetch-package/*.rpm
222+
build/dfetch-package/*.pkg
223+
build/dfetch-package/*.msi
224+
predicate-type: 'https://slsa.dev/verification_summary/v1'
225+
predicate-path: vsa-predicate.json
178226
- name: Store the distribution packages
179227
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
180228
with:

.github/workflows/ci.yml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,17 @@ jobs:
2222
contents: write
2323
security-events: write
2424

25+
source-provenance:
26+
if: github.event_name != 'pull_request'
27+
uses: ./.github/workflows/source-provenance.yml
28+
permissions:
29+
contents: read
30+
attestations: write
31+
id-token: write
32+
2533
build:
26-
needs: prep-release
34+
needs: [prep-release, source-provenance]
35+
if: needs.prep-release.result != 'failure' && needs.source-provenance.result != 'failure'
2736
uses: ./.github/workflows/build.yml
2837
permissions:
2938
contents: write
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
name: Source Provenance
2+
3+
on:
4+
push:
5+
branches: ["main"]
6+
tags: ['[0-9]*.[0-9]*.[0-9]*']
7+
workflow_call:
8+
9+
permissions:
10+
contents: read
11+
12+
jobs:
13+
attest-source:
14+
name: Generate source provenance
15+
runs-on: ubuntu-latest
16+
permissions:
17+
contents: read
18+
attestations: write
19+
id-token: write
20+
21+
steps:
22+
- name: "Harden the runner (Block egress traffic: Only allow calls to allowed endpoints)"
23+
uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1
24+
with:
25+
egress-policy: block
26+
allowed-endpoints: >+
27+
github.com:443
28+
api.github.com:443
29+
uploads.github.com:443
30+
fulcio.sigstore.dev:443
31+
rekor.sigstore.dev:443
32+
tuf-repo-cdn.sigstore.dev:443
33+
*.blob.core.windows.net:443
34+
35+
- name: Checkout repository
36+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
37+
with:
38+
persist-credentials: false
39+
40+
- name: Generate source archive
41+
run: git archive HEAD --format=tar.gz -o source.tar.gz
42+
43+
- name: Attest source provenance
44+
uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0
45+
with:
46+
subject-path: source.tar.gz
47+
48+
- name: Verify source provenance
49+
env:
50+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
51+
run: |
52+
gh attestation verify source.tar.gz \
53+
--repo "${{ github.repository }}" \
54+
--predicate-type https://slsa.dev/provenance/v1 \
55+
--cert-identity-regex "^https://github\.com/${{ github.repository }}/\.github/workflows/source-provenance\.yml@refs/(heads/main|tags/[0-9]+\.[0-9]+\.[0-9]+)$" \
56+
--cert-oidc-issuer https://token.actions.githubusercontent.com
57+
58+
- name: Upload source archive
59+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
60+
with:
61+
name: source-archive
62+
path: source.tar.gz

doc/tutorials/installation.rst

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,13 @@ complementary kinds:
100100
workflow, and records the exact inputs used at build time.
101101
- **SBOM attestation** (CycloneDX) — answers *"what is inside it?"*: lists every
102102
dependency bundled in the package so you can audit its composition.
103+
- **Verification Summary Attestation (VSA)** — answers *"was the source
104+
independently verified?"*: records that the source archive for this commit was
105+
attested and verified before the binary was produced, linking source-level
106+
trust to the binary package.
103107

104-
Binary installers carry **both** kinds of attestation (signed by ``build.yml``).
108+
Binary installers carry **all three** kinds of attestation when source
109+
provenance verification passes (signed by ``build.yml``).
105110
Python packages installed from PyPI carry an **SBOM attestation only** (signed by
106111
``python-publish.yml``).
107112

@@ -132,6 +137,16 @@ To verify, use the `GitHub CLI <https://cli.github.com/>`_. Pass
132137
--cert-identity https://github.com/dfetch-org/dfetch/.github/workflows/build.yml@refs/tags/v<version> \
133138
--cert-oidc-issuer https://token.actions.githubusercontent.com
134139
140+
**Binary installer — verify source provenance summary (VSA):**
141+
142+
.. code-block:: bash
143+
144+
$ gh attestation verify dfetch-<version>-nix.deb \
145+
--repo dfetch-org/dfetch \
146+
--predicate-type https://slsa.dev/verification_summary/v1 \
147+
--cert-identity https://github.com/dfetch-org/dfetch/.github/workflows/build.yml@refs/tags/v<version> \
148+
--cert-oidc-issuer https://token.actions.githubusercontent.com
149+
135150
**pip / PyPI wheel — verify SBOM attestation:**
136151

137152
.. code-block:: bash
@@ -164,6 +179,16 @@ To verify, use the `GitHub CLI <https://cli.github.com/>`_. Pass
164179
--cert-identity https://github.com/dfetch-org/dfetch/.github/workflows/build.yml@refs/tags/v<version> \
165180
--cert-oidc-issuer https://token.actions.githubusercontent.com
166181
182+
**Binary installer — verify source provenance summary (VSA):**
183+
184+
.. code-block:: bash
185+
186+
$ gh attestation verify dfetch-<version>-osx.pkg \
187+
--repo dfetch-org/dfetch \
188+
--predicate-type https://slsa.dev/verification_summary/v1 \
189+
--cert-identity https://github.com/dfetch-org/dfetch/.github/workflows/build.yml@refs/tags/v<version> \
190+
--cert-oidc-issuer https://token.actions.githubusercontent.com
191+
167192
**pip / PyPI wheel — verify SBOM attestation:**
168193

169194
.. code-block:: bash
@@ -196,6 +221,16 @@ To verify, use the `GitHub CLI <https://cli.github.com/>`_. Pass
196221
--cert-identity https://github.com/dfetch-org/dfetch/.github/workflows/build.yml@refs/tags/v<version> `
197222
--cert-oidc-issuer https://token.actions.githubusercontent.com
198223
224+
**Binary installer — verify source provenance summary (VSA):**
225+
226+
.. code-block:: powershell
227+
228+
> gh attestation verify dfetch-<version>-win.msi `
229+
--repo dfetch-org/dfetch `
230+
--predicate-type https://slsa.dev/verification_summary/v1 `
231+
--cert-identity https://github.com/dfetch-org/dfetch/.github/workflows/build.yml@refs/tags/v<version> `
232+
--cert-oidc-issuer https://token.actions.githubusercontent.com
233+
199234
**pip / PyPI wheel — verify SBOM attestation:**
200235

201236
.. code-block:: powershell
@@ -208,6 +243,12 @@ To verify, use the `GitHub CLI <https://cli.github.com/>`_. Pass
208243
209244
See `GitHub artifact attestations`_ for details.
210245

246+
.. note::
247+
248+
The VSA is present on releases built from a commit whose source provenance
249+
was verified. If the ``verification_summary`` attestation is absent for a
250+
release, fall back to checking build provenance and SBOM independently.
251+
211252
.. note::
212253

213254
``--cert-oidc-issuer https://token.actions.githubusercontent.com`` pins

0 commit comments

Comments
 (0)