Repository navigation
Chore: Bump lfreleng-actions/generic-workflows/.github/workflows/clear-action-cache.yaml from 0.0.5 to 0.2.1 #41
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| --- | |
| # SPDX-License-Identifier: Apache-2.0 | |
| # SPDX-FileCopyrightText: 2026 The Linux Foundation | |
| # Organisation-wide AI slop / code quality scan using aislop. | |
| # | |
| # This workflow lives in lfreleng-actions/.github and runs across the | |
| # organisation as a "required workflow" via an organisation ruleset | |
| # (Settings -> Rules -> Rulesets at the org level), so it executes on | |
| # every selected repository without a per-repository file. It also | |
| # audits this repository on demand (workflow_dispatch) and on its | |
| # own pull requests. | |
| # | |
| # Scope: the scan covers ONLY the files changed on the pull request | |
| # (aislop --changes --base), not the whole repository, so the check | |
| # reports on what the PR introduces rather than pre-existing state. | |
| # The scheduled aislop-sarif-publish.yaml workflow owns whole-repo | |
| # scanning and default-branch code-scanning SARIF. | |
| # | |
| # Gating: the scan (delegated to aislop-scan-action, which pins and | |
| # verifies the aislop CLI) never fails on findings by itself; a | |
| # separate gate step decides enforcement. The gate level is chosen by | |
| # the organisation variable AISLOP_GATE_LEVEL: | |
| # | |
| # any (default) Block the run when the pull request's changed | |
| # files carry ANY finding, at any severity: high, | |
| # medium and low all block. This is the "no new | |
| # slop" gate: the scan scope is the changed files, | |
| # so passing it means the pull request is not adding | |
| # findings. | |
| # high Block only on HIGH-severity findings (aislop | |
| # error-severity). Medium and low remain advisory. | |
| # The previous default; use it as a per-repository | |
| # escape hatch while a backlog is remediated. | |
| # all Block on the full aislop quality gate (score below | |
| # the configured threshold OR any high-severity | |
| # finding). | |
| # off Advisory only: report via the step summary and | |
| # inline annotations without blocking anything. | |
| # | |
| # A repository variable of the same name overrides the organisation | |
| # value, so a repository carrying a pre-existing backlog can sit at | |
| # 'high' without weakening the estate-wide default. | |
| # | |
| # For backward compatibility, when AISLOP_GATE_LEVEL is unset the | |
| # legacy AISLOP_ENFORCE='true' variable still selects the 'all' tier; | |
| # otherwise the default is 'any'. | |
| # | |
| # See README.md ("Organisation-wide aislop scan") for org-admin setup. | |
| name: 'AI Slop Scan 🧹' | |
| # yamllint disable-line rule:truthy | |
| on: | |
| workflow_dispatch: | |
| pull_request: | |
| permissions: {} | |
| # Scope the group to this check, not to '${{ github.workflow }}', which | |
| # resolves to the workflow NAME and so collides with any workflow in | |
| # the target repository sharing it. See semantic-pull-request.yaml. | |
| concurrency: | |
| group: 'org-aislop-${{ github.ref }}' | |
| cancel-in-progress: true | |
| jobs: | |
| audit: | |
| name: 'Audit changes' | |
| runs-on: 'ubuntu-latest' | |
| timeout-minutes: 15 | |
| permissions: | |
| contents: read | |
| steps: | |
| # Load the egress allow-list out-of-band from | |
| # lfreleng-actions/.github and publish it as | |
| # $CONNECTION_ALLOW_LIST for the harden-runner step below. | |
| # yamllint disable-line rule:line-length | |
| - uses: lfreleng-actions/harden-runner-block-action@805eedb0508c07714b61887a2b87a5c4bbeff22a # v0.12.1 | |
| with: | |
| config: '@8f4f0cf83e6a015957e83261ed379fd811fc060e' # v0.5.1 | |
| # Harden the runner with the just-loaded allow-list. | |
| - name: 'Harden runner (block)' | |
| # yamllint disable-line rule:line-length | |
| uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0 | |
| with: | |
| egress-policy: 'block' | |
| allowed-endpoints: > | |
| ${{ env.CONNECTION_ALLOW_LIST }} | |
| - name: 'Checkout repository under audit' | |
| # yamllint disable-line rule:line-length | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| # Full history so aislop can resolve the merge base of the | |
| # pull request branch against the base branch. | |
| fetch-depth: 0 | |
| persist-credentials: false | |
| - name: 'Run aislop quality gate (changed files)' | |
| id: 'scan' | |
| # yamllint disable-line rule:line-length | |
| uses: lfreleng-actions/aislop-scan-action@4004a907f2894763ff1f9fc904b2f7b4b7a7cc40 # v0.2.7 | |
| with: | |
| # On pull_request events the diff base is the PR base branch; | |
| # on workflow_dispatch fall back to the default branch (an | |
| # empty diff, so the run is a no-op smoke test). | |
| scan-mode: 'changes' | |
| # yamllint disable-line rule:line-length | |
| base: 'origin/${{ github.base_ref || github.event.repository.default_branch }}' | |
| - name: 'Enforce quality gate' | |
| shell: 'bash' | |
| env: | |
| # Gate level: 'any' (default) blocks on any finding at any | |
| # severity on the changed files; 'high' blocks on | |
| # high-severity only; 'all' blocks on the full aislop gate; | |
| # 'off' keeps the run advisory. AISLOP_ENFORCE is the legacy | |
| # switch honoured only when AISLOP_GATE_LEVEL is unset. | |
| AISLOP_GATE_LEVEL: '${{ vars.AISLOP_GATE_LEVEL }}' | |
| AISLOP_ENFORCE: '${{ vars.AISLOP_ENFORCE }}' | |
| SCAN_RC: '${{ steps.scan.outputs.exit-code }}' | |
| REPORT_FILE: '${{ steps.scan.outputs.report-file }}' | |
| run: | | |
| # Enforce quality gate | |
| set -euo pipefail | |
| # Resolve the effective gate level. AISLOP_GATE_LEVEL wins; | |
| # when it is unset, the legacy AISLOP_ENFORCE='true' selects | |
| # the strict 'all' tier, otherwise the default is 'any'. | |
| level="${AISLOP_GATE_LEVEL:-}" | |
| if [ -z "${level}" ]; then | |
| if [ "${AISLOP_ENFORCE:-}" = 'true' ]; then | |
| level='all' | |
| else | |
| level='any' | |
| fi | |
| fi | |
| case "${level}" in | |
| any|high|all|off) ;; | |
| *) | |
| echo "::error::invalid AISLOP_GATE_LEVEL '${level}';" \ | |
| "expected 'any', 'high', 'all', or 'off'" | |
| exit 1 | |
| ;; | |
| esac | |
| # 'off' is advisory and never blocks, not even on a broken | |
| # scan: surface the high-severity count when a report is | |
| # available, then pass regardless. | |
| if [ "${level}" = 'off' ]; then | |
| if [ -n "${REPORT_FILE}" ] && [ -f "${REPORT_FILE}" ]; then | |
| high="$(jq '[.diagnostics[]? | |
| | select(.severity == "error")] | length' \ | |
| "${REPORT_FILE}")" | |
| if [ "${high}" != '0' ]; then | |
| msg="aislop found ${high} high-severity finding(s)" | |
| msg="${msg} (advisory mode; not enforced)" | |
| echo "::warning::${msg}" | |
| fi | |
| fi | |
| echo 'Advisory mode (AISLOP_GATE_LEVEL=off): passing.' | |
| exit 0 | |
| fi | |
| # Enforcing tiers ('high' and 'all') need a readable report | |
| # to evaluate, so fail closed when it is missing: a broken | |
| # scan must not let findings slip past an active gate. (The | |
| # action already fails its own step when the tool produces no | |
| # readable report, so this is a defensive backstop.) | |
| if [ -z "${REPORT_FILE}" ] || [ ! -f "${REPORT_FILE}" ]; then | |
| echo "::error::aislop report not found; cannot evaluate gate" | |
| exit 1 | |
| fi | |
| # A failed scan can still emit valid JSON, for example an | |
| # object carrying an 'error' key and no diagnostics. The | |
| # counting below uses jq's optional iterator, which turns | |
| # such a report into zero findings and would pass the gate | |
| # on a scan that never ran. Require the diagnostics array | |
| # explicitly and fail closed when it is absent. | |
| if ! jq -e '(.diagnostics | type) == "array"' \ | |
| "${REPORT_FILE}" > /dev/null 2>&1; then | |
| echo "::error::aislop report carries no diagnostics array;" \ | |
| "treating this as a failed scan rather than a clean" \ | |
| "result (gate exit code ${SCAN_RC})" | |
| exit 1 | |
| fi | |
| # Count findings on the changed files. aislop maps | |
| # error-severity diagnostics to SARIF 'error' (high in code | |
| # scanning), warning to medium, and info to low. The action | |
| # leaves the JSON report in place (only its install dir is | |
| # cleaned), so the report path stays readable here. | |
| high="$(jq '[.diagnostics[]? | |
| | select(.severity == "error")] | length' \ | |
| "${REPORT_FILE}")" | |
| medium="$(jq '[.diagnostics[]? | |
| | select(.severity == "warning")] | length' \ | |
| "${REPORT_FILE}")" | |
| low="$(jq '[.diagnostics[]? | |
| | select(.severity == "info")] | length' \ | |
| "${REPORT_FILE}")" | |
| # Total counts every diagnostic, whatever its severity, so a | |
| # severity this gate does not name still blocks. | |
| total="$(jq '[.diagnostics[]?] | length' "${REPORT_FILE}")" | |
| echo "aislop findings on changed files: ${total}" \ | |
| "(high ${high}, medium ${medium}, low ${low})" | |
| echo "aislop gate exit code: ${SCAN_RC}" | |
| case "${level}" in | |
| any) | |
| # The scan scope is the changed files, so a finding here | |
| # is one this pull request adds, or leaves behind in code | |
| # it touched. Every severity blocks, low included. | |
| if [ "${total}" != '0' ]; then | |
| echo "::error::aislop quality gate failed:" \ | |
| "${total} finding(s) on the changed files" \ | |
| "(high ${high}, medium ${medium}, low ${low});" \ | |
| "a pull request must not add findings." \ | |
| "Remediate them, or set the repository variable" \ | |
| "AISLOP_GATE_LEVEL=high while an existing backlog" \ | |
| "is cleared." | |
| exit 1 | |
| fi | |
| if [ "${SCAN_RC}" != '0' ]; then | |
| msg='aislop score gate did not pass (advisory at the' | |
| msg="${msg} 'any' gate level; set AISLOP_GATE_LEVEL=all" | |
| msg="${msg} to enforce the score threshold too)" | |
| echo "::warning::${msg}" | |
| fi | |
| echo 'aislop quality gate passed (no findings).' | |
| ;; | |
| high) | |
| if [ "${high}" != '0' ]; then | |
| echo "::error::aislop quality gate failed:" \ | |
| "${high} high-severity finding(s) on this" \ | |
| "pull request" | |
| exit 1 | |
| fi | |
| if [ "${SCAN_RC}" != '0' ]; then | |
| msg='aislop score gate did not pass (advisory at the' | |
| msg="${msg} 'high' gate level; set AISLOP_GATE_LEVEL=all" | |
| msg="${msg} to enforce it)" | |
| echo "::warning::${msg}" | |
| fi | |
| echo 'aislop quality gate passed (no high-severity findings).' | |
| ;; | |
| all) | |
| # Fail on the full aislop gate. aislop ci already exits | |
| # non-zero on any high-severity finding, but check high | |
| # explicitly too so the tier matches its documented | |
| # "score below threshold OR any high-severity finding" | |
| # even if that coupling ever changes. | |
| if [ "${high}" != '0' ] || [ "${SCAN_RC}" != '0' ]; then | |
| echo "::error::aislop quality gate failed (rc=${SCAN_RC};" \ | |
| "${high} high-severity finding(s))" | |
| exit 1 | |
| fi | |
| echo 'aislop quality gate passed.' | |
| ;; | |
| esac |