Skip to content

ci: validate referenced component paths in plugin manifests - #244

Draft
rootkiller6788 wants to merge 1 commit into
cursor:mainfrom
rootkiller6788:fix-validate-plugin-paths
Draft

ci: validate referenced component paths in plugin manifests#244
rootkiller6788 wants to merge 1 commit into
cursor:mainfrom
rootkiller6788:fix-validate-plugin-paths

Conversation

@rootkiller6788

@rootkiller6788 rootkiller6788 commented Aug 21, 2026

Copy link
Copy Markdown

What

scripts/validate-plugins.mjs only checks plugin.json against the JSON schema and that the marketplace name matches the manifest name. A typo'd component path — e.g. "skills": "./skils/" or a renamed hooks/hooks.json — passes schema validation and CI but silently fails to load in Cursor. This PR adds an existence check for every path declared in plugin.json:

  • skills, agents, commands, rules, hooks, mcpServers, logo
  • Paths are resolved relative to the plugin directory (./ prefix stripped)
  • Inline hooks/mcpServers objects and absolute-URL logo values are skipped, matching the schema's allowed shapes
  • Glob patterns (e.g. skills/*) are validated against their static directory prefix so a typo in the base directory is still caught
  • Paths that escape the plugin directory (..) or are absolute are rejected

Also adds scripts/** to the validate-plugins.yml paths filter, so a PR that only changes the validator itself now triggers the job that runs it (previously a broken validator could merge without CI ever executing it).

Why

All 32 current marketplace plugins pass the new check (verified locally). The check only guards future PRs — which is the point of a merge gate: a contributor adding a new plugin or tweaking an existing manifest can't merge a path that Cursor will silently ignore.

Verification

  • node scripts/validate-plugins.mjs exits 0 on the current repo.
  • Intentionally breaking a path (skills -> ./skils/) produces a clear error and non-zero exit: ERROR: Plugin "teaching": skills path "./skils/" does not exist (resolved to teaching\skils).
  • Edge cases exercised: inline hooks object (skipped), absolute-URL logo (skipped), glob with valid/invalid prefix, and ../ path traversal (rejected).

Note

Low Risk
CI-only validator and workflow path filter; no runtime, auth, or marketplace data changes.

Overview
Plugin validation now checks that component paths in plugin.json actually exist under the plugin directory, so typos (e.g. skils/ or a renamed hooks file) fail CI instead of silently failing to load in Cursor.

Checks cover skills, agents, commands, rules, hooks, mcpServers, and logo. Inline objects and absolute-URL logos are skipped. Globs are validated on their static directory prefix; absolute paths and .. escapes are rejected.

Also includes scripts/** in the validate-plugins workflow path filter so validator-only PRs still run the job.

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

validate-plugins.mjs only checks plugin.json against the JSON schema and
that the marketplace name matches. A typo'd component path (skills/agents/
commands/rules/hooks/mcpServers/logo) passes schema validation and CI but
silently fails to load in Cursor. Add an existence check for every path
declared in plugin.json, resolved relative to the plugin directory, with
inline hooks/mcpServers objects and absolute-URL logos skipped.

Also add scripts/** to the validate-plugins workflow paths filter so a PR
that only changes the validator itself triggers the job that runs it.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.

Fix All in Cursor

Bugbot Autofix is ON, but it could not run because the branch was deleted or merged before autofix could start.

Reviewed by Cursor Bugbot for commit 7b25915. Configure here.

// a typo in the base directory is still caught.
function checkReferencedPath(pluginName, pluginDir, field, declared) {
if (typeof declared !== "string" || declared.trim().length === 0) return;
if (isAbsoluteUrl(declared)) return;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

URL skip not logo-only

Medium Severity · Logic Bug

checkReferencedPath returns early for any http(s): or data: value on every component field. The schema only allows absolute URLs for logo; for skills, agents, commands, rules, hooks, and mcpServers those strings are local paths. Remote-looking values therefore skip the existence check and can pass CI while Cursor still fails to load them.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 7b25915. Configure here.

// Cursor. Glob patterns are checked against their static directory prefix so
// a typo in the base directory is still caught.
function checkReferencedPath(pluginName, pluginDir, field, declared) {
if (typeof declared !== "string" || declared.trim().length === 0) return;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Empty paths skip checks

Low Severity · Logic Bug

When a declared component path is empty or only whitespace, checkReferencedPath returns without calling fail. An explicit empty skills/hooks/similar value therefore passes validation even though it is not a usable relative path and will not load in Cursor.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 7b25915. Configure here.

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.

1 participant