Skip to content

Commit f685598

Browse files
committed
Add test attestation
1 parent addfa6e commit f685598

3 files changed

Lines changed: 85 additions & 7 deletions

File tree

.github/workflows/ci.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,13 @@ jobs:
4949
security-events: write
5050

5151
test:
52+
needs: source-provenance
53+
if: needs.source-provenance.result != 'failure'
5254
uses: ./.github/workflows/test.yml
5355
permissions:
5456
contents: read
57+
attestations: write
58+
id-token: write
5559
secrets:
5660
CODACY_PROJECT_TOKEN: ${{ secrets.CODACY_PROJECT_TOKEN }}
5761

.github/workflows/test.yml

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ permissions:
1212
jobs:
1313
test:
1414
runs-on: ubuntu-latest
15+
permissions:
16+
contents: read
17+
attestations: write
18+
id-token: write
1519
steps:
1620
- name: "Harden the runner (Block egress traffic: Only allow calls to allowed endpoints)"
1721
uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1
@@ -48,6 +52,12 @@ jobs:
4852
security.ubuntu.com:443
4953
svn.code.sf.net:3690
5054
svn.code.sf.net:443
55+
api.github.com:443
56+
uploads.github.com:443
57+
fulcio.sigstore.dev:443
58+
rekor.sigstore.dev:443
59+
tuf-repo-cdn.sigstore.dev:443
60+
*.blob.core.windows.net:443
5161
5262
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
5363
with:
@@ -81,8 +91,10 @@ jobs:
8191
- run: pydocstyle dfetch # Checks doc strings
8292
- run: bandit -r dfetch # Checks security issues
8393
- run: xenon -b B -m A -a A dfetch # Check code quality
84-
- run: pytest --cov=dfetch tests # Run tests
85-
- run: coverage run --source=dfetch --append -m behave features # Run features tests
94+
- id: pytest
95+
run: pytest --cov=dfetch tests # Run tests
96+
- id: behave
97+
run: coverage run --source=dfetch --append -m behave features # Run features tests
8698
- run: coverage xml -o coverage.xml # Create XML report
8799
- run: pyroma --directory --min=10 . # Check pyproject
88100
- run: find dfetch -name "*.py" | xargs pyupgrade --py310-plus # Check syntax
@@ -96,3 +108,45 @@ jobs:
96108
env:
97109
CODACY_PROJECT_TOKEN: ${{ secrets.CODACY_PROJECT_TOKEN }}
98110
if: "${{ (!!env.CODACY_PROJECT_TOKEN) }}"
111+
112+
- name: Download canonical source archive
113+
id: download-source
114+
if: github.event_name != 'pull_request'
115+
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v5
116+
with:
117+
name: source-archive
118+
119+
- name: Generate test result predicate
120+
if: steps.download-source.outcome == 'success'
121+
run: |
122+
if [[ "${{ steps.pytest.outcome }}" == "success" && "${{ steps.behave.outcome }}" == "success" ]]; then
123+
tests_result="PASSED"
124+
else
125+
tests_result="FAILED"
126+
fi
127+
cat > test-result-predicate.json <<JSONEOF
128+
{
129+
"result": "${tests_result}",
130+
"configuration": [{
131+
"uri": "https://github.com/${{ github.repository }}/blob/${{ github.sha }}/.github/workflows/test.yml",
132+
"digest": {"gitCommit": "${{ github.sha }}"}
133+
}],
134+
"url": "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
135+
}
136+
JSONEOF
137+
138+
- name: Verify subject artifact exists
139+
if: steps.download-source.outcome == 'success'
140+
run: |
141+
if [ ! -f source.tar.gz ]; then
142+
echo "Error: source.tar.gz not found after artifact download" >&2
143+
exit 1
144+
fi
145+
146+
- name: Attest test results
147+
if: steps.download-source.outcome == 'success'
148+
uses: actions/attest@59d89421af93a897026c735860bf21b6eb4f7b26 # v4.1.0
149+
with:
150+
subject-path: source.tar.gz
151+
predicate-type: https://in-toto.io/attestation/test-result/v0.1
152+
predicate-path: test-result-predicate.json

doc/tutorials/installation.rst

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,10 @@ Run the following command to verify the installation
9191
Verifying release integrity
9292
---------------------------
9393

94-
Every dfetch release carries cryptographic attestations signed by GitHub Actions
95-
and anchored in `Sigstore <https://www.sigstore.dev/>`_. There are two
96-
complementary kinds:
94+
Every dfetch release has cryptographic attestations signed by GitHub Actions
95+
and anchored in `Sigstore <https://www.sigstore.dev/>`_, all published in the
96+
`attestation registry <https://github.com/dfetch-org/dfetch/attestations>`_.
97+
There are four complementary kinds:
9798

9899
- **SLSA build provenance** — answers *"where did this come from?"*: proves the
99100
artifact was produced from the official source commit by the official CI
@@ -104,11 +105,15 @@ complementary kinds:
104105
independently verified?"*: records that the source archive for this commit was
105106
attested and verified before the binary was produced, linking source-level
106107
trust to the binary package.
108+
- **Test result attestation** (in-toto) — answers *"did the source pass its tests?"*:
109+
records that the full CI test suite ran against this exact source archive and every
110+
check passed, before any binary was produced.
107111

108-
Binary installers carry **all three** kinds of attestation when source
112+
Binary installers have **build provenance, SBOM, and VSA** attestations when source
109113
provenance verification passes (signed by ``build.yml``).
110-
Python packages installed from PyPI carry an **SBOM attestation only** (signed by
114+
Python packages installed from PyPI have an **SBOM attestation only** (signed by
111115
``python-publish.yml``).
116+
The source archive has a **test result attestation** (signed by ``test.yml``).
112117

113118
To verify, use the `GitHub CLI <https://cli.github.com/>`_. Pass
114119
``--predicate-type`` to target one kind specifically; omit it to accept either.
@@ -241,6 +246,21 @@ To verify, use the `GitHub CLI <https://cli.github.com/>`_. Pass
241246
--cert-identity https://github.com/dfetch-org/dfetch/.github/workflows/python-publish.yml@refs/tags/v<version> `
242247
--cert-oidc-issuer https://token.actions.githubusercontent.com
243248
249+
**Source archive — verify test results:**
250+
251+
The test result attestation proves the full CI suite passed on that exact source
252+
before any binary was produced.
253+
To verify locally, download ``source.tar.gz`` from the *Artifacts* section of the
254+
release CI run, then run:
255+
256+
.. code-block:: bash
257+
258+
$ gh attestation verify source.tar.gz \
259+
--repo dfetch-org/dfetch \
260+
--predicate-type https://in-toto.io/attestation/test-result/v0.1 \
261+
--cert-identity https://github.com/dfetch-org/dfetch/.github/workflows/test.yml@refs/tags/v<version> \
262+
--cert-oidc-issuer https://token.actions.githubusercontent.com
263+
244264
See `GitHub artifact attestations`_ for details.
245265

246266
.. note::

0 commit comments

Comments
 (0)