diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 27c5b540..ee9b6019 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -32,8 +32,8 @@ jobs: - python steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - uses: github/codeql-action/init@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4.37.0 + - uses: github/codeql-action/init@5595ccaf912efad79be6eef63a5619ff05969be3 # v4.37.6 with: languages: ${{ matrix.language }} - - uses: github/codeql-action/autobuild@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4.37.0 - - uses: github/codeql-action/analyze@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4.37.0 + - uses: github/codeql-action/autobuild@5595ccaf912efad79be6eef63a5619ff05969be3 # v4.37.6 + - uses: github/codeql-action/analyze@5595ccaf912efad79be6eef63a5619ff05969be3 # v4.37.6 diff --git a/.github/workflows/ossf-scorecard.yml b/.github/workflows/ossf-scorecard.yml index 2a4b6eaa..a3c28778 100644 --- a/.github/workflows/ossf-scorecard.yml +++ b/.github/workflows/ossf-scorecard.yml @@ -79,6 +79,6 @@ jobs: python3 trusted-scorecard-scripts/scripts/checks/normalize_scorecard_sarif.py scorecard-sarif/results.sarif normalized-scorecard-results.sarif - - uses: github/codeql-action/upload-sarif@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4.37.0 peeled commit; SHA pinning retained as supply-chain attack mitigation. + - uses: github/codeql-action/upload-sarif@5595ccaf912efad79be6eef63a5619ff05969be3 # v4.37.6; immutable SHA pinning retained as supply-chain attack mitigation. with: sarif_file: normalized-scorecard-results.sarif diff --git a/.github/workflows/trivy.yml b/.github/workflows/trivy.yml index d79ec32e..cd417efb 100644 --- a/.github/workflows/trivy.yml +++ b/.github/workflows/trivy.yml @@ -48,7 +48,7 @@ jobs: skip-dirs: 'services/analysis-engine/.venv' trivyignores: ./.trivyignore - name: Upload Trivy scan results to GitHub Security tab - uses: github/codeql-action/upload-sarif@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4.37.0 peeled commit; SHA pinning retained as supply-chain attack mitigation. + uses: github/codeql-action/upload-sarif@5595ccaf912efad79be6eef63a5619ff05969be3 # v4.37.6; immutable SHA pinning retained as supply-chain attack mitigation. if: always() with: sarif_file: trivy-results.sarif diff --git a/CHANGELOG.md b/CHANGELOG.md index eea69689..105f06d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ - Display the analyzed song tempo (BPM) as a badge in the rehearsal workspace. - 각 합주 역할(Role)별 개인 연습 진행도를 0~100% 범위로 기록 및 시각화할 수 있는 연습 진척도(`practiceProgress`) 트래커 기능 추가. UI 컨트롤(슬라이더 및 +/- 버튼)과 한/영 다국어 지원 포함. +### Changed + +- Updated every CodeQL Action phase and SARIF uploader together to the reviewed immutable `v4.37.6` revision, with a regression contract that prevents mixed `init`, `autobuild`, `analyze`, and `upload-sarif` versions. + ## [0.1.3] - 2026-04-29 ### Fixed diff --git a/docs/doctoring/codeql-action-atomic-revision.md b/docs/doctoring/codeql-action-atomic-revision.md new file mode 100644 index 00000000..61312f4f --- /dev/null +++ b/docs/doctoring/codeql-action-atomic-revision.md @@ -0,0 +1,61 @@ +# Atomic CodeQL Action revision policy + +## Decision + +BandScope treats the CodeQL Action lifecycle as one supply-chain dependency. Every checked-in reference to `github/codeql-action/init`, `autobuild`, `analyze`, and `upload-sarif` must use the same reviewed full-length commit SHA and matching release annotation. + +The current reviewed revision is CodeQL Action `v4.37.6` at commit `5595ccaf912efad79be6eef63a5619ff05969be3`. + +GitHub documents `init` as the phase that initializes CodeQL, `autobuild` as the optional automatic build phase, and `analyze` as the phase that finalizes the database, runs queries, and uploads results. `upload-sarif` publishes SARIF generated by other tools. These phases exchange state and therefore move together in this repository rather than through independent dependency pull requests. + +## Threat and compatibility boundary + +A full commit SHA is the immutable execution identity. Tags remain useful release labels, but they are not accepted as the workflow execution reference. GitHub identifies a full-length commit SHA as the strongest immutable action reference and supports organization policy requiring that form. + +Independently updating one phase can leave the repository with mixed JavaScript bundles, CodeQL CLI expectations, feature flags, or SARIF transport behavior. Even when each individual release is valid, the mixed lifecycle has not been reviewed or tested as a unit. The atomic policy prevents both persistent drift and the transient mixed state that can occur when several Dependabot pull requests merge at different times. + +```mermaid +flowchart LR + A[CodeQL init] --> B[CodeQL autobuild] + B --> C[CodeQL analyze] + C --> D[GitHub code scanning] + E[Trivy and Scorecard SARIF] --> F[CodeQL upload-sarif] + R[One reviewed release SHA] --> A + R --> B + R --> C + R --> F +``` + +The change does not alter workflow triggers, language selection, build behavior, SARIF paths, permissions, or failure handling. It changes only the immutable CodeQL Action implementation identity and version comments. + +## Verification contract + +`services/analysis-engine/tests/test_codeql_action_revision_contract.py` scans every workflow and fails unless: + +1. all CodeQL Action phases use one exact reviewed SHA; +2. every reference carries the matching `v4.37.6` annotation; and +3. `codeql.yml` keeps `init`, `autobuild`, and `analyze` on that same revision. + +Repository CI, CodeQL, SAST, dependency/security scans, SBOM generation, central coverage evidence, automated review, independent approval, and branch protection must all validate the final exact head. Results from split predecessor pull requests are not transferable. + +## Update procedure + +1. Identify the newest supported CodeQL Action v4 release from the upstream GitHub repository. +2. Verify the tag resolves to the intended upstream commit and inspect the release notes. +3. Add or update the contract expectation first and observe the RED failure against the old revision. +4. Update every `init`, `autobuild`, `analyze`, and `upload-sarif` reference in one branch. +5. Run the focused contract, workflow/static checks, and the complete repository gates. +6. Merge only after exact-current-head review and branch protection succeed without bypass. +7. Close split dependency pull requests as superseded; do not reuse their checks or approvals. + +## Rollback + +Rollback restores the previously accepted full-length SHA across every CodeQL Action phase in one reviewed commit. A partial rollback is prohibited. After rollback, rerun the same exact-head security, quality, SARIF publication, and review gates before accepting the branch. + +## References + +GitHub. (2026). *CodeQL Action v4.37.6* [Software release]. https://github.com/github/codeql-action/releases/tag/v4.37.6 + +GitHub. (n.d.). *CodeQL code scanning for compiled languages*. GitHub Docs. Retrieved August 7, 2026, from https://docs.github.com/en/code-security/how-tos/find-and-fix-code-vulnerabilities/manage-your-configuration/codeql-for-compiled-languages + +GitHub. (n.d.). *Secure use reference*. GitHub Docs. Retrieved August 7, 2026, from https://docs.github.com/en/actions/reference/security/secure-use diff --git a/services/analysis-engine/tests/test_codeql_action_revision_contract.py b/services/analysis-engine/tests/test_codeql_action_revision_contract.py new file mode 100644 index 00000000..1f9bc2d6 --- /dev/null +++ b/services/analysis-engine/tests/test_codeql_action_revision_contract.py @@ -0,0 +1,54 @@ +"""Supply-chain contracts for a coherent GitHub CodeQL Action revision.""" + +from __future__ import annotations + +import re +from pathlib import Path + +_REPOSITORY_ROOT = Path(__file__).resolve().parents[3] +_WORKFLOW_ROOT = _REPOSITORY_ROOT / ".github" / "workflows" +_EXPECTED_CODEQL_ACTION_SHA = "5595ccaf912efad79be6eef63a5619ff05969be3" +_EXPECTED_CODEQL_ACTION_VERSION = "v4.37.6" +_CODEQL_ACTION_REFERENCE = re.compile( + r"github/codeql-action/(init|autobuild|analyze|upload-sarif)@([0-9a-f]{40})([^\n]*)" +) + + +def _codeql_action_references() -> list[tuple[Path, str, str, str]]: + """Return every pinned CodeQL Action reference from checked-in workflows.""" + references: list[tuple[Path, str, str, str]] = [] + for workflow_path in sorted(_WORKFLOW_ROOT.glob("*.y*ml")): + workflow_text = workflow_path.read_text(encoding="utf-8") + for action_name, revision_sha, suffix in _CODEQL_ACTION_REFERENCE.findall(workflow_text): + references.append((workflow_path, action_name, revision_sha, suffix.strip())) + return references + + +def test_every_codeql_action_step_uses_the_same_reviewed_revision() -> None: + """Prevent independently updated phases from creating mixed CodeQL runtimes.""" + references = _codeql_action_references() + + assert references + assert {revision_sha for _, _, revision_sha, _ in references} == { + _EXPECTED_CODEQL_ACTION_SHA + } + assert all( + f"# {_EXPECTED_CODEQL_ACTION_VERSION}" in suffix + for _, _, _, suffix in references + ) + + +def test_analysis_workflow_keeps_init_autobuild_and_analyze_atomic() -> None: + """Require the analysis lifecycle to move as one immutable dependency unit.""" + workflow_path = _WORKFLOW_ROOT / "codeql.yml" + workflow_text = workflow_path.read_text(encoding="utf-8") + references = { + action_name: revision_sha + for action_name, revision_sha, _suffix in _CODEQL_ACTION_REFERENCE.findall(workflow_text) + } + + assert references == { + "init": _EXPECTED_CODEQL_ACTION_SHA, + "autobuild": _EXPECTED_CODEQL_ACTION_SHA, + "analyze": _EXPECTED_CODEQL_ACTION_SHA, + }