Browse Source

Strengthen marketplace validator and remove orphaned test file

- validate-marketplace.ts: check duplicate names and required fields
  (name, description, source) per entry, not just valid JSON
- remove .github/workflows/test-marketplace-check.js: tested a
  checkMarketplaceViolations function that doesn't exist in the PR,
  and was in workflows/ instead of scripts/
Tobin South 6 tháng trước cách đây
mục cha
commit
73856575d6

+ 32 - 4
.github/scripts/validate-marketplace.ts

@@ -1,6 +1,7 @@
 #!/usr/bin/env bun
 /**
- * Validates that marketplace.json is well-formed JSON with a plugins array.
+ * Validates marketplace.json: well-formed JSON, plugins array present,
+ * each entry has required fields, and no duplicate plugin names.
  *
  * Usage:
  *   bun validate-marketplace.ts <path-to-marketplace.json>
@@ -38,9 +39,36 @@ async function main() {
     process.exit(1);
   }
 
-  console.log(
-    `marketplace.json is valid (${marketplace.plugins.length} plugins)`
-  );
+  const errors: string[] = [];
+  const seen = new Set<string>();
+  const required = ["name", "description", "source"] as const;
+
+  marketplace.plugins.forEach((p, i) => {
+    if (!p || typeof p !== "object") {
+      errors.push(`plugins[${i}]: must be an object`);
+      return;
+    }
+    const entry = p as Record<string, unknown>;
+    for (const field of required) {
+      if (!entry[field]) {
+        errors.push(`plugins[${i}] (${entry.name ?? "?"}): missing required field "${field}"`);
+      }
+    }
+    if (typeof entry.name === "string") {
+      if (seen.has(entry.name)) {
+        errors.push(`plugins[${i}]: duplicate plugin name "${entry.name}"`);
+      }
+      seen.add(entry.name);
+    }
+  });
+
+  if (errors.length) {
+    console.error(`ERROR: ${filePath} has ${errors.length} validation error(s):`);
+    for (const e of errors) console.error(`  - ${e}`);
+    process.exit(1);
+  }
+
+  console.log(`OK: ${marketplace.plugins.length} plugins, no duplicates, all required fields present`);
 }
 
 main().catch((err) => {

+ 0 - 174
.github/workflows/test-marketplace-check.js

@@ -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);