From cc1a03867af0db9752e9cad58218dc63e1236ead Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 3 Sep 2026 23:27:30 +0900 Subject: [PATCH] ci(sbom): combine exact artifact quality runners Run Python 3.10 syntax and Python 3.14 coverage contracts on one exact-head runner, preserve all evidence thresholds, and scope stale-run cancellation to workflow, repository, and pull request identity. --- ...xact-artifact-sbom-attestation-quality.yml | 47 ++++----- ...t-artifact-quality-runner-consolidation.md | 9 ++ ...m-quality-runner-consolidation-20260903.md | 60 +++++++++++ ...st_exact_artifact_quality_single_runner.py | 99 +++++++++++++++++++ 4 files changed, 186 insertions(+), 29 deletions(-) create mode 100644 CHANGELOG.d/20260903-exact-artifact-quality-runner-consolidation.md create mode 100644 docs/doctoring/exact-artifact-sbom-quality-runner-consolidation-20260903.md create mode 100644 tests/test_exact_artifact_quality_single_runner.py diff --git a/.github/workflows/exact-artifact-sbom-attestation-quality.yml b/.github/workflows/exact-artifact-sbom-attestation-quality.yml index 851878e2e3..ba67d8ef11 100644 --- a/.github/workflows/exact-artifact-sbom-attestation-quality.yml +++ b/.github/workflows/exact-artifact-sbom-attestation-quality.yml @@ -10,8 +10,11 @@ on: - "tests/test_exact_artifact_sbom_attestation_contract.py" - "tests/test_exact_artifact_sbom_review_regressions.py" - "tests/test_verify_exact_artifact_sbom_handoff.py" + - "tests/test_exact_artifact_quality_single_runner.py" - "docs/doctoring/exact-artifact-sbom-attestation.md" + - "docs/doctoring/exact-artifact-sbom-quality-runner-consolidation-20260903.md" - "CHANGELOG.md" + - "CHANGELOG.d/20260903-exact-artifact-quality-runner-consolidation.md" push: branches: [main] paths: @@ -21,21 +24,24 @@ on: - "tests/test_exact_artifact_sbom_attestation_contract.py" - "tests/test_exact_artifact_sbom_review_regressions.py" - "tests/test_verify_exact_artifact_sbom_handoff.py" + - "tests/test_exact_artifact_quality_single_runner.py" - "docs/doctoring/exact-artifact-sbom-attestation.md" + - "docs/doctoring/exact-artifact-sbom-quality-runner-consolidation-20260903.md" - "CHANGELOG.md" + - "CHANGELOG.d/20260903-exact-artifact-quality-runner-consolidation.md" concurrency: - group: exact-artifact-sbom-attestation-quality-${{ github.event.pull_request.number || github.ref }} + group: exact-artifact-sbom-attestation-quality-${{ github.repository }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true permissions: contents: read jobs: - minimum-python-contract: - name: Python 3.10 contract + exact_artifact_quality: + name: Python 3.10 and 3.14 exact artifact contract runs-on: ubuntu-24.04 - timeout-minutes: 10 + timeout-minutes: 20 steps: - name: Harden runner uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 @@ -64,28 +70,8 @@ jobs: scripts/ci/verify_exact_artifact_sbom_handoff.py \ tests/test_exact_artifact_sbom_attestation_contract.py \ tests/test_exact_artifact_sbom_review_regressions.py \ - tests/test_verify_exact_artifact_sbom_handoff.py - - exact-contract: - name: Python 3.14 exact contract and complete coverage - runs-on: ubuntu-24.04 - timeout-minutes: 15 - steps: - - name: Harden runner - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 - with: - egress-policy: audit - - - name: Checkout exact contributor head - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - persist-credentials: false - ref: ${{ github.event.pull_request.head.sha || github.sha }} - - - name: Verify exact workflow source checkout - env: - EXPECTED_SOURCE_SHA: ${{ github.event.pull_request.head.sha || github.sha }} - run: test "$(git rev-parse HEAD)" = "$EXPECTED_SOURCE_SHA" + tests/test_verify_exact_artifact_sbom_handoff.py \ + tests/test_exact_artifact_quality_single_runner.py - name: Set up current stable Python uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 @@ -103,17 +89,20 @@ jobs: python -m coverage run --branch -m pytest -q \ tests/test_exact_artifact_sbom_attestation_contract.py \ tests/test_exact_artifact_sbom_review_regressions.py \ - tests/test_verify_exact_artifact_sbom_handoff.py + tests/test_verify_exact_artifact_sbom_handoff.py \ + tests/test_exact_artifact_quality_single_runner.py python -m coverage report \ --include=scripts/ci/verify_exact_artifact_sbom_handoff.py \ --show-missing \ --fail-under=100 python -m interrogate --fail-under=100 scripts/ci/verify_exact_artifact_sbom_handoff.py - - name: Compile production and contract files + - name: Compile production and contract files on Python 3.14 run: | python -m compileall -q \ scripts/ci/verify_exact_artifact_sbom_handoff.py \ tests/test_exact_artifact_sbom_attestation_contract.py \ tests/test_exact_artifact_sbom_review_regressions.py \ - tests/test_verify_exact_artifact_sbom_handoff.py + tests/test_verify_exact_artifact_sbom_handoff.py \ + tests/test_exact_artifact_quality_single_runner.py + git diff --check diff --git a/CHANGELOG.d/20260903-exact-artifact-quality-runner-consolidation.md b/CHANGELOG.d/20260903-exact-artifact-quality-runner-consolidation.md new file mode 100644 index 0000000000..f53d408990 --- /dev/null +++ b/CHANGELOG.d/20260903-exact-artifact-quality-runner-consolidation.md @@ -0,0 +1,9 @@ +## Changed + +- Exact Artifact SBOM Attestation 품질 검증의 Python 3.10 compile job과 Python 3.14 + coverage job을 한 exact-head runner로 통합했습니다. +- runner 부팅·harden-runner·checkout을 실행당 2회에서 1회로 줄이고 최소 Python + 호환성, branch coverage 100%, docstring 100% 계약은 보존했습니다. +- PR concurrency를 + `exact-artifact-sbom-attestation-quality-{repository}-{PR번호}`와 + `cancel-in-progress: true`로 고정했습니다. diff --git a/docs/doctoring/exact-artifact-sbom-quality-runner-consolidation-20260903.md b/docs/doctoring/exact-artifact-sbom-quality-runner-consolidation-20260903.md new file mode 100644 index 0000000000..70fd333edf --- /dev/null +++ b/docs/doctoring/exact-artifact-sbom-quality-runner-consolidation-20260903.md @@ -0,0 +1,60 @@ +# Exact Artifact SBOM 품질 runner 통합 + +- 기준: `ContextualWisdomLab/.github@5afbf58cc62c8ff12a57c60d426d1352307fcd04` +- 확인 시점: 2026-09-03 KST +- 상태: 구현 및 current-head 검증 대상 + +## 문제 + +`Exact Artifact SBOM Attestation Quality`는 동일 source revision을 검증하기 위해 +Python 3.10 compile job과 Python 3.14 coverage job을 별도 runner에 배치했다. 그 결과 +한 workflow run마다 runner 부팅, harden-runner, checkout, exact-head 검증이 두 번 +수행됐다. + +Python 3.10 경로는 compile만 수행하며 Python 3.14 경로와 병렬 결과를 합성하지 않는다. +따라서 두 job 사이에 독립 장애 격리나 병렬 계산상 이점이 없고, 60-job ceiling에서는 +별도 runner가 queue slot과 boot 시간을 추가 소비한다. + +## 선택 + +두 Python 검증을 하나의 `exact_artifact_quality` job에서 순차 실행한다. + +1. runner hardening, checkout, exact-head 검증은 한 번만 수행한다. +2. Python 3.10을 설치해 production과 contract 파일을 compile한다. +3. 같은 runner에서 Python 3.14를 활성화해 hash-locked tooling을 설치한다. +4. 기존 세 contract suite와 새 workflow regression을 실행한다. +5. verifier branch coverage 100%, docstring 100%, Python 3.14 compile을 그대로 보존한다. +6. PR concurrency는 + `exact-artifact-sbom-attestation-quality-{repository}-{PR번호}`를 사용하고 + `cancel-in-progress: true`로 같은 PR의 구형 품질 실행만 취소한다. +7. push 검증에서는 PR 번호 대신 ref를 사용해 default-branch revision별 품질 검증을 + 이어간다. +8. API polling, runner-held sleep, manual dispatch를 두지 않는다. + +## RED와 GREEN 계약 + +`tests/test_exact_artifact_quality_single_runner.py`는 다음을 고정한다. + +- `runs-on`, harden-runner, checkout이 각각 정확히 1회 +- Python 3.10과 3.14 setup이 각각 1회 +- 3.10 compile이 3.14 coverage보다 먼저 실행 +- concurrency group에 workflow 이름, repository, PR 번호가 포함 +- `cancel-in-progress: true` +- predecessor의 production 및 contract 파일 전부 보존 +- branch coverage·docstring threshold 100% 보존 +- `gh api`, `sleep`, `workflow_dispatch` 없음 + +## 효과 + +한 workflow run의 runner job 수는 2개에서 1개로 50% 줄어든다. hardening과 checkout도 +각각 2회에서 1회로 줄어든다. Python runtime setup은 최소 지원 버전과 현재 버전을 +실제로 검증해야 하므로 2회를 유지하지만, 두 setup은 동일 runner에서 수행된다. + +이 변경은 SBOM publication workflow나 attestation mutation을 취소하지 않는다. 오직 +품질 검증 workflow만 stale-run cancellation 대상이다. + +## Rollback + +문제가 발견되면 이 commit 전체를 revert해 두 job 구조와 기존 context를 함께 복원한다. +Python 3.10 compile 또는 Python 3.14 coverage 중 하나만 제거하는 부분 rollback은 하지 +않는다. diff --git a/tests/test_exact_artifact_quality_single_runner.py b/tests/test_exact_artifact_quality_single_runner.py new file mode 100644 index 0000000000..683ac86747 --- /dev/null +++ b/tests/test_exact_artifact_quality_single_runner.py @@ -0,0 +1,99 @@ +"""Contracts for the single-runner exact artifact quality workflow.""" + +from __future__ import annotations + +import re +from pathlib import Path + + +REPOSITORY_ROOT = Path(__file__).resolve().parents[1] +WORKFLOW_PATH = ( + REPOSITORY_ROOT + / ".github" + / "workflows" + / "exact-artifact-sbom-attestation-quality.yml" +) + + +def _workflow_text() -> str: + """Return the exact artifact quality workflow source.""" + + return WORKFLOW_PATH.read_text(encoding="utf-8") + + +def test_exact_artifact_quality_uses_one_runner_boot() -> None: + """Compile both supported Python versions without a second runner job.""" + + workflow = _workflow_text() + + assert workflow.count("runs-on:") == 1 + assert workflow.count("step-security/harden-runner@") == 1 + assert workflow.count("actions/checkout@") == 1 + assert workflow.count('python-version: "3.10"') == 1 + assert workflow.count('python-version: "3.14"') == 1 + + +def test_minimum_python_compile_precedes_current_python_contracts() -> None: + """Keep the Python 3.10 syntax gate before the Python 3.14 test suite.""" + + workflow = _workflow_text() + + minimum_setup = workflow.index("- name: Set up minimum supported Python") + minimum_compile = workflow.index( + "- name: Compile production and contracts on Python 3.10" + ) + current_setup = workflow.index("- name: Set up current stable Python") + current_contract = workflow.index( + "- name: Run exact contracts with complete verifier branch coverage" + ) + + assert minimum_setup < minimum_compile < current_setup < current_contract + + +def test_pr_concurrency_uses_workflow_repository_and_pr_identity() -> None: + """Cancel only an older run of this workflow for the same repository and PR.""" + + workflow = _workflow_text() + concurrency = workflow.split("concurrency:", 1)[1].split( + "permissions:", 1 + )[0] + + assert ( + "group: exact-artifact-sbom-attestation-quality-" + "${{ github.repository }}-" + "${{ github.event.pull_request.number || github.ref }}" + in concurrency + ) + assert "cancel-in-progress: true" in concurrency + assert "github.sha" not in concurrency + assert "pull_request.head.sha" not in concurrency + + +def test_successor_preserves_all_exact_artifact_contracts() -> None: + """Retain every predecessor test, coverage, docstring, and syntax gate.""" + + workflow = _workflow_text() + + for required_path in ( + "scripts/ci/verify_exact_artifact_sbom_handoff.py", + "tests/test_exact_artifact_sbom_attestation_contract.py", + "tests/test_exact_artifact_sbom_review_regressions.py", + "tests/test_verify_exact_artifact_sbom_handoff.py", + "tests/test_exact_artifact_quality_single_runner.py", + ): + assert required_path in workflow + + assert "coverage run --branch" in workflow + assert "--fail-under=100" in workflow + assert "interrogate --fail-under=100" in workflow + assert workflow.count("compileall -q") == 2 + + +def test_quality_runner_has_no_polling_or_runner_held_sleep() -> None: + """Keep the quality lane deterministic and free of API polling waits.""" + + workflow = _workflow_text() + + assert "gh api" not in workflow + assert re.search(r"(?m)^[ \t]*sleep[ \t]+", workflow) is None + assert "workflow_dispatch:" not in workflow