Skip to content

(fix: plugin-manager): Restrict plugin installation to repos containing plugin.json at root level - #87

Open
jphinspace wants to merge 1 commit into
got-feedBack:mainfrom
jphinspace:install
Open

(fix: plugin-manager): Restrict plugin installation to repos containing plugin.json at root level#87
jphinspace wants to merge 1 commit into
got-feedBack:mainfrom
jphinspace:install

Conversation

@jphinspace

@jphinspace jphinspace commented Jul 9, 2026

Copy link
Copy Markdown

The existing behavior clones pretty much any repository link passed in, whether or not it has anything to do with feedBack. This change is to add a check that plugin.json exists in the repo before downloading any file contents. It also now aborts the installation if plugin.json is not present (previously it just logged a warning message).

Summary by CodeRabbit

  • Bug Fixes
    • Plugin installation now fails early with a clear message when a plugin package is missing required metadata.
    • Prevents incomplete plugin folders from being left behind after an unsuccessful install.
    • Improves reliability of plugin setup by verifying the package before finishing installation.

@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The installPlugin flow in plugin-manager.ts was changed to use a partial, checkout-less git clone followed by a git ls-tree check for plugin.json at the repo root. If missing, the target directory is removed and installation fails; if present, a git checkout retrieves the working tree.

Changes

Plugin Install Verification

Layer / File(s) Summary
Partial clone and plugin.json verification
src/main/plugin-manager.ts
installPlugin now clones with --depth 1 --filter=blob:none --no-checkout, checks for plugin.json via git ls-tree, deletes the directory and aborts if missing, and runs git checkout if present, replacing the prior full-clone-with-warning approach.

Estimated code review effort: 2 (Simple) | ~10 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: plugin installs are now limited to repositories with a root-level plugin.json.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/main/plugin-manager.ts (1)

146-150: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

ls-tree name match doesn't confirm plugin.json is a file.

git ls-tree --name-only HEAD -- plugin.json matches any tree entry with that name, including a directory. A repo with a plugin.json/ folder at root would pass this gate despite having no actual manifest, defeating the intent of this fix. Prefer checking the entry type/mode explicitly.

🔍 Proposed fix using full ls-tree output to verify blob type
-            const out = await execFileAsync('git', ['ls-tree', '--name-only', 'HEAD', '--', 'plugin.json'], targetDir);
-            hasManifest = out.trim() === 'plugin.json';
+            const out = await execFileAsync('git', ['ls-tree', 'HEAD', '--', 'plugin.json'], targetDir);
+            // Format: "<mode> blob <sha>\tplugin.json" — require a regular file (100644/100755).
+            const match = out.trim().match(/^(\d+)\s+blob\s+\S+\s+plugin\.json$/);
+            hasManifest = !!match && (match[1] === '100644' || match[1] === '100755');
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/plugin-manager.ts` around lines 146 - 150, The manifest check in
plugin-manager’s hasManifest logic only matches the name returned by git
ls-tree, so it can incorrectly accept a plugin.json directory; update the git
lookup in that block to verify the entry is a blob/file type explicitly rather
than comparing only the name. Keep the existing try/catch flow, but parse the
ls-tree result in a way that distinguishes files from tree entries so
hasManifest is true only for an actual plugin.json file.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/main/plugin-manager.ts`:
- Around line 152-155: The missing-plugin.json branch in `plugin-manager.ts` is
letting `fs.rmSync` throw and override the intended install failure message.
Update the `hasManifest` check in the plugin install flow so cleanup of
`targetDir` is best-effort and cannot replace the `"has no plugin.json"` result;
handle any removal error locally and still return the existing `{ success:
false, message: ... }` from the manifest validation path. Use the `hasManifest`
block and the outer install/catch flow in `plugin-manager.ts` to preserve the
original failure reason.

---

Nitpick comments:
In `@src/main/plugin-manager.ts`:
- Around line 146-150: The manifest check in plugin-manager’s hasManifest logic
only matches the name returned by git ls-tree, so it can incorrectly accept a
plugin.json directory; update the git lookup in that block to verify the entry
is a blob/file type explicitly rather than comparing only the name. Keep the
existing try/catch flow, but parse the ls-tree result in a way that
distinguishes files from tree entries so hasManifest is true only for an actual
plugin.json file.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 55e002bb-ec1a-4185-a3e2-0cfc8b5c452c

📥 Commits

Reviewing files that changed from the base of the PR and between 3e3f1f8 and 8f7275d.

📒 Files selected for processing (1)
  • src/main/plugin-manager.ts

Comment on lines +152 to 155
if (!hasManifest) {
fs.rmSync(targetDir, { recursive: true });
return { success: false, message: `"${name}" has no plugin.json at its root — not a valid plugin. Install aborted.` };
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Unguarded rmSync can mask the real "missing plugin.json" failure.

If this cleanup fs.rmSync throws (e.g. transient lock/permission error), the exception propagates to the outer catch (Line 162-166), and the user sees "Failed to clone: <rmSync error>" instead of the accurate "has no plugin.json" message from Line 154.

🔧 Proposed fix to preserve the correct failure message
         if (!hasManifest) {
-            fs.rmSync(targetDir, { recursive: true });
+            try { fs.rmSync(targetDir, { recursive: true, force: true }); } catch { /* best-effort cleanup */ }
             return { success: false, message: `"${name}" has no plugin.json at its root — not a valid plugin. Install aborted.` };
         }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (!hasManifest) {
fs.rmSync(targetDir, { recursive: true });
return { success: false, message: `"${name}" has no plugin.json at its root — not a valid plugin. Install aborted.` };
}
if (!hasManifest) {
try { fs.rmSync(targetDir, { recursive: true, force: true }); } catch { /* best-effort cleanup */ }
return { success: false, message: `"${name}" has no plugin.json at its root — not a valid plugin. Install aborted.` };
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/plugin-manager.ts` around lines 152 - 155, The missing-plugin.json
branch in `plugin-manager.ts` is letting `fs.rmSync` throw and override the
intended install failure message. Update the `hasManifest` check in the plugin
install flow so cleanup of `targetDir` is best-effort and cannot replace the
`"has no plugin.json"` result; handle any removal error locally and still return
the existing `{ success: false, message: ... }` from the manifest validation
path. Use the `hasManifest` block and the outer install/catch flow in
`plugin-manager.ts` to preserve the original failure reason.

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