diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7f016a7..ed7d83c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -44,7 +44,7 @@ jobs: contents: read steps: - name: Harden runner - uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0 + uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1 with: egress-policy: block allowed-endpoints: > @@ -99,7 +99,7 @@ jobs: contents: read steps: - name: Harden runner - uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0 + uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1 with: egress-policy: block allowed-endpoints: > diff --git a/.github/workflows/cpp-ci.yml b/.github/workflows/cpp-ci.yml index 9baef38..b4ffb7f 100644 --- a/.github/workflows/cpp-ci.yml +++ b/.github/workflows/cpp-ci.yml @@ -95,7 +95,7 @@ jobs: - name: Set up ccache if: ${{ inputs.enable_ccache }} - uses: hendrikmuhs/ccache-action@d62db5f07c26379fc4b4e0916f098a92573c3b03 # v1.2.23 + uses: hendrikmuhs/ccache-action@f09c25b45002a07be2955cbe52e8cee55643f89d # v1.2.24 with: key: ${{ inputs.ccache_key }} diff --git a/.github/workflows/dependabot-catalog-convergence.yml b/.github/workflows/dependabot-catalog-convergence.yml index a7b8c49..4f61d97 100644 --- a/.github/workflows/dependabot-catalog-convergence.yml +++ b/.github/workflows/dependabot-catalog-convergence.yml @@ -31,7 +31,7 @@ jobs: timeout-minutes: 10 steps: - name: Harden runner - uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0 + uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1 with: egress-policy: audit - name: Checkout trusted generator diff --git a/.github/workflows/docs-quality.yml b/.github/workflows/docs-quality.yml index 5452e81..097248e 100644 --- a/.github/workflows/docs-quality.yml +++ b/.github/workflows/docs-quality.yml @@ -75,7 +75,7 @@ jobs: - name: Spell check (typos) if: ${{ inputs.typos }} - uses: crate-ci/typos@8a48f81b6c64dcfea44b3633223084c4be58ac5f # v1.49.0 + uses: crate-ci/typos@4d9c206a77c041268485162b8e2579ad7a5cb9a3 # v1.50.0 with: files: ${{ inputs.typos_files }} diff --git a/.github/workflows/grype-scan.yml b/.github/workflows/grype-scan.yml index de8382d..dcfd441 100644 --- a/.github/workflows/grype-scan.yml +++ b/.github/workflows/grype-scan.yml @@ -44,7 +44,7 @@ jobs: persist-credentials: false - name: Grype scan - uses: anchore/scan-action@e1165082ffb1fe366ebaf02d8526e7c4989ea9d2 # v7.4.0 + uses: anchore/scan-action@27805bf3b4e84b4a5c980df22ed233c00390a439 # v7.4.2 with: path: ${{ inputs.path }} fail-build: ${{ inputs.fail_build }} diff --git a/.github/workflows/iac-scan.yml b/.github/workflows/iac-scan.yml index 4d2cd4c..8c04bc7 100644 --- a/.github/workflows/iac-scan.yml +++ b/.github/workflows/iac-scan.yml @@ -48,7 +48,7 @@ jobs: persist-credentials: false - name: Checkov - uses: bridgecrewio/checkov-action@59b9d7edfcad5b87fbe3f473a9a134a721ad03f8 # v12.3119.0 + uses: bridgecrewio/checkov-action@f967808197a8d784d3e72919f38c3ff0cda7884e # v12.3122.0 with: directory: ${{ inputs.directory }} framework: ${{ inputs.framework }} diff --git a/.github/workflows/maintenance.yml b/.github/workflows/maintenance.yml index 7115752..97b1906 100644 --- a/.github/workflows/maintenance.yml +++ b/.github/workflows/maintenance.yml @@ -39,7 +39,7 @@ jobs: issues: write # file/update the single tracking issue steps: - name: Harden runner - uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0 + uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1 with: egress-policy: block allowed-endpoints: > diff --git a/.github/workflows/nddev-security-bundle.yml b/.github/workflows/nddev-security-bundle.yml index 2969bb1..0aef92e 100644 --- a/.github/workflows/nddev-security-bundle.yml +++ b/.github/workflows/nddev-security-bundle.yml @@ -40,7 +40,7 @@ jobs: security-events: write # publish zizmor SARIF to code scanning steps: - name: Harden runner - uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0 + uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1 with: egress-policy: audit @@ -160,7 +160,7 @@ jobs: - name: Upload zizmor SARIF if: ${{ !cancelled() && steps.scan.conclusion != 'skipped' }} - uses: github/codeql-action/upload-sarif@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4.37.8 + uses: github/codeql-action/upload-sarif@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9 with: sarif_file: ${{ runner.temp }}/private-security-zizmor.sarif category: zizmor diff --git a/.github/workflows/public-codeql.yml b/.github/workflows/public-codeql.yml index 6dc7bf0..181033d 100644 --- a/.github/workflows/public-codeql.yml +++ b/.github/workflows/public-codeql.yml @@ -79,7 +79,7 @@ jobs: language: ${{ fromJSON(inputs.languages) }} steps: - name: Harden runner - uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0 + uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1 with: egress-policy: ${{ inputs.egress_policy }} @@ -115,21 +115,21 @@ jobs: - name: Initialize CodeQL if: ${{ inputs.config_file == '' }} - uses: github/codeql-action/init@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4.37.8 + uses: github/codeql-action/init@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9 with: languages: ${{ matrix.language }} queries: ${{ inputs.queries }} - name: Initialize CodeQL with config if: ${{ inputs.config_file != '' }} - uses: github/codeql-action/init@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4.37.8 + uses: github/codeql-action/init@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9 with: languages: ${{ matrix.language }} config-file: ${{ inputs.config_file }} - name: Autobuild if: ${{ inputs.autobuild && inputs.build_command == '' }} - uses: github/codeql-action/autobuild@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4.37.8 + uses: github/codeql-action/autobuild@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9 - name: Custom build if: ${{ inputs.build_command != '' }} @@ -139,13 +139,13 @@ jobs: - name: Analyze if: ${{ inputs.output_directory == '' }} - uses: github/codeql-action/analyze@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4.37.8 + uses: github/codeql-action/analyze@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9 with: category: "/language:${{ matrix.language }}" - name: Analyze with output directory if: ${{ inputs.output_directory != '' }} - uses: github/codeql-action/analyze@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4.37.8 + uses: github/codeql-action/analyze@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9 with: category: "/language:${{ matrix.language }}" output: ${{ inputs.output_directory }} diff --git a/.github/workflows/public-dependency-review.yml b/.github/workflows/public-dependency-review.yml index c576644..a071914 100644 --- a/.github/workflows/public-dependency-review.yml +++ b/.github/workflows/public-dependency-review.yml @@ -36,7 +36,7 @@ jobs: pull-requests: write # post the dependency-review summary comment steps: - name: Harden runner - uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0 + uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1 with: egress-policy: audit diff --git a/.github/workflows/public-scorecard-analysis.yml b/.github/workflows/public-scorecard-analysis.yml index c7edc11..fe72bb3 100644 --- a/.github/workflows/public-scorecard-analysis.yml +++ b/.github/workflows/public-scorecard-analysis.yml @@ -34,7 +34,7 @@ jobs: actions: read # Scorecard inspects workflow definitions steps: - name: Harden runner - uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0 + uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1 with: egress-policy: audit diff --git a/.github/workflows/public-scorecard-json.yml b/.github/workflows/public-scorecard-json.yml index 32950a4..d8ac080 100644 --- a/.github/workflows/public-scorecard-json.yml +++ b/.github/workflows/public-scorecard-json.yml @@ -39,7 +39,7 @@ jobs: actions: read # Scorecard inspects workflow definitions steps: - name: Harden runner - uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0 + uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1 with: egress-policy: audit diff --git a/.github/workflows/public-scorecard.yml b/.github/workflows/public-scorecard.yml index 8428166..ed8a496 100644 --- a/.github/workflows/public-scorecard.yml +++ b/.github/workflows/public-scorecard.yml @@ -51,7 +51,7 @@ jobs: actions: read # Scorecard inspects workflow definitions steps: - name: Harden runner - uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0 + uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1 with: egress-policy: audit @@ -165,7 +165,7 @@ jobs: - name: Upload SARIF to code scanning id: upload-sarif if: ${{ github.event_name != 'pull_request' || inputs.upload_sarif_on_forks || github.event.pull_request.head.repo.full_name == github.repository }} - uses: github/codeql-action/upload-sarif@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4.37.8 + uses: github/codeql-action/upload-sarif@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9 with: sarif_file: results.sarif category: ${{ inputs.sarif_category }} diff --git a/.github/workflows/qt-ci.yml b/.github/workflows/qt-ci.yml index 2f0e649..a00d815 100644 --- a/.github/workflows/qt-ci.yml +++ b/.github/workflows/qt-ci.yml @@ -289,7 +289,7 @@ jobs: - name: Set up ccache if: ${{ inputs.enable_ccache }} - uses: hendrikmuhs/ccache-action@d62db5f07c26379fc4b4e0916f098a92573c3b03 # v1.2.23 + uses: hendrikmuhs/ccache-action@f09c25b45002a07be2955cbe52e8cee55643f89d # v1.2.24 with: key: ${{ inputs.ccache_key }} diff --git a/.github/workflows/r-ci.yml b/.github/workflows/r-ci.yml index 9d36945..eda79fd 100644 --- a/.github/workflows/r-ci.yml +++ b/.github/workflows/r-ci.yml @@ -64,7 +64,7 @@ jobs: persist-credentials: false - name: Set up R - uses: r-lib/actions/setup-r@d3c5be51b12e724e68f33216ca3c148b66d5f0b6 # v2.12.1 + uses: r-lib/actions/setup-r@465b7d8e732ca3921382b1674c59bada9cbf3399 # v2.13.0 with: r-version: ${{ inputs.r_version }} use-public-rspm: ${{ inputs.use_public_rspm }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8c5c874..a70d1fb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -46,7 +46,7 @@ jobs: version: ${{ steps.v.outputs.version }} steps: - name: Harden runner - uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0 + uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1 with: egress-policy: block allowed-endpoints: > diff --git a/.github/workflows/rust-supply-chain.yml b/.github/workflows/rust-supply-chain.yml index d6382f9..18c9379 100644 --- a/.github/workflows/rust-supply-chain.yml +++ b/.github/workflows/rust-supply-chain.yml @@ -97,7 +97,7 @@ jobs: with: persist-credentials: false - name: Install cargo-audit - uses: taiki-e/install-action@b6ff580856c41316412a0b9b60540fbc6f8c82cc # v2.86.7 + uses: taiki-e/install-action@1ed6d7be6168f6c9046541087ff549b6bc581fdf # v2.87.2 with: tool: cargo-audit@${{ inputs.cargo_audit_version }} - name: Run cargo-audit @@ -116,7 +116,7 @@ jobs: with: persist-credentials: false - name: Install cargo-machete - uses: taiki-e/install-action@b6ff580856c41316412a0b9b60540fbc6f8c82cc # v2.86.7 + uses: taiki-e/install-action@1ed6d7be6168f6c9046541087ff549b6bc581fdf # v2.87.2 with: tool: cargo-machete@${{ inputs.cargo_machete_version }} - name: Run cargo-machete diff --git a/.github/workflows/zizmor-sarif.yml b/.github/workflows/zizmor-sarif.yml index b8cf1ce..31d47c7 100644 --- a/.github/workflows/zizmor-sarif.yml +++ b/.github/workflows/zizmor-sarif.yml @@ -47,7 +47,7 @@ jobs: security-events: write # publish zizmor SARIF to code scanning steps: - name: Harden runner - uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0 + uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1 with: egress-policy: audit @@ -82,7 +82,7 @@ jobs: "${ZIZMOR_TARGET}" > zizmor.sarif - name: Upload SARIF to code scanning - uses: github/codeql-action/upload-sarif@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4.37.8 + uses: github/codeql-action/upload-sarif@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9 with: sarif_file: zizmor.sarif category: zizmor diff --git a/CHANGELOG.md b/CHANGELOG.md index b40599b..f945e9f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ The project follows Semantic Versioning. ## [Unreleased] +- Synchronize pins by catalog action family, preserving independent subpath actions + and reusable workflows in the same repository. Apply the reviewed dependency + updates from #92 with matching catalog and transitive-image records; historical + evidence digests are no longer rewritten by an unrelated action update. + - Stop treating the publisher as an Enterprise Cloud buyer of Code Security, Secret Protection and Code Quality. Paid programmes stay explicitly selectable; public CodeQL, SARIF, Scorecard and attestations stay. Private diff --git a/catalog/action-images.yml b/catalog/action-images.yml index b52dd0e..e96e51e 100644 --- a/catalog/action-images.yml +++ b/catalog/action-images.yml @@ -33,7 +33,7 @@ images: published-evidence path for the public tier, so a substituted image would change what the SARIF and JSON attest to. - action: bridgecrewio/checkov-action - image: docker://ghcr.io/bridgecrewio/checkov:3.3.13 + image: docker://ghcr.io/bridgecrewio/checkov:3.3.16 used_by: - .github/workflows/iac-scan.yml reason: >- diff --git a/catalog/python-execution.yml b/catalog/python-execution.yml index 68fa983..843700e 100644 --- a/catalog/python-execution.yml +++ b/catalog/python-execution.yml @@ -625,6 +625,9 @@ "_workflow_yaml", "check_python_execution_contract", "check_scorecard_evidence_contract" + ], + "sync_action_catalog.py": [ + "_strict_yaml" ] }, "direct_external_imports": { diff --git a/catalog/scorecard-evidence.yml b/catalog/scorecard-evidence.yml index fa84c71..bc78d22 100644 --- a/catalog/scorecard-evidence.yml +++ b/catalog/scorecard-evidence.yml @@ -11,7 +11,7 @@ entrypoint_matrix: contents: read harden_runner: required: true - pin: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c + pin: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 egress_policy: audit position: first allowed_callers: @@ -38,7 +38,7 @@ entrypoint_matrix: security-events: write harden_runner: required: true - pin: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c + pin: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 egress_policy: audit position: first allowed_callers: @@ -66,7 +66,7 @@ category_contract: guid: null source_urls: - https://github.com/ossf/scorecard/blob/v5.5.0/pkg/scorecard/sarif.go - - https://github.com/github/codeql-action/blob/db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28/src/upload-lib.ts + - https://github.com/github/codeql-action/blob/cdf488f595d80d6e07e03d4674febd5ab45fa938/src/upload-lib.ts - https://docs.github.com/en/code-security/reference/code-scanning/sarif-files/sarif-support-for-code-scanning attempts: - attempt: 1 diff --git a/catalog/tools.yml b/catalog/tools.yml index b7e0d01..4ae522f 100644 --- a/catalog/tools.yml +++ b/catalog/tools.yml @@ -94,8 +94,8 @@ tools: name: step-security/harden-runner homepage: "https://github.com/step-security/harden-runner" kind: action - current_version: "v2.21.0" - pin: "step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c" + current_version: "v2.21.1" + pin: "step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1" used_by: - .github/workflows/ci.yml - .github/workflows/dependabot-catalog-convergence.yml @@ -108,20 +108,20 @@ tools: - .github/workflows/public-scorecard.yml - .github/workflows/release.yml - .github/workflows/zizmor-sarif.yml - last_verified: "2026-07-10" + last_verified: "2026-09-07" - id: codeql-action name: github/codeql-action homepage: "https://github.com/github/codeql-action" kind: action - current_version: "v4.37.8" - pin: "github/codeql-action@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28" + current_version: "v4.37.9" + pin: "github/codeql-action@cdf488f595d80d6e07e03d4674febd5ab45fa938" used_by: - .github/workflows/nddev-security-bundle.yml - .github/workflows/public-codeql.yml - .github/workflows/public-scorecard.yml - .github/workflows/zizmor-sarif.yml - last_verified: "2026-09-01" + last_verified: "2026-09-07" - id: dependency-review-action name: actions/dependency-review-action @@ -275,12 +275,12 @@ tools: name: hendrikmuhs/ccache-action homepage: "https://github.com/hendrikmuhs/ccache-action" kind: action - current_version: "v1.2.23" - pin: "hendrikmuhs/ccache-action@d62db5f07c26379fc4b4e0916f098a92573c3b03" + current_version: "v1.2.24" + pin: "hendrikmuhs/ccache-action@f09c25b45002a07be2955cbe52e8cee55643f89d" used_by: - .github/workflows/cpp-ci.yml - .github/workflows/qt-ci.yml - last_verified: "2026-07-08" + last_verified: "2026-09-07" - id: setup-gradle name: gradle/actions/setup-gradle @@ -317,11 +317,11 @@ tools: name: r-lib/actions/setup-r homepage: "https://github.com/r-lib/actions" kind: action - current_version: "v2.12.1" - pin: "r-lib/actions@d3c5be51b12e724e68f33216ca3c148b66d5f0b6" + current_version: "v2.13.0" + pin: "r-lib/actions@465b7d8e732ca3921382b1674c59bada9cbf3399" used_by: - .github/workflows/r-ci.yml - last_verified: "2026-07-08" + last_verified: "2026-09-07" - id: codecov-action name: codecov/codecov-action @@ -357,11 +357,11 @@ tools: name: crate-ci/typos homepage: "https://github.com/crate-ci/typos" kind: action - current_version: "v1.49.0" - pin: "crate-ci/typos@8a48f81b6c64dcfea44b3633223084c4be58ac5f" + current_version: "v1.50.0" + pin: "crate-ci/typos@4d9c206a77c041268485162b8e2579ad7a5cb9a3" used_by: - .github/workflows/docs-quality.yml - last_verified: "2026-07-08" + last_verified: "2026-09-07" - id: markdownlint-cli2-action name: DavidAnson/markdownlint-cli2-action @@ -439,11 +439,11 @@ tools: name: anchore/scan-action homepage: "https://github.com/anchore/scan-action" kind: action - current_version: "v7.4.0" - pin: "anchore/scan-action@e1165082ffb1fe366ebaf02d8526e7c4989ea9d2" + current_version: "v7.4.2" + pin: "anchore/scan-action@27805bf3b4e84b4a5c980df22ed233c00390a439" used_by: - .github/workflows/grype-scan.yml - last_verified: "2026-07-08" + last_verified: "2026-09-07" - id: hadolint name: hadolint @@ -459,11 +459,11 @@ tools: name: bridgecrewio/checkov-action homepage: "https://github.com/bridgecrewio/checkov-action" kind: action - current_version: "v12.3119.0" - pin: "bridgecrewio/checkov-action@59b9d7edfcad5b87fbe3f473a9a134a721ad03f8" + current_version: "v12.3122.0" + pin: "bridgecrewio/checkov-action@f967808197a8d784d3e72919f38c3ff0cda7884e" used_by: - .github/workflows/iac-scan.yml - last_verified: "2026-09-01" + last_verified: "2026-09-07" - id: github-action-benchmark name: benchmark-action/github-action-benchmark @@ -681,11 +681,11 @@ tools: name: taiki-e/install-action homepage: "https://github.com/taiki-e/install-action" kind: action - current_version: "v2.86.7" - pin: "taiki-e/install-action@b6ff580856c41316412a0b9b60540fbc6f8c82cc" + current_version: "v2.87.2" + pin: "taiki-e/install-action@1ed6d7be6168f6c9046541087ff549b6bc581fdf" used_by: - .github/workflows/rust-supply-chain.yml - last_verified: "2026-09-01" + last_verified: "2026-09-07" # Upstream tags no release, so the pin comment carries the commit date rather # than a version. Bump it by picking a newer commit deliberately, not by diff --git a/docs/generated/scorecard-evidence.md b/docs/generated/scorecard-evidence.md index bea11ae..08a0e02 100644 --- a/docs/generated/scorecard-evidence.md +++ b/docs/generated/scorecard-evidence.md @@ -23,8 +23,8 @@ private, fork, skipped-step, wrong-tool, and wrong-category runs are rejected. | Entrypoint | Public / private tier | Runner | Capability | Permissions | Harden-Runner | Allowed callers | Evidence | | --- | --- | --- | --- | --- | --- | --- | --- | -| `.github/workflows/public-scorecard-analysis.yml` | `conditional-public-oss` / `unsupported` | `github-hosted-standard` | `sarif-analysis-no-publication` | `actions:read, contents:read` | `step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c`; `first`; `audit` | public non-fork; push,schedule; actual-default-branch; ubuntu-latest | job-and-analysis-step-success, no-oidc-or-write-permission, no-artifact-or-sarif-upload-step, exact-caller-and-reusable-sha | -| `.github/workflows/public-scorecard.yml` | `public-oss` / `unsupported` | `github-hosted-standard` | `scorecard-publication-and-sarif-upload` | `actions:read, contents:read, id-token:write, security-events:write` | `step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c`; `first`; `audit` | public non-fork; push,schedule; actual-default-branch; ubuntu-latest | analysis-and-upload-steps-success, exact-caller-and-reusable-sha, accepted-code-scanning-analysis-set, exact-ref-sha-workflow-tool-and-category-set | +| `.github/workflows/public-scorecard-analysis.yml` | `conditional-public-oss` / `unsupported` | `github-hosted-standard` | `sarif-analysis-no-publication` | `actions:read, contents:read` | `step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1`; `first`; `audit` | public non-fork; push,schedule; actual-default-branch; ubuntu-latest | job-and-analysis-step-success, no-oidc-or-write-permission, no-artifact-or-sarif-upload-step, exact-caller-and-reusable-sha | +| `.github/workflows/public-scorecard.yml` | `public-oss` / `unsupported` | `github-hosted-standard` | `scorecard-publication-and-sarif-upload` | `actions:read, contents:read, id-token:write, security-events:write` | `step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1`; `first`; `audit` | public non-fork; push,schedule; actual-default-branch; ubuntu-latest | analysis-and-upload-steps-success, exact-caller-and-reusable-sha, accepted-code-scanning-analysis-set, exact-ref-sha-workflow-tool-and-category-set | | Preserved failed attempt | `3` / `contract-test-failure` | | Failure receipt | [issue receipt](https://github.com/NDDev-OpenNetwork/ci-workflows/issues/128#issuecomment-5275483568) (base `d1d5376da29bb2c494498630e04c5454287575a4`) | | Preserved recovery failure | `1` / `product-contract-failure` | diff --git a/scripts/sync_action_catalog.py b/scripts/sync_action_catalog.py index 83bef57..84876e4 100644 --- a/scripts/sync_action_catalog.py +++ b/scripts/sync_action_catalog.py @@ -10,6 +10,8 @@ import urllib.request from collections.abc import Callable +from ci_workflows_tools._strict_yaml import strict_load + PIN = re.compile(r"uses:\s*([^\s#@]+)@([0-9a-f]{40})\s*#\s*(\S+)") IMAGE = re.compile(r"(?m)^\s*image:\s*[\"']?(docker://[^\s\"']+)") @@ -45,9 +47,28 @@ def resolve_action_image(action: str, sha: str) -> str: ) +def action_prefixes(root: pathlib.Path) -> tuple[str, ...]: + """Use the same action families as the tool registry, including subpaths. + + One repository can publish independent actions and reusable workflows at + different revisions. Only a catalog action entry defines a shared pin. + """ + tools = (strict_load(root / "catalog/tools.yml") or {}).get("tools") or [] + return tuple(sorted({ + str(tool["pin"]).rsplit("@", 1)[0] + for tool in tools if tool.get("kind") == "action" and tool.get("pin") + }, key=lambda prefix: (-len(prefix), prefix))) + + +def action_prefix(reference: str, prefixes: tuple[str, ...]) -> str | None: + return next((prefix for prefix in prefixes + if reference == prefix or reference.startswith(prefix + "/")), None) + + def workflow_pins( root: pathlib.Path, *, require_unique: bool = False ) -> dict[str, tuple[str, str]]: + prefixes = action_prefixes(root) found: dict[str, collections.Counter[tuple[str, str]]] = {} for path in sorted((root / ".github/workflows").glob("*.yml")): for line in path.read_text(encoding="utf-8").splitlines(): @@ -55,8 +76,9 @@ def workflow_pins( if match is None: continue reference, sha, version = match.groups() - repository = "/".join(reference.split("/")[:2]) - found.setdefault(repository, collections.Counter())[(sha, version)] += 1 + prefix = action_prefix(reference, prefixes) + if prefix is not None: + found.setdefault(prefix, collections.Counter())[(sha, version)] += 1 result: dict[str, tuple[str, str]] = {} for repository, identities in found.items(): ranked = identities.most_common() @@ -82,6 +104,7 @@ def synchronize( catalog_only: bool = False, ) -> list[str]: pins = workflow_pins(root, require_unique=catalog_only) + prefixes = action_prefixes(root) changed: list[str] = [] if not catalog_only: for path in sorted((root / ".github/workflows").glob("*.yml")): @@ -91,9 +114,9 @@ def synchronize( match = PIN.search(line) if match is not None: reference, sha, version = match.groups() - repository = "/".join(reference.split("/")[:2]) - expected = pins[repository] - if (sha, version) != expected: + prefix = action_prefix(reference, prefixes) + expected = pins.get(prefix) if prefix is not None else None + if expected is not None and (sha, version) != expected: line = ( line[:match.start(2)] + expected[0] @@ -126,8 +149,15 @@ def synchronize( new_sha, new_version = identity if old_sha != new_sha: lines[index] = f' pin: "{repository}@{new_sha}"' - replacements.append((old_sha, new_sha)) replacements.append((f"{repository}@{old_sha}", f"{repository}@{new_sha}")) + parts = repository.split("/") + origin = "/".join(parts[:2]) + subpath = "/".join(parts[2:]) + suffix = f"/{subpath}/" if subpath else "/" + replacements.append(( + f"https://github.com/{origin}/blob/{old_sha}{suffix}", + f"https://github.com/{origin}/blob/{new_sha}{suffix}", + )) changed_repositories.add(repository) for version_index in range(index - 1, max(-1, index - 8), -1): if lines[version_index].startswith(" current_version: "): @@ -151,7 +181,7 @@ def synchronize( continue if not line.startswith(" image: ") or current_action is None: continue - repository = "/".join(current_action.split("/")[:2]) + repository = action_prefix(current_action, prefixes) if repository not in changed_repositories: continue sha, _ = pins[repository] diff --git a/scripts/test_sync_action_catalog.py b/scripts/test_sync_action_catalog.py index c6f9d3d..5160fd0 100644 --- a/scripts/test_sync_action_catalog.py +++ b/scripts/test_sync_action_catalog.py @@ -128,6 +128,52 @@ def check() -> list[str]: problems.append("full synchronization did not rewrite the straggler workflow pin") if ".github/workflows/other.yml" not in changed: problems.append("full synchronization did not report the rewritten workflow") + with tempfile.TemporaryDirectory() as directory: + root = pathlib.Path(directory) + (root / ".github/workflows").mkdir(parents=True) + (root / "catalog").mkdir() + (root / "docs/generated").mkdir(parents=True) + old, new, workflow_sha = "a" * 40, "b" * 40, "c" * 40 + (root / "catalog/tools.yml").write_text( + "tools:\n - id: cache\n kind: action\n" + f' current_version: "v1"\n pin: "mono/repo/actions/cache@{old}"\n' + " - id: setup\n kind: action\n" + f' current_version: "v1"\n pin: "mono/repo/actions/setup@{old}"\n' + " - id: feedback\n kind: reusable-workflow\n" + f' current_version: "commit:{workflow_sha}"\n' + f' pin: "mono/repo/.github/workflows/feedback.yml@{workflow_sha}"\n', + encoding="utf-8", + ) + workflow = root / ".github/workflows/ci.yml" + before = ( + f"jobs:\n feedback:\n uses: mono/repo/.github/workflows/feedback.yml@{workflow_sha} # commit:{workflow_sha}\n" + f" test:\n steps:\n - uses: mono/repo/actions/cache@{new} # v2\n" + f" - uses: mono/repo/actions/setup@{old} # v1\n" + ) + workflow.write_text(before, encoding="utf-8") + evidence = (f"mono/repo/actions/cache@{old}\nmono/repo/actions/setup@{old}\n" + f"https://github.com/mono/repo/blob/{old}/actions/cache/action.yml\n" + f"https://github.com/mono/repo/blob/{old}/actions/setup/action.yml\n" + f"historic_artifact_sha: {old}\n") + for relative in ("catalog/scorecard-evidence.yml", "docs/generated/scorecard-evidence.md"): + (root / relative).write_text(evidence, encoding="utf-8") + synchronize(root, catalog_only=True) + tools = (root / "catalog/tools.yml").read_text(encoding="utf-8") + if (f"mono/repo/actions/cache@{new}" not in tools + or f"mono/repo/actions/setup@{old}" not in tools + or f"feedback.yml@{workflow_sha}" not in tools): + problems.append("independent components in one repository lost their declared pins") + if workflow.read_text(encoding="utf-8") != before: + problems.append("catalog-only rewrote an independently pinned workflow") + evidence_after = (root / "catalog/scorecard-evidence.yml").read_text(encoding="utf-8") + if (f"mono/repo/actions/cache@{new}" not in evidence_after + or f"mono/repo/actions/setup@{old}" not in evidence_after + or f"/blob/{new}/actions/cache/action.yml" not in evidence_after + or f"/blob/{old}/actions/setup/action.yml" not in evidence_after + or f"historic_artifact_sha: {old}" not in evidence_after): + problems.append("evidence replacement escaped the changed action reference") + if synchronize(root, catalog_only=True): + problems.append("independent component synchronization was not idempotent") return problems