Skip to content

validate-plugins.mjs rejects marketplace entries whose source is a remote URL, which the schema explicitly allows #640

Description

@rahul05ranjan

What happens

schemas/marketplace.schema.json explicitly documents that a marketplace plugin entry's source may be either a local path or a remote URL:

schemas/marketplace.schema.json:68 (pluginEntry.source description):
"Path to the plugin directory (relative to the marketplace root) or a remote URL."

But the official validator, scripts/validate-plugins.mjs, only understands local paths:

// scripts/validate-plugins.mjs:53-61
const pluginDir = resolve(root, entry.source);
const pluginJsonPath = resolve(pluginDir, ".cursor-plugin/plugin.json");
if (!existsSync(pluginDir)) {
  fail(
    `Plugin "${entry.name}": source directory "${entry.source}" does not exist`
  );
  continue;
}

A remote URL is never a valid input to path.resolve() — resolve(root, "https://github.com/user/plugin") produces <root>/https:/github.com/user/plugin, so existsSync() is always false.

Walkthrough

Take a marketplace.json that is valid against marketplace.schema.json:

{
  "name": "my-marketplace",
  "plugins": [
    { "name": "some-plugin", "source": "https://github.com/user/some-plugin" }
  ]
}
  1. Schema validation of the entry passes (source is a non-empty string; the schema puts no other constraint on it).
  2. validate-plugins.mjs computes pluginDir = resolve(root, "https://github.com/user/some-plugin") → <root>/https:/github.com/user/some-plugin.
  3. existsSync(pluginDir) is false → the run fails with:
    ERROR: Plugin "some-plugin": source directory "https://github.com/user/some-plugin" does not exist
  4. process.exit(1) — a schema-valid marketplace cannot pass the repo's own validator.

Expected vs actual

  • Expected: an entry whose source is a remote URL validates the same way it does in the schema (or the validator fetches/skips it with a distinct message).
  • Actual: any marketplace using the documented remote-URL form is rejected as a nonexistent local directory, i.e. the tool contradicts the spec it claims to enforce.

Impact

Third-party plugin authors writing a marketplace per the schema's documented source semantics get a hard CI failure with a misleading error ("does not exist") when using the repo's own validation script.

Suggested fix

Before resolving, detect a remote source and handle it separately, e.g.:

const isRemote = /^[a-z][a-z0-9+.-]*:\/\//i.test(entry.source);
if (isRemote) continue; // or fetch and validate the remote plugin.json

Alternatively, if remote sources are not actually supported by the toolchain, tighten pluginEntry.source in the schema (e.g. "pattern": "^(?!https?://)" or a format description saying local-relative only) so spec and tooling agree.

Activity

  1. deanrie commented on Oct 16, 2026

    @deanrie

    Hey @rahul05ranjan, confirmed on main: the schema says "path ... or a remote URL" and the validator runs resolve(root, entry.source) on everything, so an https source turns into <root>/https:/... and is reported as a missing directory. Fix is up as #646: entries whose source starts with http(s):// are skipped with an explicit "remote source, not validated locally" line and still schema-checked; nothing fetches them, which I think is the right scope for a repo validator. The official marketplace has no remote sources, so CI here is unchanged; the people this helps are third-party marketplaces that copy the script.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions