Loading .gitlab-ci.yml +1 −1 Changes for .gitlab-ci.yml: 1 added line, 1 removed line. Original line number Diff line number Diff line Loading @@ -173,7 +173,7 @@ publish-package: - job: srm-consumer rules: - if: '$CI_COMMIT_TAG =~ /^v2[.]0[.][0-9]+(rc[1-9][0-9]*)?$/ && $CI_COMMIT_REF_PROTECTED == "true"' when: manual when: on_success allow_failure: false - when: never script: Loading ci/README.md +7 −6 Changes for ci/README.md: 7 added lines, 6 removed lines. Original line number Diff line number Diff line Loading @@ -26,11 +26,12 @@ Source, sdist and wheel are checked before publication. Branch pushes cannot publish packages. Release promotion reuses the built and tested bytes; never rebuild a package under an existing version. The candidate version is 2.0.0rc5. Create a protected matching release tag when the intended candidate is ready. After required CI jobs pass, a maintainer plays publish-package: this single action approves publication. No qualification file, extra pipeline IDs or exception variables are required. CI_JOB_TOKEN uploads the verified artifacts; tag/version/source and checksum guards remain mandatory. The candidate version is 2.0.0rc5. Review the release scope and applicable E2E evidence, then create a protected matching release tag when publication is approved. After required CI jobs pass, publish-package automatically uploads the verified artifacts using CI_JOB_TOKEN. No manual job, qualification file, extra pipeline IDs or exception variables are required. Tag/version/source and checksum guards remain mandatory. An automatic informational release-qualification.json preserves actual SDK and linked downstream test reports. Missing reports remain visible; applicable E2E results are reviewed in the release MR. See [the release procedure](RELEASE.md). Loading @@ -43,7 +44,7 @@ Python support is bounded to >=3.10,<3.14, matching the classifiers and tested matrix; the current pinned pydantic-core cannot build with Python 3.14. Release reports record available evidence, not signed attestations or a claimed SLSA level. The release owner judges whether the tested scope is sufficient for the release; the manual publisher records that decision in GitLab. release before creating its protected publication tag. Consumer qualification follows a protected SRM candidate branch. GitLab fixes the downstream checkout when creating that pipeline, and its receipt records Loading ci/RELEASE.md +13 −11 Changes for ci/RELEASE.md: 13 added lines, 11 removed lines. Original line number Diff line number Diff line # Release an SDK package 1. Review and merge the intended source/version through the release MR. 2. Create its matching protected tag, for example v2.0.0rc5 or v2.0.0. 1. Review the release scope and applicable OEG-driven acceptance results, and merge the intended source/version through the release MR. 2. Create its matching protected tag, for example v2.0.0. Creating the tag approves publication after successful checks. CI builds the wheel and source distribution once, tests those bytes and runs the linked SRM consumer. The release matrix and dependency audit also run. 3. Review the green pipeline and applicable OEG-driven acceptance results, then play **publish-package**. That one click approves and uploads the tested artifacts to the project's GitLab Python package registry. 3. After required CI jobs pass, **publish-package** automatically uploads the tested artifacts to the project's GitLab Python package registry. No qualification file, pipeline-ID input, extra approval form or exception flag is required. The authorized manual job is the publication decision. Merging the release MR integrates source; branch pipelines continue to avoid package uploads. No manual job, qualification file, pipeline-ID input, extra approval form or exception flag is required. Merging the release MR integrates source; branch pipelines continue to avoid package uploads. The publisher automatically saves release-qualification.json with artifact identity, the GitLab approval job URL, actual SDK JUnit summary and linked identity, the GitLab publication job URL, actual SDK JUnit summary and linked downstream pipeline/test results. It uses the current public project APIs without a new token. Missing or inaccessible reports are recorded as unavailable and cannot add a new publication gate. External E2E runs remain visible in their Loading @@ -22,8 +23,9 @@ application, NEF or device acceptance from SDK/consumer results. The existing required jobs and protected tag/version/source/checksum checks remain enforced. Report collection changes no test outcome. If evidence is incomplete, the release owner decides whether to wait or proceed and can explain the decision in the existing MR. No separate exception workflow is needed. incomplete, the release owner decides whether to wait or proceed before creating the tag and can explain the decision in the existing MR. No separate exception workflow is needed. If a required job fails, fix/retry it or use an explicitly approved targeted CI change through the normal review process. Loading ci/release.py +1 −1 Changes for ci/release.py: 1 added line, 1 removed line. Original line number Diff line number Diff line Loading @@ -57,7 +57,7 @@ def verify_release(): "source_sha": manifest["source_sha"], "wheel_sha256": sha256(wheel), "release_type": "candidate" if Version(version).is_prerelease else "final", "approval_job_url": os.getenv("CI_JOB_URL"), "publication_job_url": os.getenv("CI_JOB_URL"), }, ) receipt = json.loads((OUT / "release-check.json").read_text()) Loading tests/ci/test_release_reports.py +3 −3 Changes for tests/ci/test_release_reports.py: 3 added lines, 3 removed lines. Original line number Diff line number Diff line """One manual publisher records CI evidence without requiring hand-written files.""" """The publisher records CI evidence without requiring hand-written files.""" import io import json Loading Loading @@ -52,7 +52,7 @@ def candidate(tmp_path, monkeypatch): return tmp_path, wheel def test_manual_publication_needs_no_qualification_file_or_extra_parameters(candidate, monkeypatch): def test_publication_needs_no_qualification_file_or_extra_parameters(candidate, monkeypatch): monkeypatch.setattr(release, "collect_reports", lambda: {"sdk_tests": {"total": 374}}) commands = [] monkeypatch.setattr( Loading @@ -65,7 +65,7 @@ def test_manual_publication_needs_no_qualification_file_or_extra_parameters(cand release.main() output, wheel = candidate receipt = json.loads((output / "release-qualification.json").read_text()) assert receipt["approval_job_url"].endswith("/jobs/20") assert receipt["publication_job_url"].endswith("/jobs/20") assert receipt["wheel_sha256"] == release.sha256(wheel) assert receipt["sdk_tests"]["total"] == 374 assert commands[-1][1:4] == ["-m", "twine", "upload"] Loading Loading
.gitlab-ci.yml +1 −1 Changes for .gitlab-ci.yml: 1 added line, 1 removed line. Original line number Diff line number Diff line Loading @@ -173,7 +173,7 @@ publish-package: - job: srm-consumer rules: - if: '$CI_COMMIT_TAG =~ /^v2[.]0[.][0-9]+(rc[1-9][0-9]*)?$/ && $CI_COMMIT_REF_PROTECTED == "true"' when: manual when: on_success allow_failure: false - when: never script: Loading
ci/README.md +7 −6 Changes for ci/README.md: 7 added lines, 6 removed lines. Original line number Diff line number Diff line Loading @@ -26,11 +26,12 @@ Source, sdist and wheel are checked before publication. Branch pushes cannot publish packages. Release promotion reuses the built and tested bytes; never rebuild a package under an existing version. The candidate version is 2.0.0rc5. Create a protected matching release tag when the intended candidate is ready. After required CI jobs pass, a maintainer plays publish-package: this single action approves publication. No qualification file, extra pipeline IDs or exception variables are required. CI_JOB_TOKEN uploads the verified artifacts; tag/version/source and checksum guards remain mandatory. The candidate version is 2.0.0rc5. Review the release scope and applicable E2E evidence, then create a protected matching release tag when publication is approved. After required CI jobs pass, publish-package automatically uploads the verified artifacts using CI_JOB_TOKEN. No manual job, qualification file, extra pipeline IDs or exception variables are required. Tag/version/source and checksum guards remain mandatory. An automatic informational release-qualification.json preserves actual SDK and linked downstream test reports. Missing reports remain visible; applicable E2E results are reviewed in the release MR. See [the release procedure](RELEASE.md). Loading @@ -43,7 +44,7 @@ Python support is bounded to >=3.10,<3.14, matching the classifiers and tested matrix; the current pinned pydantic-core cannot build with Python 3.14. Release reports record available evidence, not signed attestations or a claimed SLSA level. The release owner judges whether the tested scope is sufficient for the release; the manual publisher records that decision in GitLab. release before creating its protected publication tag. Consumer qualification follows a protected SRM candidate branch. GitLab fixes the downstream checkout when creating that pipeline, and its receipt records Loading
ci/RELEASE.md +13 −11 Changes for ci/RELEASE.md: 13 added lines, 11 removed lines. Original line number Diff line number Diff line # Release an SDK package 1. Review and merge the intended source/version through the release MR. 2. Create its matching protected tag, for example v2.0.0rc5 or v2.0.0. 1. Review the release scope and applicable OEG-driven acceptance results, and merge the intended source/version through the release MR. 2. Create its matching protected tag, for example v2.0.0. Creating the tag approves publication after successful checks. CI builds the wheel and source distribution once, tests those bytes and runs the linked SRM consumer. The release matrix and dependency audit also run. 3. Review the green pipeline and applicable OEG-driven acceptance results, then play **publish-package**. That one click approves and uploads the tested artifacts to the project's GitLab Python package registry. 3. After required CI jobs pass, **publish-package** automatically uploads the tested artifacts to the project's GitLab Python package registry. No qualification file, pipeline-ID input, extra approval form or exception flag is required. The authorized manual job is the publication decision. Merging the release MR integrates source; branch pipelines continue to avoid package uploads. No manual job, qualification file, pipeline-ID input, extra approval form or exception flag is required. Merging the release MR integrates source; branch pipelines continue to avoid package uploads. The publisher automatically saves release-qualification.json with artifact identity, the GitLab approval job URL, actual SDK JUnit summary and linked identity, the GitLab publication job URL, actual SDK JUnit summary and linked downstream pipeline/test results. It uses the current public project APIs without a new token. Missing or inaccessible reports are recorded as unavailable and cannot add a new publication gate. External E2E runs remain visible in their Loading @@ -22,8 +23,9 @@ application, NEF or device acceptance from SDK/consumer results. The existing required jobs and protected tag/version/source/checksum checks remain enforced. Report collection changes no test outcome. If evidence is incomplete, the release owner decides whether to wait or proceed and can explain the decision in the existing MR. No separate exception workflow is needed. incomplete, the release owner decides whether to wait or proceed before creating the tag and can explain the decision in the existing MR. No separate exception workflow is needed. If a required job fails, fix/retry it or use an explicitly approved targeted CI change through the normal review process. Loading
ci/release.py +1 −1 Changes for ci/release.py: 1 added line, 1 removed line. Original line number Diff line number Diff line Loading @@ -57,7 +57,7 @@ def verify_release(): "source_sha": manifest["source_sha"], "wheel_sha256": sha256(wheel), "release_type": "candidate" if Version(version).is_prerelease else "final", "approval_job_url": os.getenv("CI_JOB_URL"), "publication_job_url": os.getenv("CI_JOB_URL"), }, ) receipt = json.loads((OUT / "release-check.json").read_text()) Loading
tests/ci/test_release_reports.py +3 −3 Changes for tests/ci/test_release_reports.py: 3 added lines, 3 removed lines. Original line number Diff line number Diff line """One manual publisher records CI evidence without requiring hand-written files.""" """The publisher records CI evidence without requiring hand-written files.""" import io import json Loading Loading @@ -52,7 +52,7 @@ def candidate(tmp_path, monkeypatch): return tmp_path, wheel def test_manual_publication_needs_no_qualification_file_or_extra_parameters(candidate, monkeypatch): def test_publication_needs_no_qualification_file_or_extra_parameters(candidate, monkeypatch): monkeypatch.setattr(release, "collect_reports", lambda: {"sdk_tests": {"total": 374}}) commands = [] monkeypatch.setattr( Loading @@ -65,7 +65,7 @@ def test_manual_publication_needs_no_qualification_file_or_extra_parameters(cand release.main() output, wheel = candidate receipt = json.loads((output / "release-qualification.json").read_text()) assert receipt["approval_job_url"].endswith("/jobs/20") assert receipt["publication_job_url"].endswith("/jobs/20") assert receipt["wheel_sha256"] == release.sha256(wheel) assert receipt["sdk_tests"]["total"] == 374 assert commands[-1][1:4] == ["-m", "twine", "upload"] Loading