mirror of
https://github.com/anthropics/claude-plugins-official.git
synced 2026-05-13 15:05:51 -03:00
Make Scan Plugins a viable required check; auto-dispatch on bump PRs (#1815)
Scan Plugins is meant to gate every change to marketplace.json, but two gaps made that unenforceable: 1. The bump workflow opens PRs with GITHUB_TOKEN, which GitHub exempts from on:pull_request triggers. Weekly bump PRs (e.g. #1809) get no scan check at all. 2. The workflow had a paths filter, so a required-check ruleset for `scan` would block every PR that doesn't touch marketplace.json (no check run = pending forever). Fixes: scan-plugins.yml - Drop the paths filter; replace with a step-level `git diff --quiet` early-exit on the same paths. The check now reports on every PR, which makes it safe to require. - Fail closed when ANTHROPIC_API_KEY is unset and a scan is needed. The shared action no-ops gracefully in that case (right default for community repos), but a required check that silently does nothing is a rubber stamp. bump-plugin-shas.yml - After the action opens the bump PR, `gh workflow run scan-plugins.yml --ref bump/plugin-shas`. workflow_dispatch is exempt from the GITHUB_TOKEN recursion guard, and the resulting check run lands on the branch HEAD (= PR head), so it satisfies the required check. - Add `actions: write` so the dispatch is allowed. Follow-up: add a repo ruleset on main requiring the `scan` check (integration: github-actions) once this merges.
This commit is contained in:
parent
7f6f5a8836
commit
45896c8f2f
21
.github/workflows/bump-plugin-shas.yml
vendored
21
.github/workflows/bump-plugin-shas.yml
vendored
@ -4,9 +4,13 @@ name: Bump Plugin SHAs
|
|||||||
# its pinned SHA, validate at the new SHA with `claude plugin validate`
|
# its pinned SHA, validate at the new SHA with `claude plugin validate`
|
||||||
# inline, then open one PR with all passing bumps.
|
# inline, then open one PR with all passing bumps.
|
||||||
#
|
#
|
||||||
# Bot-free — uses the default GITHUB_TOKEN. Because GITHUB_TOKEN-opened PRs
|
# Bot-free — uses the default GITHUB_TOKEN. PRs opened with GITHUB_TOKEN don't
|
||||||
# don't trigger on:pull_request workflows, validation runs in this workflow
|
# trigger on:pull_request workflows, so the policy scan (`Scan Plugins`, a
|
||||||
# before the PR is opened; the PR body links back here as the CI evidence.
|
# required status check on main) would never run and the bump PR could never
|
||||||
|
# merge. workflow_dispatch is exempt from that recursion guard, so we dispatch
|
||||||
|
# the scan ourselves on the bump branch after the PR is opened. The check run
|
||||||
|
# lands on the branch HEAD — the same SHA as the PR head — and satisfies the
|
||||||
|
# required check.
|
||||||
|
|
||||||
on:
|
on:
|
||||||
schedule:
|
schedule:
|
||||||
@ -21,6 +25,7 @@ on:
|
|||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
|
actions: write # gh workflow run scan-plugins.yml on the bump branch
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: bump-plugin-shas
|
group: bump-plugin-shas
|
||||||
@ -34,7 +39,17 @@ jobs:
|
|||||||
# createCommitOnBranch-based bump so commits are signed by GitHub and
|
# createCommitOnBranch-based bump so commits are signed by GitHub and
|
||||||
# satisfy the org-level required_signatures ruleset on main.
|
# satisfy the org-level required_signatures ruleset on main.
|
||||||
- uses: anthropics/claude-plugins-community/.github/actions/bump-plugin-shas@c41c6911de0afffd2bc5cd8b21fb1e06444ee13b
|
- uses: anthropics/claude-plugins-community/.github/actions/bump-plugin-shas@c41c6911de0afffd2bc5cd8b21fb1e06444ee13b
|
||||||
|
id: bump
|
||||||
with:
|
with:
|
||||||
marketplace-path: .claude-plugin/marketplace.json
|
marketplace-path: .claude-plugin/marketplace.json
|
||||||
max-bumps: ${{ inputs.max_bumps || '20' }}
|
max-bumps: ${{ inputs.max_bumps || '20' }}
|
||||||
claude-cli-version: latest
|
claude-cli-version: latest
|
||||||
|
|
||||||
|
# `bump/plugin-shas` is the action's default `pr-branch`. The scan diffs
|
||||||
|
# the branch against origin/main (the action's base-ref fallback when
|
||||||
|
# there's no pull_request event) and scans only the bumped entries.
|
||||||
|
- name: Dispatch policy scan on bump branch
|
||||||
|
if: steps.bump.outputs.pr-url != ''
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ github.token }}
|
||||||
|
run: gh workflow run scan-plugins.yml --ref bump/plugin-shas
|
||||||
|
|||||||
46
.github/workflows/scan-plugins.yml
vendored
46
.github/workflows/scan-plugins.yml
vendored
@ -1,10 +1,15 @@
|
|||||||
name: Scan Plugins
|
name: Scan Plugins
|
||||||
|
|
||||||
|
# Claude policy scan of changed external marketplace entries.
|
||||||
|
#
|
||||||
|
# `scan` is a required status check on main. A path-filtered workflow never
|
||||||
|
# reports a check run when its paths don't match, which would leave unrelated
|
||||||
|
# PRs blocked forever — so this workflow runs on every PR and skips the heavy
|
||||||
|
# scan setup at the step level when nothing scan-relevant changed. The check
|
||||||
|
# always reports.
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
|
||||||
- '.claude-plugin/marketplace.json'
|
|
||||||
- '.github/policy/**'
|
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
scan_all:
|
scan_all:
|
||||||
@ -24,9 +29,42 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
|
# Same paths the workflow-level filter used to gate on. workflow_dispatch
|
||||||
|
# always runs the scan (no PR diff to inspect).
|
||||||
|
- name: Check for scan-relevant changes
|
||||||
|
id: changes
|
||||||
|
env:
|
||||||
|
EVENT_NAME: ${{ github.event_name }}
|
||||||
|
BASE_SHA: ${{ github.event.pull_request.base.sha }}
|
||||||
|
run: |
|
||||||
|
if [[ "$EVENT_NAME" == "workflow_dispatch" ]]; then
|
||||||
|
echo "relevant=true" >> "$GITHUB_OUTPUT"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
if git diff --quiet "$BASE_SHA" HEAD -- .claude-plugin/marketplace.json .github/policy/; then
|
||||||
|
echo "relevant=false" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "::notice::No changes to marketplace.json or policy/ — skipping policy scan."
|
||||||
|
else
|
||||||
|
echo "relevant=true" >> "$GITHUB_OUTPUT"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# The shared action no-ops gracefully when ANTHROPIC_API_KEY is unset
|
||||||
|
# (sensible default for community repos). Here `scan` is a required
|
||||||
|
# check, so a silent no-op would make it a rubber stamp — fail closed.
|
||||||
|
- name: Require ANTHROPIC_API_KEY when a scan is needed
|
||||||
|
if: steps.changes.outputs.relevant == 'true'
|
||||||
|
env:
|
||||||
|
API_KEY_SET: ${{ secrets.ANTHROPIC_API_KEY != '' }}
|
||||||
|
run: |
|
||||||
|
if [[ "$API_KEY_SET" != "true" ]]; then
|
||||||
|
echo "::error::ANTHROPIC_API_KEY is not configured; refusing to skip a required policy scan."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
# Blocking: policy failures fail the job. Loosen by removing
|
# Blocking: policy failures fail the job. Loosen by removing
|
||||||
# fail-on-findings if the false-positive rate is too high.
|
# fail-on-findings if the false-positive rate is too high.
|
||||||
- uses: anthropics/claude-plugins-community/.github/actions/scan-plugins@b277757588871fe55b2620de8c6dfda470e2e9d8
|
- if: steps.changes.outputs.relevant == 'true'
|
||||||
|
uses: anthropics/claude-plugins-community/.github/actions/scan-plugins@b277757588871fe55b2620de8c6dfda470e2e9d8
|
||||||
with:
|
with:
|
||||||
anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
|
anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
|
||||||
policy-prompt: .github/policy/prompt.md
|
policy-prompt: .github/policy/prompt.md
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user