Commit Graph

7 Commits

Author SHA1 Message Date
Bryan Thompson f540d5605f chore(ci): add external-PR curation workflows (port from claude-plugins-official) (#428)
knowledge-work-plugins is a curated surface, but unlike claude-plugins-official
it had no gate on external pull requests — so the open-PR queue had accumulated
~87 external contributions (README edits, "fixes" to first-party plugins,
unsolicited new community plugins) that we do not accept here.

Ports the established -official mechanism verbatim:

- close-external-prs.yml — on PR opened, if the author is not an org member
  (write/admin) and the PR is not an in-scope contribution, posts the standard
  redirect comment (submit via clau.de/plugin-directory-submission) and closes it.
- external-pr-scope-guard.yml — advisory (NOT required) check surfacing the
  in-scope carve-out for reviewers.
- .github/scripts/external-pr-scope.js — shared trust-the-source-repo logic
  (MARKETPLACE = .claude-plugin/marketplace.json, matches this repo).

Carve-out (verbatim from -official): a non-member PR may stay open only if it
ADDS marketplace.json entries whose source repo already backs a live plugin
here, and changes nothing else. Members + the bump bot are exempt. Kill switch:
repo var DISABLE_EXTERNAL_PR_CHECK=true.

Prospective only (fires on `opened`) — does not touch the existing open queue.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 19:58:31 -05:00
Bryan Thompson bf5b78a6c1 ci(bump): flip bump-plugin-shas batch → per-entry (cohort 2) (#350)
knowledge-work-plugins is the last marketplace still opening a single batch
bump/plugin-shas PR; official + community are already per-entry. Set
pr-mode: per-entry and replace the single scan dispatch with a per-entry
fan-out over pr-urls, dispatching scan-plugins.yml per bump/<slug> branch.

Scan-only fan-out (NOT official's 3-workflow loop): KWP's only bump-blocking
required check is scan — this repo has no validate-plugins.yml and check-mcp-urls
is local-source-only + not required. An in-code comment + header guard the next
editor against re-introducing the validate-plugins dispatch (would 404 nightly).

Uses official's tmpfile failure-accumulation idiom (the jq|while subshell would
drop a shell-variable counter). max-bumps default 130 → 30 (per-entry scans are
one workflow run per branch; conservative cap for the first nights).
revert-failed-bumps stays inert under per-entry (gated on the old bump/plugin-shas
branch), exactly as in official — failing bumps isolate in their own PR.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 19:05:48 -05:00
Bryan Thompson 14531d76c6 chore(ci): re-pin scan-plugins + bump-plugin-shas to community 426e469f (#349)
* chore(bump-plugin-shas): re-pin to community 426e469f (subdir-existence guard #267)

Picks up anthropics/claude-plugins-community#267 — guards subdir existence
before manifest synthesis, so a strict:false external whose source.path subdir
vanished at the new SHA is a clean "subdir not found" skip instead of a phantom
synthesized manifest + false bump. Clean one-commit pull-forward from a27629fc.

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

* chore(scan-plugins): re-pin to community 426e469f (self-healing install)

Folds the scan-plugins pin bump into this PR so KWP pins BOTH shared actions to the
same current community SHA (426e469f) in one go. scan-plugins was still on the old
e85f0d65 (no self-healing CLI install). Supersedes #344.

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-19 14:34:59 -05:00
Bryan Thompson 47fd046c90 chore(bump-plugin-shas): pin to claude-plugins-community a27629fc + add single-plugin plugin dispatch target (#346)
Bumps the bump-plugin-shas action pin to the new claude-plugins-community SHA
(a27629fc), which adds (1) manifest synthesis for strict:false skills-only
externals — so they can be bumped instead of drifting — and (2) an `only`
input to target ONE plugin on demand.

Surfaces the targeting as a `plugin` workflow_dispatch input threaded into the
action's `with:` block:
  gh workflow run bump-plugin-shas.yml --repo anthropics/knowledge-work-plugins -f plugin=<name>
(e.g. the now-eligible strict:false entry learn-with-coursera). Empty
`plugin` = unchanged nightly behavior.

The plugin->only->ONLY->bump.sh chain was reviewed (ultra) and e2e-verified
live on claude-plugins-community before this pin bump.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 12:49:08 -05:00
Bryan Thompson f718febe12 policy(scan): review whole payload incl. .claude/ + flag cross-service credential routing (#296)
* policy(scan): review whole payload incl .claude/ + flag credential extraction

The review rubric anchored "read every relevant file" to the loaded plugin
surface (skills/*/SKILL.md, hook-referenced source) and checked credential
reads (~/.ssh, ~/.aws/credentials) only within hooks. Code that reads the user's
live secrets from a non-loaded location — e.g. a dotdir like .claude/ that still
ships to the user's disk on a git-source install — could fall through both.

Two fixes:
- Scope: direct the reviewer to read the WHOLE shipped payload incl. dotdirs
  like .claude/ (clones to disk, agent-reachable though not auto-loaded).
- Detector: add an explicit credential/secret-extraction check across ALL
  shipped code (not just hooks), naming OS credential-store CLIs + token
  harvest, with the set-your-own-key vs harvest trust-boundary distinction.

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

* policy(scan): scope credential-extraction flag to CROSS-service routing (cut same-service FPs)

A full faithful scan of all 159 -official url-source plugins surfaced false
positives: the credential clause flagged plugins that use the user's OWN
service token to call that SAME service (e.g. a Railway plugin reading the
Railway CLI token to call Railway; a gcloud token used against Google) — normal
integration behavior. The "flag even if the destination is the vendor's own
service" wording inverted the right rule.

Corrected: flag only CROSS-service routing — a credential for service A sent to
a DIFFERENT service or third party (the vercel-style misuse: Anthropic's
ANTHROPIC_AUTH_TOKEN routed to a non-Anthropic endpoint). Same-service use
(token for X used to call X) is explicitly NOT a violation.

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

* policy(scan): judge credential ownership by NAME/source, not plugin-claimed use

Refines the cross-service rule after the full -official re-validation showed the
prior wording let a plugin pass by *claiming* an ANTHROPIC_*-named token was
"its gateway key." Now: which service a credential belongs to is judged by its
NAME / storage location (ANTHROPIC_AUTH_TOKEN => Anthropic; ~/.railway/config.json
=> Railway; ~/.aws/credentials => AWS), NOT by how the plugin repurposes it. So
reading an ANTHROPIC_*-named token and routing it to a non-Anthropic endpoint is
cross-service (flag) even if the code treats it as a gateway key; same-service
use (Railway token -> Railway) still passes. Catches the wrong-credential-class
trust-boundary breach while preserving the same-service FP fix.

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-17 12:42:37 -05:00
zenexer-ant f2c8f30b5b ci: migrate scan-plugins.yml to Workload Identity Federation auth (#248)
* ci: migrate scan-plugins.yml to Workload Identity Federation auth

Replaces the static ANTHROPIC_API_KEY repo secret with Workload
Identity Federation: the scan-plugins shared action mints a GitHub
OIDC token (id-token: write) and the claude CLI exchanges it for a
short-lived bearer. The federation rule is bound to this repository
(repository_id-pinned).

Depends on anthropics/claude-plugins-community#34 (adds the WIF
inputs to the shared action). Pinned to that PR's head SHA; will
re-pin to a main-branch SHA once #34 merges.

Drops the 'Require ANTHROPIC_API_KEY' fail-closed guard — the WIF
inputs are literal in this file, so the action's skip-if-no-auth
path can't trigger. Updates the prompt-injection security comment
to reflect the short-lived bearer model.

* scan-plugins: re-pin to cpc#34 merge commit on main

claude-plugins-community#34 merged at e85f0d65b4fc87f07862e1dcdc467950514414ec — re-pinning from
the PR head SHA to the squash-merge commit on main so the pin survives
any future branch GC.
2026-05-24 14:48:50 -07:00
Tobin South 6445c15068 Add SHA bump pipeline, policy scan, and MCP URL liveness check (#236)
* Add SHA bump pipeline, policy scan, and MCP URL liveness check

Brings this marketplace's CI in line with claude-plugins-official:

- bump-plugin-shas.yml: nightly sweep that bumps every external entry's
  pinned SHA to upstream HEAD, validates each at the new SHA, opens one
  signed PR (createCommitOnBranch satisfies required_signatures), and
  dispatches the policy scan on the bump branch.

- scan-plugins.yml: Claude policy review of changed external entries.
  Caches verdicts in Actions cache keyed (plugin, sha, policy hash) so
  the nightly force-reset doesn't re-burn scan time on already-reviewed
  SHAs. Cached pass/fail verdicts are served from disk; only uncached
  SHAs are scanned. Fails closed when ANTHROPIC_API_KEY is unset.
  Designed to be a required status check on main.

- revert-failed-bumps.yml: drops policy-failing entries from a bump PR
  via a follow-up signed commit and re-dispatches the scan, so one bad
  upstream can't block the rest. Bounded at 3 passes/night, restricted
  to SHA-only diffs and first-party-repo PRs.

- check-mcp-urls.yml: probes every http/sse MCP server URL declared by
  vendored plugins. Fails on 404/410/unreachable; passes on auth/method
  errors (expected without credentials). Deduplicates shared servers so
  cost is bounded by unique URLs, not (plugins x servers). Skips empty
  and templated URLs.

- .github/policy/: the policy prompt and structured-output schema the
  scan reviews against.

Two operator steps after merge:
1. Set the ANTHROPIC_API_KEY repo secret (the scan refuses to silently
   skip a required policy review without it).
2. Add a required_status_checks ruleset on main requiring the `scan`
   check from GitHub Actions. Adding it before this merges would block
   every PR.

* Fix MCP URL probe: connection failure was reported as PASS

curl writes "000" to -w '%{http_code}' on a connection failure AND exits
nonzero. The previous fallback put the echo inside the command
substitution — both wrote, the captured value was "000000", and the
case statement's 000) arm didn't match, so dead hosts fell through to
PASS. Move the fallback assignment outside the substitution so the
captured value is exactly "000" and connection failures fail.
2026-05-18 21:19:13 -07:00