From 3dc85d4ffe5f5ea3f12a45cf2ac7cd768bf4310e Mon Sep 17 00:00:00 2001
From: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com>
Date: Wed, 4 Nov 2026 19:55:50 +0800
Subject: [PATCH] fix(plugins): list the marketplace and install plugins from
the welcome screen
The Plugins page on the welcome screen showed "[object Object]" and "There
is no online plugin repository" (even with a marketplace configured), and
Install did nothing.
- Marketplace and package commands (index, download, unpack, install
preview, theme import) only touch the IDE's own state and are allowed
without a trusted project.
- Installing, uninstalling, enabling and granting plugins are allowed
where no project is open; an untrusted project still blocks them.
- Errors rejected as plain backend error objects show their message, and
a marketplace that couldn't be read shows the error instead of the
"no online repository" note.
---
crates/ide-host/src/trust.rs | 30 ++++++++++++++++++-
crates/ide-host/tests/trust.rs | 13 ++++++--
src/features/plugins/PluginsPage.tsx | 2 +-
.../plugins/__tests__/plugins.test.tsx | 15 ++++++++++
src/features/plugins/store.ts | 8 ++++-
5 files changed, 63 insertions(+), 5 deletions(-)
diff --git a/crates/ide-host/src/trust.rs b/crates/ide-host/src/trust.rs
index ea9b9604..0e828db4 100644
--- a/crates/ide-host/src/trust.rs
+++ b/crates/ide-host/src/trust.rs
@@ -274,6 +274,15 @@ pub fn restricted_command_allowed(cmd: &str) -> bool {
| "plugin_set_theme_frame"
| "plugin_catalog"
| "plugin_assets"
+ | "plugin_market"
+ | "plugin_market_url"
+ | "plugin_set_market_url"
+ | "plugin_market_download"
+ | "plugin_unpack_package"
+ | "plugin_stage_package"
+ | "plugin_preview_install"
+ | "plugin_read_intellij_theme"
+ | "plugin_installed_intellij_themes"
| "notebook_open"
| "notebook_get"
| "notebook_edit"
@@ -319,12 +328,31 @@ pub fn restricted_command_allowed(cmd: &str) -> bool {
) || cmd.starts_with("plugin:")
}
+/// Commands that change which plugin code runs: allowed where no project is open (the
+/// welcome screen), otherwise only in a trusted project.
+pub fn projectless_command_allowed(cmd: &str) -> bool {
+ matches!(
+ cmd,
+ "plugin_install_dir"
+ | "plugin_uninstall"
+ | "plugin_set_enabled"
+ | "plugin_grant"
+ | "plugin_set_capability"
+ | "plugin_roll_back"
+ | "plugin_reload"
+ )
+}
+
impl crate::Host {
pub fn authorize_command(&self, window: &str, command: &str) -> IdeResult<()> {
if restricted_command_allowed(command) {
return Ok(());
}
- self.project(window)?.require_trust()
+ match self.project(window) {
+ Ok(project) => project.require_trust(),
+ Err(_) if projectless_command_allowed(command) => Ok(()),
+ Err(error) => Err(error),
+ }
}
}
diff --git a/crates/ide-host/tests/trust.rs b/crates/ide-host/tests/trust.rs
index eb2868ad..a5ec8d05 100644
--- a/crates/ide-host/tests/trust.rs
+++ b/crates/ide-host/tests/trust.rs
@@ -58,6 +58,11 @@ async fn application_commands_work_in_restricted_projects_and_without_a_project(
"vcs_write_patch",
"remote_bootstrap_list",
"deploy_test_connection",
+ "plugin_market",
+ "plugin_market_url",
+ "plugin_set_market_url",
+ "plugin_market_download",
+ "plugin_preview_install",
] {
assert!(ide_host::trust::restricted_command_allowed(command), "{command}");
for window in ["main", "welcome"] {
@@ -72,8 +77,6 @@ async fn application_commands_work_in_restricted_projects_and_without_a_project(
"tools_list",
"tools_install",
"tools_uninstall",
- "plugin_install_dir",
- "plugin_reload",
"vcs_git_version",
"docker_compose_op",
"db_execute",
@@ -93,6 +96,12 @@ async fn application_commands_work_in_restricted_projects_and_without_a_project(
assert!(host.authorize_command(window, command).is_err(), "{window}: {command}");
}
}
+ // Plugin installs run plugin code: from the welcome screen, but not in an untrusted project.
+ for command in ["plugin_install_dir", "plugin_uninstall", "plugin_set_enabled", "plugin_reload"] {
+ assert!(!ide_host::trust::restricted_command_allowed(command), "{command}");
+ assert!(host.authorize_command("main", command).is_err(), "{command}");
+ assert!(host.authorize_command("welcome", command).is_ok(), "{command}");
+ }
// These requests validate the vendor before any network access, independently of project trust.
for window in ["main", "welcome"] {
let error = ide_host::ops::tools::jdk_download_releases(
diff --git a/src/features/plugins/PluginsPage.tsx b/src/features/plugins/PluginsPage.tsx
index 3f8da6c6..f2dac512 100644
--- a/src/features/plugins/PluginsPage.tsx
+++ b/src/features/plugins/PluginsPage.tsx
@@ -924,7 +924,7 @@ export function PluginsPage() {