8383 mkdir build-environment-evidence
8484 python -m pip list --format=freeze \
8585 | LC_ALL=C sort -f > build-environment-evidence/environment.lock
86+ package_version="$(python -c 'import tomllib; print(tomllib.load(open("pyproject.toml", "rb"))["project"]["version"])')"
8687 cyclonedx-py environment --output-reproducible --of JSON \
8788 --pyproject pyproject.toml \
88- -o build-environment-evidence/engraphis-${GITHUB_REF_NAME#v }.cdx.json
89+ -o " build-environment-evidence/engraphis-${package_version }.cdx.json"
8990
9091 - name : Build source and universal wheel distributions
9192 shell : bash
@@ -370,16 +371,18 @@ jobs:
370371
371372
372373 installed-artifact-platform-smoke :
373- name : Installed wheel smoke (${{ matrix.os }})
374+ name : Installed wheel journey (${{ matrix.os }}, ${{ matrix.profile }})
374375 needs : build
375376 runs-on : ${{ matrix.os }}
377+ timeout-minutes : 25
376378 if : >-
377379 github.event_name == 'push' ||
378380 inputs.release_tag == ''
379381 strategy :
380382 fail-fast : false
381383 matrix :
382- os : [windows-latest, macos-latest]
384+ os : [ubuntu-latest, windows-latest, macos-latest]
385+ profile : [base, mcp, server]
383386 env :
384387 PIP_CONSTRAINT : ${{ github.workspace }}/.github/release-constraints.txt
385388 PIP_BUILD_CONSTRAINT : ${{ github.workspace }}/.github/release-constraints.txt
@@ -393,11 +396,15 @@ jobs:
393396 with :
394397 name : python-package-distributions
395398 path : dist/
396- - name : Install and smoke the downloaded wheel on Windows and macOS
399+ - name : Install and exercise the downloaded wheel on supported platforms
400+ env :
401+ ENGRAPHIS_SMOKE_PROFILE : ${{ matrix.profile }}
397402 shell : bash
398403 run : |
399404 set -euo pipefail
400405 python - <<'PY'
406+ import hashlib
407+ import json
401408 import os
402409 from pathlib import Path
403410 import subprocess
@@ -408,9 +415,11 @@ jobs:
408415 executable = environment / ("Scripts/python.exe" if os.name == "nt" else "bin/python")
409416 wheels = list(Path("dist").glob("*.whl"))
410417 assert len(wheels) == 1
418+ profile = os.environ["ENGRAPHIS_SMOKE_PROFILE"]
419+ requirement = str(wheels[0].resolve()) + ("" if profile == "base" else f"[{profile}]")
411420 subprocess.run(
412421 [str(executable), "-m", "pip", "install", "--disable-pip-version-check",
413- str(wheels[0].resolve()) ],
422+ requirement ],
414423 check=True,
415424 )
416425 subprocess.run([str(executable), "-m", "pip", "check"], check=True)
@@ -419,7 +428,32 @@ jobs:
419428 cwd=os.environ["RUNNER_TEMP"],
420429 check=True,
421430 )
431+ if profile != "base":
432+ evidence = Path(os.environ["RUNNER_TEMP"])
433+ (evidence / "installed-environment.lock").write_text(subprocess.check_output(
434+ [str(executable), "-m", "pip", "freeze", "--all"], text=True,
435+ ), encoding="utf-8")
436+ (evidence / "installed-artifact.json").write_text(json.dumps({
437+ "profile": profile, "wheel": wheels[0].name,
438+ "wheel_sha256": hashlib.sha256(wheels[0].read_bytes()).hexdigest(),
439+ }), encoding="utf-8")
440+ subprocess.run(
441+ [str(executable), "-m", "scripts.smoke_installed_product", "--surface", profile,
442+ "--output", str(Path(os.environ["RUNNER_TEMP"]) / "installed-journey.json")],
443+ cwd=os.environ["RUNNER_TEMP"],
444+ check=True,
445+ )
422446 PY
447+ - name : Retain installed journey evidence
448+ if : matrix.profile != 'base'
449+ uses : actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
450+ with :
451+ name : installed-journey-${{ matrix.os }}-${{ matrix.profile }}
452+ path : |
453+ ${{ runner.temp }}/installed-journey.json
454+ ${{ runner.temp }}/installed-environment.lock
455+ ${{ runner.temp }}/installed-artifact.json
456+ if-no-files-found : error
423457
424458 encryption :
425459 name : Encryption driver release gate (Python ${{ matrix.python-version }})
@@ -732,6 +766,11 @@ jobs:
732766 with :
733767 name : independent-reproducibility
734768 path : release-evidence/
769+ - name : Download complete installed journey evidence
770+ uses : actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
771+ with :
772+ pattern : installed-journey-*
773+ path : installed-journey-inputs/
735774 - name : Generate evidence from captured release artifacts
736775 shell : bash
737776 run : |
@@ -745,6 +784,7 @@ jobs:
745784 --image-digest "$(tr -d '\r\n' < release-evidence/image.digest)" \
746785 --image-scan release-evidence/grype.json \
747786 --reproducibility release-evidence/reproducibility.json \
787+ --installed-journeys installed-journey-inputs \
748788 --verified-check ruff \
749789 --verified-check pyright-core-backends \
750790 --verified-check codeql \
@@ -777,6 +817,7 @@ jobs:
777817 publish :
778818 name : Publish to PyPI
779819 needs : release-evidence
820+ environment : release-qualification
780821 # Manual dispatch is intentionally build/check-only. Publication requires a pushed
781822 # semver tag, whose value was matched to pyproject.toml in the build job above.
782823 if : github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
@@ -811,6 +852,19 @@ jobs:
811852 mkdir verified-dist
812853 cp dist/*.whl dist/*.tar.gz verified-dist/
813854
855+ - name : Require signed full-product qualification before PyPI publication
856+ env :
857+ ENGRAPHIS_RELEASE_QUALIFICATION : ${{ vars.ENGRAPHIS_RELEASE_QUALIFICATION }}
858+ ENGRAPHIS_RELEASE_VERIFY_KEY : ${{ vars.ENGRAPHIS_RELEASE_VERIFY_KEY }}
859+ ENGRAPHIS_RELEASE_CANDIDATE_ID : ${{ vars.ENGRAPHIS_RELEASE_CANDIDATE_ID }}
860+ ENGRAPHIS_RELEASE_LEDGER_SHA256 : ${{ vars.ENGRAPHIS_RELEASE_LEDGER_SHA256 }}
861+ shell : bash
862+ run : |
863+ set -euo pipefail
864+ python -m pip install --disable-pip-version-check "cryptography==50.0.0"
865+ python -m scripts.verify_release_qualification --dist dist \
866+ --commit "$GITHUB_SHA" --tag "$GITHUB_REF_NAME"
867+
814868 - name : Publish distributions to PyPI
815869 uses : pypa/gh-action-pypi-publish@ba38be9e461d3875417946c167d0b5f3d385a247 # v1.14.1
816870 with :
@@ -825,12 +879,17 @@ jobs:
825879 github-release :
826880 name : Publish GitHub Release
827881 needs : publish
882+ environment : release-qualification
828883 if : github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
829884 runs-on : ubuntu-latest
830885 permissions :
831886 contents : write
832887
833888 steps :
889+ - uses : actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
890+ - uses : actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
891+ with :
892+ python-version : " 3.11"
834893 - name : Download distributions
835894 uses : actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
836895 with :
@@ -843,6 +902,19 @@ jobs:
843902 name : public-release-evidence
844903 path : release-evidence/
845904
905+ - name : Require signed full-product qualification before GitHub publication
906+ env :
907+ ENGRAPHIS_RELEASE_QUALIFICATION : ${{ vars.ENGRAPHIS_RELEASE_QUALIFICATION }}
908+ ENGRAPHIS_RELEASE_VERIFY_KEY : ${{ vars.ENGRAPHIS_RELEASE_VERIFY_KEY }}
909+ ENGRAPHIS_RELEASE_CANDIDATE_ID : ${{ vars.ENGRAPHIS_RELEASE_CANDIDATE_ID }}
910+ ENGRAPHIS_RELEASE_LEDGER_SHA256 : ${{ vars.ENGRAPHIS_RELEASE_LEDGER_SHA256 }}
911+ shell : bash
912+ run : |
913+ set -euo pipefail
914+ python -m pip install --disable-pip-version-check "cryptography==50.0.0"
915+ python -m scripts.verify_release_qualification --dist dist \
916+ --commit "$GITHUB_SHA" --tag "$GITHUB_REF_NAME"
917+
846918 - name : Create GitHub Release
847919 env :
848920 GH_TOKEN : ${{ github.token }}
@@ -867,6 +939,7 @@ jobs:
867939
868940 github-release-repair :
869941 name : Repair GitHub Release
942+ environment : release-qualification
870943 if : >-
871944 github.event_name == 'workflow_dispatch' &&
872945 github.ref == 'refs/heads/main' &&
@@ -962,6 +1035,7 @@ jobs:
9621035 import json
9631036 import sys
9641037 from pathlib import Path
1038+ from scripts.release_evidence import installed_bundle_records
9651039
9661040 tag, commit = sys.argv[1:]
9671041 evidence_root = Path("candidate-evidence")
@@ -991,6 +1065,8 @@ jobs:
9911065 evidence["container"]["sbom"],
9921066 evidence["container"]["vulnerability_scan"],
9931067 ]
1068+ if "installed_journeys" in evidence:
1069+ records.extend(installed_bundle_records(evidence["installed_journeys"], actual))
9941070 for record in records:
9951071 path = evidence_root / Path(record["path"]).name
9961072 assert path.is_file()
@@ -1004,6 +1080,7 @@ jobs:
10041080 fi
10051081 done < "$RUNNER_TEMP/release-run-candidates"
10061082 test -n "$selected_run"
1083+ printf 'ENGRAPHIS_REPAIR_COMMIT=%s\n' "$tag_sha" >> "$GITHUB_ENV"
10071084
10081085 - name : Verify any previously published subset
10091086 env :
@@ -1021,6 +1098,20 @@ jobs:
10211098 mkdir verified-dist
10221099 cp dist/*.whl dist/*.tar.gz verified-dist/
10231100
1101+ - name : Require signed full-product qualification before PyPI repair
1102+ env :
1103+ RELEASE_TAG : ${{ inputs.release_tag }}
1104+ ENGRAPHIS_RELEASE_QUALIFICATION : ${{ vars.ENGRAPHIS_RELEASE_QUALIFICATION }}
1105+ ENGRAPHIS_RELEASE_VERIFY_KEY : ${{ vars.ENGRAPHIS_RELEASE_VERIFY_KEY }}
1106+ ENGRAPHIS_RELEASE_CANDIDATE_ID : ${{ vars.ENGRAPHIS_RELEASE_CANDIDATE_ID }}
1107+ ENGRAPHIS_RELEASE_LEDGER_SHA256 : ${{ vars.ENGRAPHIS_RELEASE_LEDGER_SHA256 }}
1108+ shell : bash
1109+ run : |
1110+ set -euo pipefail
1111+ python -m pip install --disable-pip-version-check "cryptography==50.0.0"
1112+ python -m scripts.verify_release_qualification --dist dist \
1113+ --commit "$ENGRAPHIS_REPAIR_COMMIT" --tag "$RELEASE_TAG"
1114+
10241115 - name : Publish only missing verified distributions
10251116 uses : pypa/gh-action-pypi-publish@ba38be9e461d3875417946c167d0b5f3d385a247 # v1.14.1
10261117 with :
@@ -1034,6 +1125,19 @@ jobs:
10341125 python scripts/verify_release_artifacts.py --dist verified-dist
10351126 --version "${RELEASE_TAG#v}" --retries 18 --delay 10
10361127
1128+ - name : Require signed full-product qualification before GitHub repair
1129+ env :
1130+ RELEASE_TAG : ${{ inputs.release_tag }}
1131+ ENGRAPHIS_RELEASE_QUALIFICATION : ${{ vars.ENGRAPHIS_RELEASE_QUALIFICATION }}
1132+ ENGRAPHIS_RELEASE_VERIFY_KEY : ${{ vars.ENGRAPHIS_RELEASE_VERIFY_KEY }}
1133+ ENGRAPHIS_RELEASE_CANDIDATE_ID : ${{ vars.ENGRAPHIS_RELEASE_CANDIDATE_ID }}
1134+ ENGRAPHIS_RELEASE_LEDGER_SHA256 : ${{ vars.ENGRAPHIS_RELEASE_LEDGER_SHA256 }}
1135+ shell : bash
1136+ run : |
1137+ set -euo pipefail
1138+ python -m scripts.verify_release_qualification --dist verified-dist \
1139+ --commit "$ENGRAPHIS_REPAIR_COMMIT" --tag "$RELEASE_TAG"
1140+
10371141 - name : Repair GitHub Release
10381142 env :
10391143 GH_TOKEN : ${{ github.token }}
0 commit comments