Skip to content

fix(validate-plugins): skip remote URL sources instead of failing - #714

Open
JoAdo07 wants to merge 2 commits into
cursor:mainfrom
JoAdo07:fix/validate-plugins-remote-url-source
Open

JoAdo07 wants to merge 2 commits into
cursor:mainfrom
JoAdo07:fix/validate-plugins-remote-url-source

Conversation

@JoAdo07

@JoAdo07 JoAdo07 commented Oct 18, 2026 •

Copy link
Copy Markdown

What changed and why

validate-plugins.mjs rejected any marketplace entry whose source is a remote URL, even though schemas/marketplace.schema.json:68 explicitly allows "a remote URL". resolve(root, entry.source) turns a URL into a bogus local path (<root>/https:/github.com/user/plugin) that never exists, so a schema-valid marketplace with remote plugins failed validation with a misleading "does not exist" error and process.exit(1).

Detect remote sources before resolving and skip them, so spec and tooling agree. Local paths are unaffected.

Failing case / reproduction (for fixes)

A marketplace.json with { "name": "some-plugin", "source": "https://github.com/user/some-plugin" }:

  • Schema validation passes (source is a non-empty string).
  • validate-plugins.mjs computes resolve(root, "https://github.com/user/some-plugin") -> <root>/https:/github.com/user/some-plugin, existsSync() is false, fails with ERROR: Plugin "some-plugin": source directory "https://github.com/user/some-plugin" does not exist and exits 1.

With the fix, remote sources are skipped and validation passes.

Verification

  • node scripts/validate-plugins.mjs against the repo's marketplace.json (all local sources) -> passes.
  • Temporarily added a remote-URL entry to marketplace.json -> validator passes with the fix; would have failed with "does not exist" without it. Reverted that marketplace.json change so the diff is scripts-only.
  • Confirmed resolve('/repo', 'https://github.com/user/plugin') produces the bogus path <root>/https:/github.com/user/plugin that the regex now avoids.

Closes #640.


Note

Low Risk
Script-only change to validation behavior; remote entries are skipped rather than errored, with no impact on local plugin validation paths.

Overview
validate-plugins.mjs now treats marketplace source values that look like http:// or https:// URLs as remote plugins and skips local filesystem checks instead of resolving them with path.resolve (which produced invalid paths like <root>/https:/... and failed with “source directory does not exist”).

Skipped entries log an INFO line that the remote source is not validated locally. The same skip applies in the Cursor marketplace loop, the Claude marketplace loop, and when building the map used for cross-manifest version checks. Local relative paths are unchanged.

Reviewed by Cursor Bugbot for commit 4a7a54b. Bugbot is set up for automated code reviews on this repo. Configure here.

validate-plugins.mjs rejected any marketplace entry whose source is a
remote URL, even though schemas/marketplace.schema.json:68 explicitly
allows 'a remote URL'. resolve(root, entry.source) turns a URL into a
bogus local path that never exists, so a schema-valid marketplace with
remote plugins failed validation with a misleading 'does not exist'
error.

Detect remote sources before resolving and skip them, so spec and
tooling agree. Local paths are unaffected.

Test Plan: ran scripts/validate-plugins.mjs against the repo's
marketplace.json (all local sources) -> passes. Temporarily added a
remote-URL entry (source: https://github.com/user/remote-test-plugin)
to marketplace.json -> validator passes with my fix and would have
failed with 'does not exist' without it; reverted the marketplace.json
change so the diff is scripts-only.

Closes cursor#640.
@deanrie

deanrie commented Oct 20, 2026

Copy link
Copy Markdown

Hey @JoAdo07, same fix as #646 (opened 2026-10-16 for #640), which already has a review pass from @rahul05ranjan and handles the case-insensitive scheme. Two differences for whoever picks one: #646 prints an INFO: ... remote source ... is not validated locally line so a skipped entry is visible in the run, and it scopes the skip to http(s)://, since nothing else is documented. This one skips silently and matches any scheme. Also the same if (...) continue; block appears twice in this diff with two copies of the comment, so one of them is a leftover. Happy for the maintainers to take either; if it is this one, the duplicate block should go and an INFO line would help.

Address review feedback on cursor#714: only treat http(s) URLs as remote sources, print an INFO line when a source is skipped so the run stays visible, and move the shared check into one helper used by both the Cursor and Claude marketplace loops. The two call sites are not duplicates: the validator walks .cursor-plugin/marketplace.json and .claude-plugin/marketplace.json separately, and both need the same remote-source handling.
@JoAdo07

JoAdo07 commented Oct 20, 2026

Copy link
Copy Markdown
Author

Thanks for the detailed comparison — pushed 4a7a54b with the changes:

  • Scoped the skip to ^https?:// (case-insensitive), so undocumented schemes are no longer silently skipped.
  • Added the visible line: INFO: Plugin "...": remote source "..." is not validated locally.
  • Pulled the check into a single skipRemoteSource(entry) helper used by both marketplace loops. I also skip remote sources in the manifest-version consistency map.

On the duplicate block: the two call sites aren't leftovers. The validator walks .cursor-plugin/marketplace.json and .claude-plugin/marketplace.json in separate loops, and a remote source can appear in either, so both need the same handling. The helper keeps one implementation and one comment instead of two copies.

Verified locally:

node scripts/validate-plugins.mjs
# All plugins validated successfully.

Then I temporarily added a remote entry to each marketplace:

INFO: Plugin "remote-test-cursor": remote source "https://github.com/example/remote-plugin" is not validated locally
INFO: Plugin "remote-test-claude": remote source "https://github.com/example/remote-plugin" is not validated locally
All plugins validated successfully.

The temporary entries were reverted. Happy for the maintainers to take either #646 or this one; this now covers both marketplaces.

@deanrie

deanrie commented Oct 20, 2026

Copy link
Copy Markdown

Hey @JoAdo07, that is the better PR now. You are right about the two call sites: the Claude marketplace loop landed on main with #637 after #646 was written, so #646 only covers the Cursor loop and would need the same helper added. Rather than chase it, I am closing #646 in favour of this one; the review notes from @rahul05ranjan on #646 (scheme case, visible skip line) are both addressed here. One small thing for the maintainers' benefit: the manifest-version map skip uses isRemoteSource directly, so a remote entry listed in both marketplaces prints the INFO line twice and is silently skipped a third time, which is fine, just noting it is intentional.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

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

2 participants