Skip to content

Commit f02a228

Browse files
committed
Add SLSA Source Provenance Attestation via slsa-source-corroborator
Closes gap C-037. Publishes a Source Provenance Attestation (predicate type https://slsa.dev/source_provenance/v1) on every push to main via slsa-framework/slsa-source-corroborator, proving that branch protection, mandatory code review, and ancestry enforcement (C-038) were applied to each commit.
1 parent 2c73c25 commit f02a228

4 files changed

Lines changed: 97 additions & 48 deletions

File tree

.github/workflows/source-provenance.yml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,37 @@ permissions:
1010
contents: read
1111

1212
jobs:
13+
attest-source-governance:
14+
name: Attest source governance (SLSA Source Track)
15+
runs-on: ubuntu-latest
16+
if: github.ref == 'refs/heads/main'
17+
permissions:
18+
contents: read
19+
attestations: write
20+
id-token: write
21+
22+
steps:
23+
- name: "Harden the runner (Block egress traffic: Only allow calls to allowed endpoints)"
24+
uses: step-security/harden-runner@ab7a9404c0f3da075243ca237b5fac12c98deaa5 # v2.19.3
25+
with:
26+
egress-policy: block
27+
allowed-endpoints: >+
28+
github.com:443
29+
api.github.com:443
30+
uploads.github.com:443
31+
fulcio.sigstore.dev:443
32+
rekor.sigstore.dev:443
33+
tuf-repo-cdn.sigstore.dev:443
34+
*.blob.core.windows.net:443
35+
36+
- name: Checkout repository
37+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
38+
with:
39+
persist-credentials: false
40+
41+
- name: Attest source governance (SLSA Source Track)
42+
uses: slsa-framework/slsa-source-corroborator@v0.1.0
43+
1344
attest-source:
1445
name: Generate source provenance
1546
runs-on: ubuntu-latest

doc/explanation/threat_model_supply_chain.rst

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ Actors
131131
- External contributor submitting pull requests, or an adversary attempting supply-chain manipulation (malicious PR, action-poisoning, or MITM on CI network traffic). Code review, branch protection, and SHA-pinned Actions are the primary controls at this boundary.
132132

133133
* - Consumer / End User
134-
- Installs dfetch from PyPI (``pip install dfetch``) or from binary installer, then invokes it on a developer workstation or in a CI pipeline. Can verify four complementary attestation types using ``gh attestation verify`` as documented in the release-integrity guide (see C-026, C-039, C-040): SBOM attestation on the PyPI wheel; SBOM, SLSA build provenance, and VSA on binary installers; SLSA build provenance and in-toto test result attestation on the source archive.
134+
- Installs dfetch from PyPI (``pip install dfetch``) or from binary installer, then invokes it on a developer workstation or in a CI pipeline. Can verify five complementary attestation types using ``gh attestation verify`` as documented in the release-integrity guide (see C-026, C-037, C-039, C-040): SBOM attestation on the PyPI wheel; SBOM, SLSA build provenance, and VSA on binary installers; SLSA build provenance, in-toto test result attestation, and SLSA Source Provenance Attestation on the source archive and main-branch commits.
135135

136136

137137
Boundaries
@@ -319,6 +319,12 @@ Controls
319319
- Tampering
320320
- DFT-28
321321
- Mitigates: ccache and clcache keys in ``build.yml`` include ``${{ github.ref_name }}`` so cache entries written by a pull-request build are scoped to the PR's branch name and cannot be restored by a release-tag build. A malicious fork PR step cannot pre-populate a cache slot that the release workflow will restore, because the release tag name is not reachable from the PR's branch ref. ``.github/workflows/build.yml``
322+
* - C-037
323+
- SLSA Source Provenance Attestation of repository governance controls
324+
- Low
325+
- Repudiation, Spoofing
326+
- DFT-31
327+
- Mitigates: Source Provenance Attestations are published via ``slsa-framework/slsa-source-corroborator`` on every push to ``main``. These attestations prove the specific source-level governance controls applied on each commit: branch protection, mandatory code review, and ancestry enforcement (C-038). Predicate type ``https://slsa.dev/source_provenance/v1`` is signed by GitHub Actions via Sigstore and stored in the GitHub Attestation registry. Consumers can verify using ``gh attestation verify`` with ``--predicate-type https://slsa.dev/source_provenance/v1`` and ``--cert-identity`` pinned to ``source-provenance.yml@refs/heads/main``. ``.github/workflows/source-provenance.yml``
322328
* - C-038
323329
- Ancestry enforcement on dfetch main branch
324330
- Low
@@ -330,7 +336,7 @@ Controls
330336
- High
331337
- Spoofing, Tampering, Repudiation
332338
- DFT-31, DFT-25
333-
- Mitigates: Every dfetch release ships two complementary Sigstore-signed attestations that together let consumers trace the full source → binary chain. SLSA build provenance (``source-provenance.yml``) on the source archive proves the archive was produced from the official tagged commit by the official CI workflow, recording the exact inputs used at build time. A Verification Summary Attestation (VSA, ``build.yml``) on binary installers records that the source archive was itself attested and verified before the binary was produced, linking source-level trust to the installed package. Both are signed by GitHub Actions via Sigstore and can be verified using ``gh attestation verify`` with ``--predicate-type https://slsa.dev/provenance/v1`` or ``--predicate-type https://slsa.dev/verification_summary/v1`` respectively. This substantially mitigates DFT-31 (consumers now have attestations to verify against) and DFT-25 (forged provenance would fail Sigstore verification). The remaining gap (no formal SLSA Source Level attestation of governance controls) is tracked in C-037. ``doc/howto/verify-integrity.rst``
339+
- Mitigates: Every dfetch release ships two complementary Sigstore-signed attestations that together let consumers trace the full source → binary chain. SLSA build provenance (``source-provenance.yml``) on the source archive proves the archive was produced from the official tagged commit by the official CI workflow, recording the exact inputs used at build time. A Verification Summary Attestation (VSA, ``build.yml``) on binary installers records that the source archive was itself attested and verified before the binary was produced, linking source-level trust to the installed package. Both are signed by GitHub Actions via Sigstore and can be verified using ``gh attestation verify`` with ``--predicate-type https://slsa.dev/provenance/v1`` or ``--predicate-type https://slsa.dev/verification_summary/v1`` respectively. This substantially mitigates DFT-31 (consumers now have attestations to verify against) and DFT-25 (forged provenance would fail Sigstore verification). The formal SLSA Source Level attestation of governance controls is addressed by C-037. ``doc/howto/verify-integrity.rst``
334340
* - C-040
335341
- Test result attestation on source archive
336342
- Medium
@@ -358,12 +364,6 @@ Gaps
358364
- Tampering
359365
- DFT-10
360366
- Affects: ``pip install .`` and ``pip install --upgrade pip build`` in CI do not use ``--require-hashes``. A compromised PyPI mirror can substitute malicious build tooling.
361-
* - C-037
362-
- No formal SLSA Source Level attestation of repository governance controls
363-
- Low
364-
- Repudiation, Spoofing
365-
- DFT-31
366-
- Affects: dfetch now publishes SLSA build provenance for source archives, VSAs for binary installers (C-039), and in-toto test result attestations (C-040). These close the 'no attestation to verify against' concern: consumers can cryptographically verify the artifact chain. The remaining, narrower gap is that dfetch does not publish formal SLSA Source Provenance Attestations generated by a SLSA Source Generator — attestations that would prove the specific source-level governance controls applied on each commit (branch protection, mandatory code review, ancestry enforcement). C-038 establishes that ancestry enforcement is in place and C-026 documents what consumers can verify; the gap is in machine-readable, verifiable proof of those governance controls rather than the controls themselves. Risk is Low: the missing piece is a formal SLSA Source Level certificate (per the SLSA Source Track spec) rather than the absence of any assurance. Fix: publish Source Provenance Attestations via ``slsa-framework/slsa-source-corroborator`` or equivalent on each push to main.
367367
* - C-025
368368
- No hardware-token MFA for release operations
369369
- High

doc/howto/verify-integrity.rst

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,32 @@ Every dfetch release, and every commit merged to ``main``, has cryptographic
55
attestations signed by GitHub Actions and anchored in
66
`Sigstore <https://www.sigstore.dev/>`_, all published in the
77
`attestation registry <https://github.com/dfetch-org/dfetch/attestations>`_.
8-
There are four complementary kinds:
8+
There are five complementary kinds, in pipeline order from source to artifact:
99

10+
- **Source Provenance Attestation** (SLSA Source Track) — answers *"did this commit
11+
meet governance requirements?"*: proves that branch protection, mandatory code
12+
review, and ancestry enforcement were in place when the commit was merged to
13+
``main``.
14+
- **Test result attestation** (in-toto) — answers *"did the test suite pass?"*:
15+
records that the full CI test suite ran against this exact source archive and every
16+
check passed, before any binary was produced.
1017
- **SLSA build provenance** — answers *"where did this come from?"*: proves the
1118
artifact was produced from the official source commit by the official CI
1219
workflow, and records the exact inputs used at build time.
1320
- **SBOM attestation** (CycloneDX) — answers *"what is inside it?"*: lists every
1421
dependency bundled in the package so you can audit its composition.
15-
- **Verification Summary Attestation (VSA)** — answers *"was the source
16-
independently verified?"*: records that the source archive for this commit was
17-
attested and verified before the binary was produced, linking source-level
18-
trust to the binary package.
19-
- **Test result attestation** (in-toto) — answers *"did the source pass its tests?"*:
20-
records that the full CI test suite ran against this exact source archive and every
21-
check passed, before any binary was produced.
22+
- **Verification Summary Attestation (VSA)** — answers *"was the full chain
23+
verified?"*: records that the source archive was itself attested and verified
24+
before the binary was produced, linking source-level trust to the artifact.
2225

2326
Binary installers have **build provenance, SBOM, and VSA** attestations when source
2427
provenance verification passes (signed by ``build.yml``).
2528
Python packages installed from PyPI have an **SBOM attestation only** (signed by
2629
``python-publish.yml``).
2730
The source archive has a **SLSA build provenance** attestation (signed by
2831
``source-provenance.yml``) and a **test result attestation** (signed by ``test.yml``).
32+
Every commit merged to ``main`` has a **SLSA Source Provenance Attestation** proving
33+
branch governance controls were applied (signed by ``source-provenance.yml``).
2934

3035
To verify, use the `GitHub CLI <https://cli.github.com/>`_. Pass
3136
``--predicate-type`` to target one kind specifically; omit it to accept any.
@@ -201,6 +206,24 @@ any binary was produced):
201206
--cert-identity https://github.com/dfetch-org/dfetch/.github/workflows/test.yml@refs/tags/v<version> \
202207
--cert-oidc-issuer https://token.actions.githubusercontent.com
203208
209+
**Source governance — verify SLSA Source Provenance Attestation:**
210+
211+
Every commit merged to ``main`` has a Source Provenance Attestation proving that
212+
branch protection, mandatory code review, and ancestry enforcement were in place
213+
when the commit landed. These attestations are published by
214+
``slsa-framework/slsa-source-corroborator`` and stored in the
215+
`attestation registry <https://github.com/dfetch-org/dfetch/attestations>`_.
216+
Replace ``<sha>`` with the 40-character commit SHA you want to verify:
217+
218+
.. code-block:: bash
219+
220+
$ gh attestation verify \
221+
"git+https://github.com/dfetch-org/dfetch@<sha>" \
222+
--repo dfetch-org/dfetch \
223+
--predicate-type https://slsa.dev/source_provenance/v1 \
224+
--cert-identity https://github.com/dfetch-org/dfetch/.github/workflows/source-provenance.yml@refs/heads/main \
225+
--cert-oidc-issuer https://token.actions.githubusercontent.com
226+
204227
See `GitHub artifact attestations`_ for details.
205228

206229
.. note::

security/tm_supply_chain.py

Lines changed: 27 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,11 @@ def _make_sc_actors_and_entities(
9898
consumer.description = (
9999
"Installs dfetch from PyPI (``pip install dfetch``) or from binary installer, "
100100
"then invokes it on a developer workstation or in a CI pipeline. "
101-
"Can verify four complementary attestation types using ``gh attestation verify`` as "
102-
"documented in the release-integrity guide (see C-026, C-039, C-040): "
101+
"Can verify five complementary attestation types using ``gh attestation verify`` as "
102+
"documented in the release-integrity guide (see C-026, C-037, C-039, C-040): "
103103
"SBOM attestation on the PyPI wheel; SBOM, SLSA build provenance, and VSA on binary "
104-
"installers; SLSA build provenance and in-toto test result attestation on the source archive."
104+
"installers; SLSA build provenance, in-toto test result attestation, and SLSA Source "
105+
"Provenance Attestation on the source archive and main-branch commits."
105106
)
106107
gh_repository = ExternalEntity("A-01: GitHub Repository")
107108
gh_repository.inBoundary = b_github
@@ -658,6 +659,28 @@ def build_model() -> TM:
658659
"the PR's branch ref."
659660
),
660661
),
662+
Control(
663+
id="C-037",
664+
name="SLSA Source Provenance Attestation of repository governance controls",
665+
assets=["A-01"],
666+
threats=["DFT-31"],
667+
reference=".github/workflows/source-provenance.yml",
668+
assessment=ControlAssessment(
669+
status="implemented", risk="Low", stride=["Repudiation", "Spoofing"]
670+
),
671+
description=(
672+
"Source Provenance Attestations are published via "
673+
"``slsa-framework/slsa-source-corroborator`` on every push to ``main``. "
674+
"These attestations prove the specific source-level governance controls "
675+
"applied on each commit: branch protection, mandatory code review, and "
676+
"ancestry enforcement (C-038). "
677+
"Predicate type ``https://slsa.dev/source_provenance/v1`` is signed by "
678+
"GitHub Actions via Sigstore and stored in the GitHub Attestation registry. "
679+
"Consumers can verify using ``gh attestation verify`` with "
680+
"``--predicate-type https://slsa.dev/source_provenance/v1`` and "
681+
"``--cert-identity`` pinned to ``source-provenance.yml@refs/heads/main``."
682+
),
683+
),
661684
Control(
662685
id="C-038",
663686
name="Ancestry enforcement on dfetch main branch",
@@ -701,8 +724,7 @@ def build_model() -> TM:
701724
"or ``--predicate-type https://slsa.dev/verification_summary/v1`` respectively. "
702725
"This substantially mitigates DFT-31 (consumers now have attestations to verify "
703726
"against) and DFT-25 (forged provenance would fail Sigstore verification). "
704-
"The remaining gap (no formal SLSA Source Level attestation of governance "
705-
"controls) is tracked in C-037."
727+
"The formal SLSA Source Level attestation of governance controls is addressed by C-037."
706728
),
707729
),
708730
Control(
@@ -742,33 +764,6 @@ def build_model() -> TM:
742764
"malicious build tooling."
743765
),
744766
),
745-
Control(
746-
id="C-037",
747-
name="No formal SLSA Source Level attestation of repository governance controls",
748-
assets=["A-01"],
749-
threats=["DFT-31"],
750-
assessment=ControlAssessment(
751-
status="gap", risk="Low", stride=["Repudiation", "Spoofing"]
752-
),
753-
description=(
754-
"dfetch now publishes SLSA build provenance for source archives, VSAs for "
755-
"binary installers (C-039), and in-toto test result attestations (C-040). "
756-
"These close the 'no attestation to verify against' concern: consumers can "
757-
"cryptographically verify the artifact chain. "
758-
"The remaining, narrower gap is that dfetch does not publish formal SLSA "
759-
"Source Provenance Attestations generated by a SLSA Source Generator — "
760-
"attestations that would prove the specific source-level governance controls "
761-
"applied on each commit (branch protection, mandatory code review, ancestry "
762-
"enforcement). "
763-
"C-038 establishes that ancestry enforcement is in place and C-026 documents "
764-
"what consumers can verify; the gap is in machine-readable, verifiable "
765-
"proof of those governance controls rather than the controls themselves. "
766-
"Risk is Low: the missing piece is a formal SLSA Source Level certificate "
767-
"(per the SLSA Source Track spec) rather than the absence of any assurance. "
768-
"Fix: publish Source Provenance Attestations via "
769-
"``slsa-framework/slsa-source-corroborator`` or equivalent on each push to main."
770-
),
771-
),
772767
Control(
773768
id="C-025",
774769
name="No hardware-token MFA for release operations",

0 commit comments

Comments
 (0)