From 0095566205b341a4e5df6048d281f74966e33538 Mon Sep 17 00:00:00 2001 From: Danil Silantyev Date: Fri, 24 Jul 2026 23:26:25 +0500 Subject: [PATCH] ci: apply the public OSS security suite to this repository This repository ships CodeQL, OSSF Scorecard, Dependency Review and gitleaks to the estate and consumed none of them itself. It self-applied only actionlint, zizmor and release-supply-chain, so the repository that defines the estate's security posture had the weakest one in it. Add four self-application callers using relative refs, matching ci.yml's existing convention; only external consumers pin by full SHA. The gitleaks caller is named gitleaks.yml because secret-scan.yml is the reusable definition. Triggers follow the repository's own examples/public-oss shapes: Scorecard is push-to-default plus schedule because the action does not support pull_request, and Dependency Review is pull_request only. SELF_WORKFLOWS gains the four names. That set already existed to mark files that are this repository applying its own catalog rather than reusable definitions, so they carry no catalog, runtime-coverage or inventory entry. The same literal set was duplicated in three places: _workflow_yaml.py held the constant while validate_catalog.py and generate_docs.py each hardcoded {ci.yml, release.yml} again. Both now import it, so the exemption is defined once. Without that, the generated inventory listed the new callers as MISSING rather than internal. scripts/validate_all.py exits 0. Signed-off-by: Danil Silantyev --- .github/workflows/codeql.yml | 28 +++++++++++++++++++++++++ .github/workflows/dependency-review.yml | 17 +++++++++++++++ .github/workflows/gitleaks.yml | 21 +++++++++++++++++++ .github/workflows/scorecard.yml | 19 +++++++++++++++++ CHANGELOG.md | 20 ++++++++++++++++++ docs/generated/workflow-inventory.md | 4 ++++ scripts/_workflow_yaml.py | 13 ++++++++++-- scripts/generate_docs.py | 4 +++- scripts/validate_catalog.py | 4 +++- 9 files changed, 126 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/codeql.yml create mode 100644 .github/workflows/dependency-review.yml create mode 100644 .github/workflows/gitleaks.yml create mode 100644 .github/workflows/scorecard.yml diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..9c7656c --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,28 @@ +# CodeQL on this repository's own Python and Actions sources. Self-application: +# ci-workflows ships this capability to the estate, so it must consume it too. +# Self-references stay relative; only external consumers pin by full SHA. +name: codeql + +on: + push: + branches: [main] + pull_request: + branches: [main] + schedule: + - cron: "0 5 * * 1" + +permissions: {} + +concurrency: + group: codeql-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + codeql: + permissions: + actions: read # read workflow run metadata for the actions analysis + contents: read + security-events: write # upload CodeQL SARIF to the Security tab + uses: ./.github/workflows/public-codeql.yml + with: + languages: '["python","actions"]' diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml new file mode 100644 index 0000000..074e8d8 --- /dev/null +++ b/.github/workflows/dependency-review.yml @@ -0,0 +1,17 @@ +# Dependency Review — pull_request only, free on public repositories. +name: dependency-review + +on: + pull_request: + branches: [main] + +permissions: {} + +jobs: + dependency-review: + permissions: + contents: read + pull-requests: write # post the dependency review summary on the PR + uses: ./.github/workflows/public-dependency-review.yml + with: + fail_on_severity: moderate diff --git a/.github/workflows/gitleaks.yml b/.github/workflows/gitleaks.yml new file mode 100644 index 0000000..d3d86c2 --- /dev/null +++ b/.github/workflows/gitleaks.yml @@ -0,0 +1,21 @@ +# Gitleaks over this repository's own history. Named gitleaks.yml because +# secret-scan.yml is the reusable definition itself. +name: gitleaks + +on: + push: + branches: [main] + pull_request: + branches: [main] + +permissions: {} + +concurrency: + group: gitleaks-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + gitleaks: + permissions: + contents: read + uses: ./.github/workflows/secret-scan.yml diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml new file mode 100644 index 0000000..b529f76 --- /dev/null +++ b/.github/workflows/scorecard.yml @@ -0,0 +1,19 @@ +# OSSF Scorecard — push-to-default + weekly schedule only. The Scorecard action +# supports only push and schedule on the default branch. +name: scorecard + +on: + push: + branches: [main] + schedule: + - cron: "31 2 * * 1" + +permissions: {} + +jobs: + scorecard: + permissions: + id-token: write # OIDC token for Scorecard provenance checks + contents: read + actions: read # inspect workflow definitions for the scoring checks + uses: ./.github/workflows/public-scorecard-json.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index 258b109..bbd19ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,26 @@ ## [Unreleased] +### Added + +- **Self-application of the public OSS security suite.** This repository shipped + CodeQL, OSSF Scorecard, Dependency Review, and gitleaks to the estate while + consuming none of them itself; it self-applied only `actionlint`, `zizmor`, + and `release-supply-chain`. New self workflows `codeql.yml`, `gitleaks.yml`, + `dependency-review.yml`, and `scorecard.yml` call the matching reusables + through relative refs, with triggers taken from this repository's own + `examples/public-oss/` shapes. + +### Fixed + +- **`SELF_WORKFLOWS` was duplicated as a literal in three places.** + `_workflow_yaml.py` held the named constant while `validate_catalog.py` and + `generate_docs.py` each hardcoded `{"ci.yml", "release.yml"}` again. Both now + import it. With the constant honoured in only one of the three, + `validate_all.py` passed while `docs/generated/workflow-inventory.md` listed + the new self workflows as `MISSING` instead of `internal` — a green gate over + wrong generated output. + ## [0.12.0] - 2026-07-21 ### Changed diff --git a/docs/generated/workflow-inventory.md b/docs/generated/workflow-inventory.md index 8e697c3..a4d0f3c 100644 --- a/docs/generated/workflow-inventory.md +++ b/docs/generated/workflow-inventory.md @@ -7,15 +7,18 @@ | `.github/workflows/benchmark-compare.yml` | `benchmark-compare` | ga | | `.github/workflows/benchmark.yml` | `benchmark` | ga | | `.github/workflows/ci.yml` | internal | internal | +| `.github/workflows/codeql.yml` | internal | internal | | `.github/workflows/container-ci.yml` | `container-scan-trivy` | ga | | `.github/workflows/coverage-gate.yml` | `coverage-gate` | ga | | `.github/workflows/cpp-ci.yml` | `cpp-ci` | ga | | `.github/workflows/cross-platform-smoke.yml` | `cross-platform-smoke` | ga | | `.github/workflows/dart-flutter-ci.yml` | `dart-flutter-ci` | ga | +| `.github/workflows/dependency-review.yml` | internal | internal | | `.github/workflows/docs-ci.yml` | `docs-ci` | ga | | `.github/workflows/docs-quality.yml` | `docs-quality` | ga | | `.github/workflows/dotnet-ci.yml` | `dotnet-ci` | ga | | `.github/workflows/fuzzing.yml` | `fuzzing` | ga | +| `.github/workflows/gitleaks.yml` | internal | internal | | `.github/workflows/go-ci.yml` | `go-ci` | ga | | `.github/workflows/grype-scan.yml` | `grype-sca` | ga | | `.github/workflows/hadolint-ci.yml` | `hadolint-dockerfile` | ga | @@ -39,6 +42,7 @@ | `.github/workflows/release-supply-chain.yml` | `artifact-attestations`, `sbom-generation`, `slsa-build-provenance`, `release-supply-chain` | ga | | `.github/workflows/release.yml` | internal | internal | | `.github/workflows/rust-ci.yml` | `rust-ci` | ga | +| `.github/workflows/scorecard.yml` | internal | internal | | `.github/workflows/secret-scan.yml` | `gitleaks-secret-scan` | ga | | `.github/workflows/semgrep-ci.yml` | `semgrep-sast` | ga | | `.github/workflows/sql-ci.yml` | `sql-ci` | ga | diff --git a/scripts/_workflow_yaml.py b/scripts/_workflow_yaml.py index 546bf54..153e229 100644 --- a/scripts/_workflow_yaml.py +++ b/scripts/_workflow_yaml.py @@ -14,8 +14,17 @@ REPO_ROOT = Path(__file__).resolve().parent.parent WORKFLOWS_DIR = REPO_ROOT / ".github" / "workflows" -# Self workflows are not reusable (they are not `on: workflow_call`). -SELF_WORKFLOWS = {"ci.yml", "release.yml"} +# Self workflows are not reusable (they are not `on: workflow_call`). They are +# this repository applying its own catalog to itself, so they carry no catalog, +# runtime-coverage, or generated-inventory entry. +SELF_WORKFLOWS = { + "ci.yml", + "codeql.yml", + "dependency-review.yml", + "gitleaks.yml", + "release.yml", + "scorecard.yml", +} def workflow_files() -> list[Path]: diff --git a/scripts/generate_docs.py b/scripts/generate_docs.py index 96591dd..e8e07e5 100644 --- a/scripts/generate_docs.py +++ b/scripts/generate_docs.py @@ -13,6 +13,8 @@ import yaml +from _workflow_yaml import SELF_WORKFLOWS + REPO_ROOT = Path(__file__).resolve().parent.parent CATALOG = REPO_ROOT / "catalog" / "capabilities.yml" WORKFLOWS_DIR = REPO_ROOT / ".github" / "workflows" @@ -83,7 +85,7 @@ def workflow_inventory(caps: list[dict[str, Any]]) -> str: ] for path in sorted(WORKFLOWS_DIR.glob("*.yml")): rel = f".github/workflows/{path.name}" - if path.name in {"ci.yml", "release.yml"}: + if path.name in SELF_WORKFLOWS: ids = "internal" statuses = "internal" else: diff --git a/scripts/validate_catalog.py b/scripts/validate_catalog.py index c4b433a..60e2c65 100644 --- a/scripts/validate_catalog.py +++ b/scripts/validate_catalog.py @@ -12,6 +12,8 @@ import yaml +from _workflow_yaml import SELF_WORKFLOWS + REPO_ROOT = Path(__file__).resolve().parent.parent CATALOG_DIR = REPO_ROOT / "catalog" WORKFLOWS_DIR = REPO_ROOT / ".github" / "workflows" @@ -121,7 +123,7 @@ def check() -> list[str]: workflow_files = { f".github/workflows/{path.name}" for path in WORKFLOWS_DIR.glob("*.yml") - if path.name not in {"ci.yml", "release.yml"} + if path.name not in SELF_WORKFLOWS } missing_workflows = workflow_files - workflows_in_catalog if missing_workflows: