mirror of
https://github.com/anthropics/claude-plugins-official.git
synced 2026-05-19 21:02:40 +00:00
Compare commits
6 Commits
tobin/fix-
...
tobin/add-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa6387a0e3 | ||
|
|
9f0275ae44 | ||
|
|
0b9a622ecb | ||
|
|
b7c0654137 | ||
|
|
af4e1ad69e | ||
|
|
de2bcc9411 |
@@ -18,7 +18,7 @@
|
||||
"source": "git-subdir",
|
||||
"url": "https://github.com/42Crunch-AI/claude-plugins.git",
|
||||
"path": "plugins/api-security-testing",
|
||||
"ref": "v1.0.1",
|
||||
"ref": "v1.5.5",
|
||||
"sha": "faf5305385de8afed9468904e8639be737aff39e"
|
||||
},
|
||||
"homepage": "https://42crunch.com"
|
||||
@@ -151,6 +151,34 @@
|
||||
},
|
||||
"homepage": "https://www.apollo.io/"
|
||||
},
|
||||
{
|
||||
"name": "apollo-skills",
|
||||
"description": "Apollo GraphQL agent skills for Claude Code — Apollo Client, Server, Federation, Connectors, Router, Rover CLI, iOS, Kotlin, and the Apollo MCP server. Covers schema design, query optimization, and GraphQL best practices.",
|
||||
"author": {
|
||||
"name": "Apollo GraphQL"
|
||||
},
|
||||
"category": "development",
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/apollographql/skills.git",
|
||||
"sha": "64d4087d629e413da1bac780abeaefd653847440"
|
||||
},
|
||||
"homepage": "https://www.apollographql.com"
|
||||
},
|
||||
{
|
||||
"name": "appwrite",
|
||||
"description": "Appwrite tools for Claude Code, including SDK skills, Appwrite MCP servers, and deployment commands.",
|
||||
"author": {
|
||||
"name": "Appwrite"
|
||||
},
|
||||
"category": "development",
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/appwrite/claude-plugin.git",
|
||||
"sha": "a42b16918159183a0d556e305fea4d240a9e3823"
|
||||
},
|
||||
"homepage": "https://appwrite.io"
|
||||
},
|
||||
{
|
||||
"name": "asana",
|
||||
"description": "Asana project management integration. Create and manage tasks, search projects, update assignments, track progress, and integrate your development workflow with Asana's work management platform.",
|
||||
@@ -217,7 +245,7 @@
|
||||
"url": "https://github.com/auth0/agent-skills.git",
|
||||
"path": "plugins/auth0",
|
||||
"ref": "main",
|
||||
"sha": "1c32754fcb934109451435ecd4a6ea9b068f0937"
|
||||
"sha": "3aa943b620a640be8a04d462e2abce11671653c3"
|
||||
},
|
||||
"homepage": "https://auth0.com/docs/quickstart/agent-skills"
|
||||
},
|
||||
@@ -233,7 +261,7 @@
|
||||
"url": "https://github.com/aws/agent-toolkit-for-aws.git",
|
||||
"path": "plugins/aws-agents",
|
||||
"ref": "main",
|
||||
"sha": "14780bf3440aa1532eadfbb2ff547f58969fcfb2"
|
||||
"sha": "ba1cc8ca4f063d88ca40c6acf3f670e6321b7a7f"
|
||||
},
|
||||
"homepage": "https://github.com/aws/agent-toolkit-for-aws"
|
||||
},
|
||||
@@ -262,7 +290,7 @@
|
||||
"url": "https://github.com/aws/agent-toolkit-for-aws.git",
|
||||
"path": "plugins/aws-core",
|
||||
"ref": "main",
|
||||
"sha": "14780bf3440aa1532eadfbb2ff547f58969fcfb2"
|
||||
"sha": "ba1cc8ca4f063d88ca40c6acf3f670e6321b7a7f"
|
||||
},
|
||||
"homepage": "https://github.com/aws/agent-toolkit-for-aws"
|
||||
},
|
||||
@@ -278,7 +306,7 @@
|
||||
"url": "https://github.com/aws/agent-toolkit-for-aws.git",
|
||||
"path": "plugins/aws-data-analytics",
|
||||
"ref": "main",
|
||||
"sha": "14780bf3440aa1532eadfbb2ff547f58969fcfb2"
|
||||
"sha": "ba1cc8ca4f063d88ca40c6acf3f670e6321b7a7f"
|
||||
},
|
||||
"homepage": "https://github.com/aws/agent-toolkit-for-aws"
|
||||
},
|
||||
@@ -318,7 +346,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/microsoft/azure-skills.git",
|
||||
"sha": "2a5c5080b8c501d00408eb00f7ee4ed8effa7b2c"
|
||||
"sha": "350e050ca30fe3464483f66193a8ff3a973b1d77"
|
||||
},
|
||||
"homepage": "https://github.com/microsoft/azure-skills"
|
||||
},
|
||||
@@ -388,6 +416,20 @@
|
||||
},
|
||||
"homepage": "https://docs.brightdata.com"
|
||||
},
|
||||
{
|
||||
"name": "buildkite",
|
||||
"description": "Official Buildkite skills for Claude Code, Cursor, and other AI coding agents — pipelines, migration, preflight, agent runtime, CLI, and API",
|
||||
"author": {
|
||||
"name": "Buildkite"
|
||||
},
|
||||
"category": "development",
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/buildkite/skills.git",
|
||||
"sha": "252476999d4813b8f7412215e47328e1b60ae51c"
|
||||
},
|
||||
"homepage": "https://buildkite.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",
|
||||
@@ -400,7 +442,7 @@
|
||||
"url": "https://github.com/carta/plugins.git",
|
||||
"path": "plugins/carta-cap-table",
|
||||
"ref": "main",
|
||||
"sha": "980fd3966ec79b61ff94f39db4592f7df9d6ed80"
|
||||
"sha": "49db52aa7d59fd4a855c6b17a1cf31c245f41e2c"
|
||||
},
|
||||
"homepage": "https://carta.com"
|
||||
},
|
||||
@@ -416,7 +458,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/cap-js/mcp-server.git",
|
||||
"sha": "4d59d7070a52761a9b8028cbe710c8d7477cbc92"
|
||||
"sha": "ef840d4315fa34264be6b71d0077a3b5288cb5fa"
|
||||
},
|
||||
"homepage": "https://cap.cloud.sap/"
|
||||
},
|
||||
@@ -427,10 +469,26 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/ChromeDevTools/chrome-devtools-mcp.git",
|
||||
"sha": "a1612be8e01401cf1711c64bc2ef5da5763ba956"
|
||||
"sha": "32dc50d59bdb87242c67391ddc755368ebe77104"
|
||||
},
|
||||
"homepage": "https://github.com/ChromeDevTools/chrome-devtools-mcp"
|
||||
},
|
||||
{
|
||||
"name": "circle-skills",
|
||||
"description": "Ship stablecoin apps faster. Best-practice skills for USDC payments, cross-chain transfers, wallets, and smart contracts — plus Circle's MCP server for real-time SDK and documentation guidance.",
|
||||
"author": {
|
||||
"name": "Circle"
|
||||
},
|
||||
"category": "development",
|
||||
"source": {
|
||||
"source": "git-subdir",
|
||||
"url": "https://github.com/circlefin/skills.git",
|
||||
"path": "plugins/circle",
|
||||
"ref": "master",
|
||||
"sha": "d076fe3ff992a1a9c30e2770031970b31429e905"
|
||||
},
|
||||
"homepage": "https://www.circle.com"
|
||||
},
|
||||
{
|
||||
"name": "circleback",
|
||||
"description": "Circleback conversational context integration. Search and access meetings, emails, calendar events, and more.",
|
||||
@@ -505,10 +563,24 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/ClickHouse/clickhouse-claude-code-plugin.git",
|
||||
"sha": "db1c108dde6e5c81a1ca65f3b6700d6fff288545"
|
||||
"sha": "13a2df004af0df46661c9de2d4ef4e85eba2f040"
|
||||
},
|
||||
"homepage": "https://github.com/ClickHouse/clickhouse-claude-code-plugin"
|
||||
},
|
||||
{
|
||||
"name": "clickhouse-best-practices",
|
||||
"description": "28 best practice rules for ClickHouse schema design, query optimization, and data ingestion — prioritized by impact",
|
||||
"author": {
|
||||
"name": "ClickHouse Inc"
|
||||
},
|
||||
"category": "database",
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/ClickHouse/agent-skills.git",
|
||||
"sha": "2d30c3619eb44a2216ef19c531efb28d5bc916a9"
|
||||
},
|
||||
"homepage": "https://clickhouse.com"
|
||||
},
|
||||
{
|
||||
"name": "cloud-sql-postgresql",
|
||||
"description": "Create, connect, and interact with a Cloud SQL for PostgreSQL database and data.",
|
||||
@@ -519,7 +591,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/gemini-cli-extensions/cloud-sql-postgresql.git",
|
||||
"sha": "69c0c820513d7f75a63eeb3ec84b01478037caeb"
|
||||
"sha": "966f7b883998692d05389e4c3d3793412ca0659f"
|
||||
},
|
||||
"homepage": "https://cloud.google.com/sql"
|
||||
},
|
||||
@@ -528,7 +600,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/cloudflare/skills.git",
|
||||
"sha": "0397d7d88fa6ac7517a88389622eb0799e86ded2"
|
||||
"sha": "60147cbb773649eadca89cee92b4e0caf02234b4"
|
||||
},
|
||||
"description": "Skills for the Cloudflare developer platform: Workers, Durable Objects, Agents SDK, MCP servers, Wrangler CLI, and web performance.",
|
||||
"category": "deployment",
|
||||
@@ -554,7 +626,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/cockroachdb/claude-plugin.git",
|
||||
"sha": "31d0cc99fac1c97614cc787a96720104ea642375"
|
||||
"sha": "736bd11df55bac97e2a6c98be8e93503b125902c"
|
||||
},
|
||||
"homepage": "https://github.com/cockroachdb/claude-plugin"
|
||||
},
|
||||
@@ -602,6 +674,20 @@
|
||||
},
|
||||
"homepage": "https://github.com/coderabbitai/skills"
|
||||
},
|
||||
{
|
||||
"name": "codspeed",
|
||||
"description": "CodSpeed is the all-in-one performance testing toolkit. Dive into benchmarking results, flamegraphs, and performance comparisons — give Claude granular profiling context to pinpoint bottlenecks and autonomously iterate on performance via the CodSpeed MCP server.",
|
||||
"author": {
|
||||
"name": "CodSpeed"
|
||||
},
|
||||
"category": "development",
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/CodSpeedHQ/codspeed.git",
|
||||
"sha": "149a618d9f18bc3afb3d2af51b7b835765d60633"
|
||||
},
|
||||
"homepage": "https://codspeed.io"
|
||||
},
|
||||
{
|
||||
"name": "commit-commands",
|
||||
"description": "Commands for git commit workflows including commit, push, and PR creation",
|
||||
@@ -623,6 +709,20 @@
|
||||
"community-managed"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "convex-backend",
|
||||
"description": "Convex backend skill for building reactive, type-safe, production-grade backends. Helps Claude design schemas, server functions, auth, file storage, scheduled jobs, and real-time multiplayer features on Convex.",
|
||||
"author": {
|
||||
"name": "Convex"
|
||||
},
|
||||
"category": "development",
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/get-convex/convex-backend-skill.git",
|
||||
"sha": "9acbc5495dd26749a5e6341dc2438146c4caa03b"
|
||||
},
|
||||
"homepage": "https://convex.dev"
|
||||
},
|
||||
{
|
||||
"name": "crowdstrike-falcon-foundry",
|
||||
"description": "CrowdStrike Falcon Foundry development skills for building cybersecurity applications on the Falcon platform. Includes UI development, collections, functions, workflows, API integration, security patterns, and debugging workflows.",
|
||||
@@ -679,7 +779,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/dash0hq/dash0-agent-plugin.git",
|
||||
"sha": "38c6d74e637bd7dbe1fa2c364de66d07efe88a9a"
|
||||
"sha": "feae46e4099d31a1a76debe39f22aebb72a18ce5"
|
||||
},
|
||||
"homepage": "https://dash0.com/"
|
||||
},
|
||||
@@ -690,7 +790,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/astronomer/agents.git",
|
||||
"sha": "5935c4330dea4dfb8e93568956b10a543ecdb3d1"
|
||||
"sha": "535a040ca9e27aaed6da13f0f959625fb3294820"
|
||||
},
|
||||
"homepage": "https://github.com/astronomer/agents"
|
||||
},
|
||||
@@ -704,7 +804,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/gemini-cli-extensions/data-agent-kit-starter-pack.git",
|
||||
"sha": "04c4354242c1192191c76fca2d4b03d94401d9fa"
|
||||
"sha": "7bc75b5e53d6eaae103132fd1a47de26239e4ae4"
|
||||
},
|
||||
"homepage": "https://github.com/gemini-cli-extensions/data-agent-kit-starter-pack"
|
||||
},
|
||||
@@ -714,7 +814,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/astronomer/agents.git",
|
||||
"sha": "5935c4330dea4dfb8e93568956b10a543ecdb3d1"
|
||||
"sha": "535a040ca9e27aaed6da13f0f959625fb3294820"
|
||||
},
|
||||
"homepage": "https://github.com/astronomer/agents"
|
||||
},
|
||||
@@ -727,7 +827,7 @@
|
||||
"url": "https://github.com/awslabs/agent-plugins.git",
|
||||
"path": "plugins/databases-on-aws",
|
||||
"ref": "main",
|
||||
"sha": "6cfb70e55aa142a8eda66e6ef7966d5921bdf9a2"
|
||||
"sha": "95381e8bcb92f58a28edb4f83eb7e163c7461a0a"
|
||||
},
|
||||
"homepage": "https://github.com/awslabs/agent-plugins"
|
||||
},
|
||||
@@ -741,10 +841,24 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/datadog-labs/claude-code-plugin.git",
|
||||
"sha": "95d38f561e3d5e4fe9fb66c3c0bb19fb75e0458a"
|
||||
"sha": "eeb2f746a857f8d97f69cd0968fb63874541c112"
|
||||
},
|
||||
"homepage": "https://www.datadoghq.com/"
|
||||
},
|
||||
{
|
||||
"name": "datahub-skills",
|
||||
"description": "DataHub development and interaction toolkit with connector planning, PR review, catalog search, metadata enrichment, lineage tracing, data quality management, and connection setup skills",
|
||||
"author": {
|
||||
"name": "DataHub"
|
||||
},
|
||||
"category": "database",
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/datahub-project/datahub-skills.git",
|
||||
"sha": "f7c7c53648b71dc0841742781e108051d46fa360"
|
||||
},
|
||||
"homepage": "https://datahub.com"
|
||||
},
|
||||
{
|
||||
"name": "datarobot-agent-skills",
|
||||
"description": "DataRobot skills for AI/ML workflows — model training, deployment, predictions, feature engineering, monitoring, explainability, data preparation, App Framework CI/CD, and external agent monitoring.",
|
||||
@@ -755,7 +869,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/datarobot-oss/datarobot-agent-skills.git",
|
||||
"sha": "b3e8fd33d7c36592c802359026c15f3e067a0646"
|
||||
"sha": "6a13377ad0b3317c7c4133fce36b7fcc626334cd"
|
||||
},
|
||||
"homepage": "https://datarobot.com"
|
||||
},
|
||||
@@ -768,7 +882,7 @@
|
||||
"url": "https://github.com/microsoft/Dataverse-skills.git",
|
||||
"path": ".github/plugins/dataverse",
|
||||
"ref": "main",
|
||||
"sha": "b2f21c1eec233d1b20e89618c3ffcb25cfdd55e4"
|
||||
"sha": "5f186bf8ab1a3d6e242492d982276bbd7443ee0f"
|
||||
},
|
||||
"homepage": "https://github.com/microsoft/Dataverse-skills"
|
||||
},
|
||||
@@ -781,7 +895,7 @@
|
||||
"url": "https://github.com/awslabs/agent-plugins.git",
|
||||
"path": "plugins/deploy-on-aws",
|
||||
"ref": "main",
|
||||
"sha": "6cfb70e55aa142a8eda66e6ef7966d5921bdf9a2"
|
||||
"sha": "95381e8bcb92f58a28edb4f83eb7e163c7461a0a"
|
||||
},
|
||||
"homepage": "https://github.com/awslabs/agent-plugins"
|
||||
},
|
||||
@@ -797,7 +911,7 @@
|
||||
"url": "https://github.com/wonderwhy-er/DesktopCommanderMCP.git",
|
||||
"path": "plugins/claude",
|
||||
"ref": "main",
|
||||
"sha": "8c03d3392d1633923057f4492f2b5014e2c4a6bf"
|
||||
"sha": "9c44119a480ec6460f82d59aeb90cf274bc3dd7b"
|
||||
},
|
||||
"homepage": "https://desktopcommander.app"
|
||||
},
|
||||
@@ -807,6 +921,48 @@
|
||||
"category": "productivity",
|
||||
"source": "./external_plugins/discord"
|
||||
},
|
||||
{
|
||||
"name": "dominodatalab",
|
||||
"description": "Full Domino Data Lab platform support — workspaces, jobs, model deployment, experiment tracking, GenAI tracing, Spark/Ray/Dask, and app deployment for data science teams",
|
||||
"author": {
|
||||
"name": "Domino Data Lab"
|
||||
},
|
||||
"category": "development",
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/dominodatalab/domino-claude-plugin.git",
|
||||
"sha": "3cc932f7a5a29ad6fab2a514df71513b1b0e0557"
|
||||
},
|
||||
"homepage": "https://www.domino.ai"
|
||||
},
|
||||
{
|
||||
"name": "duckdb-skills",
|
||||
"description": "DuckDB-powered skills for Claude Code: read any data file, attach and query DuckDB databases, search DuckDB/DuckLake docs, search past session logs, and install/update DuckDB extensions.",
|
||||
"author": {
|
||||
"name": "DuckDB Foundation"
|
||||
},
|
||||
"category": "database",
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/duckdb/duckdb-skills.git",
|
||||
"sha": "7feda8e01e22bc0886c86123f3884947e36d8c69"
|
||||
},
|
||||
"homepage": "https://duckdb.org"
|
||||
},
|
||||
{
|
||||
"name": "duende-skills",
|
||||
"description": "Duende development skills and agents for Claude Code — covering OAuth/OIDC protocols, IdentityServer, token management, ASP.NET Core authentication/authorization, BFF patterns, and secure identity architecture",
|
||||
"author": {
|
||||
"name": "Duende Software"
|
||||
},
|
||||
"category": "security",
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/DuendeSoftware/duende-skills.git",
|
||||
"sha": "2c803785061db150d8ecea098327b404b74dbf6a"
|
||||
},
|
||||
"homepage": "https://duendesoftware.com"
|
||||
},
|
||||
{
|
||||
"name": "exa",
|
||||
"description": "Exa AI web search, deep research, and content extraction. Provides MCP tools and research skills for comprehensive web search, people discovery, company research, academic papers, and more.",
|
||||
@@ -817,7 +973,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/exa-labs/exa-mcp-server.git",
|
||||
"sha": "bd2ccdd52ca7a35fbc2207ad266bb2a961c0e793"
|
||||
"sha": "5ce6c53bae8baa3248a1d197a4e89b7e464227e3"
|
||||
},
|
||||
"homepage": "https://exa.ai/docs/reference/exa-mcp"
|
||||
},
|
||||
@@ -841,7 +997,7 @@
|
||||
"url": "https://github.com/expo/skills.git",
|
||||
"path": "plugins/expo",
|
||||
"ref": "main",
|
||||
"sha": "786398d3574f33eb6714380f44ec09355819516e"
|
||||
"sha": "47f0ef64821f10e42a600758b5087bfe89c09474"
|
||||
},
|
||||
"homepage": "https://github.com/expo/skills/blob/main/plugins/expo/README.md"
|
||||
},
|
||||
@@ -857,7 +1013,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/fastly/fastly-agent-toolkit.git",
|
||||
"sha": "329331c887512850f13e481b45c4298c0387a4d2"
|
||||
"sha": "e0f4205723b843de0b07da4a2aea6c84a3bcb579"
|
||||
},
|
||||
"homepage": "https://github.com/fastly/fastly-agent-toolkit/blob/main/README.md"
|
||||
},
|
||||
@@ -878,7 +1034,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/voxel51/fiftyone-skills.git",
|
||||
"sha": "02bd4ea170ca01a751c2d2dd6bf2df8f62e65626"
|
||||
"sha": "a79e53c6fd1784e1476421185f3ed67637e642b4"
|
||||
},
|
||||
"homepage": "https://docs.voxel51.com/"
|
||||
},
|
||||
@@ -889,7 +1045,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/figma/mcp-server-guide.git",
|
||||
"sha": "fabc1ca81d839602ba7c1ca0f445a64246b3870e"
|
||||
"sha": "a742f0a700a7772ff5ed85f7c9fc1dad5afa9fcc"
|
||||
},
|
||||
"homepage": "https://github.com/figma/mcp-server-guide"
|
||||
},
|
||||
@@ -907,10 +1063,24 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/firecrawl/firecrawl-claude-plugin.git",
|
||||
"sha": "122a6ae6cefb4393c2c30740aee55ba02532ccdc"
|
||||
"sha": "48edd7943009eb4442a6f0102bbd0c251eecef3e"
|
||||
},
|
||||
"homepage": "https://github.com/firecrawl/firecrawl-claude-plugin.git"
|
||||
},
|
||||
{
|
||||
"name": "forge-skills",
|
||||
"description": "Forge-focused skills and MCP configuration for Atlassian Forge: scaffold and deploy apps (forge create, templates, dev spaces), build Teamwork Graph connectors for Rovo Search/Rovo Chat, pre-deploy review, systematic debugging, plus Forge docs and Atlassian Design System lookups via MCP.",
|
||||
"author": {
|
||||
"name": "Atlassian"
|
||||
},
|
||||
"category": "development",
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/atlassian/forge-skills.git",
|
||||
"sha": "bfe376cee02cac671b3b7d91e2ed34ac0220da5c"
|
||||
},
|
||||
"homepage": "https://developer.atlassian.com/platform/forge/"
|
||||
},
|
||||
{
|
||||
"name": "frontend-design",
|
||||
"description": "Create distinctive, production-grade frontend interfaces with high design quality. Generates creative, polished code that avoids generic AI aesthetics.",
|
||||
@@ -1000,6 +1170,34 @@
|
||||
},
|
||||
"homepage": "https://github.com/huggingface/skills.git"
|
||||
},
|
||||
{
|
||||
"name": "hunter",
|
||||
"description": "Find and verify professional email addresses, search contacts by domain, and enrich company data -- directly in Claude.",
|
||||
"author": {
|
||||
"name": "Hunter.io"
|
||||
},
|
||||
"category": "productivity",
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/hunter-io/claude-plugin.git",
|
||||
"sha": "dc66d586699a439ead4848ba8ef0bd3dd7859bfe"
|
||||
},
|
||||
"homepage": "https://hunter.io"
|
||||
},
|
||||
{
|
||||
"name": "hyperframes",
|
||||
"description": "HyperFrames by HeyGen. Write HTML, render video. Compositions, GSAP and runtime adapter animations, captions, voiceovers, audio-reactive visuals, and website-to-video capture for HyperFrames.",
|
||||
"author": {
|
||||
"name": "HeyGen"
|
||||
},
|
||||
"category": "design",
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/heygen-com/hyperframes.git",
|
||||
"sha": "d9183ba27daaf2a6ed92aead21a06d5dffd47db1"
|
||||
},
|
||||
"homepage": "https://hyperframes.heygen.com"
|
||||
},
|
||||
{
|
||||
"name": "imessage",
|
||||
"description": "iMessage messaging bridge with built-in access control. Reads chat.db directly, sends via AppleScript. Manage pairing, allowlists, and policy via /imessage:access.",
|
||||
@@ -1049,8 +1247,8 @@
|
||||
"source": {
|
||||
"source": "github",
|
||||
"repo": "jfrog/claude-plugin",
|
||||
"commit": "761921eaa12b845beba1688d699a2d45091dfe83",
|
||||
"sha": "d80db066e219aab8190f3dc4a463b71a3a180250"
|
||||
"commit": "259c8e718266c16e99b4f30ae9b1ed0f9f00d98d",
|
||||
"sha": "259c8e718266c16e99b4f30ae9b1ed0f9f00d98d"
|
||||
},
|
||||
"homepage": "https://jfrog.com"
|
||||
},
|
||||
@@ -1185,6 +1383,34 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "lumen",
|
||||
"description": "Precise local semantic code search via MCP. Indexes your codebase with Go AST parsing, embeds with Ollama or LM Studio, and exposes vector search to Claude through an MCP server — no cloud, no npm.",
|
||||
"author": {
|
||||
"name": "Ory Corp"
|
||||
},
|
||||
"category": "development",
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/ory/lumen.git",
|
||||
"sha": "e310ed03e97894c071d588d1d3522ba8ed5d54cd"
|
||||
},
|
||||
"homepage": "https://www.ory.sh"
|
||||
},
|
||||
{
|
||||
"name": "mapbox",
|
||||
"description": "Mapbox skills and MCP servers for building location-aware applications with AI. Includes geospatial tools, style management, and patterns for web, iOS, Android, and AI agent frameworks.",
|
||||
"author": {
|
||||
"name": "Mapbox"
|
||||
},
|
||||
"category": "location",
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/mapbox/mapbox-agent-skills.git",
|
||||
"sha": "fc705cd9a4f823e10d5d4ee5adad4c6cd16de0a9"
|
||||
},
|
||||
"homepage": "https://www.mapbox.com"
|
||||
},
|
||||
{
|
||||
"name": "math-olympiad",
|
||||
"description": "Solve competition math (IMO, Putnam, USAMO) with adversarial verification that catches what self-verification misses. Fresh-context verifiers attack proofs with specific failure patterns. Calibrated abstention over bluffing.",
|
||||
@@ -1196,6 +1422,22 @@
|
||||
"category": "math",
|
||||
"homepage": "https://github.com/anthropics/claude-plugins-official/tree/main/plugins/math-olympiad"
|
||||
},
|
||||
{
|
||||
"name": "mcp-apps",
|
||||
"description": "Skills for creating MCP Apps with the MCP Apps SDK",
|
||||
"author": {
|
||||
"name": "Anthropic / Model Context Protocol"
|
||||
},
|
||||
"category": "development",
|
||||
"source": {
|
||||
"source": "git-subdir",
|
||||
"url": "https://github.com/modelcontextprotocol/ext-apps.git",
|
||||
"path": "plugins/mcp-apps",
|
||||
"ref": "main",
|
||||
"sha": "9a37ad71827d076af06978fa7f7f510449687061"
|
||||
},
|
||||
"homepage": "https://modelcontextprotocol.io"
|
||||
},
|
||||
{
|
||||
"name": "mcp-server-dev",
|
||||
"description": "Skills for designing and building MCP servers that work seamlessly with Claude. Guides you through deployment models (remote HTTP, MCPB, local), tool design patterns, auth, and interactive MCP apps.",
|
||||
@@ -1654,20 +1896,51 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/RevenueCat/rc-claude-code-plugin.git",
|
||||
"sha": "af7cb77996aee4e7e3c109c5afec81f716139032"
|
||||
"path": "revenuecat",
|
||||
"sha": "407e4651ff74dbaf47c457948ab540e620403c2a"
|
||||
},
|
||||
"homepage": "https://www.revenuecat.com"
|
||||
},
|
||||
{
|
||||
"name": "redis-development",
|
||||
"description": "Redis development best practices — data structures, query engine, vector search, caching, and performance optimization",
|
||||
"author": {
|
||||
"name": "Redis"
|
||||
},
|
||||
"category": "database",
|
||||
"source": {
|
||||
"source": "git-subdir",
|
||||
"url": "https://github.com/redis/agent-skills.git",
|
||||
"path": "plugins/redis-development",
|
||||
"ref": "main",
|
||||
"sha": "4eaff191fcb830b64b6ac05bb8ef0ee067c73a9f"
|
||||
},
|
||||
"homepage": "https://redis.io"
|
||||
},
|
||||
{
|
||||
"name": "remember",
|
||||
"description": "Continuous memory for Claude Code. Extracts, summarizes, and compresses conversations into tiered daily logs. Claude remembers what you did yesterday.",
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/Digital-Process-Tools/claude-remember.git",
|
||||
"sha": "914445ac5f06a164800ea90ba4db41a0486321ae"
|
||||
"sha": "aa55ba3f553e23f4d84387f5d7ece1ba0ce68d93"
|
||||
},
|
||||
"homepage": "https://github.com/Digital-Process-Tools/claude-remember"
|
||||
},
|
||||
{
|
||||
"name": "resend",
|
||||
"description": "Agent skills for working with Resend to send and receive emails — email API integration, agent inbox, CLI, React Email components, and deliverability best practices. Includes the Resend MCP server.",
|
||||
"author": {
|
||||
"name": "Resend"
|
||||
},
|
||||
"category": "development",
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/resend/resend-skills.git",
|
||||
"sha": "78469829399beec62b8f815f109ebfcfa3b0680b"
|
||||
},
|
||||
"homepage": "https://resend.com"
|
||||
},
|
||||
{
|
||||
"name": "revenuecat",
|
||||
"description": "Configure RevenueCat projects, apps, products, entitlements, and offerings directly from Claude Code. Manage your in-app purchase backend without leaving your development workflow.",
|
||||
@@ -1675,10 +1948,25 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/RevenueCat/rc-claude-code-plugin.git",
|
||||
"sha": "af7cb77996aee4e7e3c109c5afec81f716139032"
|
||||
"path": "revenuecat",
|
||||
"sha": "407e4651ff74dbaf47c457948ab540e620403c2a"
|
||||
},
|
||||
"homepage": "https://www.revenuecat.com"
|
||||
},
|
||||
{
|
||||
"name": "rootly",
|
||||
"description": "Full-lifecycle incident management: deploy safety, incident response, on-call management, and retrospectives.",
|
||||
"author": {
|
||||
"name": "Rootly"
|
||||
},
|
||||
"category": "monitoring",
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/Rootly-AI-Labs/rootly-claude-plugin.git",
|
||||
"sha": "942aa5de3dbb2b13132c329c589e7da46fe0641d"
|
||||
},
|
||||
"homepage": "https://rootly.com"
|
||||
},
|
||||
{
|
||||
"name": "ruby-lsp",
|
||||
"description": "Ruby language server for code intelligence and analysis",
|
||||
@@ -1703,6 +1991,20 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "runway-api",
|
||||
"description": "Video generation at scale. Generate videos, images, and audio with Runway's API — batch ad campaigns, product videos, multishot stories, and creative iteration. Supports seedance2, gen4.5, veo3, Nano, Banana Pro, and more.",
|
||||
"author": {
|
||||
"name": "Runway"
|
||||
},
|
||||
"category": "design",
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/runwayml/skills.git",
|
||||
"sha": "c5674fd2bfcf34c006fb8d9cadf912f21027e310"
|
||||
},
|
||||
"homepage": "https://runwayml.com"
|
||||
},
|
||||
{
|
||||
"name": "rust-analyzer-lsp",
|
||||
"description": "Rust language server for code intelligence and analysis",
|
||||
@@ -1733,7 +2035,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/sanity-io/agent-toolkit.git",
|
||||
"sha": "bc09fa9854507c538a856648aafbd4e1a775a95c"
|
||||
"sha": "236348e29b31e834ce71e4e2e3072184dd1c1e27"
|
||||
},
|
||||
"homepage": "https://www.sanity.io"
|
||||
},
|
||||
@@ -1749,7 +2051,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/cap-js/mcp-server.git",
|
||||
"sha": "8ce2e13ac70bd78415aedeaab0061af9396d3372"
|
||||
"sha": "ef840d4315fa34264be6b71d0077a3b5288cb5fa"
|
||||
},
|
||||
"homepage": "https://cap.cloud.sap/"
|
||||
},
|
||||
@@ -1767,7 +2069,7 @@
|
||||
"url": "https://github.com/SAP/open-ux-tools.git",
|
||||
"path": "packages/fiori-mcp-server",
|
||||
"ref": "main",
|
||||
"sha": "d9d4ab7e69fe453f8fd682304ff1e3ac40a216c6"
|
||||
"sha": "157120fda8577fda6fb7546ed1b2305bfa65b9f5"
|
||||
},
|
||||
"homepage": "https://github.com/SAP/open-ux-tools/tree/main/packages/fiori-mcp-server"
|
||||
},
|
||||
@@ -1783,7 +2085,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/SAP/mdk-mcp-server.git",
|
||||
"sha": "af81fe6c2421c5748388c65241da6a1b319a2c8f"
|
||||
"sha": "10ff6ccfee094b9fb3b3877a41f00fa278b1bcc4"
|
||||
},
|
||||
"homepage": "https://help.sap.com/docs/MDK"
|
||||
},
|
||||
@@ -1822,7 +2124,7 @@
|
||||
"source": "git-subdir",
|
||||
"url": "https://github.com/semgrep/mcp-marketplace.git",
|
||||
"path": "plugin",
|
||||
"sha": "3711c33ad790df16e67c911eca792c473ec9a2a4"
|
||||
"sha": "274846f6f9da5f56be53b19170bc008d357142a7"
|
||||
},
|
||||
"homepage": "https://github.com/semgrep/mcp-marketplace.git"
|
||||
},
|
||||
@@ -1833,10 +2135,26 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/getsentry/sentry-for-claude.git",
|
||||
"sha": "fb398fdfff2055abc3d55917f6b6f0c0d5ad5e3b"
|
||||
"sha": "cf7efd373069d6fb073413324fe313319fb54ad9"
|
||||
},
|
||||
"homepage": "https://github.com/getsentry/sentry-for-claude/tree/main"
|
||||
},
|
||||
{
|
||||
"name": "sentry-cli",
|
||||
"description": "Skills for using the Sentry CLI to interact with Sentry from the command line",
|
||||
"author": {
|
||||
"name": "Sentry"
|
||||
},
|
||||
"category": "monitoring",
|
||||
"source": {
|
||||
"source": "git-subdir",
|
||||
"url": "https://github.com/getsentry/cli.git",
|
||||
"path": "plugins/sentry-cli",
|
||||
"ref": "main",
|
||||
"sha": "4d2475540309e7824cbacc5271806180346bb941"
|
||||
},
|
||||
"homepage": "https://sentry.io"
|
||||
},
|
||||
{
|
||||
"name": "serena",
|
||||
"description": "Semantic code analysis MCP server providing intelligent code understanding, refactoring suggestions, and codebase navigation through language server protocol integration.",
|
||||
@@ -1898,7 +2216,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/Shopify/Shopify-AI-Toolkit.git",
|
||||
"sha": "c5c18d86ce7b2a7ca51ebac7c4b1a4eda00c8e25"
|
||||
"sha": "c164cf45c4bc1d17bbc105168d99a4f744cfaac2"
|
||||
},
|
||||
"homepage": "https://shopify.dev"
|
||||
},
|
||||
@@ -1936,7 +2254,7 @@
|
||||
"url": "https://github.com/Snowflake-Labs/snowflake-ai-kit.git",
|
||||
"path": "plugins/cortex-code",
|
||||
"ref": "main",
|
||||
"sha": "28192345cae4a758a909f5e510e24fea10666400"
|
||||
"sha": "b16692d548e9c785be640c06f3f3220ddf46c065"
|
||||
},
|
||||
"homepage": "https://docs.snowflake.com/en/user-guide/cortex-code"
|
||||
},
|
||||
@@ -1950,7 +2268,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/SonarSource/sonarqube-agent-plugins.git",
|
||||
"sha": "91eb175d6cf5d47a3edadbe61bdf782c31f0a65a"
|
||||
"sha": "c64e09af314406a8d8806d57cd11cda81578ce20"
|
||||
},
|
||||
"homepage": "https://www.sonarsource.com"
|
||||
},
|
||||
@@ -1983,7 +2301,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/spotify/ads-claude-plugin.git",
|
||||
"sha": "63585cc919da51dd24fab594d829869595301922"
|
||||
"sha": "cc3db744f4a4c14f7265ef3e9fb50f44cf08e0e7"
|
||||
},
|
||||
"homepage": "https://github.com/spotify/ads-claude-plugin"
|
||||
},
|
||||
@@ -1996,7 +2314,7 @@
|
||||
"url": "https://github.com/stripe/ai.git",
|
||||
"path": "providers/claude/plugin",
|
||||
"ref": "main",
|
||||
"sha": "14623416d84fdfad0aea8744d4c6f838ebc87654"
|
||||
"sha": "ec93d4c4b9ffdbc994ac45ce692d4ec1cdb755f0"
|
||||
},
|
||||
"homepage": "https://github.com/stripe/ai/tree/main/providers/claude/plugin"
|
||||
},
|
||||
@@ -2007,7 +2325,8 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/sumup/sumup-skills.git",
|
||||
"sha": "0fd0a911ecaffd7187fe35e914d8ead6de584ffd"
|
||||
"path": "providers/claude/plugin",
|
||||
"sha": "a4b5a9789e10e27fb375b68279bb0916074b8dd4"
|
||||
},
|
||||
"homepage": "https://www.sumup.com/"
|
||||
},
|
||||
@@ -2053,6 +2372,20 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"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.",
|
||||
"author": {
|
||||
"name": "JetBrains"
|
||||
},
|
||||
"category": "development",
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/JetBrains/teamcity-cli.git",
|
||||
"sha": "af537a9f4db0f3b7367522a9e00e4af284c94941"
|
||||
},
|
||||
"homepage": "https://www.jetbrains.com/teamcity/"
|
||||
},
|
||||
{
|
||||
"name": "telegram",
|
||||
"description": "Telegram messaging bridge with built-in access control. Manage pairing, allowlists, and policy via /telegram:access.",
|
||||
@@ -2070,6 +2403,20 @@
|
||||
"source": "./external_plugins/terraform",
|
||||
"homepage": "https://github.com/anthropics/claude-plugins-public/tree/main/external_plugins/terraform"
|
||||
},
|
||||
{
|
||||
"name": "togetherai-skills",
|
||||
"description": "Agent Skills for Together AI platform — inference, training, embeddings, audio, video, images, function calling, and infrastructure. Covers serverless chat completions, image/video generation, fine-tuning, batch inference, evaluations, sandboxes, dedicated endpoints, and GPU clusters.",
|
||||
"author": {
|
||||
"name": "Together AI"
|
||||
},
|
||||
"category": "development",
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/togethercomputer/skills.git",
|
||||
"sha": "7dcd48e3531068a71d7987993524bf110ee6f22c"
|
||||
},
|
||||
"homepage": "https://www.together.ai"
|
||||
},
|
||||
{
|
||||
"name": "twilio-developer-kit",
|
||||
"description": "Twilio Skills provide procedural knowledge for AI coding agents — which APIs to use, in what order, and what to avoid. Covers SMS, Voice, WhatsApp, Verify, SendGrid, Compliance, and 30+ products.",
|
||||
@@ -2080,7 +2427,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/twilio/ai.git",
|
||||
"sha": "0713fb1f40b5e871cad4c1c99f603c812431692a"
|
||||
"sha": "7d15b215240df28e86a0b7305520524a2c005005"
|
||||
},
|
||||
"homepage": "https://www.twilio.com"
|
||||
},
|
||||
@@ -2128,7 +2475,7 @@
|
||||
"url": "https://github.com/UI5/plugins-claude.git",
|
||||
"path": "plugins/ui5",
|
||||
"ref": "main",
|
||||
"sha": "cec940abd4b7b6866de8e7e4522f3dba0449379d"
|
||||
"sha": "19b2fb384719425a25d55830d5dcdba75f13045c"
|
||||
},
|
||||
"homepage": "https://github.com/UI5/plugins-claude"
|
||||
},
|
||||
@@ -2146,7 +2493,7 @@
|
||||
"url": "https://github.com/UI5/plugins-claude.git",
|
||||
"path": "plugins/ui5-typescript-conversion",
|
||||
"ref": "main",
|
||||
"sha": "cec940abd4b7b6866de8e7e4522f3dba0449379d"
|
||||
"sha": "19b2fb384719425a25d55830d5dcdba75f13045c"
|
||||
},
|
||||
"homepage": "https://github.com/UI5/plugins-claude"
|
||||
},
|
||||
@@ -2171,7 +2518,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/vercel/vercel-plugin.git",
|
||||
"sha": "61f1903bed7b322c9745f6ba67095bc006de7e63"
|
||||
"sha": "1edb125d13a29a1e6212f5ca5afcdf1b89b9b211"
|
||||
},
|
||||
"homepage": "https://github.com/vercel/vercel-plugin"
|
||||
},
|
||||
@@ -2196,7 +2543,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/wix/skills.git",
|
||||
"sha": "bf25b5a45b2413b3581f3dcbcd63f3737791a051"
|
||||
"sha": "7ae38286b49e5e0cbf7069b6fd8cf6b5db2ba786"
|
||||
},
|
||||
"homepage": "https://dev.wix.com/docs/wix-cli/guides/development/about-wix-skills"
|
||||
},
|
||||
@@ -2210,6 +2557,22 @@
|
||||
},
|
||||
"homepage": "https://developer.wordpress.com/wordpress-com-claude-code-plugin/"
|
||||
},
|
||||
{
|
||||
"name": "workos",
|
||||
"description": "WorkOS integration skills for AuthKit, SSO, Directory Sync, RBAC, Vault, Audit Logs, migrations, and API references.",
|
||||
"author": {
|
||||
"name": "WorkOS"
|
||||
},
|
||||
"category": "security",
|
||||
"source": {
|
||||
"source": "git-subdir",
|
||||
"url": "https://github.com/workos/skills.git",
|
||||
"path": "plugins/workos",
|
||||
"ref": "main",
|
||||
"sha": "e8900cc504fd759407d1a963d13f59383fa39ebc"
|
||||
},
|
||||
"homepage": "https://workos.com"
|
||||
},
|
||||
{
|
||||
"name": "youdotcom-agent-skills",
|
||||
"description": "You.com agent skills for web search, research with citations, and content extraction. Guided integrations for Vercel AI SDK, Claude Agent SDK, OpenAI Agents SDK, crewAI, LangChain, Microsoft Teams.ai, direct REST API, and bash CLI.",
|
||||
@@ -2220,7 +2583,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/youdotcom-oss/agent-skills.git",
|
||||
"sha": "362d510732362bd679e1647f72f734ca2d2fa710"
|
||||
"sha": "4712250ae8e5ce3095cad3b43b62b33608888863"
|
||||
},
|
||||
"homepage": "https://you.com"
|
||||
},
|
||||
@@ -2247,7 +2610,8 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/zilliztech/zilliz-plugin.git",
|
||||
"sha": "17cf04e6a3c272320b707d429484e4c00b3bec0b"
|
||||
"path": "plugins/zilliz",
|
||||
"sha": "e960396da0bd0b1cb219fa97e3bcbb425ee1abbd"
|
||||
},
|
||||
"homepage": "https://docs.zilliz.com"
|
||||
},
|
||||
@@ -2258,7 +2622,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/zoom/zoom-plugin.git",
|
||||
"sha": "ab0f09b2ddc6682a7f69055c7861009ec6062775"
|
||||
"sha": "88f6ca3529c2dca7a38db24359ecf6fd15a23379"
|
||||
},
|
||||
"homepage": "https://developers.zoom.us/"
|
||||
},
|
||||
@@ -2286,7 +2650,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/zscaler/zscaler-mcp-server.git",
|
||||
"sha": "6cf365968eb3b1e11306c973c51c1e54e98e704a"
|
||||
"sha": "246430c8d2d99726ad6cdcb00d1adc4e316cb966"
|
||||
},
|
||||
"homepage": "https://github.com/zscaler/zscaler-mcp-server"
|
||||
}
|
||||
|
||||
16
.github/workflows/bump-plugin-shas.yml
vendored
16
.github/workflows/bump-plugin-shas.yml
vendored
@@ -13,6 +13,14 @@ name: Bump Plugin SHAs
|
||||
# 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.
|
||||
#
|
||||
# max-bumps is set above the external-entry count so a single run can clear
|
||||
# any backlog. The cost-control mechanisms are downstream:
|
||||
# - scan-plugins.yml caches verdicts by (plugin, sha) so an unchanged SHA
|
||||
# is never re-scanned across nightly force-resets.
|
||||
# - revert-failed-bumps.yml drops policy-failing entries from the bump PR
|
||||
# so one bad upstream can't block the rest.
|
||||
# See those files for details.
|
||||
|
||||
on:
|
||||
schedule:
|
||||
@@ -22,7 +30,7 @@ on:
|
||||
max_bumps:
|
||||
description: Cap on plugins bumped this run
|
||||
required: false
|
||||
default: '20'
|
||||
default: '130'
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
@@ -35,6 +43,10 @@ concurrency:
|
||||
jobs:
|
||||
bump:
|
||||
runs-on: ubuntu-latest
|
||||
# Per-bump cost is ~2s (ls-remote + shallow clone + validate); 130 entries
|
||||
# is ~5 min. The 60 min ceiling absorbs slow upstreams without letting a
|
||||
# pathological run consume the default 360 min budget.
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
@@ -44,7 +56,7 @@ jobs:
|
||||
id: bump
|
||||
with:
|
||||
marketplace-path: .claude-plugin/marketplace.json
|
||||
max-bumps: ${{ inputs.max_bumps || '20' }}
|
||||
max-bumps: ${{ inputs.max_bumps || '130' }}
|
||||
claude-cli-version: latest
|
||||
|
||||
# `bump/plugin-shas` is the action's default `pr-branch`. The scan diffs
|
||||
|
||||
284
.github/workflows/revert-failed-bumps.yml
vendored
Normal file
284
.github/workflows/revert-failed-bumps.yml
vendored
Normal file
@@ -0,0 +1,284 @@
|
||||
name: Revert Failed Bumps
|
||||
|
||||
# Drops policy-failing entries from a bump PR so one bad upstream can't
|
||||
# block the rest. Runs after a Scan Plugins workflow_run on bump/plugin-shas
|
||||
# concludes with a failure: read the per-entry verdicts the scan uploaded,
|
||||
# revert just the failing entries' source.sha back to main's pin, push a
|
||||
# follow-up signed commit, and re-dispatch the scan. The re-dispatched scan
|
||||
# finds only cached-pass entries in the new diff and goes green in seconds.
|
||||
#
|
||||
# Scope and guardrails — this job has contents:write so it must be tight:
|
||||
# - Only acts on bump/plugin-shas (literal branch match).
|
||||
# - Only acts when the scan was dispatched (workflow_dispatch event), i.e.
|
||||
# by bump-plugin-shas.yml. A scan on a regular PR never triggers this.
|
||||
# - Only reverts source.sha. If any other field in a failing entry differs
|
||||
# from main, the run aborts — that means the bump branch was tampered
|
||||
# with and a human needs to look.
|
||||
# - Bounded at MAX_REVERT_PASSES per night via a PR comment marker; a
|
||||
# persistent loop means the cache or scan is broken and a human needs
|
||||
# to look.
|
||||
# - The revert commit is created with createCommitOnBranch (GitHub-signed,
|
||||
# compare-and-swap via expectedHeadOid) — no signing key on the runner.
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: ["Scan Plugins"]
|
||||
types: [completed]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
MARKETPLACE: .claude-plugin/marketplace.json
|
||||
BUMP_BRANCH: bump/plugin-shas
|
||||
MAX_REVERT_PASSES: '3'
|
||||
REVERT_MARKER: '<!-- revert-failed-bumps -->'
|
||||
|
||||
jobs:
|
||||
revert:
|
||||
# Tight gate: the triggering scan must be a workflow_dispatch run on the
|
||||
# bump branch (i.e. the one bump-plugin-shas.yml dispatched) that failed.
|
||||
# A scan on a regular PR, a passing scan, or a manual dispatch on another
|
||||
# branch must never reach this job.
|
||||
if: >
|
||||
github.event.workflow_run.conclusion == 'failure' &&
|
||||
github.event.workflow_run.event == 'workflow_dispatch' &&
|
||||
github.event.workflow_run.head_branch == 'bump/plugin-shas'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
permissions:
|
||||
contents: write # createCommitOnBranch on bump/plugin-shas
|
||||
pull-requests: write # comment on / close the bump PR
|
||||
actions: write # gh workflow run scan-plugins.yml --ref bump/plugin-shas
|
||||
concurrency:
|
||||
group: revert-failed-bumps
|
||||
cancel-in-progress: false
|
||||
steps:
|
||||
# The artifact carries run-failed.json (just plugin names) and
|
||||
# run-verdicts.json (full per-entry verdicts for the PR comment). It is
|
||||
# uploaded by scan-plugins.yml for every relevant run so we can tell
|
||||
# "policy failures found" from "scan never ran" (infra error → no revert).
|
||||
# The artifact won't exist when the scan died before the upload step
|
||||
# (cache restore error, jq failure, timeout) — that is an infra error,
|
||||
# not a policy failure, so the right move is to do nothing. The
|
||||
# download must not fail the job; the next step handles the missing file.
|
||||
- name: Download scan verdicts
|
||||
continue-on-error: true
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: scan-verdicts
|
||||
run-id: ${{ github.event.workflow_run.id }}
|
||||
github-token: ${{ github.token }}
|
||||
path: scan-out
|
||||
|
||||
- name: Determine revert set
|
||||
id: plan
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if [[ ! -f scan-out/run-failed.json ]]; then
|
||||
echo "::warning::No run-failed.json in scan artifact — nothing to revert."
|
||||
echo "act=false" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
if ! jq -e 'type == "array"' scan-out/run-failed.json >/dev/null 2>&1; then
|
||||
echo "::warning::run-failed.json is not a JSON array — refusing to act."
|
||||
echo "act=false" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
fail_count="$(jq 'length' scan-out/run-failed.json)"
|
||||
if [[ "$fail_count" -eq 0 ]]; then
|
||||
# The scan job failed but reported zero policy failures: that is
|
||||
# an infra error (API key missing, clone failure, schema break).
|
||||
# Reverting nothing is correct; surfacing the infra error is the
|
||||
# scan job's responsibility.
|
||||
echo "::notice::Scan failed with zero parsed policy failures — infra error, not a policy failure. Not reverting."
|
||||
echo "act=false" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
echo "act=true" >> "$GITHUB_OUTPUT"
|
||||
echo "fail_count=$fail_count" >> "$GITHUB_OUTPUT"
|
||||
echo "Failing entries:"
|
||||
jq -r '.[]' scan-out/run-failed.json
|
||||
|
||||
- name: Locate bump PR and check revert budget
|
||||
if: steps.plan.outputs.act == 'true'
|
||||
id: pr
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
REPO: ${{ github.repository }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
# Resolve the bump PR by head ref. `gh pr list --head <ref>` matches
|
||||
# by ref name across forks, so reject any PR whose head repo isn't
|
||||
# ours — a fork PR named bump/plugin-shas must never reach the
|
||||
# contents:write paths below.
|
||||
pr_json="$(gh api "repos/$REPO/pulls?head=${REPO%%/*}:$BUMP_BRANCH&base=main&state=open&per_page=1" \
|
||||
--jq '.[0] // empty')"
|
||||
if [[ -z "$pr_json" ]]; then
|
||||
echo "::warning::No open bump PR on $BUMP_BRANCH — nothing to revert."
|
||||
echo "act=false" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
pr_number="$(jq -r '.number' <<<"$pr_json")"
|
||||
head_repo="$(jq -r '.head.repo.full_name' <<<"$pr_json")"
|
||||
head_sha="$(jq -r '.head.sha' <<<"$pr_json")"
|
||||
# The list endpoint omits `commits`; the single-PR endpoint has it.
|
||||
commit_count="$(gh api "repos/$REPO/pulls/$pr_number" --jq '.commits')"
|
||||
if [[ "$head_repo" != "$REPO" ]]; then
|
||||
echo "::error::Bump PR head is from $head_repo, not $REPO — refusing to act."
|
||||
echo "act=false" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
# Loop bound: every nightly bump force-resets the branch to a single
|
||||
# commit and every revert pass adds exactly one. Counting commits is
|
||||
# therefore the per-night pass count + 1, with no date math, no
|
||||
# pagination, and no exposure to comment spoofing.
|
||||
if [[ "$commit_count" -gt $(( MAX_REVERT_PASSES + 1 )) ]]; then
|
||||
echo "::error::Revert budget exhausted ($((commit_count - 1))/$MAX_REVERT_PASSES passes on this PR). The cache or scan is likely broken — needs a human."
|
||||
gh pr comment "$pr_number" --repo "$REPO" --body \
|
||||
"$REVERT_MARKER"$'\n\n'"⚠️ Revert budget exhausted ($((commit_count - 1)) passes). The scan keeps failing after reverting — likely a cache or scan bug. Pausing automatic reverts until the next nightly bump."
|
||||
echo "act=false" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
echo "Bump PR #$pr_number @ $head_sha ($commit_count commit(s))"
|
||||
{
|
||||
echo "act=true"
|
||||
echo "number=$pr_number"
|
||||
echo "head_sha=$head_sha"
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Revert failing SHAs
|
||||
if: steps.plan.outputs.act == 'true' && steps.pr.outputs.act == 'true'
|
||||
id: revert
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
REPO: ${{ github.repository }}
|
||||
HEAD_SHA: ${{ steps.pr.outputs.head_sha }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p work
|
||||
|
||||
gh api "repos/$REPO/contents/${MARKETPLACE}?ref=$HEAD_SHA" --jq '.content' | base64 -d > work/head.json
|
||||
gh api "repos/$REPO/contents/${MARKETPLACE}?ref=main" --jq '.content' | base64 -d > work/base.json
|
||||
|
||||
# Build the reverted marketplace: for each failing plugin, restore
|
||||
# source.sha to main's value. Refuse if anything else differs — a
|
||||
# difference outside source.sha on a bump-branch entry means the
|
||||
# branch was tampered with.
|
||||
jq -c -s \
|
||||
'.[0] as $head | .[1] as $base | (.[2] | map({(.): true}) | add // {}) as $fail
|
||||
| ($base.plugins | map({(.name): .}) | add // {}) as $b
|
||||
| $head | .plugins = [
|
||||
.plugins[] |
|
||||
if ($fail[.name] // false) and ($b[.name] // null) != null then
|
||||
# Verify the only delta is source.sha — never silently
|
||||
# accept a structural change masquerading as a bump.
|
||||
if (. | del(.source.sha)) == ($b[.name] | del(.source.sha)) then
|
||||
.source.sha = $b[.name].source.sha
|
||||
else
|
||||
error("entry \(.name) differs from main beyond source.sha — refusing to revert")
|
||||
end
|
||||
else . end
|
||||
]' \
|
||||
work/head.json work/base.json scan-out/run-failed.json > work/reverted.json.compact
|
||||
|
||||
# Match the marketplace's existing pretty-print so the diff is
|
||||
# human-reviewable.
|
||||
jq --indent 2 '.' work/reverted.json.compact > work/reverted.json
|
||||
|
||||
# Two no-action cases:
|
||||
# - nothing actually reverted (failed names not in this PR's diff)
|
||||
# - everything reverted (the file is back to main → PR is empty)
|
||||
if cmp -s work/reverted.json.compact <(jq -c '.' work/head.json); then
|
||||
echo "::notice::No entries to revert (failing names not in this PR)."
|
||||
echo "committed=false" >> "$GITHUB_OUTPUT"
|
||||
echo "empty=false" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
if cmp -s work/reverted.json.compact <(jq -c '.' work/base.json); then
|
||||
echo "::warning::Every bumped entry failed policy — the PR would be empty."
|
||||
echo "committed=false" >> "$GITHUB_OUTPUT"
|
||||
echo "empty=true" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Vendored entries have a string `source` — restrict to object
|
||||
# sources or `.source.sha` errors.
|
||||
reverted="$(jq -c -s \
|
||||
'.[0] as $head | .[1] as $rev
|
||||
| ($head.plugins | map(select(.source | type == "object") | {(.name): .source.sha}) | add // {}) as $h
|
||||
| [$rev.plugins[] | select(.source | type == "object")
|
||||
| select(($h[.name] // null) != .source.sha) | .name]' \
|
||||
work/head.json work/reverted.json.compact)"
|
||||
echo "Reverted: $reverted"
|
||||
echo "reverted=$reverted" >> "$GITHUB_OUTPUT"
|
||||
|
||||
msg="Drop $(jq 'length' <<<"$reverted") policy-failing entries from bump"
|
||||
# createCommitOnBranch: GitHub-signed, expectedHeadOid CAS so a
|
||||
# concurrent force-reset from the nightly bump fails this push
|
||||
# loudly instead of being clobbered. The base64'd marketplace can
|
||||
# exceed MAX_ARG_STRLEN, so the body travels via stdin.
|
||||
oid="$(jq -n \
|
||||
--rawfile content work/reverted.json \
|
||||
--arg repo "$REPO" \
|
||||
--arg branch "$BUMP_BRANCH" \
|
||||
--arg oid "$HEAD_SHA" \
|
||||
--arg msg "$msg" \
|
||||
--arg path "$MARKETPLACE" \
|
||||
'{
|
||||
query: "mutation($repo:String!,$branch:String!,$oid:GitObjectID!,$msg:String!,$path:String!,$contents:Base64String!){createCommitOnBranch(input:{branch:{repositoryNameWithOwner:$repo,branchName:$branch},message:{headline:$msg},fileChanges:{additions:[{path:$path,contents:$contents}]},expectedHeadOid:$oid}){commit{oid}}}",
|
||||
variables: { repo: $repo, branch: $branch, oid: $oid, msg: $msg, path: $path, contents: ($content | @base64) }
|
||||
}' \
|
||||
| gh api graphql --input - --jq '.data.createCommitOnBranch.commit.oid')"
|
||||
[[ "$oid" =~ ^[0-9a-f]{40}$ ]] || { echo "::error::createCommitOnBranch did not return a commit OID."; exit 1; }
|
||||
echo "committed=true" >> "$GITHUB_OUTPUT"
|
||||
echo "empty=false" >> "$GITHUB_OUTPUT"
|
||||
echo "::notice::Pushed revert commit $oid to $BUMP_BRANCH."
|
||||
|
||||
- name: Close empty bump PR
|
||||
if: steps.revert.outputs.empty == 'true'
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
REPO: ${{ github.repository }}
|
||||
PR: ${{ steps.pr.outputs.number }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
gh pr comment "$PR" --repo "$REPO" --body \
|
||||
"$REVERT_MARKER"$'\n\n'"Every bumped entry failed the policy scan. Closing — the next nightly run will retry."
|
||||
gh pr close "$PR" --repo "$REPO"
|
||||
|
||||
- name: Comment with revert detail
|
||||
if: steps.revert.outputs.committed == 'true'
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
REPO: ${{ github.repository }}
|
||||
PR: ${{ steps.pr.outputs.number }}
|
||||
REVERTED: ${{ steps.revert.outputs.reverted }}
|
||||
SCAN_RUN_URL: ${{ github.event.workflow_run.html_url }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
{
|
||||
printf '%s\n\n' "$REVERT_MARKER"
|
||||
echo "Dropped $(jq 'length' <<<"$REVERTED") entrie(s) that failed the policy scan. The remaining bumps were unaffected."
|
||||
echo
|
||||
echo "| Plugin | Violations |"
|
||||
echo "|---|---|"
|
||||
# `violations` is model-generated text shaped by a cloned external
|
||||
# repo. Strip markdown control characters and wrap in a code span
|
||||
# so a prompt-injected upstream can't smuggle links/images/table
|
||||
# breakouts into a public PR comment.
|
||||
jq -r --argjson rev "$REVERTED" \
|
||||
'def neutralize: gsub("[|\n\r\\[\\]<>`]"; " ");
|
||||
.[] | select(.name as $n | $rev | index($n))
|
||||
| "| \(.name) | `\(.violations | neutralize | .[0:200])` |"' \
|
||||
scan-out/run-verdicts.json
|
||||
echo
|
||||
echo "These entries will be retried at their next upstream SHA. See the [scan run]($SCAN_RUN_URL) for full verdicts."
|
||||
} > /tmp/comment.md
|
||||
gh pr comment "$PR" --repo "$REPO" --body-file /tmp/comment.md
|
||||
|
||||
- name: Re-dispatch scan on revised bump branch
|
||||
if: steps.revert.outputs.committed == 'true'
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: gh workflow run scan-plugins.yml --ref "$BUMP_BRANCH"
|
||||
317
.github/workflows/scan-plugins.yml
vendored
317
.github/workflows/scan-plugins.yml
vendored
@@ -7,6 +7,19 @@ name: Scan Plugins
|
||||
# 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.
|
||||
#
|
||||
# Verdict cache: each (plugin, sha) pair is scanned at most once. The bump
|
||||
# workflow force-resets bump/plugin-shas every night, which makes the same
|
||||
# SHAs reappear in the diff on consecutive nights — without a cache, the
|
||||
# scan would re-burn ~90s of Claude time per entry per night. The cache is
|
||||
# keyed on the policy hash so a prompt or schema change invalidates all
|
||||
# verdicts and triggers a clean re-scan.
|
||||
#
|
||||
# Failure handling: a cached `passes:false` verdict still fails the job. The
|
||||
# Revert Failed Bumps workflow (revert-failed-bumps.yml) reacts to that by
|
||||
# dropping the failing entries from the bump PR, so one bad upstream can't
|
||||
# block the rest. After the revert, the re-dispatched scan finds only
|
||||
# cached-pass entries and goes green in seconds.
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
@@ -20,6 +33,18 @@ on:
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
# Serialize scans per ref so concurrent runs (a re-dispatch racing the
|
||||
# original, or a manual dispatch) don't both restore the same cache, scan
|
||||
# overlapping sets, and lose one another's verdicts on save.
|
||||
concurrency:
|
||||
group: scan-plugins-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: false
|
||||
|
||||
env:
|
||||
MARKETPLACE: .claude-plugin/marketplace.json
|
||||
CACHE_DIR: ${{ github.workspace }}/.scan-cache
|
||||
CACHE_TTL_DAYS: '30'
|
||||
|
||||
jobs:
|
||||
scan:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -37,11 +62,14 @@ jobs:
|
||||
EVENT_NAME: ${{ github.event_name }}
|
||||
BASE_SHA: ${{ github.event.pull_request.base.sha }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if [[ "$EVENT_NAME" == "workflow_dispatch" ]]; then
|
||||
echo "relevant=true" >> "$GITHUB_OUTPUT"
|
||||
echo "base_ref=origin/main" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
if git diff --quiet "$BASE_SHA" HEAD -- .claude-plugin/marketplace.json .github/policy/; then
|
||||
echo "base_ref=$BASE_SHA" >> "$GITHUB_OUTPUT"
|
||||
if git diff --quiet "$BASE_SHA" HEAD -- "$MARKETPLACE" .github/policy/; then
|
||||
echo "relevant=false" >> "$GITHUB_OUTPUT"
|
||||
echo "::notice::No changes to marketplace.json or policy/ — skipping policy scan."
|
||||
else
|
||||
@@ -61,13 +89,292 @@ jobs:
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Blocking: policy failures fail the job. Loosen by removing
|
||||
# fail-on-findings if the false-positive rate is too high.
|
||||
- if: steps.changes.outputs.relevant == 'true'
|
||||
# Verdict cache, keyed on the policy content hash. A prompt change
|
||||
# invalidates every cached verdict — that is intentional. The save key
|
||||
# includes run_id so each run writes a fresh cache; restore-keys picks
|
||||
# the most recent one. Verdicts older than CACHE_TTL_DAYS are pruned on
|
||||
# restore to bound cache size as the marketplace grows.
|
||||
- name: Restore verdict cache
|
||||
if: steps.changes.outputs.relevant == 'true'
|
||||
id: cache-restore
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
path: .scan-cache
|
||||
# run_attempt so a re-run can save its own verdicts (cache keys are
|
||||
# immutable; without it a re-run would silently fail to save).
|
||||
key: scan-verdicts-${{ hashFiles('.github/policy/**') }}-${{ github.run_id }}-${{ github.run_attempt }}
|
||||
restore-keys: |
|
||||
scan-verdicts-${{ hashFiles('.github/policy/**') }}-
|
||||
|
||||
# Split the diff into cached (skip) and uncached (scan) entries. The
|
||||
# cache key is "<name>@<sha>" — a SHA is immutable, so a verdict for a
|
||||
# given (plugin, sha) is permanent under a fixed policy.
|
||||
- name: Filter scan targets against cache
|
||||
if: steps.changes.outputs.relevant == 'true'
|
||||
id: filter
|
||||
env:
|
||||
BASE_REF: ${{ steps.changes.outputs.base_ref }}
|
||||
SCAN_ALL: ${{ inputs.scan_all || 'false' }}
|
||||
TTL_DAYS: ${{ env.CACHE_TTL_DAYS }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p "$CACHE_DIR"
|
||||
|
||||
# Initialize / prune the verdict map.
|
||||
if [[ -f "$CACHE_DIR/verdicts.json" ]] && jq -e 'type == "object"' "$CACHE_DIR/verdicts.json" >/dev/null 2>&1; then
|
||||
# Drop entries older than TTL. Verdicts are immutable per (plugin, sha)
|
||||
# but pruning keeps the cache from accumulating forever.
|
||||
cutoff="$(date -u -d "-${TTL_DAYS} days" +%Y-%m-%dT%H:%M:%SZ)"
|
||||
jq --arg cutoff "$cutoff" \
|
||||
'with_entries(select(.value.scanned_at >= $cutoff))' \
|
||||
"$CACHE_DIR/verdicts.json" > "$CACHE_DIR/verdicts.json.tmp"
|
||||
mv "$CACHE_DIR/verdicts.json.tmp" "$CACHE_DIR/verdicts.json"
|
||||
else
|
||||
echo '{}' > "$CACHE_DIR/verdicts.json"
|
||||
fi
|
||||
|
||||
# Build the change set: entries in HEAD whose object differs from base.
|
||||
# scan_all overrides to "every external entry" (full re-review).
|
||||
if [[ "$SCAN_ALL" == "true" ]]; then
|
||||
jq -c '[.plugins[] | select(.source | type == "object")]' "$MARKETPLACE" \
|
||||
> "$CACHE_DIR/changed.json"
|
||||
else
|
||||
if git cat-file -e "${BASE_REF}:${MARKETPLACE}" 2>/dev/null; then
|
||||
git show "${BASE_REF}:${MARKETPLACE}" > "$CACHE_DIR/base.json"
|
||||
else
|
||||
echo '{"plugins":[]}' > "$CACHE_DIR/base.json"
|
||||
fi
|
||||
jq -c -s \
|
||||
'(.[0].plugins | map({(.name): .}) | add // {}) as $b
|
||||
| [.[1].plugins[]
|
||||
| select(.source | type == "object")
|
||||
| select(($b[.name] // null) != .)]' \
|
||||
"$CACHE_DIR/base.json" "$MARKETPLACE" > "$CACHE_DIR/changed.json"
|
||||
fi
|
||||
|
||||
changed_count="$(jq 'length' "$CACHE_DIR/changed.json")"
|
||||
|
||||
# Split changed entries into cached vs uncached. A hit requires the
|
||||
# *whole* source object (repo, sha, path, ref) to match the cached
|
||||
# entry, not just name@sha — a repo migration or path change with the
|
||||
# same SHA is different scan content and must miss the cache.
|
||||
jq -c -s \
|
||||
'.[0] as $cache
|
||||
| (.[1] | map(. + {key: (.name + "@" + (.source.sha // "")) })) as $entries
|
||||
| {
|
||||
to_scan: [$entries[] | select(($cache[.key].source // null) != .source)],
|
||||
cached: [$entries[] | select(($cache[.key].source // null) == .source)
|
||||
| . + {verdict: $cache[.key]}]
|
||||
}' \
|
||||
"$CACHE_DIR/verdicts.json" "$CACHE_DIR/changed.json" > "$CACHE_DIR/split.json"
|
||||
|
||||
jq -c '.to_scan' "$CACHE_DIR/split.json" > "$CACHE_DIR/to-scan.json"
|
||||
jq -c '.cached' "$CACHE_DIR/split.json" > "$CACHE_DIR/cached.json"
|
||||
|
||||
to_scan_count="$(jq 'length' "$CACHE_DIR/to-scan.json")"
|
||||
cached_count="$(jq 'length' "$CACHE_DIR/cached.json")"
|
||||
cached_fail_count="$(jq '[.[] | select(.verdict.passes == false)] | length' "$CACHE_DIR/cached.json")"
|
||||
|
||||
# Build a filtered marketplace containing only the uncached entries.
|
||||
# Passing this as the action's marketplace-path means the action's own
|
||||
# base diff (which can't resolve a path outside git) falls back to an
|
||||
# empty base and scans everything in the file — which is exactly the
|
||||
# to-scan set. Annotations point to the temp file rather than the real
|
||||
# marketplace, but the per-entry verdicts still land in the artifact
|
||||
# and the step summary.
|
||||
jq -c '{plugins: .}' "$CACHE_DIR/to-scan.json" > "$CACHE_DIR/scan-targets.json"
|
||||
|
||||
{
|
||||
echo "changed=$changed_count"
|
||||
echo "to_scan=$to_scan_count"
|
||||
echo "cached=$cached_count"
|
||||
echo "cached_failures=$cached_fail_count"
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
|
||||
echo "::notice::$changed_count changed entrie(s): $cached_count cached ($cached_fail_count failing), $to_scan_count to scan."
|
||||
|
||||
- name: Scan uncached entries
|
||||
if: steps.changes.outputs.relevant == 'true' && steps.filter.outputs.to_scan != '0'
|
||||
id: scan
|
||||
# Capture the action's per-entry outputs even when it exits nonzero.
|
||||
# The verdict (cached + fresh) is what gates the job, not the action's
|
||||
# exit code, and the revert workflow needs the artifact even on failure.
|
||||
continue-on-error: true
|
||||
uses: anthropics/claude-plugins-community/.github/actions/scan-plugins@b277757588871fe55b2620de8c6dfda470e2e9d8
|
||||
with:
|
||||
anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
|
||||
marketplace-path: .scan-cache/scan-targets.json
|
||||
policy-prompt: .github/policy/prompt.md
|
||||
fail-on-findings: "true"
|
||||
scan-all-external: ${{ inputs.scan_all || 'false' }}
|
||||
claude-cli-version: latest
|
||||
|
||||
# Merge fresh verdicts into the cache and assemble this run's full
|
||||
# verdict set (cached + fresh) for downstream consumers. Runs even when
|
||||
# the scan step failed so that fail verdicts are also cached — that is
|
||||
# what lets the revert workflow drop them and what stops the same
|
||||
# failing SHA from being re-scanned every night.
|
||||
- name: Merge verdicts and assemble run report
|
||||
if: steps.changes.outputs.relevant == 'true'
|
||||
id: report
|
||||
# The action's `scanned` output travels here via an env var, which is
|
||||
# subject to the OS argv/envp size limit (~128 KiB on Linux). At ~300
|
||||
# bytes/entry that is ~400 entries — an order of magnitude above the
|
||||
# cold-start case, and steady state with the cache is ~10/night. If
|
||||
# the limit is ever hit the runner fails the step before the script
|
||||
# runs ("argument list too long") — the right response is to clear
|
||||
# the cache key and lower max-bumps temporarily. Documented here so
|
||||
# nobody has to rediscover it.
|
||||
env:
|
||||
SCANNED_JSON: ${{ steps.scan.outputs.scanned || '[]' }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p "$CACHE_DIR"
|
||||
[[ -f "$CACHE_DIR/cached.json" ]] || echo '[]' > "$CACHE_DIR/cached.json"
|
||||
[[ -f "$CACHE_DIR/changed.json" ]] || echo '[]' > "$CACHE_DIR/changed.json"
|
||||
|
||||
# Defensive: a partial or unparseable action output must not poison
|
||||
# the cache. Treat it as "scanned nothing".
|
||||
printf '%s' "$SCANNED_JSON" > "$CACHE_DIR/scanned-raw.json"
|
||||
if ! jq -e 'type == "array"' "$CACHE_DIR/scanned-raw.json" >/dev/null 2>&1; then
|
||||
echo "::warning::scan action output is not a valid JSON array — treating as empty."
|
||||
echo '[]' > "$CACHE_DIR/scanned-raw.json"
|
||||
fi
|
||||
|
||||
# Defense in depth: the scan action runs Claude with Read access over
|
||||
# a cloned external repo and ANTHROPIC_API_KEY in its process env. A
|
||||
# successful prompt injection could coerce the model to put key
|
||||
# material into `summary`/`violations`. The action's own step summary
|
||||
# already carries that risk; this workflow adds an artifact and a PR
|
||||
# comment, both public sinks. Scrub any key-shaped token here so it
|
||||
# never reaches the cache, artifact, or comment.
|
||||
jq -c '(.. | strings) |= gsub("sk-ant-[A-Za-z0-9_-]{8,}"; "[REDACTED]")' \
|
||||
"$CACHE_DIR/scanned-raw.json" > "$CACHE_DIR/scanned-raw.json.tmp"
|
||||
mv "$CACHE_DIR/scanned-raw.json.tmp" "$CACHE_DIR/scanned-raw.json"
|
||||
|
||||
now="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
|
||||
# The action's `scanned` output has no SHA or source — join it with
|
||||
# the change set by name to recover both for the cache key + the
|
||||
# source-equality lookup guard.
|
||||
jq -c -s --arg now "$now" \
|
||||
'.[0] as $changed
|
||||
| (.[1] // []) as $scanned
|
||||
| ($changed | map({(.name): .source}) | add // {}) as $srcs
|
||||
| [$scanned[]
|
||||
| . + {source: ($srcs[.name] // null), sha: ($srcs[.name].sha // ""), scanned_at: $now}]' \
|
||||
"$CACHE_DIR/changed.json" "$CACHE_DIR/scanned-raw.json" \
|
||||
> "$CACHE_DIR/fresh.json"
|
||||
|
||||
# Merge fresh verdicts into the cache, keyed by name@sha. The
|
||||
# full source object is stored so a future repo/path change with the
|
||||
# same SHA fails the lookup guard. summary/violations are model
|
||||
# output — truncate to bound cache size (the artifact carries the
|
||||
# full text for the run that produced it).
|
||||
jq -c -s \
|
||||
'.[0] + ([.[1][] | select(.sha != "") | {(.name + "@" + .sha): {
|
||||
source: .source,
|
||||
passes: .passes,
|
||||
summary: ((.summary // "") | .[0:300]),
|
||||
violations: ((.violations // "") | .[0:500]),
|
||||
scanned_at: .scanned_at
|
||||
}}] | add // {})' \
|
||||
"$CACHE_DIR/verdicts.json" "$CACHE_DIR/fresh.json" \
|
||||
> "$CACHE_DIR/verdicts.json.tmp"
|
||||
mv "$CACHE_DIR/verdicts.json.tmp" "$CACHE_DIR/verdicts.json"
|
||||
|
||||
# The full per-entry verdict for THIS run's diff: cached verdicts
|
||||
# plus freshly-scanned verdicts. The revert workflow consumes the
|
||||
# `failed` list to know exactly which SHAs to drop.
|
||||
jq -c -s \
|
||||
'(.[0] | map({name, sha: .source.sha, passes: .verdict.passes,
|
||||
summary: (.verdict.summary // ""),
|
||||
violations: (.verdict.violations // ""),
|
||||
source: "cache"}))
|
||||
+ (.[1] | map({name, sha, passes,
|
||||
summary: (.summary // ""),
|
||||
violations: (.violations // ""),
|
||||
source: "scan"}))' \
|
||||
"$CACHE_DIR/cached.json" "$CACHE_DIR/fresh.json" \
|
||||
> "$CACHE_DIR/run-verdicts.json"
|
||||
|
||||
jq -c '[.[] | select(.passes == false) | .name]' "$CACHE_DIR/run-verdicts.json" \
|
||||
> "$CACHE_DIR/run-failed.json"
|
||||
|
||||
fail_count="$(jq 'length' "$CACHE_DIR/run-failed.json")"
|
||||
total="$(jq 'length' "$CACHE_DIR/run-verdicts.json")"
|
||||
|
||||
{
|
||||
echo "failed_count=$fail_count"
|
||||
echo "total=$total"
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
|
||||
# `summary` and `violations` are model-generated text shaped by a
|
||||
# cloned external repo. Strip markdown control characters AND wrap
|
||||
# in code spans before they hit a publicly-rendered sink — code
|
||||
# spans neutralize auto-linked bare URLs that a prompt-injected
|
||||
# upstream could smuggle in. Stripping backticks first stops a
|
||||
# breakout from the code span.
|
||||
{
|
||||
echo "## Policy scan (with verdict cache)"
|
||||
echo
|
||||
echo "Changed entries: ${total} · cached: $(jq 'length' "$CACHE_DIR/cached.json") · scanned fresh: $(jq 'length' "$CACHE_DIR/fresh.json") · failures: ${fail_count}"
|
||||
echo
|
||||
if [[ "$total" -gt 0 ]]; then
|
||||
echo "| Plugin | SHA | Passes | Source | Summary |"
|
||||
echo "|---|---|---|---|---|"
|
||||
jq -r 'def neutralize: gsub("[|\n\r\\[\\]<>`]"; " ");
|
||||
.[] | "| \(.name) | `\(.sha[0:8])` | \(if .passes then "✅" else "❌" end) | \(.source) | `\(.summary | neutralize | .[0:120])` |"' \
|
||||
"$CACHE_DIR/run-verdicts.json"
|
||||
fi
|
||||
if [[ "$fail_count" -gt 0 ]]; then
|
||||
echo
|
||||
echo "### Violations"
|
||||
jq -r 'def neutralize: gsub("[|\n\r\\[\\]<>`]"; " ");
|
||||
.[] | select(.passes == false) | "- **\(.name)** — `\(.violations | neutralize | .[0:500])`"' "$CACHE_DIR/run-verdicts.json"
|
||||
fi
|
||||
} >> "$GITHUB_STEP_SUMMARY"
|
||||
|
||||
# Used by revert-failed-bumps.yml to know which entries to drop. Always
|
||||
# uploaded when relevant so the revert workflow can distinguish "scan
|
||||
# found policy failures" from "scan never ran" (infra error → no revert).
|
||||
- name: Upload scan verdicts artifact
|
||||
if: steps.changes.outputs.relevant == 'true'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: scan-verdicts
|
||||
path: |
|
||||
.scan-cache/run-verdicts.json
|
||||
.scan-cache/run-failed.json
|
||||
retention-days: 7
|
||||
|
||||
# Save even when the scan failed — fail verdicts are what stop us from
|
||||
# re-burning Claude time on a known-bad SHA every night.
|
||||
- name: Save verdict cache
|
||||
if: always() && steps.changes.outputs.relevant == 'true'
|
||||
uses: actions/cache/save@v4
|
||||
with:
|
||||
path: .scan-cache
|
||||
key: scan-verdicts-${{ hashFiles('.github/policy/**') }}-${{ github.run_id }}-${{ github.run_attempt }}
|
||||
|
||||
# Required-check gate. Fails on either fresh or cached policy failures —
|
||||
# a known-bad SHA must keep failing until it is reverted or upstream
|
||||
# fixes it (a new SHA is a new cache key and gets a fresh scan).
|
||||
- name: Gate on policy verdict
|
||||
if: steps.changes.outputs.relevant == 'true'
|
||||
env:
|
||||
FAILED: ${{ steps.report.outputs.failed_count || '0' }}
|
||||
SCAN_OUTCOME: ${{ steps.scan.outcome }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if [[ "$FAILED" != "0" ]]; then
|
||||
echo "::error::$FAILED entrie(s) fail policy. See the run summary for verdicts."
|
||||
exit 1
|
||||
fi
|
||||
# The action can also fail without a policy verdict (clone error,
|
||||
# API error, schema mismatch). With zero parsed failures and a
|
||||
# nonzero exit, that is an infra error — fail loudly so the revert
|
||||
# workflow does NOT misread it as "everything passed".
|
||||
if [[ "$SCAN_OUTCOME" == "failure" ]]; then
|
||||
echo "::error::Scan step failed without a parseable policy verdict (likely an infra error)."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user