diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 2df162d89..8221219aa 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -38,4 +38,4 @@ updates: open-pull-requests-limit: 10 labels: - "dependencies" - - "github-actions" + - "area: ci-cd" diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 27c5b540f..54616541d 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@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4.37.8 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@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4.37.8 + - uses: github/codeql-action/analyze@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4.37.8 diff --git a/.github/workflows/ossf-scorecard.yml b/.github/workflows/ossf-scorecard.yml index 2a4b6eaa9..a66720ee9 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@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4.37.8 peeled commit; 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 d79ec32e1..db6c3db87 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@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4.37.8 peeled commit; SHA pinning retained as supply-chain attack mitigation. if: always() with: sarif_file: trivy-results.sarif diff --git a/services/analysis-engine/tests/test_codeql_action_version_contract.py b/services/analysis-engine/tests/test_codeql_action_version_contract.py new file mode 100644 index 000000000..6e225686d --- /dev/null +++ b/services/analysis-engine/tests/test_codeql_action_version_contract.py @@ -0,0 +1,22 @@ +"""Regression contract for coordinated CodeQL Action component upgrades.""" + +from __future__ import annotations + +import re +from pathlib import Path + +REPO_ROOT = Path(__file__).resolve().parents[3] +CODEQL_WORKFLOW = REPO_ROOT / ".github" / "workflows" / "codeql.yml" +CODEQL_ACTION_PATTERN = re.compile( + r"github/codeql-action/(?:init|autobuild|analyze)@([0-9a-f]{40})\s+#\s+(v[0-9.]+)" +) + + +def test_codeql_job_uses_one_action_release() -> None: + """Require init, autobuild, and analyze to use one reviewed CodeQL release.""" + workflow = CODEQL_WORKFLOW.read_text(encoding="utf-8") + action_refs = CODEQL_ACTION_PATTERN.findall(workflow) + + assert len(action_refs) == 3 + assert len({sha for sha, _version in action_refs}) == 1 + assert len({version for _sha, version in action_refs}) == 1 diff --git a/services/analysis-engine/tests/test_codeql_upload_sarif_version_contract.py b/services/analysis-engine/tests/test_codeql_upload_sarif_version_contract.py new file mode 100644 index 000000000..523c548b1 --- /dev/null +++ b/services/analysis-engine/tests/test_codeql_upload_sarif_version_contract.py @@ -0,0 +1,23 @@ +"""Regression contracts for CodeQL SARIF uploader provenance comments.""" + +from __future__ import annotations + +from pathlib import Path + +REPO_ROOT = Path(__file__).resolve().parents[3] +EXPECTED_SHA = "db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28" +EXPECTED_VERSION = "v4.37.8" +UPLOAD_SARIF_REF = ( + f"github/codeql-action/upload-sarif@{EXPECTED_SHA} # {EXPECTED_VERSION} peeled commit;" +) +WORKFLOWS = ( + REPO_ROOT / ".github" / "workflows" / "ossf-scorecard.yml", + REPO_ROOT / ".github" / "workflows" / "trivy.yml", +) + + +def test_upload_sarif_sha_and_version_comment_move_together() -> None: + """Keep each immutable SARIF uploader pin paired with its reviewed release label.""" + for workflow in WORKFLOWS: + contents = workflow.read_text(encoding="utf-8") + assert contents.count(UPLOAD_SARIF_REF) == 1 diff --git a/services/analysis-engine/tests/test_dependabot_label_contract.py b/services/analysis-engine/tests/test_dependabot_label_contract.py new file mode 100644 index 000000000..4bec93429 --- /dev/null +++ b/services/analysis-engine/tests/test_dependabot_label_contract.py @@ -0,0 +1,18 @@ +"""Regression contract for Dependabot's configured repository labels.""" + +from __future__ import annotations + +from pathlib import Path + + +REPO_ROOT = Path(__file__).resolve().parents[3] +DEPENDABOT_CONFIG = REPO_ROOT / ".github" / "dependabot.yml" + + +def test_github_actions_updates_use_repository_ci_cd_taxonomy() -> None: + """Keep GitHub Actions updates on an existing CI/CD taxonomy label.""" + config = DEPENDABOT_CONFIG.read_text(encoding="utf-8") + github_actions = config.split('package-ecosystem: "github-actions"', maxsplit=1)[1] + + assert '- "area: ci-cd"' in github_actions + assert '- "github-actions"' not in github_actions