docs(work-items): de-slop instruction surfaces (0.39.23) #5502
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
| name: claude-security-review | |
| # Dedicated LLM security-review pass via the ci-workflows reusable workflow — the | |
| # security sibling of claude-review.yml, ADR 0002's default-on advisory posture. | |
| # The caller owns the triggers, the GITHUB_TOKEN grant, and the `paths-file` | |
| # input pointing at `.github/claude-security-paths`, the repo-owned list of this | |
| # repo's security-sensitive surfaces (workflows, scripts, hooks, shell, and | |
| # permission/settings config) that the reusable reads from the PR's BASE branch. | |
| # There is deliberately NO workflow-level path filter: a path miss would leave | |
| # the required execution check Pending and wedge prose PRs, so the reusable | |
| # workflow evaluates those patterns in a job-level gate and a not-applicable PR | |
| # yields a name-stable skipped check the required-check ruleset reads as | |
| # success. The verdict stays advisory per ADR 0002. Fork PRs receive no secrets | |
| # and a read-only token, so they are simply not reviewed by design. Requires | |
| # `claude-code-plugins` in the CLAUDE_CODE_OAUTH_TOKEN org secret's | |
| # selected-repositories scope. Public repo: hosted default runner. | |
| on: | |
| pull_request: | |
| types: [opened, synchronize, ready_for_review, reopened] | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: claude-security-review-${{ github.event.pull_request.number }} | |
| cancel-in-progress: false | |
| jobs: | |
| security-review: | |
| permissions: | |
| contents: read # checkout + read the diff | |
| pull-requests: write # post the security review | |
| id-token: write # OIDC — mints the Claude GitHub App token | |
| uses: melodic-software/ci-workflows/.github/workflows/claude-security-review.yml@7107b34832a7b6db5d08d3b132621c599fbe5e50 # v0.14.2 | |
| with: | |
| runner: ubuntu-24.04 | |
| paths-file: .github/claude-security-paths | |
| # Stated explicitly, never left to the reusable's default: this list IS | |
| # ADR 0002's skip-actor exception, and the exception must be readable and | |
| # reviewable in the repo it applies to. An inherited default silently | |
| # rewrites the exception whenever ci-workflows changes it — which is how | |
| # `claude[bot]` and `melodic-ai[bot]` entered it (#1766 dropped this line | |
| # while re-pinning to a version whose default had widened). | |
| # | |
| # DO NOT delete this line at a re-pin, and do not "simplify" it away. | |
| # Deleting it is not a no-op even when the value matches the upstream | |
| # default of the moment: the four actors here are ADR 0002's 2026-08-04 | |
| # ratified baseline, and inheriting instead re-delegates that decision to | |
| # whatever ci-workflows ships next. Every actor in an inherited default | |
| # satisfies this repo's REQUIRED `security-review / security-review` | |
| # check with no review run, on security-sensitive paths. | |
| # | |
| # The failure directions are asymmetric, which is why explicit wins here | |
| # and not everywhere. A stale explicit list fails CLOSED and LOUD: for an | |
| # actor the reusable's `allowed_bots` does not permit, the action throws | |
| # and this lane's fail-closed mapping turns that into a RED required | |
| # check no push can fix — a merge block, not an extra review (ADR 0002, | |
| # "skip-actors and the action's allowed_bots are different levers"). | |
| # Un-skipping such an actor for real means widening `allowed_bots` | |
| # upstream, which is why removing a name here is never a one-line change. | |
| # A stale inherited default fails OPEN and SILENT: an actor this repo | |
| # never deliberated skips review with CI green — exactly what #1766 did. | |
| # Loud-and-blocking is the direction to fail in; silent-and-permissive is | |
| # not. runner-policy rejects inputs outside the reviewed contract but | |
| # cannot REQUIRE one, so dropping this line re-widens the exception with | |
| # nothing said. That residual gap is standards#308. | |
| skip-actors: dependabot[bot],claude[bot],melodic-ai[bot],melodic-standards-sync[bot],cursor[bot] | |
| # One named secret (least privilege), never `secrets: inherit`. | |
| secrets: | |
| CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} | |
| # Repo-owned fail-closed supplement for #2337: the reusable workflow is | |
| # advisory on some infra-failure classes and can report success without a | |
| # review when the action skips itself on an in-scope diff. This job is | |
| # intentionally separate so the guard stays readable in-repo. | |
| # | |
| # It reads the lane's DECLARED outputs, passed below out of `needs`. It used | |
| # to scrape the lane's job log instead, and a log is not a contract: the | |
| # lane's `Report review outcome` step is an inline github-script whose source | |
| # is echoed into that log, so the grep matched the source that mentions the | |
| # skip phrases and reddened every successful in-scope pull request (#2517). | |
| # Those outputs exist as of ci-workflows v0.14.2, which is why this job is | |
| # now coupled to the pin above — the guard fails CLOSED when they are absent | |
| # at an unmoved head, so a re-pin BACKWARDS past that release turns this red. | |
| # The release, never a pull request number: a reader checking whether their | |
| # pin carries the outputs needs a version they can compare against, and the | |
| # guard's own message says the same thing the same way. | |
| security-review-evidence: | |
| needs: security-review | |
| if: >- | |
| always() && | |
| github.event_name == 'pull_request' && | |
| needs.security-review.result != 'cancelled' | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 5 | |
| permissions: | |
| contents: read | |
| # The guard reads the pull request's live head on one path only — | |
| # telling a retired superseded run apart from an absent verdict. It no | |
| # longer reads run jobs or logs, so `actions: read` is gone with them. | |
| pull-requests: read | |
| steps: | |
| - name: Check out | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| # Self-test first, so a broken guard cannot mask the regression it exists | |
| # to catch — the shape #2517 was: the guard agreed with itself while | |
| # failing every pull request. | |
| - name: Run security-review evidence guard tests | |
| run: bash scripts/verify-security-review-evidence.sh.test.sh | |
| - name: Verify security-review execution evidence | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| GITHUB_REPOSITORY: ${{ github.repository }} | |
| GITHUB_EVENT_NAME: ${{ github.event_name }} | |
| GITHUB_ACTOR: ${{ github.actor }} | |
| PR_NUMBER: ${{ github.event.pull_request.number }} | |
| EVENT_HEAD_SHA: ${{ github.event.pull_request.head.sha }} | |
| LANE_RESULT: ${{ needs.security-review.result }} | |
| LANE_RELEVANT: ${{ needs.security-review.outputs.relevant }} | |
| LANE_REVIEW_RAN: ${{ needs.security-review.outputs.review-ran }} | |
| LANE_REVIEW_FAILED: ${{ needs.security-review.outputs.review-failed }} | |
| LANE_FAILURE_CLASS: ${{ needs.security-review.outputs.failure-class }} | |
| SKIP_ACTORS: dependabot[bot],claude[bot],melodic-ai[bot],melodic-standards-sync[bot],cursor[bot] | |
| run: bash scripts/verify-security-review-evidence.sh |