64 lines
2.8 KiB
YAML
64 lines
2.8 KiB
YAML
name: 'Plugin registry validate'
|
|
|
|
# Runs on PRs that touch the curated plugin registry. Uses `pull_request` (NOT
|
|
# pull_request_target), read-only permissions, and NO secrets — so cloning +
|
|
# statically auditing a submitter's plugin can never reach a token or write the
|
|
# repo. No plugin code is executed (the manifest is parsed, the audit is static).
|
|
on:
|
|
pull_request:
|
|
paths:
|
|
- 'plugins-registry/**'
|
|
- 'plugins-registry.json' # legacy single-file location (pre-migration forks)
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
# Cancel superseded runs when the same PR is pushed again.
|
|
concurrency:
|
|
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
jobs:
|
|
validate:
|
|
name: Validate registry entries
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
# fetch-depth: 0 so the "One plugin per PR" diff below has the base
|
|
# branch's history + merge-base available (a shallow checkout truncates it).
|
|
- uses: actions/checkout@v7
|
|
with:
|
|
fetch-depth: 0
|
|
- uses: actions/setup-node@v6
|
|
with:
|
|
node-version: '24'
|
|
|
|
# Deterministic shape gate (no network).
|
|
- name: Validate registry shape
|
|
run: node validate-plugin-registry.mjs
|
|
|
|
# Deep gate: clone each entry at its pinned SHA + static-validate + audit.
|
|
# No secrets are present in this job; nothing the plugin ships is executed.
|
|
- name: Clone + audit each registry entry
|
|
run: node validate-plugin-registry.mjs --deep
|
|
|
|
- name: One plugin per PR
|
|
# base_ref goes through env, never ${{ }}-spliced into the script —
|
|
# anything expanded inside run: is literal shell code (template injection).
|
|
env:
|
|
BASE_REF: ${{ github.base_ref }}
|
|
run: |
|
|
# Make origin/$BASE_REF resolvable (checkout of a PR merge ref does not
|
|
# create the base remote-tracking branch on its own).
|
|
git fetch --no-tags origin "$BASE_REF"
|
|
# One-time migration exemption: the PR that removes the legacy single
|
|
# file necessarily rewrites every entry into plugins-registry/<id>.json.
|
|
# This can only ever match the migration itself — once it lands,
|
|
# plugins-registry.json no longer exists for any future PR to delete,
|
|
# so the one-plugin gate below still holds for all registration PRs.
|
|
if git diff --name-only --diff-filter=D "origin/$BASE_REF"...HEAD -- plugins-registry.json | grep -q .; then
|
|
echo "Migration PR (removes legacy plugins-registry.json) — one-plugin-per-PR gate not applicable."
|
|
exit 0
|
|
fi
|
|
CHANGED=$(git diff --name-only "origin/$BASE_REF"...HEAD -- 'plugins-registry/*.json' plugins-registry.json | wc -l)
|
|
if [ "$CHANGED" -gt 1 ]; then echo "A registry PR may add or bump exactly one plugins-registry/<id>.json file"; exit 1; fi
|