name: Close External PRs on: pull_request_target: types: [opened] permissions: pull-requests: write issues: write contents: read jobs: check-membership: if: vars.DISABLE_EXTERNAL_PR_CHECK != 'true' runs-on: ubuntu-latest steps: # pull_request_target: checks out the BASE repo (trusted), so the allowlist + shared # script below are this repo's versions, never the fork's. - uses: actions/checkout@v4 - name: Close PR unless author is a member or the PR is an in-scope external contribution uses: actions/github-script@v7 with: script: | const author = context.payload.pull_request.user.login; const { evaluate, isExemptAuthor } = require(`${process.env.GITHUB_WORKSPACE}/.github/scripts/external-pr-scope.js`); // Members (write/admin) and the repo's own automation bot (bump SHA PRs) are never // auto-closed. const ex = await isExemptAuthor({ github, context }); if (ex.exempt) { console.log(`${ex.reason} — allowing PR`); return; } // Non-member: allow the PR to stay open ONLY if it is an in-scope external // contribution — it adds marketplace.json entries whose source repo ALREADY backs // a live plugin here, and changes nothing else. (No maintained allowlist: the set // of allowed repos is derived from the live marketplace.) This grants only the // right to open a reviewable PR; the validate + scan checks and a maintainer // approval still gate the merge (the External PR Scope Guard is advisory signal, // not a required check). const result = await evaluate({ github, context }); if (result.ok && result.added.length > 0) { console.log(`In-scope external contribution (adds: ${result.added.join(', ')}) — allowing PR.`); return; } console.log(`Closing PR from ${author}: ${result.problems.join('; ') || 'out of scope'}`); await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.payload.pull_request.number, body: `Thanks for your interest! This repo only accepts contributions from Anthropic team members. If you'd like to submit a plugin to the marketplace, please submit your plugin [here](https://clau.de/plugin-directory-submission).` }); await github.rest.pulls.update({ owner: context.repo.owner, repo: context.repo.repo, pull_number: context.payload.pull_request.number, state: 'closed' });