Compare commits

...

77 Commits

Author SHA1 Message Date
github-actions[bot]
fe5e5408b0 bump(vercel): 5f3f0ad7 → 3b6cbeb8 2026-06-27 00:02:03 +00:00
Bryan Thompson
307b006258 Add unreal-engine-skills-for-claude-code plugin (#3396) 2026-06-26 16:32:27 -07:00
Bryan Thompson
b92dc518fe Add tavily plugin (#3384) 2026-06-26 16:32:12 -07:00
Bryan Thompson
a4892eba3b Add canva plugin (#3387) 2026-06-26 16:32:10 -07:00
github-actions[bot]
7718c3c84d bump(oracle-ai-data-platform-workbench-spark-connectors): 13e7a913 → ca1ab4e5 (#3432)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-26 13:17:10 -05:00
github-actions[bot]
7cc2e2be16 bump(data-agent-kit-starter-pack): 86cd0201 → 9bc90f9e (#3425)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-26 13:16:48 -05:00
github-actions[bot]
8fcaa2a35c bump(aws-data-analytics): 49ca7520 → 49c4592d (#3420)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-26 13:16:24 -05:00
github-actions[bot]
da6f51df03 bump(carta-cap-table): d73954d3 → 8d49ea8b (#3422)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-26 13:16:01 -05:00
github-actions[bot]
2220995220 bump(migration-to-aws): e49c21bf → 59db838b (#3430)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-26 13:15:36 -05:00
github-actions[bot]
6f7d4a8f86 bump(aws-core): 7898a914 → 49c4592d (#3419)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-26 13:15:22 -05:00
github-actions[bot]
9a27a46fe0 bump(carta-investors): f1640dc5 → 8d49ea8b (#3423)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-26 13:15:15 -05:00
github-actions[bot]
2ab7f9bc65 bump(langfuse-observability): 938df416 → 4615df55 (#3429)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-26 13:15:09 -05:00
github-actions[bot]
d27324777f bump(pydantic-ai): f0c20b98 → 96e5d761 (#3433)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-26 13:14:45 -05:00
github-actions[bot]
04e6ed01e0 bump(sentry-cli): 20b469aa → 97e7fcce (#3435)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-26 13:14:17 -05:00
github-actions[bot]
f3efd8a231 bump(teamcity-cli): 3776102f → 32dfd91c (#3437)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-26 13:13:49 -05:00
github-actions[bot]
99a7821483 bump(auth0): 81847212 → aacefa7d (#3418)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-26 13:13:13 -05:00
github-actions[bot]
76cafe3c9c bump(azure): 2cd48ca6 → c752fe85 (#3421)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-26 13:12:41 -05:00
github-actions[bot]
0b4b7aebdf bump(dash0): bb2ba10a → 4eac30a4 (#3424)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-26 13:12:09 -05:00
github-actions[bot]
d0bb0029f9 bump(databricks): e337277c → ae99f56b (#3426)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-26 13:11:36 -05:00
github-actions[bot]
11e454d706 bump(hunter): 0bea093c → 6db1c0ae (#3427)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-26 13:11:05 -05:00
github-actions[bot]
a37ecb4e8a bump(hyperframes): 0c1e236d → 13b115e0 (#3428)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-26 13:10:35 -05:00
github-actions[bot]
43fd4d1837 bump(nimble): 1a599ea1 → 958fca1c (#3431)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-26 13:10:03 -05:00
github-actions[bot]
8cff23c1c1 bump(sentry): 12529ba8 → 83df938b (#3434)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-26 13:09:30 -05:00
github-actions[bot]
a0a3f2f695 bump(sumup): b69ff6f5 → 700da2e8 (#3436)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-26 13:08:57 -05:00
github-actions[bot]
78457a28aa bump(sentry): f69cf097 → 12529ba8 (#3412)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-26 11:04:32 -05:00
github-actions[bot]
02b6d7f579 bump(chrome-devtools-mcp): 6a946637 → e5bd334c (#3408)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-26 11:04:15 -05:00
github-actions[bot]
a1c74e73ba bump(data): ed2fe757 → d33a14dd (#3410)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-26 11:03:56 -05:00
github-actions[bot]
0b16870038 bump(teamcity-cli): 42ce6a22 → 3776102f (#3414)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-26 11:03:38 -05:00
github-actions[bot]
91404dbe27 bump(stripe): 23b54f12 → f54c9e6c (#3413)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-26 11:03:23 -05:00
github-actions[bot]
e7078a01e5 bump(hyperframes): 92385711 → 0c1e236d (#3411)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-26 11:03:19 -05:00
github-actions[bot]
e55ed38966 bump(dash0): fb9a6207 → bb2ba10a (#3409)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-26 11:03:16 -05:00
github-actions[bot]
a03bb78ed2 bump(carta-investors): 4bd05d34 → f1640dc5 (#3407)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-26 11:03:12 -05:00
github-actions[bot]
2fe4bfae86 bump(auth0): 3e3a5d84 → 81847212 (#3406)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-26 11:03:06 -05:00
github-actions[bot]
7185b68b1c bump(langfuse): c3978907 → 6b6c44cf (#3415)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-26 10:51:31 -05:00
Bryan Thompson
cbc7d77931 Exempt the bump bot from the external-PR scope guard (#3402)
* Exempt the bump bot from the external-PR scope guard

The External PR Scope Guard (#3353) and the auto-closer both look up the
PR author's collaborator permission and, for anyone who is not write/admin,
require the PR to ADD marketplace.json entries (additions-only). Internal
bump PRs are authored by github-actions[bot], which is not reported as a
member, so a SHA-bump — a legitimate MODIFY of an existing entry — fails the
guard (e.g. #3391 "modifies existing entry: astronomer-data-agents").

Add a shared isExemptAuthor() helper that exempts both org members and the
repo's own automation bot, and route both workflows through it. Safe under
pull_request_target: a fork PR cannot author as github-actions[bot] (only
the org's own GITHUB_TOKEN workflow can), and the member path is still a
real permission lookup. The helper also wraps getCollaboratorPermissionLevel
in try/catch — previously a non-collaborator/unknown-user lookup threw and
errored the job instead of falling through to scope evaluation.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Correct stale "required status check" guidance in scope-guard comments

The scope guard is advisory, not a required status check — the merge gate is
validate + scan + a maintainer approval. The old header told operators to add
it to branch protection, which is now contra-indicated (it would block the
no-approval bump-merge path). Update both workflow comments to match.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 08:45:10 -07:00
github-actions[bot]
82f22ec4f0 bump(remember): f1a00382 → 9d732495 (#3400)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-26 00:03:13 -05:00
github-actions[bot]
92fcf8973b bump(hunter): 0a03795d → 0bea093c (#3398)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-26 00:02:54 -05:00
github-actions[bot]
f2e1d01b77 bump(crowdstrike-falcon-foundry): 20ef548a → 7b2cda5c (#3393)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-26 00:02:37 -05:00
github-actions[bot]
b6d4f81be3 bump(data-engineering): ed2fe757 → d33a14dd (#3394)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-26 00:02:34 -05:00
github-actions[bot]
50c34b2478 bump(semgrep): 5ee984a4 → 8e652ba6 (#3401)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-26 00:02:16 -05:00
github-actions[bot]
a30e0614d3 bump(hyperframes): 56859b61 → 92385711 (#3399)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-26 00:01:59 -05:00
github-actions[bot]
c63064637d bump(exa): 40d9990f → f7e90323 (#3397)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-26 00:01:56 -05:00
github-actions[bot]
d1410844ad bump(carta-investors): d73a3615 → 4bd05d34 (#3392)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-26 00:01:51 -05:00
github-actions[bot]
89aae89012 bump(astronomer-data-agents): ed2fe757 → d33a14dd (#3391)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-26 00:01:45 -05:00
github-actions[bot]
c8e9219efb bump(databases-on-aws): 66dd3cf5 → 96a073a1 (#3395)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-25 21:39:15 -05:00
github-actions[bot]
6b93bc00d3 bump(ui5-modernization): 1d4dedd5 → d1e3a43f (#3380)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-25 19:06:37 -05:00
github-actions[bot]
16c1372836 bump(sentry-cli): 6acb9aa8 → 20b469aa (#3379)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-25 19:06:25 -05:00
github-actions[bot]
ff23096dcd bump(aikido): 01e8cf54 → fbe11e28 (#3356)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-25 19:05:41 -05:00
github-actions[bot]
06c6d8878b bump(data): e4ebf9a7 → ed2fe757 (#3361)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-25 19:05:27 -05:00
github-actions[bot]
324d8ebe73 bump(dash0): f8c31f6f → fb9a6207 (#3360)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-25 19:05:12 -05:00
github-actions[bot]
c0236a0ffd bump(dataproc): c36c7f8b → 6d6ac388 (#3363)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-25 19:04:58 -05:00
Bryan Thompson
a8237e1537 Allow non-member PRs scoped to an already-listed plugin repo (#3353)
* feat(ci): allow live external contributors to open scoped PRs

Add an opt-in allowlist so a vetted external developer who already has a
plugin live in this marketplace — but cannot use the submission form
(e.g. an enterprise partner without a Claude account) — can open a
reviewable PR instead of having it auto-closed.

- .github/external-contributors.json: username -> allowed_sources map
  (doubles as the allowlist and the per-author source scope).
- close-external-prs.yml: skip the auto-close for allowlisted authors
  (reads the list from the trusted base checkout). Grants ONLY the right
  to open a PR; CI + maintainer approval are unchanged.
- external-pr-scope-guard.yml: required check for allowlisted external
  authors. Fails unless the PR touches ONLY marketplace.json and the
  delta is additions-only, with every added entry's source.url under
  that author's allowed_sources. Anthropic members are unrestricted.
  Reads head marketplace.json as data via the API (no untrusted checkout).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(ci): neutral wording in external-contributors allowlist note

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor(ci): key external-PR allowlist on source org, not individuals

Replace the per-username allowlist with a source-org allowlist so no
individual is named in the repo. A non-member PR stays open only if it
adds marketplace.json entries whose source.url is under an allowlisted
prefix and changes nothing else; merge still requires CI + maintainer
approval.

- external-pr-allowed-sources.json: flat allowed_sources prefixes (no usernames)
- scripts/external-pr-scope.js: shared additions-only / allowed-source logic
- close-external-prs.yml + external-pr-scope-guard.yml: both use the shared module

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor(ci): derive external-PR scope from live repos, no maintained list

Replace the curated source-org allowlist with auto-derivation from the
live marketplace. A non-member PR stays open only if it ADDS entries
whose source.url repo ALREADY backs a live plugin here, additions-only,
nothing else touched. No list to maintain, no individuals named.

Trust is anchored in the source repo + pinned SHA (org-controlled), not
the submitter's identity; merge still requires CI + maintainer approval.

- remove external-pr-allowed-sources.json
- scripts/external-pr-scope.js: derive allowed repos from base marketplace.json
- both workflows drop the allowlist-file arg

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(ci): diff external-PR scope against the merge-base, not base tip

Comparing base-branch-tip -> head made a fork that is behind main report
all of main's later additions as phantom removals/modifications, which
would wrongly fail the scope guard for a legitimate additions-only PR.
Diff merge-base -> head (the PR's actual changes) instead; keep the
"already live" check against the current base branch.

Found by an end-to-end run of evaluate() against real PR data (#3298
stayed clean; #3044's phantom drift collapsed to its real one-line change).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 21:55:04 +01:00
github-actions[bot]
0dcbdd33a2 bump(exa): 34a6b2aa → 40d9990f (#3365)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-25 13:30:10 -05:00
github-actions[bot]
c39d4bb19a bump(expo): 81ee6546 → ad897fdf (#3366)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-25 13:23:26 -05:00
github-actions[bot]
286e9f2217 bump(hunter): 9929ccf4 → 0a03795d (#3368)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-25 13:23:13 -05:00
github-actions[bot]
28112e303c bump(jfrog): ac0ea16e → 320a5585 (#3370)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-25 13:22:42 -05:00
github-actions[bot]
805cb8ec16 bump(oracle-ai-data-platform-workbench-databricks-migrator): 80a37379 → a88bcf3a (#3374)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-25 13:21:57 -05:00
github-actions[bot]
02540bfb49 bump(sap-fiori-mcp-server): 10d3bfcb → 0cddd1a5 (#3378)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-25 13:21:28 -05:00
github-actions[bot]
d96849b22e bump(astronomer-data-agents): e4ebf9a7 → ed2fe757 (#3357)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-25 13:20:57 -05:00
github-actions[bot]
60d98420a3 bump(aws-data-analytics): ff1dc6f4 → 49ca7520 (#3358)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-25 13:20:26 -05:00
github-actions[bot]
0c47f2e0b8 bump(datarobot-agent-skills): f4b3c29d → 0e28dc83 (#3364)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-25 13:19:54 -05:00
github-actions[bot]
ec08d81de6 bump(migration-to-aws): ac1d6251 → e49c21bf (#3372)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-25 13:19:21 -05:00
github-actions[bot]
3b5666f0aa bump(teamcity-cli): 25c5f8d3 → 42ce6a22 (#3347)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-25 13:18:50 -05:00
github-actions[bot]
7a5090872c bump(agentforce-adlc): 772aaa20 → 2b2f59d9 (#3355)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-25 13:18:16 -05:00
github-actions[bot]
9679408140 bump(brightdata-plugin): 8d427e98 → e825f02f (#3359)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-25 13:17:40 -05:00
github-actions[bot]
8b6c3cc8f7 bump(data-engineering): e4ebf9a7 → ed2fe757 (#3362)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-25 13:17:06 -05:00
github-actions[bot]
a837737d47 bump(huggingface-skills): 093e0bb8 → 35e8c35a (#3367)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-25 13:16:32 -05:00
github-actions[bot]
8ac5884387 bump(langfuse-observability): 597af67d → 938df416 (#3371)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-25 13:15:56 -05:00
github-actions[bot]
d5f8b26fe2 bump(qdrant-skills): 7a91f320 → 0651740b (#3376)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-25 13:15:37 -05:00
github-actions[bot]
da79cb089b bump(hyperframes): 64eaad7d → 56859b61 (#3369)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-25 13:15:19 -05:00
github-actions[bot]
ecdac18ae0 bump(nightvision): c7807ab1 → 67af610a (#3373)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-25 13:15:11 -05:00
github-actions[bot]
26461e1116 bump(posthog): 39a8593e → 835f4f64 (#3375)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-25 13:15:07 -05:00
github-actions[bot]
976a80e08f bump(rill): 9bdc4efa → c8c8738f (#3377)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-25 13:14:28 -05:00
github-actions[bot]
38cd9fc7c2 bump(valtown): e32973e4 → 22594eb2 (#3381)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-25 13:13:50 -05:00
github-actions[bot]
6e2d1f2f91 bump(wix): a50d4c06 → 1ea953a2 (#3382)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-25 13:13:11 -05:00
github-actions[bot]
4976ad9034 bump(zapier): 28ad6ea1 → 469651fe (#3383)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-25 13:12:30 -05:00
Bryan Thompson
28280efa24 feat(plugin/ui5-modernization): add UI5 Modernization plugin (#3352)
Add the SAP UI5 Modernization plugin (SAP SE / github.com/UI5) to the
official marketplace. Sibling of the already-listed ui5 and
ui5-typescript-conversion plugins from the same repo.

Onboarded on behalf of the developer (Florian Vogt, SAP): the original
contribution PR #3298 was auto-closed by the external-contributor gate,
and SAP cannot currently use the submission form.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 16:46:03 +01:00
4 changed files with 343 additions and 58 deletions

View File

@@ -57,7 +57,7 @@
"source": {
"source": "url",
"url": "https://github.com/SalesforceAIResearch/agentforce-adlc.git",
"sha": "772aaa20ebdd97736a94ebcd9d60fd3949342b60"
"sha": "2b2f59d9f29d3dae3a4bec0b953237f03bbba7af"
},
"homepage": "https://github.com/SalesforceAIResearch/agentforce-adlc"
},
@@ -77,7 +77,7 @@
"source": {
"source": "url",
"url": "https://github.com/AikidoSec/aikido-claude-plugin.git",
"sha": "01e8cf542500e579cff948a0fa0365e4f819d7b4"
"sha": "fbe11e287175e5eda448516dd2f741a63b276514"
},
"homepage": "https://github.com/AikidoSec/aikido-claude-plugin"
},
@@ -223,7 +223,7 @@
"source": {
"source": "url",
"url": "https://github.com/astronomer/agents.git",
"sha": "e4ebf9a7ad3f8dbf3fcfda9c245a65eb1415967b"
"sha": "d33a14ddd4cd8045f90acfe49d2552120feeeced"
},
"homepage": "https://github.com/astronomer/agents"
},
@@ -276,7 +276,7 @@
"url": "https://github.com/auth0/agent-skills.git",
"path": "plugins/auth0",
"ref": "main",
"sha": "3e3a5d84fe922378bd2c2eafb7f7986759e3c87e"
"sha": "aacefa7dcbdf2d32ac14d3d7790b610cf716bd3c"
},
"homepage": "https://auth0.com"
},
@@ -337,7 +337,7 @@
"url": "https://github.com/aws/agent-toolkit-for-aws.git",
"path": "plugins/aws-core",
"ref": "main",
"sha": "7898a91483218173d096db3de6892c2dc545d160"
"sha": "49c4592dc490f569d5adf0c483239886bad2f09b"
},
"homepage": "https://github.com/aws/agent-toolkit-for-aws"
},
@@ -353,7 +353,7 @@
"url": "https://github.com/aws/agent-toolkit-for-aws.git",
"path": "plugins/aws-data-analytics",
"ref": "main",
"sha": "ff1dc6f45f5203147f6cd52662cc74ded4bb0825"
"sha": "49c4592dc490f569d5adf0c483239886bad2f09b"
},
"homepage": "https://github.com/aws/agent-toolkit-for-aws"
},
@@ -425,7 +425,7 @@
"source": {
"source": "url",
"url": "https://github.com/microsoft/azure-skills.git",
"sha": "2cd48ca625cddcc1d377d2861fbddd54417c70cc"
"sha": "c752fe85c8e499e32e34eb8a5498c22d5dd586c8"
},
"homepage": "https://github.com/microsoft/azure-skills"
},
@@ -521,7 +521,7 @@
"source": {
"source": "url",
"url": "https://github.com/brightdata/skills.git",
"sha": "8d427e9871566efe3f0a1c8888f98b6fe8288831"
"sha": "e825f02fbcd7a89087fd1053a57ddcd45113370f"
},
"homepage": "https://docs.brightdata.com"
},
@@ -539,6 +539,22 @@
},
"homepage": "https://buildkite.com"
},
{
"name": "canva",
"description": "Create, edit, review, resize, and brand-check Canva designs with the Canva MCP server.",
"author": {
"name": "Canva"
},
"category": "design",
"source": {
"source": "git-subdir",
"url": "https://github.com/canva-sdks/canva-skills.git",
"path": "plugins/canva",
"ref": "main",
"sha": "b56291ea0a36d0a941e1478b47959be5f1771dee"
},
"homepage": "https://www.canva.com"
},
{
"name": "carta-cap-table",
"description": "Carta Cap Table plugin — skills and hooks for querying cap tables, grants, SAFEs, 409A valuations, waterfall scenarios, and more",
@@ -551,7 +567,7 @@
"url": "https://github.com/carta/plugins.git",
"path": "plugins/carta-cap-table",
"ref": "main",
"sha": "d73954d3d9ce1e3fce1ec2b9ee6819922dd539e3"
"sha": "8d49ea8bbb0ef82f3495dc246478ea2eacf3e3a0"
},
"homepage": "https://carta.com"
},
@@ -583,7 +599,7 @@
"url": "https://github.com/carta/plugins.git",
"path": "plugins/carta-investors",
"ref": "main",
"sha": "d73a3615864a5590ad6105df1b3e1b26324d1813"
"sha": "8d49ea8bbb0ef82f3495dc246478ea2eacf3e3a0"
},
"homepage": "https://carta.com"
},
@@ -610,7 +626,7 @@
"source": {
"source": "url",
"url": "https://github.com/ChromeDevTools/chrome-devtools-mcp.git",
"sha": "6a9466378c13b6ccba91b54091ea83a5ca37a8db"
"sha": "e5bd334c97b4f25207cad586684cca8208f1657e"
},
"homepage": "https://github.com/ChromeDevTools/chrome-devtools-mcp"
},
@@ -935,7 +951,7 @@
"source": {
"source": "url",
"url": "https://github.com/CrowdStrike/foundry-skills.git",
"sha": "20ef548a615a5a8a18de7edbe65eb4bb10c8563b"
"sha": "7b2cda5cd3c5383924c365a3194172feb9fbac59"
},
"homepage": "https://github.com/CrowdStrike/foundry-skills"
},
@@ -981,7 +997,7 @@
"source": {
"source": "url",
"url": "https://github.com/dash0hq/dash0-agent-plugin.git",
"sha": "f8c31f6fcdc6588a27153ceed09e561a40da3a86"
"sha": "4eac30a47b4dd3819e0719f9f01b9772cde7ca24"
},
"homepage": "https://dash0.com/"
},
@@ -992,7 +1008,7 @@
"source": {
"source": "url",
"url": "https://github.com/astronomer/agents.git",
"sha": "e4ebf9a7ad3f8dbf3fcfda9c245a65eb1415967b"
"sha": "d33a14ddd4cd8045f90acfe49d2552120feeeced"
},
"homepage": "https://github.com/astronomer/agents"
},
@@ -1006,7 +1022,7 @@
"source": {
"source": "url",
"url": "https://github.com/gemini-cli-extensions/data-agent-kit-starter-pack.git",
"sha": "86cd0201237ed5ac30d8645c2ba50000fac84972"
"sha": "9bc90f9ec22b156a71f37c45157cf3f551005a45"
},
"homepage": "https://github.com/gemini-cli-extensions/data-agent-kit-starter-pack"
},
@@ -1016,7 +1032,7 @@
"source": {
"source": "url",
"url": "https://github.com/astronomer/agents.git",
"sha": "e4ebf9a7ad3f8dbf3fcfda9c245a65eb1415967b"
"sha": "d33a14ddd4cd8045f90acfe49d2552120feeeced"
},
"homepage": "https://github.com/astronomer/agents"
},
@@ -1029,7 +1045,7 @@
"url": "https://github.com/awslabs/agent-plugins.git",
"path": "plugins/databases-on-aws",
"ref": "main",
"sha": "66dd3cf5acdf374cc0d79af2bf51fa6fbb975c07"
"sha": "96a073a195491f2192c256ba66730b631ced03e1"
},
"homepage": "https://github.com/awslabs/agent-plugins"
},
@@ -1045,7 +1061,7 @@
"url": "https://github.com/databricks/databricks-agent-skills.git",
"path": "plugins/databricks/claude",
"ref": "main",
"sha": "e337277c9771597bd2a67dfc5f8dd1d1afc887c6"
"sha": "ae99f56bbadc5ac0bac8df11791eb6a5224a2a36"
},
"homepage": "https://developers.databricks.com/"
},
@@ -1087,7 +1103,7 @@
"source": {
"source": "url",
"url": "https://github.com/gemini-cli-extensions/dataproc.git",
"sha": "c36c7f8bb53a1f8903382471366986ef226c509d"
"sha": "6d6ac3889bf448e33a0ad96174bc5b0849c74ebe"
},
"homepage": "https://github.com/gemini-cli-extensions/dataproc"
},
@@ -1101,7 +1117,7 @@
"source": {
"source": "url",
"url": "https://github.com/datarobot-oss/datarobot-agent-skills.git",
"sha": "f4b3c29db60e1d735285a6f51328a69a2b500338"
"sha": "0e28dc839859f523f4d8d418612cdadb7a4a3ce7"
},
"homepage": "https://datarobot.com"
},
@@ -1221,7 +1237,7 @@
"source": {
"source": "url",
"url": "https://github.com/exa-labs/exa-mcp-server.git",
"sha": "34a6b2aa877307639a1750ad6b1a1f74c66a34f5"
"sha": "f7e9032308a6dca9dbad76d22bc3cda287ba6775"
},
"homepage": "https://exa.ai/docs/reference/exa-mcp"
},
@@ -1245,7 +1261,7 @@
"url": "https://github.com/expo/skills.git",
"path": "plugins/expo",
"ref": "main",
"sha": "81ee6546b0745dc666ebacfc1f48e4bff74fbf44"
"sha": "ad897fdf0c6593d0cc7523198aa752c6f62adeda"
},
"homepage": "https://github.com/expo/skills/blob/main/plugins/expo/README.md"
},
@@ -1428,7 +1444,7 @@
"source": {
"source": "url",
"url": "https://github.com/huggingface/skills.git",
"sha": "093e0bb81e568503fbb091d694fbcdb6273d7f44"
"sha": "35e8c35a1ae5b462e0bb23d444d25569c3bb6700"
},
"homepage": "https://github.com/huggingface/skills.git"
},
@@ -1442,7 +1458,7 @@
"source": {
"source": "url",
"url": "https://github.com/hunter-io/claude-plugin.git",
"sha": "9929ccf4f228171398049633da7afd8f1b65646b"
"sha": "6db1c0ae9a789da21b415d65a59a3409dd99ca38"
},
"homepage": "https://hunter.io"
},
@@ -1456,7 +1472,7 @@
"source": {
"source": "url",
"url": "https://github.com/heygen-com/hyperframes.git",
"sha": "64eaad7d69b3c11b9e95b912f2c0b5070994078b"
"sha": "13b115e00684a8b6ed1ebed952b6fec2868d5c86"
},
"homepage": "https://hyperframes.heygen.com"
},
@@ -1510,7 +1526,7 @@
"source": "github",
"repo": "jfrog/claude-plugin",
"commit": "259c8e718266c16e99b4f30ae9b1ed0f9f00d98d",
"sha": "ac0ea16e9e96c9837b26d3c7d6bdfecd41cb6149"
"sha": "320a5585d6d9747668bd20e1c512c577d1e871d3"
},
"homepage": "https://jfrog.com"
},
@@ -1563,7 +1579,7 @@
"source": {
"source": "url",
"url": "https://github.com/langfuse/claude-observability-plugin.git",
"sha": "597af67d6c6b369f3e55db6cfa2ebe444f1af46c"
"sha": "4615df55428bdcd8a2095fdea2cbe970b2c5152e"
},
"homepage": "https://langfuse.com/integrations/other/claude-code"
},
@@ -1867,7 +1883,7 @@
"url": "https://github.com/awslabs/startups.git",
"path": "migrate/plugins/migration-to-aws",
"ref": "main",
"sha": "ac1d625107f2d1905e448f4886e60c3cb264ea00"
"sha": "59db838b8731291753007a31a4a370472bbdb6d5"
},
"homepage": "https://github.com/awslabs/startups"
},
@@ -1981,7 +1997,7 @@
"source": {
"source": "url",
"url": "https://github.com/nvsecurity/nightvision-skills.git",
"sha": "c7807ab1e2064890bfa6c96af17fc5b5c58eeab7"
"sha": "67af610a1da439e10b1714d3896a2a02bf1ebd63"
},
"homepage": "https://github.com/nvsecurity/nightvision-skills"
},
@@ -1991,7 +2007,7 @@
"source": {
"source": "url",
"url": "https://github.com/Nimbleway/agent-skills.git",
"sha": "1a599ea15f71d20cc6f85692030021146931997a"
"sha": "958fca1cca704c247fe75929c572fbad6a302ba5"
},
"homepage": "https://docs.nimbleway.com/integrations/agent-skills/plugin-installation"
},
@@ -2034,7 +2050,7 @@
"url": "https://github.com/oracle-samples/oracle-aidp-samples.git",
"path": "ai/claude-code-plugins/oracle-ai-data-platform-workbench-databricks-migrator",
"ref": "main",
"sha": "80a37379a3c503dc8099872f2ce6780e7232f275"
"sha": "a88bcf3a9f9acca94663a727de42d8535e869486"
},
"homepage": "https://docs.oracle.com/en/cloud/paas/ai-data-platform/index.html"
},
@@ -2066,7 +2082,7 @@
"url": "https://github.com/oracle-samples/oracle-aidp-samples.git",
"path": "ai/claude-code-plugins/oracle-ai-data-platform-workbench-spark-connectors",
"ref": "main",
"sha": "13e7a9139b3b62172119c7fc1a63bf4a2eac919d"
"sha": "ca1ab4e5689bdc6cb22b842fed5d98829847fd64"
},
"homepage": "https://docs.oracle.com/en/cloud/paas/ai-data-platform/index.html"
},
@@ -2206,7 +2222,7 @@
"source": {
"source": "url",
"url": "https://github.com/PostHog/ai-plugin.git",
"sha": "39a8593ef773f643c34cfdb759c0c0d6f7311c93"
"sha": "835f4f647fec8a8fbde8ea00cf9b2432a35d7e5b"
},
"homepage": "https://posthog.com/docs/model-context-protocol"
},
@@ -2272,7 +2288,7 @@
"url": "https://github.com/pydantic/skills.git",
"path": "plugins/ai",
"ref": "main",
"sha": "f0c20b9895f06d58823032f13e68c6aaae9dd3fa"
"sha": "96e5d761173b496a4ce4188ce4aaada86d93a5c3"
},
"homepage": "https://github.com/pydantic/skills/tree/main/plugins/ai"
},
@@ -2310,7 +2326,7 @@
"source": {
"source": "url",
"url": "https://github.com/qdrant/skills.git",
"sha": "7a91f32069374463d22b0ae7836fd42f3f98b1f6"
"sha": "0651740b38ed466ad12907bfb848e5f4b71b25e2"
},
"homepage": "https://skills.qdrant.tech"
},
@@ -2411,7 +2427,7 @@
"source": {
"source": "url",
"url": "https://github.com/Digital-Process-Tools/claude-remember.git",
"sha": "f1a00382598ef627c858d9eed6438047b072ba41"
"sha": "9d7324957b4d6e92fd57d265a2685a363e93f63e"
},
"homepage": "https://github.com/Digital-Process-Tools/claude-remember"
},
@@ -2451,7 +2467,7 @@
"source": {
"source": "url",
"url": "https://github.com/rilldata/agent-skills.git",
"sha": "9bdc4efa38a9ad419104fc2d1bb3e89529202487"
"sha": "c8c8738f44826150d52304cd4fb70cc3ecbdca2e"
},
"homepage": "https://docs.rilldata.com/developers/build/ai-configuration"
},
@@ -2584,7 +2600,7 @@
"url": "https://github.com/SAP/open-ux-tools.git",
"path": "packages/fiori-mcp-server",
"ref": "main",
"sha": "10d3bfcb04eea88c6b1a61f7f13479d95398a8db"
"sha": "0cddd1a565895e5a12623b9e6aa19758cdbf80df"
},
"homepage": "https://github.com/SAP/open-ux-tools/tree/main/packages/fiori-mcp-server"
},
@@ -2656,7 +2672,7 @@
"source": "git-subdir",
"url": "https://github.com/semgrep/mcp-marketplace.git",
"path": "plugin",
"sha": "5ee984a4aeee83b3edae3ed44be4be8d333d24d1"
"sha": "8e652ba6f586bb20377a72792c402c5a85a9b284"
},
"homepage": "https://github.com/semgrep/mcp-marketplace.git"
},
@@ -2667,7 +2683,7 @@
"source": {
"source": "url",
"url": "https://github.com/getsentry/plugin-claude.git",
"sha": "f69cf097dd4c2fd56cab2738442e78848ff6d206"
"sha": "83df938b934e154c5be2a059fab500711ac54c3f"
},
"homepage": "https://github.com/getsentry/plugin-claude"
},
@@ -2683,7 +2699,7 @@
"url": "https://github.com/getsentry/cli.git",
"path": "plugins/sentry-cli",
"ref": "main",
"sha": "6acb9aa84a8e02d2cc4b029e05266427fdb79559"
"sha": "97e7fccea763d388c49f5f69eaebac59749bf65d"
},
"homepage": "https://sentry.io"
},
@@ -2860,7 +2876,7 @@
"url": "https://github.com/stripe/ai.git",
"path": "providers/claude/plugin",
"ref": "main",
"sha": "23b54f12503eb18bb05eb9de9fbaeb301bec80b0"
"sha": "f54c9e6c0e8b6cfe4e648745eec68ecab3ddc994"
},
"homepage": "https://github.com/stripe/ai/tree/main/providers/claude/plugin"
},
@@ -2872,7 +2888,7 @@
"source": "url",
"url": "https://github.com/sumup/sumup-skills.git",
"path": "providers/claude/plugin",
"sha": "b69ff6f5afcd5934af70529e529c0dd8abe46cbe"
"sha": "700da2e866a71c7acbfcb0f2940ad7fa19955ae4"
},
"homepage": "https://www.sumup.com/"
},
@@ -2918,6 +2934,20 @@
}
}
},
{
"name": "tavily",
"description": "Build AI applications with real-time web data using Tavily's search, extract, crawl, and research APIs.",
"author": {
"name": "Tavily Team"
},
"category": "development",
"source": {
"source": "url",
"url": "https://github.com/tavily-ai/skills.git",
"sha": "ea5e8201b0d3ed9c10b70b71187589bd761fe2d2"
},
"homepage": "https://www.tavily.com/"
},
{
"name": "teamcity-cli",
"description": "Agent skill for interacting with TeamCity CI/CD using the teamcity CLI. Enables Claude to explore builds, view logs, start jobs, manage queues, agents, and more.",
@@ -2928,7 +2958,7 @@
"source": {
"source": "url",
"url": "https://github.com/JetBrains/teamcity-cli.git",
"sha": "25c5f8d3bada8b56244f84fb7a119c330a80d998"
"sha": "32dfd91cc8a9b6d44f47896c1ef1b183ab58e973"
},
"homepage": "https://www.jetbrains.com/teamcity/"
},
@@ -3025,6 +3055,24 @@
},
"homepage": "https://github.com/UI5/plugins-coding-agents"
},
{
"name": "ui5-modernization",
"description": "Complete UI5 modernization toolkit with workflow and specialized fix patterns for modernizing SAPUI5/OpenUI5 applications.",
"author": {
"name": "SAP SE",
"email": "openui5@sap.com",
"url": "https://www.sap.com"
},
"category": "development",
"source": {
"source": "git-subdir",
"url": "https://github.com/UI5/plugins-coding-agents.git",
"path": "plugins/ui5-modernization",
"ref": "main",
"sha": "d1e3a43fa80ef160cb42689b88d665e25a5a81a1"
},
"homepage": "https://github.com/UI5/plugins-coding-agents"
},
{
"name": "ui5-typescript-conversion",
"description": "SAPUI5 / OpenUI5 plugin for coding agents. Convert JavaScript based UI5 projects to TypeScript.",
@@ -3043,6 +3091,20 @@
},
"homepage": "https://github.com/UI5/plugins-coding-agents"
},
{
"name": "unreal-engine-skills-for-claude-code",
"description": "Control Unreal Editor directly from Claude Code via MCP. Hundreds of tools exposed via Unreal's ToolsetRegistry across 30+ toolsets: actors, blueprints, materials, Niagara, Control Rigs, Sequencer, State Trees, widgets, Gameplay Ability System, automation testing, and more.",
"author": {
"name": "Epic Games"
},
"category": "development",
"source": {
"source": "url",
"url": "https://github.com/EpicGames/unreal-engine-skills-for-claude-code-plugin.git",
"sha": "766fb42370d9e251f7524fffb12cfdbc5b11a426"
},
"homepage": "https://dev.epicgames.com/documentation/unreal-engine/unreal-mcp-in-unreal-editor"
},
{
"name": "valtown",
"description": "Build and deploy on Val Town. Bundles the Val Town MCP server and platform skills (HTTP vals, cron/intervals, SQLite, email, OAuth, React UI, third-party integrations, templates).",
@@ -3055,7 +3117,7 @@
"url": "https://github.com/val-town/plugins.git",
"path": "plugin",
"ref": "main",
"sha": "e32973e454d92280c191f30a2b814f1adc953d14"
"sha": "22594eb245d5b06714c99248d68c333169274b21"
},
"homepage": "https://val.town"
},
@@ -3094,7 +3156,7 @@
"source": {
"source": "url",
"url": "https://github.com/vercel/vercel-plugin.git",
"sha": "5f3f0ad7931ad49d6a4c6ed43ab4bf4781a69f6d"
"sha": "3b6cbeb8a9766f8d039d8c1377a68c3d0953c9c6"
},
"homepage": "https://github.com/vercel/vercel-plugin"
},
@@ -3133,7 +3195,7 @@
"source": {
"source": "url",
"url": "https://github.com/wix/skills.git",
"sha": "a50d4c068ee95aa8646137fc6b78d12985651c14"
"sha": "1ea953a29525ce8ff07a3b5a3a107927804c3eba"
},
"homepage": "https://dev.wix.com/docs/wix-cli/guides/development/about-wix-skills"
},
@@ -3186,7 +3248,7 @@
"url": "https://github.com/zapier/zapier-mcp.git",
"path": "plugins/zapier",
"ref": "main",
"sha": "28ad6ea10009a88b9ea80748fb1524363a5d54a7"
"sha": "469651fe7fdaa3dfc6a476ef5bad6c354773366a"
},
"homepage": "https://github.com/zapier/zapier-mcp/tree/main/plugins/zapier"
},
@@ -3254,7 +3316,7 @@
"source": {
"source": "url",
"url": "https://github.com/langfuse/skills.git",
"sha": "c39789078b848160a695947907db3ba40b7a2bce"
"sha": "6b6c44cfe3c4e00860401a697d401dcb3b6e3737"
},
"homepage": "https://langfuse.com"
}

153
.github/scripts/external-pr-scope.js vendored Normal file
View File

@@ -0,0 +1,153 @@
'use strict';
// Shared logic for letting a NON-MEMBER pull request stay open and be reviewed, scoped to
// the contributor's own already-listed plugin repo. No maintained allowlist, no individuals.
//
// Trust model: we do NOT verify the submitter's identity. We trust the SOURCE REPO. A PR is
// in scope only if it ADDS marketplace.json entries whose source.url is a repo that ALREADY
// backs a live entry in this marketplace (derived from the base marketplace.json), pinned to
// a commit in that repo. Because the repo is org-controlled and the SHA pins to a real commit
// there, the shipped code is the org's code regardless of who opened the PR. Merge still
// requires CI + a maintainer approval.
//
// Used by:
// - close-external-prs.yml (skip the auto-close when in scope)
// - external-pr-scope-guard.yml (required status check: fail a non-member PR that is out of scope)
//
// Security: evaluate() reads base + head marketplace.json as DATA via the API and parses them;
// it never checks out or executes head code.
const MARKETPLACE = '.claude-plugin/marketplace.json';
function normalizeRepo(u) {
return String(u || '').trim().toLowerCase()
.replace(/^git\+/, '')
.replace(/^https?:\/\//, '')
.replace(/\.git$/, '')
.replace(/\/+$/, '');
}
function pluginsByName(json) {
const map = {};
for (const p of (json && json.plugins) || []) { if (p && p.name) map[p.name] = p; }
return map;
}
// Repos that already back a live entry, derived from the base marketplace.json.
function liveReposOf(base) {
const s = new Set();
for (const name of Object.keys(base)) {
const u = base[name] && base[name].source && base[name].source.url;
if (!u) continue;
const r = normalizeRepo(u);
if (r.split('/').length >= 3) s.add(r); // host/org/repo
}
return s;
}
// Pure decision over an already-computed diff. Returns { ok, problems, added, removed, modified }.
// before = plugins at the MERGE-BASE (what head forked from), after = plugins at HEAD,
// liveRepos = repos already live on the current base branch. Diffing before->after (not
// base-tip->head) isolates THIS PR's changes; a stale fork no longer shows main's later
// additions as phantom removals.
function analyze({ changedFiles, before, after, liveRepos }) {
const problems = [];
const off = changedFiles.filter(n => n !== MARKETPLACE);
if (off.length) problems.push(`changes files other than ${MARKETPLACE}: ${off.join(', ')}`);
const baseNames = new Set(Object.keys(before));
const headNames = new Set(Object.keys(after));
const removed = [...baseNames].filter(n => !headNames.has(n));
const added = [...headNames].filter(n => !baseNames.has(n));
const modified = [...headNames].filter(
n => baseNames.has(n) && JSON.stringify(before[n]) !== JSON.stringify(after[n])
);
if (removed.length) problems.push(`removes existing entr${removed.length > 1 ? 'ies' : 'y'}: ${removed.join(', ')}`);
if (modified.length) problems.push(`modifies existing entr${modified.length > 1 ? 'ies' : 'y'}: ${modified.join(', ')}`);
if (!off.length && !added.length && !removed.length && !modified.length) {
problems.push('makes no in-scope change (expected additions to marketplace.json)');
}
for (const name of added) {
const u = after[name] && after[name].source && after[name].source.url;
if (!u) { problems.push(`added "${name}" has no source.url to validate`); continue; }
const r = normalizeRepo(u);
if (r.split('/').length < 3) { problems.push(`added "${name}" source.url ${u} is not a valid repo URL`); continue; }
if (!liveRepos.has(r)) {
problems.push(`added "${name}" points at ${u}, a repo with no existing live plugin in this marketplace`);
}
}
return { ok: problems.length === 0, problems, added, removed, modified, liveRepoCount: liveRepos.size };
}
async function readPlugins(github, owner, repo, ref) {
try {
const { data } = await github.rest.repos.getContent({ owner, repo, ref, path: MARKETPLACE });
return pluginsByName(JSON.parse(Buffer.from(data.content, 'base64').toString('utf8')));
} catch (e) {
return null;
}
}
// API wrapper used by both workflows. Fetches the diff + base/head marketplace.json, delegates to analyze().
async function evaluate({ github, context }) {
const pr = context.payload.pull_request;
const owner = context.repo.owner, repo = context.repo.repo;
const files = await github.paginate(github.rest.pulls.listFiles, {
owner, repo, pull_number: pr.number, per_page: 100,
});
const changedFiles = files.map(f => f.filename);
// Diff THIS PR's changes (merge-base -> head), not base-tip -> head, so a fork that is
// behind main doesn't show main's later additions as phantom removals.
let mergeBaseSha = pr.base.sha;
try {
const cmp = await github.rest.repos.compareCommits({ owner, repo, base: pr.base.sha, head: pr.head.sha });
if (cmp && cmp.data && cmp.data.merge_base_commit && cmp.data.merge_base_commit.sha) {
mergeBaseSha = cmp.data.merge_base_commit.sha;
}
} catch (e) { /* fall back to base.sha */ }
const liveBase = await readPlugins(github, owner, repo, pr.base.sha); // current base branch (for "already live")
const before = await readPlugins(github, owner, repo, mergeBaseSha); // what head forked from
const after = await readPlugins(github, pr.head.repo.owner.login, pr.head.repo.name, pr.head.sha);
if (liveBase === null || before === null || after === null) {
return { ok: false, problems: ['could not read marketplace.json at base, merge-base, and/or head'], added: [], removed: [], modified: [] };
}
return analyze({ changedFiles, before, after, liveRepos: liveReposOf(liveBase) });
}
// Authors that are NOT subject to the external-contributor scope rules:
// - the repo's own automation bot — its bump PRs legitimately MODIFY existing entries
// (SHA bumps), which the additions-only external-contributor rule forbids; AND
// - org members (write/admin).
// Safe under pull_request_target: a fork PR cannot set its author to github-actions[bot]
// (that login is only ever the org's own GITHUB_TOKEN workflow), and the member path is a
// real permission lookup. Wrapped in try/catch because getCollaboratorPermissionLevel throws
// for a non-collaborator/unknown user — without this, both callers would error the job rather
// than fall through to scope evaluation.
const EXEMPT_BOTS = new Set(['github-actions[bot]']);
async function isExemptAuthor({ github, context }) {
const author = context.payload.pull_request.user.login;
if (EXEMPT_BOTS.has(author)) {
return { exempt: true, reason: `${author} is the trusted automation bot` };
}
try {
const { data } = await github.rest.repos.getCollaboratorPermissionLevel({
owner: context.repo.owner, repo: context.repo.repo, username: author,
});
if (['admin', 'write'].includes(data.permission)) {
return { exempt: true, reason: `${author} is ${data.permission} (member)` };
}
} catch (e) {
// not a collaborator / lookup failed → not exempt; fall through to scope evaluation
}
return { exempt: false };
}
module.exports = { normalizeRepo, liveReposOf, analyze, readPlugins, evaluate, isExemptAuthor, MARKETPLACE };

View File

@@ -7,30 +7,46 @@ on:
permissions:
pull-requests: write
issues: write
contents: read
jobs:
check-membership:
if: vars.DISABLE_EXTERNAL_PR_CHECK != 'true'
runs-on: ubuntu-latest
steps:
- name: Check if author has write access
# 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 { data } = await github.rest.repos.getCollaboratorPermissionLevel({
owner: context.repo.owner,
repo: context.repo.repo,
username: author
});
const { evaluate, isExemptAuthor } = require(`${process.env.GITHUB_WORKSPACE}/.github/scripts/external-pr-scope.js`);
if (['admin', 'write'].includes(data.permission)) {
console.log(`${author} has ${data.permission} access, allowing PR`);
// 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;
}
console.log(`${author} has ${data.permission} access, closing PR`);
// 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,

View File

@@ -0,0 +1,54 @@
name: External PR Scope Guard
# Advisory check that surfaces what a NON-MEMBER pull request may change.
# Members (write/admin) and the repo's own automation bot (bump SHA PRs) are unrestricted and
# skip this check. For a non-member PR this fails unless the PR is an in-scope external
# contribution per .github/scripts/external-pr-scope.js: it changes ONLY
# .claude-plugin/marketplace.json, the delta is additions-only (no existing entry modified or
# removed), and every ADDED entry's source.url is a repo that ALREADY backs a live plugin in
# this marketplace (the allowed set is derived from the live marketplace — there is no
# maintained allowlist).
#
# Do NOT add this job to branch protection as a required status check. The merge gate is the
# `validate` + `scan` checks plus a maintainer approval; this guard is advisory signal for the
# reviewer, not a hard gate. (Making it required would block the no-approval bump-merge path.)
#
# Security: runs on pull_request_target but checks out only the BASE repo (trusted) for the
# shared script; the head marketplace.json is fetched as DATA via the API and parsed, never executed.
on:
pull_request_target:
types: [opened, synchronize, reopened]
permissions:
contents: read
pull-requests: read
jobs:
scope-guard:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4 # base repo (trusted)
- uses: actions/github-script@v7
with:
script: |
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
// unrestricted; only genuinely external contributions are scope-checked.
const ex = await isExemptAuthor({ github, context });
if (ex.exempt) {
console.log(`${ex.reason} — scope guard not applicable.`);
return;
}
const result = await evaluate({ github, context });
if (!result.ok) {
core.setFailed(
`Scope guard: a non-member PR may only ADD marketplace.json entries whose source repo already backs a live plugin here.\n - ` +
result.problems.join('\n - ')
);
return;
}
console.log(`Scope guard passed: adds ${result.added.join(', ') || 'none'}, all from repos already live here.`);