|
9 | 9 | WORKFLOW_PATH = Path(__file__).resolve().parents[1] / ".github" / "workflows" / "release-assets.yml" |
10 | 10 |
|
11 | 11 |
|
12 | | -def _release_steps() -> list[Mapping[str, Any]]: |
| 12 | +def _release_job() -> Mapping[str, Any]: |
13 | 13 | document = yaml.safe_load(WORKFLOW_PATH.read_text(encoding="utf-8")) |
14 | 14 | assert isinstance(document, Mapping) |
15 | 15 | jobs = document.get("jobs") |
16 | 16 | assert isinstance(jobs, Mapping) |
17 | 17 | build = jobs.get("build") |
18 | 18 | assert isinstance(build, Mapping) |
19 | | - steps = build.get("steps") |
| 19 | + return build |
| 20 | + |
| 21 | + |
| 22 | +def _release_steps() -> list[Mapping[str, Any]]: |
| 23 | + steps = _release_job().get("steps") |
20 | 24 | assert isinstance(steps, list) |
21 | 25 | assert all(isinstance(step, Mapping) for step in steps) |
22 | 26 | return steps |
@@ -144,3 +148,41 @@ def test_release_closure_is_retryable_after_publication() -> None: |
144 | 148 | assert "2>/dev/null" in verify |
145 | 149 | assert 'gh release verify "$RELEASE_TAG" --format json' in verify |
146 | 150 | assert "sleep 15" in verify |
| 151 | + |
| 152 | + |
| 153 | +def test_distribution_provenance_precedes_irreversible_publication() -> None: |
| 154 | + assert _release_job().get("permissions") == { |
| 155 | + "artifact-metadata": "write", |
| 156 | + "attestations": "write", |
| 157 | + "contents": "write", |
| 158 | + "id-token": "write", |
| 159 | + } |
| 160 | + |
| 161 | + attest = _step("Attest wheel and source archive provenance") |
| 162 | + assert attest.get("if") == "steps.verify-tag.outputs.release_state != 'published'" |
| 163 | + assert attest.get("uses") == ("actions/attest@508db95dd578ae2727ebd6217d5ba78e4fbda05d") |
| 164 | + settings = attest.get("with") |
| 165 | + assert isinstance(settings, Mapping) |
| 166 | + assert settings.get("subject-checksums") == "dist/SHA256SUMS" |
| 167 | + |
| 168 | + verify_step = _step("Verify distribution provenance") |
| 169 | + assert "if" not in verify_step |
| 170 | + verify = _run("Verify distribution provenance") |
| 171 | + assert "dist/*.whl dist/*.tar.gz" in verify |
| 172 | + assert "for attempt in {1..20}" in verify |
| 173 | + assert '--repo "$GITHUB_REPOSITORY"' in verify |
| 174 | + assert '--signer-workflow "$signer_workflow"' in verify |
| 175 | + assert '--signer-digest "$GITHUB_SHA"' in verify |
| 176 | + assert '--source-ref "$GITHUB_REF"' in verify |
| 177 | + assert '--source-digest "$GITHUB_SHA"' in verify |
| 178 | + |
| 179 | + assert _step_index("Build tag-matched distributions and checksums") < _step_index( |
| 180 | + "Attest wheel and source archive provenance" |
| 181 | + ) |
| 182 | + assert _step_index("Attest wheel and source archive provenance") < _step_index( |
| 183 | + "Attach exact draft assets" |
| 184 | + ) |
| 185 | + assert _step_index("Attach exact draft assets") < _step_index("Verify distribution provenance") |
| 186 | + assert _step_index("Verify distribution provenance") < _step_index( |
| 187 | + "Publish complete draft release" |
| 188 | + ) |
0 commit comments