diff --git a/.codeqlignore b/.codeqlignore deleted file mode 100644 index 4de5af0f..00000000 --- a/.codeqlignore +++ /dev/null @@ -1,4 +0,0 @@ -# Exclude Jinja2 cookiecutter template directories from CodeQL analysis. -# These directories contain {{cookiecutter.variable}} template expressions -# inside Python files, causing CodeQL to report syntax errors during extraction. -{{cookiecutter.project_slug}}/ diff --git a/.github/codeql-config.yml b/.github/codeql-config.yml deleted file mode 100644 index 96bb4851..00000000 --- a/.github/codeql-config.yml +++ /dev/null @@ -1,17 +0,0 @@ ---- -# CodeQL configuration for cookiecutter-python-template -# Excludes template files containing Jinja2 syntax from analysis - -name: "CodeQL Config" - -# Exclude template directory - contains Jinja2 template syntax -# that appears invalid to static analyzers before rendering -paths-ignore: - - '{{cookiecutter.project_slug}}/**' - - '.venv/**' - - 'venv/**' - - 'node_modules/**' - - '.git/**' - - 'dist/**' - - 'build/**' - - '**/*.egg-info/**' diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml deleted file mode 100644 index 1008df07..00000000 --- a/.github/codeql/codeql-config.yml +++ /dev/null @@ -1,34 +0,0 @@ -# CodeQL configuration for cookiecutter-python-template. -# -# Files under `hooks/` are Python cookiecutter pre/post-generation hooks -# rendered by Jinja2 BEFORE execution. Lines such as -# `if "{{ cookiecutter.include_editorconfig }}" == "no":` look like -# "comparison of constants" or "constant in conditional" to a static analyzer -# that reads the file as plain Python, but at runtime the left-hand side is -# substituted with the value the project author chose ("yes" or "no") and the -# comparison is meaningful. CodeQL has no awareness of cookiecutter templating, -# so the queries below are filtered out for the `hooks/` path only. -# -# The same suppression scope intentionally does NOT cover -# `{{cookiecutter.project_slug}}/`, because the generated project's Python is -# executed as-is after rendering and benefits from full CodeQL coverage. - -name: "Custom CodeQL config for cookiecutter hooks" - -queries: - - uses: security-extended - - uses: security-and-quality - -query-filters: - - exclude: - id: py/constant-comparison - paths: - - hooks/** - - exclude: - id: py/constant-conditional-expression - paths: - - hooks/** - - exclude: - id: py/comparison-of-constants - paths: - - hooks/** diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml deleted file mode 100644 index 608cc8e8..00000000 --- a/.github/workflows/codeql.yml +++ /dev/null @@ -1,69 +0,0 @@ -# CodeQL Security Analysis -# Performs static application security testing (SAST) using GitHub CodeQL. -# -# IMPORTANT: GitHub's CodeQL "default setup" must remain DISABLED for this repo. -# Default setup and custom advanced configuration cannot both upload SARIF to the -# Security tab. To verify or disable: Settings > Code security > Code scanning > Default setup. -name: CodeQL Analysis - -on: - push: - branches: [main, master] - pull_request: - branches: [main, master] - schedule: - - cron: "0 7 * * 1" - workflow_dispatch: - -permissions: - contents: read - -concurrency: - group: codeql-${{ github.ref }} - cancel-in-progress: false - -jobs: - analyze: - name: CodeQL Analyze (Python) - runs-on: ubuntu-latest - timeout-minutes: 30 - permissions: - actions: read - contents: read - security-events: write - - steps: - - name: Harden the runner - uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 - with: - egress-policy: audit - - - name: Checkout repository - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 - with: - persist-credentials: false - - - name: Set up Python - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 - with: - python-version: "3.12" - - - name: Install uv - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 - with: - enable-cache: true - - - name: Install dependencies - run: uv sync --no-dev - - - name: Initialize CodeQL - uses: github/codeql-action/init@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2 - with: - languages: python - build-mode: none - config-file: ./.github/codeql/codeql-config.yml - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2 - with: - category: "/language:python" diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml deleted file mode 100644 index 02651b03..00000000 --- a/.github/workflows/dependency-review.yml +++ /dev/null @@ -1,38 +0,0 @@ -# Dependency Review - Analyzes dependency changes in PRs -# Checks for vulnerabilities and license compliance -# -# Features: -# - Vulnerability detection in dependency changes -# - License compliance checking -# - Blocks PRs with high severity vulnerabilities -name: Dependency Review - -on: - pull_request: - branches: [main, master, develop] - -permissions: - contents: read - pull-requests: write - -jobs: - dependency-review: - name: Dependency Review - runs-on: ubuntu-latest - steps: - - name: Harden the runner - uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 - with: - egress-policy: audit - - - name: Checkout repository - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 - - - name: Dependency Review - uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0 - with: - fail-on-severity: high - allow-licenses: MIT, Apache-2.0, BSD-2-Clause, BSD-3-Clause, ISC, MPL-2.0, LGPL-2.1, LGPL-3.0, Python-2.0, Unlicense, CC0-1.0, GPL-3.0-or-later - # codespell is a dev-only spell checker; its GPL-2.0 license never attaches to generated projects or distributed artifacts - allow-dependencies-licenses: pkg:pypi/codespell - comment-summary-in-pr: on-failure diff --git a/.github/workflows/sbom.yml b/.github/workflows/sbom.yml index 5e958be4..02c82e12 100644 --- a/.github/workflows/sbom.yml +++ b/.github/workflows/sbom.yml @@ -6,7 +6,14 @@ # - CycloneDX SBOM generation # - Trivy vulnerability scanning # - License compliance checking -# - SARIF upload to GitHub Security tab +# - SBOM/artifact results published as downloadable build artifacts. The +# upstream python-sbom.yml reusable workflow also attempts a SARIF +# upload to the GitHub Security tab for its Trivy runtime-deps scan; +# that upload is a no-op on this repo since GitHub Advanced Security +# (Code Security) is not enabled, and updating it is out of scope here +# (owned by ByronWilliamsCPA/.github). That scan has no artifact +# fallback at the currently pinned SHA, so its findings currently go +# nowhere; flagged as a follow-up. name: SBOM & Security Scan on: diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 70b21c4d..6e64a56a 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -23,8 +23,14 @@ jobs: scorecard: name: Scorecard Analysis permissions: - security-events: write id-token: write contents: read actions: read uses: ByronWilliamsCPA/.github/.github/workflows/python-scorecard.yml@961eb17d8e9b7fe0d8bfc5dbe9d23c824484fb11 # main + with: + # GitHub Advanced Security (Code Security) is not enabled on this repo, + # so the reusable workflow's upload-sarif step (default: true) has no + # destination to post to. The callee's "Upload Scorecard artifact" + # step runs unconditionally, so results remain reviewable as a build + # artifact. + upload-sarif: false diff --git a/.secrets.baseline b/.secrets.baseline index 7889add6..145ce97e 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -211,7 +211,7 @@ "filename": "README.md", "hashed_secret": "f7485c89e918d73cb3096af4ff0b916a27bf9a5d", "is_verified": false, - "line_number": 317 + "line_number": 320 } ], "central-services/auth-service/README.md": [ @@ -306,5 +306,5 @@ } ] }, - "generated_at": "2026-05-31T05:04:52Z" + "generated_at": "2026-09-02T21:12:25Z" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e881694..d8aac336 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -123,6 +123,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 SonarCloud quality-gate API. Generated child projects continue to opt into their own SonarCloud analysis via the rendered config that ships inside the template's rendered output directory. +- GitHub Advanced Security (Code Security) dependent CI, fleet-wide: GitHub + now bills this feature, so CodeQL code scanning, `actions/dependency-review-action`, + and SARIF ingestion into the Security tab no longer function without it. + Removed `.github/workflows/codeql.yml`, `.github/workflows/dependency-review.yml`, + `.github/codeql-config.yml`, `.github/codeql/codeql-config.yml`, and + `.codeqlignore` from this template repository's own CI, plus + `{{cookiecutter.project_slug}}/.github/workflows/dependency-review.yml` + from generated projects. Removed the direct `github/codeql-action/upload-sarif` + step from `{{cookiecutter.project_slug}}/.github/workflows/cifuzzy.yml` + (replaced with an `actions/upload-artifact` step) and from the standalone + branch of `{{cookiecutter.project_slug}}/.github/workflows/scorecard.yml` + (an artifact upload of the same file already existed). Flipped + `upload-sarif: true` to `false` on the org-workflow callers that expose + that toggle (`.github/workflows/scorecard.yml`, + `{{cookiecutter.project_slug}}/.github/workflows/scorecard.yml`, + `{{cookiecutter.project_slug}}/.github/workflows/container-security.yml`); + each callee already publishes an unconditional `actions/upload-artifact` + fallback, so no findings are lost. `run-codeql` / `run-dependency-review` + input lines on `security-analysis.yml` callers were intentionally left + untouched: their defaults live in the shared `ByronWilliamsCPA/.github` + reusable workflow and are being retired there in a separate coordinated + change. ### Fixed diff --git a/README.md b/README.md index 452419c4..14b94818 100644 --- a/README.md +++ b/README.md @@ -221,7 +221,10 @@ Complete project structure with: - ✅ **Architecture Decision Records** (ADRs) **Security (OWASP Top 10 Compliant):** -- ✅ **7+ security tools** (Bandit, Safety, OSV-Scanner, CodeQL, Gitleaks, etc.) +- ✅ **Security tools** (Bandit, OSV-Scanner, Trivy, Gitleaks, etc.); the org-workflow variant + can also enable CodeQL and `actions/dependency-review-action` via `security-analysis.yml`, + but both require GitHub Advanced Security (Code Security), a paid GitHub feature not assumed + to be enabled on generated projects - ✅ **SBOM generation** (CycloneDX format) - ✅ **API security middleware** (headers, rate limiting, SSRF prevention) - ✅ **Secrets scanning** with Gitleaks diff --git a/docs/org-workflows/python-sbom.yml b/docs/org-workflows/python-sbom.yml index 1a85bd98..9d9a7014 100644 --- a/docs/org-workflows/python-sbom.yml +++ b/docs/org-workflows/python-sbom.yml @@ -11,7 +11,10 @@ # - CycloneDX SBOM generation # - Trivy vulnerability scanning # - License compliance checking -# - SARIF upload to GitHub Security tab +# - Trivy runtime-deps SARIF published as a downloadable build artifact. +# github/codeql-action/upload-sarif requires GitHub Advanced Security +# (Code Security), a paid GitHub feature; do not assume it is enabled on +# the calling repo. # ============================================================================ name: Reusable Python SBOM @@ -106,7 +109,6 @@ jobs: runs-on: ubuntu-latest permissions: contents: read - security-events: write # Required for SARIF upload steps: - name: Download SBOM artifacts uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 @@ -131,12 +133,18 @@ jobs: format: sarif output: trivy-runtime-results.sarif - - name: Upload Trivy results to GitHub Security tab + # GitHub Advanced Security (Code Security) requires a paid plan; do not + # assume it is enabled on the calling repo. github/codeql-action/upload-sarif + # has no destination to post to without it. Publish the SARIF as a + # downloadable artifact instead so findings remain reviewable. + - name: Upload Trivy SARIF artifact if: always() - uses: github/codeql-action/upload-sarif@48ab28a6f5dbc2a99bf1e0131198dd8f1df78169 # v3.27.5 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: - sarif_file: trivy-runtime-results.sarif - category: trivy-runtime-deps + name: trivy-runtime-sarif + path: trivy-runtime-results.sarif + retention-days: ${{ inputs.artifact-retention-days }} + if-no-files-found: warn # ============================================================================ # Job 3: License Compliance Check diff --git a/docs/secure.md b/docs/secure.md index 1c33e14d..0378cd56 100644 --- a/docs/secure.md +++ b/docs/secure.md @@ -211,7 +211,6 @@ on: permissions: contents: read - security-events: write # For SARIF upload env: INFISICAL_DOMAIN: https://secrets.byronwilliamscpa.com @@ -288,34 +287,42 @@ jobs: INFISICAL_CLIENT_SECRET: ${{ secrets.INFISICAL_CLIENT_SECRET }} ``` -### 3.3 Dependency Review (PRs) +### 3.3 Dependency Vetting (PRs) -Add dependency review for pull requests: +`actions/dependency-review-action` relies on GitHub's dependency-graph diff +and GitHub Advanced Security (Code Security), a paid GitHub feature; without +it the action either fails to resolve a diff or (with `continue-on-error`) +silently reports nothing. Do not add `dependency-review.yml` unless GHAS is +actually enabled and verified on the target repo. + +For projects without GHAS, gate PRs with OSV-Scanner against the lockfile +instead, which needs no GitHub billing feature and no API key: ```yaml # .github/workflows/dependency-review.yml -name: Dependency Review +name: Dependency Vetting on: pull_request: branches: [main] + paths: + - 'pyproject.toml' + - 'uv.lock' permissions: contents: read - pull-requests: write jobs: - dependency-review: + osv-scan: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - name: Dependency Review - uses: actions/dependency-review-action@v4 + - name: OSV-Scanner dependency scan + uses: google/osv-scanner-action/osv-scanner-action@v2.3.8 with: - fail-on-severity: high - deny-licenses: GPL-3.0, AGPL-3.0 - allow-licenses: MIT, Apache-2.0, BSD-2-Clause, BSD-3-Clause, ISC + scan-args: |- + --lockfile=./uv.lock ``` --- diff --git a/tests/test_supply_chain_security.py b/tests/test_supply_chain_security.py index cbd08b5a..371351ac 100644 --- a/tests/test_supply_chain_security.py +++ b/tests/test_supply_chain_security.py @@ -3,7 +3,6 @@ from __future__ import annotations import json -import re from typing import TYPE_CHECKING, Any import pytest @@ -78,24 +77,26 @@ def test_setup_supply_chain_script_created( "Script should reference Infisical" ) - def test_dependency_review_workflow_created( + def test_dependency_review_workflow_not_generated( self, template_dir: Path, temp_dir: Path, supply_chain_config: dict[str, Any] ) -> None: - """Verify dependency-review.yml workflow is created.""" + """Verify dependency-review.yml is never generated, even with supply chain security enabled. + + `actions/dependency-review-action` depends on GitHub's dependency-graph + diff and GitHub Advanced Security (Code Security), a paid GitHub + feature. GitHub now bills that feature, so the action no longer + functions without it. The workflow template was removed fleet-wide; + see CHANGELOG.md [Unreleased] > Removed. + """ from tests.conftest import generate_project project_dir = generate_project(template_dir, temp_dir, supply_chain_config) workflow_file = project_dir / ".github" / "workflows" / "dependency-review.yml" - assert workflow_file.exists(), "dependency-review.yml should exist" - - content = workflow_file.read_text() - - # Verify workflow structure - assert "Dependency Review" in content, "Workflow should have Dependency Review name" - assert "pull_request" in content, "Workflow should trigger on pull requests" - assert "dependency-review-action" in content, "Workflow should use dependency-review-action" - assert "fail-on-severity" in content, "Workflow should have severity configuration" + assert not workflow_file.exists(), ( + "dependency-review.yml should not exist; actions/dependency-review-action " + "requires GitHub Advanced Security and was removed fleet-wide" + ) def test_pyproject_has_uv_index_config( self, template_dir: Path, temp_dir: Path, supply_chain_config: dict[str, Any] @@ -276,7 +277,12 @@ def test_setup_script_not_created( def test_dependency_review_workflow_not_created( self, template_dir: Path, temp_dir: Path, no_supply_chain_config: dict[str, Any] ) -> None: - """Verify dependency-review.yml is NOT created when disabled.""" + """Verify dependency-review.yml is NOT created when disabled. + + The workflow template was removed fleet-wide regardless of this flag + (see test_dependency_review_workflow_not_generated), so this remains + true; kept as regression coverage for the disabled path specifically. + """ from tests.conftest import generate_project project_dir = generate_project(template_dir, temp_dir, no_supply_chain_config) @@ -411,55 +417,23 @@ def supply_chain_project( return generate_project(template_dir, temp_dir, config) def test_dependency_review_license_config(self, supply_chain_project: Path) -> None: - """Verify dependency review workflow has proper license configuration.""" + """Verify the copyleft license deny-list is gone along with dependency-review.yml. + + This deny-list (AGPL/GPL/LGPL family SPDX ids) previously lived + exclusively in dependency-review.yml's `deny-licenses` input. + actions/dependency-review-action requires GitHub Advanced Security + (Code Security), a paid GitHub feature, so the workflow was removed + fleet-wide (see CHANGELOG.md [Unreleased] > Removed). Generated + projects currently have no equivalent copyleft-license gate; + `sbom.yml`'s `fail-on-forbidden-licenses` input defaults to `false` + and does not carry this deny-list. Tracked as a known coverage gap + pending a replacement license gate. + """ workflow = supply_chain_project / ".github" / "workflows" / "dependency-review.yml" - content = workflow.read_text() - - # Uses deny-list approach: copyleft licenses explicitly blocked, - # permissive licenses (MIT, Apache-2.0) allowed implicitly. - - assert "deny-licenses" in content, "Should use deny-list approach" - - # Strong copyleft variants that must be denied (AGPL family + GPLv2/3) - denied_required = [ - "AGPL-3.0", - "AGPL-3.0-only", - "AGPL-3.0-or-later", - "GPL-2.0-only", - "GPL-2.0-or-later", - "GPL-3.0-only", - "GPL-3.0-or-later", - "LGPL-2.0-only", - "LGPL-2.1-only", - "LGPL-3.0-only", - "LGPL-3.0-or-later", - ] - for spdx in denied_required: - assert spdx in content, f"Should deny {spdx}" - - # Negative test: permissive licenses MUST NOT appear in the deny-list. - # The comment above claims they are allowed implicitly; this assertion - # verifies the claim by failing if any permissive SPDX identifier - # accidentally lands in deny-licenses. - permissive_must_not_be_denied = [ - "MIT", - "Apache-2.0", - "BSD-3-Clause", - "BSD-2-Clause", - "ISC", - ] - # Look at only the deny-licenses section to avoid false positives from - # other YAML keys that may legitimately mention permissive licenses. - deny_section_match = re.search( - r"deny-licenses:\s*[\"']?([^\n]+(?:\n\s+[^\n]+)*)", - content, + assert not workflow.exists(), ( + "dependency-review.yml should not exist; its deny-licenses " + "configuration was removed along with it" ) - deny_block = deny_section_match.group(1) if deny_section_match else content - for spdx in permissive_must_not_be_denied: - # Use word-boundary regex so MIT does not match e.g. MITRE - assert not re.search(rf"\b{re.escape(spdx)}\b", deny_block), ( - f"{spdx} is a permissive license and must not appear in deny-licenses" - ) def test_gcp_variables_rendered_in_pyproject(self, supply_chain_project: Path) -> None: """Verify GCP variables are properly rendered in pyproject.toml.""" diff --git a/{{cookiecutter.project_slug}}/.github/workflows/cifuzzy.yml b/{{cookiecutter.project_slug}}/.github/workflows/cifuzzy.yml index 1c9cba21..73f7d141 100644 --- a/{{cookiecutter.project_slug}}/.github/workflows/cifuzzy.yml +++ b/{{cookiecutter.project_slug}}/.github/workflows/cifuzzy.yml @@ -11,7 +11,10 @@ # # Duration: 600 seconds per run # Sanitizer: AddressSanitizer for memory safety -# Reporting: SARIF format uploaded to Security tab +# Reporting: SARIF format published as a downloadable build artifact. +# GitHub Advanced Security (Code Security) requires a paid plan and is not +# assumed to be enabled on projects generated from this template, so +# results are not uploaded to the Security tab. {%- if cookiecutter.include_fuzzing == "yes" %} name: Continuous Fuzzing @@ -29,7 +32,6 @@ on: permissions: contents: read - security-events: write # For SARIF upload jobs: fuzzing: @@ -79,12 +81,19 @@ jobs: sanitizer: {% raw %}${{ matrix.sanitizer }}{% endraw %} output-sarif: true - - name: Upload SARIF + # GitHub Advanced Security (Code Security) requires a paid plan and is + # not assumed to be enabled on projects generated from this template, + # so github/codeql-action/upload-sarif has no destination to post to. + # Publish the SARIF as a downloadable artifact instead so findings + # remain reviewable. + - name: Upload fuzzing SARIF artifact if: always() && steps.check-fuzz.outputs.has-targets == 'true' - uses: github/codeql-action/upload-sarif@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: - sarif_file: results.sarif - category: fuzzing-{% raw %}${{ matrix.sanitizer }}{% endraw %} + name: fuzzing-sarif-{% raw %}${{ matrix.sanitizer }}{% endraw %} + path: results.sarif + retention-days: 30 + if-no-files-found: warn - name: Upload Crash Artifacts if: failure() && steps.check-fuzz.outputs.has-targets == 'true' diff --git a/{{cookiecutter.project_slug}}/.github/workflows/container-security.yml b/{{cookiecutter.project_slug}}/.github/workflows/container-security.yml index 4d7d84dd..ee8b5841 100644 --- a/{{cookiecutter.project_slug}}/.github/workflows/container-security.yml +++ b/{{cookiecutter.project_slug}}/.github/workflows/container-security.yml @@ -34,7 +34,6 @@ concurrency: permissions: contents: read - security-events: write packages: read jobs: @@ -51,7 +50,12 @@ jobs: run-hadolint: true hadolint-failure-threshold: 'warning' generate-sbom: true - upload-sarif: true + # GitHub Advanced Security (Code Security) requires a paid plan and is + # not assumed to be enabled on projects generated from this template. + # The reusable workflow's "Upload container security artifacts" step + # runs unconditionally (not gated on upload-sarif), so results remain + # reviewable as a build artifact even with SARIF upload disabled. + upload-sarif: false artifact-retention-days: 90 secrets: inherit {%- elif cookiecutter.include_github_actions == "yes" %} diff --git a/{{cookiecutter.project_slug}}/.github/workflows/dependency-review.yml b/{{cookiecutter.project_slug}}/.github/workflows/dependency-review.yml deleted file mode 100644 index 830c28a5..00000000 --- a/{{cookiecutter.project_slug}}/.github/workflows/dependency-review.yml +++ /dev/null @@ -1,49 +0,0 @@ -# Dependency Review - Analyzes dependency changes in PRs -# Checks for vulnerabilities and license compliance -# -# Features: -# - Vulnerability detection in dependency changes -# - License compliance checking -# - Blocks PRs with high severity vulnerabilities -{%- if cookiecutter.include_github_actions == "yes" and cookiecutter.include_supply_chain_security == "yes" %} -name: Dependency Review - -on: - pull_request: - branches: [main, master, develop] - paths: - - 'pyproject.toml' - - 'uv.lock' - - 'requirements*.txt' - -permissions: - contents: read - pull-requests: write - -jobs: - dependency-review: - name: Dependency Review - runs-on: ubuntu-latest - permissions: - contents: read - pull-requests: write - steps: - - name: Harden the runner - uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 - with: - egress-policy: audit - - - name: Checkout repository - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 - - - name: Dependency Review - uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0 - with: - fail-on-severity: high - # Deny copyleft and restrictive licenses (deny-list approach) - deny-licenses: AGPL-3.0, AGPL-3.0-only, AGPL-3.0-or-later, GPL-2.0-only, GPL-2.0-or-later, GPL-3.0-only, GPL-3.0-or-later, LGPL-2.0-only, LGPL-2.1-only, LGPL-3.0-only, LGPL-3.0-or-later - comment-summary-in-pr: on-failure -{%- else %} -# Dependency Review disabled -# Enable include_github_actions and include_supply_chain_security to use this workflow -{%- endif %} diff --git a/{{cookiecutter.project_slug}}/.github/workflows/sbom.yml b/{{cookiecutter.project_slug}}/.github/workflows/sbom.yml index 0c3b5460..3bfe4159 100644 --- a/{{cookiecutter.project_slug}}/.github/workflows/sbom.yml +++ b/{{cookiecutter.project_slug}}/.github/workflows/sbom.yml @@ -6,7 +6,12 @@ # - CycloneDX SBOM generation # - Trivy vulnerability scanning # - License compliance checking -# - SARIF upload to GitHub Security tab +# - SBOM/artifact results published as downloadable build artifacts. The +# upstream python-sbom.yml reusable workflow also attempts a SARIF +# upload to the GitHub Security tab for its Trivy runtime-deps scan; +# GitHub Advanced Security (Code Security) requires a paid plan and is +# not assumed to be enabled on projects generated from this template, so +# that upload will be a no-op unless the downstream project enables it. {%- if cookiecutter.include_github_actions == "yes" %} name: SBOM & Security Scan diff --git a/{{cookiecutter.project_slug}}/.github/workflows/scorecard.yml b/{{cookiecutter.project_slug}}/.github/workflows/scorecard.yml index 5d6b14d0..56f36bec 100644 --- a/{{cookiecutter.project_slug}}/.github/workflows/scorecard.yml +++ b/{{cookiecutter.project_slug}}/.github/workflows/scorecard.yml @@ -20,7 +20,6 @@ on: permissions: contents: read - security-events: write id-token: write actions: read @@ -31,7 +30,11 @@ jobs: name: Scorecard Analysis uses: {{ cookiecutter.github_org_or_user }}/.github/.github/workflows/python-scorecard.yml@main with: - upload-sarif: true + # GitHub Advanced Security (Code Security) requires a paid plan and is + # not assumed to be enabled on projects generated from this template. + # The reusable workflow's "Upload Scorecard artifact" step runs + # unconditionally, so results remain reviewable as a build artifact. + upload-sarif: false artifact-retention-days: 5 {%- else -%} # Standalone OpenSSF Scorecard workflow @@ -41,7 +44,6 @@ jobs: runs-on: ubuntu-latest permissions: contents: read - security-events: write id-token: write actions: read steps: @@ -66,11 +68,11 @@ jobs: # input (hyphen) removed from the org-workflow caller above. publish_results: true - - name: Upload SARIF results - uses: github/codeql-action/upload-sarif@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2 - with: - sarif_file: results.sarif - + # GitHub Advanced Security (Code Security) requires a paid plan and is + # not assumed to be enabled on projects generated from this template, + # so github/codeql-action/upload-sarif has no destination to post to. + # The artifact upload immediately below already publishes the same + # results.sarif file, so no separate SARIF upload step is needed. - name: Upload Scorecard results as artifact uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: