diff --git a/.github/workflows/source-provenance.yml b/.github/workflows/source-provenance.yml
index 8273bbcd..c7bbfb5e 100644
--- a/.github/workflows/source-provenance.yml
+++ b/.github/workflows/source-provenance.yml
@@ -10,6 +10,37 @@ permissions:
contents: read
jobs:
+ attest-source-governance:
+ name: Attest source governance (SLSA Source Track)
+ runs-on: ubuntu-latest
+ if: github.ref == 'refs/heads/main'
+ permissions:
+ contents: read
+ attestations: write
+ id-token: write
+
+ steps:
+ - name: "Harden the runner (Block egress traffic: Only allow calls to allowed endpoints)"
+ uses: step-security/harden-runner@ab7a9404c0f3da075243ca237b5fac12c98deaa5 # v2.19.3
+ with:
+ egress-policy: block
+ allowed-endpoints: >+
+ github.com:443
+ api.github.com:443
+ uploads.github.com:443
+ fulcio.sigstore.dev:443
+ rekor.sigstore.dev:443
+ tuf-repo-cdn.sigstore.dev:443
+ *.blob.core.windows.net:443
+
+ - name: Checkout repository
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ persist-credentials: false
+
+ - name: Attest source governance (SLSA Source Track)
+ uses: slsa-framework/slsa-source-corroborator@v0.1.0
+
attest-source:
name: Generate source provenance
runs-on: ubuntu-latest
diff --git a/doc/explanation/threat_model_supply_chain.rst b/doc/explanation/threat_model_supply_chain.rst
index 2629b25d..dad2e28d 100644
--- a/doc/explanation/threat_model_supply_chain.rst
+++ b/doc/explanation/threat_model_supply_chain.rst
@@ -131,7 +131,7 @@ Actors
- 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.
* - Consumer / End User
- - 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.
+ - 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.
Boundaries
@@ -319,6 +319,12 @@ Controls
- Tampering
- DFT-28
- 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``
+ * - C-037
+ - SLSA Source Provenance Attestation of repository governance controls
+ - Low
+ - Repudiation, Spoofing
+ - DFT-31
+ - 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``
* - C-038
- Ancestry enforcement on dfetch main branch
- Low
@@ -330,7 +336,7 @@ Controls
- High
- Spoofing, Tampering, Repudiation
- DFT-31, DFT-25
- - 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``
+ - 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``
* - C-040
- Test result attestation on source archive
- Medium
@@ -358,12 +364,6 @@ Gaps
- Tampering
- DFT-10
- 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.
- * - C-037
- - No formal SLSA Source Level attestation of repository governance controls
- - Low
- - Repudiation, Spoofing
- - DFT-31
- - 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.
* - C-025
- No hardware-token MFA for release operations
- High
diff --git a/doc/howto/verify-integrity.rst b/doc/howto/verify-integrity.rst
index 07408995..c159681e 100644
--- a/doc/howto/verify-integrity.rst
+++ b/doc/howto/verify-integrity.rst
@@ -5,20 +5,23 @@ Every dfetch release, and every commit merged to ``main``, has cryptographic
attestations signed by GitHub Actions and anchored in
`Sigstore `_, all published in the
`attestation registry `_.
-There are four complementary kinds:
+There are five complementary kinds, in pipeline order from source to artifact:
+- **Source Provenance Attestation** (SLSA Source Track) — answers *"did this commit
+ meet governance requirements?"*: proves that branch protection, mandatory code
+ review, and ancestry enforcement were in place when the commit was merged to
+ ``main``.
+- **Test result attestation** (in-toto) — answers *"did the test suite pass?"*:
+ records that the full CI test suite ran against this exact source archive and every
+ check passed, before any binary was produced.
- **SLSA build provenance** — answers *"where did this come from?"*: proves the
artifact was produced from the official source commit by the official CI
workflow, and records the exact inputs used at build time.
- **SBOM attestation** (CycloneDX) — answers *"what is inside it?"*: lists every
dependency bundled in the package so you can audit its composition.
-- **Verification Summary Attestation (VSA)** — answers *"was the source
- independently verified?"*: records that the source archive for this commit was
- attested and verified before the binary was produced, linking source-level
- trust to the binary package.
-- **Test result attestation** (in-toto) — answers *"did the source pass its tests?"*:
- records that the full CI test suite ran against this exact source archive and every
- check passed, before any binary was produced.
+- **Verification Summary Attestation (VSA)** — answers *"was the full chain
+ verified?"*: records that the source archive was itself attested and verified
+ before the binary was produced, linking source-level trust to the artifact.
Binary installers have **build provenance, SBOM, and VSA** attestations when source
provenance verification passes (signed by ``build.yml``).
@@ -26,6 +29,8 @@ Python packages installed from PyPI have an **SBOM attestation only** (signed by
``python-publish.yml``).
The source archive has a **SLSA build provenance** attestation (signed by
``source-provenance.yml``) and a **test result attestation** (signed by ``test.yml``).
+Every commit merged to ``main`` has a **SLSA Source Provenance Attestation** proving
+branch governance controls were applied (signed by ``source-provenance.yml``).
To verify, use the `GitHub CLI `_. Pass
``--predicate-type`` to target one kind specifically; omit it to accept any.
@@ -201,6 +206,24 @@ any binary was produced):
--cert-identity https://github.com/dfetch-org/dfetch/.github/workflows/test.yml@refs/tags/v \
--cert-oidc-issuer https://token.actions.githubusercontent.com
+**Source governance — verify SLSA Source Provenance Attestation:**
+
+Every commit merged to ``main`` has a Source Provenance Attestation proving that
+branch protection, mandatory code review, and ancestry enforcement were in place
+when the commit landed. These attestations are published by
+``slsa-framework/slsa-source-corroborator`` and stored in the
+`attestation registry `_.
+Replace ```` with the 40-character commit SHA you want to verify:
+
+.. code-block:: bash
+
+ $ gh attestation verify \
+ "git+https://github.com/dfetch-org/dfetch@" \
+ --repo dfetch-org/dfetch \
+ --predicate-type https://slsa.dev/source_provenance/v1 \
+ --cert-identity https://github.com/dfetch-org/dfetch/.github/workflows/source-provenance.yml@refs/heads/main \
+ --cert-oidc-issuer https://token.actions.githubusercontent.com
+
See `GitHub artifact attestations`_ for details.
.. note::
diff --git a/security/tm_supply_chain.py b/security/tm_supply_chain.py
index c7493875..7ea7a9ba 100644
--- a/security/tm_supply_chain.py
+++ b/security/tm_supply_chain.py
@@ -98,10 +98,11 @@ def _make_sc_actors_and_entities(
consumer.description = (
"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): "
+ "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 and in-toto test result attestation on the source archive."
+ "installers; SLSA build provenance, in-toto test result attestation, and SLSA Source "
+ "Provenance Attestation on the source archive and main-branch commits."
)
gh_repository = ExternalEntity("A-01: GitHub Repository")
gh_repository.inBoundary = b_github
@@ -658,6 +659,28 @@ def build_model() -> TM:
"the PR's branch ref."
),
),
+ Control(
+ id="C-037",
+ name="SLSA Source Provenance Attestation of repository governance controls",
+ assets=["A-01"],
+ threats=["DFT-31"],
+ reference=".github/workflows/source-provenance.yml",
+ assessment=ControlAssessment(
+ status="implemented", risk="Low", stride=["Repudiation", "Spoofing"]
+ ),
+ description=(
+ "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``."
+ ),
+ ),
Control(
id="C-038",
name="Ancestry enforcement on dfetch main branch",
@@ -701,8 +724,7 @@ def build_model() -> TM:
"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."
+ "The formal SLSA Source Level attestation of governance controls is addressed by C-037."
),
),
Control(
@@ -742,33 +764,6 @@ def build_model() -> TM:
"malicious build tooling."
),
),
- Control(
- id="C-037",
- name="No formal SLSA Source Level attestation of repository governance controls",
- assets=["A-01"],
- threats=["DFT-31"],
- assessment=ControlAssessment(
- status="gap", risk="Low", stride=["Repudiation", "Spoofing"]
- ),
- description=(
- "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."
- ),
- ),
Control(
id="C-025",
name="No hardware-token MFA for release operations",