Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion .github/workflows/fast-mlsirm-publish-pypi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,15 @@ jobs:
f"release tag does not match project version: expected {expected!r}, got {actual!r}"
)
PY
- name: Require reviewed release license helpers
run: |
set -euo pipefail
for helper in tools/select_third_party_license.sh tools/verify_wheel_license.py; do
if [ ! -f "$helper" ] || [ -L "$helper" ]; then
echo "::error::Release source lacks the reviewed license helper: $helper"
exit 1
fi
done
# Reproducible-build clock: the committer time of the exact release
# commit, never the wall clock. maturin stamps it into the embedded
# CycloneDX SBOM (timestamp/serialNumber) and archive metadata; without it
Expand Down Expand Up @@ -536,6 +545,9 @@ jobs:
# MATURIN_, ...) into the manylinux container, so SOURCE_DATE_EPOCH must
# be passed explicitly via docker-options for the Linux legs. Native
# macOS/Windows builds inherit it from the job env.
- name: Select reviewed license bundle for wheel target
shell: bash
run: bash tools/select_third_party_license.sh "${{ matrix.target }}"
- name: Build wheel
uses: PyO3/maturin-action@e83996d129638aa358a18fbd1dfb82f0b0fb5d3b
env:
Expand All @@ -548,6 +560,8 @@ jobs:
docker-options: -e SOURCE_DATE_EPOCH
before-script-linux: $CARGO_BUILD_PYTHON trusted-control/scripts/ci/capture_release_build_scope.py
args: --release --out dist -i ${{ matrix.interpreter }}
- name: Verify wheel license bytes
run: python tools/verify_wheel_license.py dist
- name: Capture first native-runner build graph
if: ${{ runner.os != 'Linux' }}
env:
Expand Down Expand Up @@ -671,6 +685,10 @@ jobs:
env:
RELEASE_COMMIT: ${{ needs.verify-release.outputs.release_commit }}
run: python trusted-control/scripts/ci/release_sdist_consumer.py prepare sdist-proof/sdist.tsv sdist-input sdist-consumer
- name: Select reviewed license bundle for sdist consumer target
working-directory: sdist-consumer/source
shell: bash
run: bash tools/select_third_party_license.sh "${{ matrix.target }}"
- name: Build this wheel target from the verified sdist
uses: PyO3/maturin-action@e83996d129638aa358a18fbd1dfb82f0b0fb5d3b
with:
Expand All @@ -682,6 +700,9 @@ jobs:
maturin-version: v1.15.0
docker-options: -e SOURCE_DATE_EPOCH
args: --release --out dist-consumer -i ${{ matrix.interpreter }}
- name: Verify sdist consumer wheel license bytes
working-directory: sdist-consumer/source
run: python tools/verify_wheel_license.py dist-consumer
- name: Capture target sdist consumer wheel
shell: bash
env:
Expand Down Expand Up @@ -1084,7 +1105,7 @@ jobs:
dependency-gate:
name: complete dependency licence and Strix gate
needs: [verify-release, reproducibility-record]
uses: ContextualWisdomLab/.github/.github/workflows/release-dependency-license-strix-gate.yml@b6cebb36dc11afe409a7fee8a3262827255c029c
uses: ContextualWisdomLab/.github/.github/workflows/release-dependency-license-strix-gate.yml@e249236e3f420c4e9c470f26925640dae59f0d93
with:
source_repository: ${{ github.repository }}
source_sha: ${{ needs.verify-release.outputs.release_commit }}
Expand Down
28 changes: 28 additions & 0 deletions tests/test_fast_mlsirm_self_hosted_workflows.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from pathlib import Path
import subprocess
import textwrap
from xml.etree import ElementTree as ET

Expand Down Expand Up @@ -67,6 +68,33 @@ def test_fast_mlsirm_reusable_workflows_keep_isolated_runner_and_gate_contracts(
assert "cargo test --locked --manifest-path crates/fast-mlsirm-py/Cargo.toml" in ci


def test_release_wheel_and_sdist_consumer_keep_selected_license_bytes():
"""Keep target selection and byte verification around both actual builds."""
text = workflow_text("fast-mlsirm-publish-pypi.yml")
wheel_selection = ' - name: Select reviewed license bundle for wheel target\n shell: bash\n run: bash tools/select_third_party_license.sh "${{ matrix.target }}"\n'
wheel_verification = ' - name: Verify wheel license bytes\n run: python tools/verify_wheel_license.py dist\n'
consumer_selection = ' - name: Select reviewed license bundle for sdist consumer target\n working-directory: sdist-consumer/source\n shell: bash\n run: bash tools/select_third_party_license.sh "${{ matrix.target }}"\n'
consumer_verification = ' - name: Verify sdist consumer wheel license bytes\n working-directory: sdist-consumer/source\n run: python tools/verify_wheel_license.py dist-consumer\n'
for step in (wheel_selection, wheel_verification, consumer_selection, consumer_verification):
assert text.count(step) == 1
assert text.index(wheel_selection) < text.index(" - name: Build wheel\n") < text.index(wheel_verification) < text.index(" - name: Capture first native-runner build graph\n")
assert text.index(" - name: Verify and unpack the same-run sdist\n") < text.index(consumer_selection) < text.index(" - name: Build this wheel target from the verified sdist\n") < text.index(consumer_verification) < text.index(" - name: Capture target sdist consumer wheel\n")


def test_older_release_source_without_license_helpers_fails_before_build(tmp_path):
"""Historical commits without the new helpers cannot enter the matrix."""
text = workflow_text("fast-mlsirm-publish-pypi.yml")
step = text.split(" - name: Require reviewed release license helpers\n", 1)[1]
script = textwrap.dedent(step.split(" run: |\n", 1)[1].split("\n # Reproducible-build clock:", 1)[0])
assert text.index(" - name: Require reviewed release license helpers\n") < text.index(" sdist:\n")
assert subprocess.run(["bash", "-e", "-c", script], cwd=tmp_path, capture_output=True).returncode == 1
tools = tmp_path / "tools"
tools.mkdir()
for name in ("select_third_party_license.sh", "verify_wheel_license.py"):
(tools / name).write_text("reviewed helper fixture")
assert subprocess.run(["bash", "-e", "-c", script], cwd=tmp_path, capture_output=True).returncode == 0


def test_disabled_release_legs_fail_the_caller_instead_of_reporting_success():
"""Expose the intentional release hold as a failing required job."""
text = workflow_text("fast-mlsirm-publish-pypi.yml")
Expand Down
Loading