mirror of
https://github.com/anthropics/claude-plugins-official.git
synced 2026-03-23 00:23:07 +00:00
Compare commits
14 Commits
9d4b44fc35
...
security
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a2ad244cd4 | ||
|
|
943b58eaeb | ||
|
|
284ce15766 | ||
|
|
fc49340cd7 | ||
|
|
5b94961619 | ||
|
|
dadb54f865 | ||
|
|
5537c70e60 | ||
|
|
f76fc32109 | ||
|
|
561954e7eb | ||
|
|
7ba8290b28 | ||
|
|
d67a345c81 | ||
|
|
993b7b7eac | ||
|
|
2cd88e7947 | ||
|
|
92ece10156 |
@@ -629,6 +629,26 @@
|
|||||||
"url": "https://github.com/coderabbitai/claude-plugin.git"
|
"url": "https://github.com/coderabbitai/claude-plugin.git"
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/coderabbitai/claude-plugin.git"
|
"homepage": "https://github.com/coderabbitai/claude-plugin.git"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "sonatype-guide",
|
||||||
|
"description": "Sonatype Guide MCP server for software supply chain intelligence and dependency security. Analyze dependencies for vulnerabilities, get secure version recommendations, and check component quality metrics.",
|
||||||
|
"category": "security",
|
||||||
|
"source": {
|
||||||
|
"source": "url",
|
||||||
|
"url": "https://github.com/sonatype/sonatype-guide-claude-plugin.git"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/sonatype/sonatype-guide-claude-plugin.git"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "firecrawl",
|
||||||
|
"description": "Web scraping and crawling powered by Firecrawl. Turn any website into clean, LLM-ready markdown or structured data. Scrape single pages, crawl entire sites, search the web, and extract structured information. Includes an AI agent for autonomous multi-source data gathering - just describe what you need and it finds, navigates, and extracts automatically.",
|
||||||
|
"category": "development",
|
||||||
|
"source": {
|
||||||
|
"source": "url",
|
||||||
|
"url": "https://github.com/firecrawl/firecrawl-claude-plugin.git"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/firecrawl/firecrawl-claude-plugin.git"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
49
.github/scripts/validate-marketplace.ts
vendored
49
.github/scripts/validate-marketplace.ts
vendored
@@ -1,49 +0,0 @@
|
|||||||
#!/usr/bin/env bun
|
|
||||||
/**
|
|
||||||
* Validates that marketplace.json is well-formed JSON with a plugins array.
|
|
||||||
*
|
|
||||||
* Usage:
|
|
||||||
* bun validate-marketplace.ts <path-to-marketplace.json>
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { readFile } from "fs/promises";
|
|
||||||
|
|
||||||
async function main() {
|
|
||||||
const filePath = process.argv[2];
|
|
||||||
if (!filePath) {
|
|
||||||
console.error("Usage: validate-marketplace.ts <path-to-marketplace.json>");
|
|
||||||
process.exit(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
const content = await readFile(filePath, "utf-8");
|
|
||||||
|
|
||||||
let parsed: unknown;
|
|
||||||
try {
|
|
||||||
parsed = JSON.parse(content);
|
|
||||||
} catch (err) {
|
|
||||||
console.error(
|
|
||||||
`ERROR: ${filePath} is not valid JSON: ${err instanceof Error ? err.message : err}`
|
|
||||||
);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
||||||
console.error(`ERROR: ${filePath} must be a JSON object`);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
const marketplace = parsed as Record<string, unknown>;
|
|
||||||
if (!Array.isArray(marketplace.plugins)) {
|
|
||||||
console.error(`ERROR: ${filePath} missing "plugins" array`);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(
|
|
||||||
`marketplace.json is valid (${marketplace.plugins.length} plugins)`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
main().catch((err) => {
|
|
||||||
console.error("Fatal error:", err);
|
|
||||||
process.exit(2);
|
|
||||||
});
|
|
||||||
174
.github/workflows/test-marketplace-check.js
vendored
174
.github/workflows/test-marketplace-check.js
vendored
@@ -1,174 +0,0 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test script for marketplace.json PR validation logic.
|
|
||||||
* Run with: node .github/workflows/test-marketplace-check.js
|
|
||||||
*/
|
|
||||||
|
|
||||||
function checkMarketplaceViolations(mainPlugins, prPlugins) {
|
|
||||||
const mainSourceByName = new Map(
|
|
||||||
mainPlugins.map(p => [p.name, JSON.stringify(p.source)])
|
|
||||||
);
|
|
||||||
|
|
||||||
const violations = [];
|
|
||||||
for (const plugin of prPlugins) {
|
|
||||||
if (!mainSourceByName.has(plugin.name)) {
|
|
||||||
violations.push(`- Adding new plugin: \`${plugin.name}\``);
|
|
||||||
} else if (mainSourceByName.get(plugin.name) !== JSON.stringify(plugin.source)) {
|
|
||||||
violations.push(`- Changing source for plugin: \`${plugin.name}\``);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return violations;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test cases
|
|
||||||
const tests = [
|
|
||||||
{
|
|
||||||
name: "No changes - should allow",
|
|
||||||
main: [
|
|
||||||
{ name: "foo", source: "./plugins/foo", description: "Foo plugin" }
|
|
||||||
],
|
|
||||||
pr: [
|
|
||||||
{ name: "foo", source: "./plugins/foo", description: "Foo plugin" }
|
|
||||||
],
|
|
||||||
expectBlocked: false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Description change only - should allow",
|
|
||||||
main: [
|
|
||||||
{ name: "foo", source: "./plugins/foo", description: "Old description" }
|
|
||||||
],
|
|
||||||
pr: [
|
|
||||||
{ name: "foo", source: "./plugins/foo", description: "New description" }
|
|
||||||
],
|
|
||||||
expectBlocked: false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Version/category change - should allow",
|
|
||||||
main: [
|
|
||||||
{ name: "foo", source: "./plugins/foo", version: "1.0.0", category: "dev" }
|
|
||||||
],
|
|
||||||
pr: [
|
|
||||||
{ name: "foo", source: "./plugins/foo", version: "2.0.0", category: "productivity" }
|
|
||||||
],
|
|
||||||
expectBlocked: false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "New plugin added - should block",
|
|
||||||
main: [
|
|
||||||
{ name: "foo", source: "./plugins/foo" }
|
|
||||||
],
|
|
||||||
pr: [
|
|
||||||
{ name: "foo", source: "./plugins/foo" },
|
|
||||||
{ name: "bar", source: "./plugins/bar" }
|
|
||||||
],
|
|
||||||
expectBlocked: true,
|
|
||||||
expectedViolation: "Adding new plugin: `bar`"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Source changed (string) - should block",
|
|
||||||
main: [
|
|
||||||
{ name: "foo", source: "./plugins/foo" }
|
|
||||||
],
|
|
||||||
pr: [
|
|
||||||
{ name: "foo", source: "./plugins/evil" }
|
|
||||||
],
|
|
||||||
expectBlocked: true,
|
|
||||||
expectedViolation: "Changing source for plugin: `foo`"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Source changed (string to object) - should block",
|
|
||||||
main: [
|
|
||||||
{ name: "foo", source: "./plugins/foo" }
|
|
||||||
],
|
|
||||||
pr: [
|
|
||||||
{ name: "foo", source: { source: "url", url: "https://evil.com/repo.git" } }
|
|
||||||
],
|
|
||||||
expectBlocked: true,
|
|
||||||
expectedViolation: "Changing source for plugin: `foo`"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Source changed (object URL) - should block",
|
|
||||||
main: [
|
|
||||||
{ name: "foo", source: { source: "url", url: "https://github.com/good/repo.git" } }
|
|
||||||
],
|
|
||||||
pr: [
|
|
||||||
{ name: "foo", source: { source: "url", url: "https://github.com/evil/repo.git" } }
|
|
||||||
],
|
|
||||||
expectBlocked: true,
|
|
||||||
expectedViolation: "Changing source for plugin: `foo`"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Plugin removed - should allow",
|
|
||||||
main: [
|
|
||||||
{ name: "foo", source: "./plugins/foo" },
|
|
||||||
{ name: "bar", source: "./plugins/bar" }
|
|
||||||
],
|
|
||||||
pr: [
|
|
||||||
{ name: "foo", source: "./plugins/foo" }
|
|
||||||
],
|
|
||||||
expectBlocked: false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Multiple violations - should block with all listed",
|
|
||||||
main: [
|
|
||||||
{ name: "foo", source: "./plugins/foo" }
|
|
||||||
],
|
|
||||||
pr: [
|
|
||||||
{ name: "foo", source: "./plugins/evil" },
|
|
||||||
{ name: "bar", source: "./plugins/bar" }
|
|
||||||
],
|
|
||||||
expectBlocked: true,
|
|
||||||
expectedViolationCount: 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Object source unchanged - should allow",
|
|
||||||
main: [
|
|
||||||
{ name: "foo", source: { source: "url", url: "https://github.com/org/repo.git" } }
|
|
||||||
],
|
|
||||||
pr: [
|
|
||||||
{ name: "foo", source: { source: "url", url: "https://github.com/org/repo.git" }, description: "Updated" }
|
|
||||||
],
|
|
||||||
expectBlocked: false
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
// Run tests
|
|
||||||
console.log("Running marketplace.json validation tests\n");
|
|
||||||
console.log("=".repeat(50));
|
|
||||||
|
|
||||||
let passed = 0;
|
|
||||||
let failed = 0;
|
|
||||||
|
|
||||||
for (const test of tests) {
|
|
||||||
const violations = checkMarketplaceViolations(test.main, test.pr);
|
|
||||||
const blocked = violations.length > 0;
|
|
||||||
|
|
||||||
let success = blocked === test.expectBlocked;
|
|
||||||
|
|
||||||
if (success && test.expectedViolation) {
|
|
||||||
success = violations.some(v => v.includes(test.expectedViolation));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (success && test.expectedViolationCount) {
|
|
||||||
success = violations.length === test.expectedViolationCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (success) {
|
|
||||||
console.log(`✓ ${test.name}`);
|
|
||||||
passed++;
|
|
||||||
} else {
|
|
||||||
console.log(`✗ ${test.name}`);
|
|
||||||
console.log(` Expected blocked: ${test.expectBlocked}, got: ${blocked}`);
|
|
||||||
if (violations.length > 0) {
|
|
||||||
console.log(` Violations: ${violations.join(", ")}`);
|
|
||||||
}
|
|
||||||
failed++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log("=".repeat(50));
|
|
||||||
console.log(`\nResults: ${passed} passed, ${failed} failed`);
|
|
||||||
|
|
||||||
process.exit(failed > 0 ? 1 : 0);
|
|
||||||
17
.github/workflows/validate-marketplace.yml
vendored
17
.github/workflows/validate-marketplace.yml
vendored
@@ -1,17 +0,0 @@
|
|||||||
name: Validate Marketplace JSON
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
- '.claude-plugin/marketplace.json'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
validate:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- uses: oven-sh/setup-bun@v2
|
|
||||||
|
|
||||||
- name: Validate marketplace.json
|
|
||||||
run: bun .github/scripts/validate-marketplace.ts .claude-plugin/marketplace.json
|
|
||||||
17
security.json
Normal file
17
security.json
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"generated_at": "2026-02-11T03:16:31.424Z",
|
||||||
|
"plugins": [
|
||||||
|
{
|
||||||
|
"plugin": "code-review@claude-plugins-official",
|
||||||
|
"added_at": "2026-02-11T03:16:31.424Z",
|
||||||
|
"reason": "just-a-test",
|
||||||
|
"text": "This is a test #5"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"plugin": "fizz@testmkt-marketplace",
|
||||||
|
"added_at": "2026-02-12T00:00:00.000Z",
|
||||||
|
"reason": "security",
|
||||||
|
"text": "this is a security test"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user