mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-08-11 21:12:11 +00:00
Fixed deleting assistant plugins which the Assistant Builder did not create
This commit is contained in:
parent
eeb890f8f1
commit
b45f55cfe1
@ -109,6 +109,34 @@ public static partial class PluginFactory
|
|||||||
/// <returns>True when the directory is nested in the plugins directory.</returns>
|
/// <returns>True when the directory is nested in the plugins directory.</returns>
|
||||||
public static bool IsInsidePluginsRoot(string? pluginPath) => IsPathInside(PLUGINS_ROOT, pluginPath);
|
public static bool IsInsidePluginsRoot(string? pluginPath) => IsPathInside(PLUGINS_ROOT, pluginPath);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks whether a plugin directory is the plugins directory itself.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// A `plugin.lua` placed directly in the plugins directory makes that directory the plugin
|
||||||
|
/// directory. Removing or replacing such a plugin means touching its directory, which would take
|
||||||
|
/// every other plugin with it.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="pluginPath">The directory of the plugin.</param>
|
||||||
|
/// <returns>True when the directory is the plugins directory.</returns>
|
||||||
|
public static bool IsPluginsRoot(string? pluginPath)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(pluginPath) || string.IsNullOrWhiteSpace(PLUGINS_ROOT))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var root = Path.GetFullPath(PLUGINS_ROOT).TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
|
||||||
|
var pluginDirectory = Path.GetFullPath(pluginPath).TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
|
||||||
|
return string.Equals(root, pluginDirectory, StringComparison.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
LOG.LogWarning(e, $"Was not able to check whether the plugin directory '{pluginPath}' is the plugins directory. Treating it as the plugins directory.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static bool IsPathInside(string rootDirectory, string? pluginPath)
|
private static bool IsPathInside(string rootDirectory, string? pluginPath)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(pluginPath) || string.IsNullOrWhiteSpace(rootDirectory))
|
if (string.IsNullOrWhiteSpace(pluginPath) || string.IsNullOrWhiteSpace(rootDirectory))
|
||||||
|
|||||||
@ -9,16 +9,16 @@ namespace AIStudio.Tools.Services;
|
|||||||
public sealed partial class PluginInstallService
|
public sealed partial class PluginInstallService
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks whether a local plugin is an Assistant Builder generated assistant that users may delete.
|
/// Checks whether an assistant plugin is one that users may delete.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static bool CanDeleteInstalledAssistant(IAvailablePlugin plugin) => string.IsNullOrWhiteSpace(GetAssistantDeletionEligibilityIssue(plugin));
|
public static bool CanDeleteInstalledAssistant(IAvailablePlugin plugin) => string.IsNullOrWhiteSpace(GetAssistantDeletionEligibilityIssue(plugin));
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The plugin types users may remove through the user interface, besides their own assistants.
|
/// The plugin types users may remove through the user interface, besides assistants.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Assistants have their own path, because only those generated by the Assistant Builder may be
|
/// Assistants have their own path, because a running assistant must not be pulled away from
|
||||||
/// deleted and because a running assistant must not be pulled away from under a user.
|
/// under a user and because removing one also removes its security audit.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
private static readonly PluginType[] DELETABLE_LOCAL_PLUGIN_TYPES = [PluginType.CONFIGURATION, PluginType.LANGUAGE];
|
private static readonly PluginType[] DELETABLE_LOCAL_PLUGIN_TYPES = [PluginType.CONFIGURATION, PluginType.LANGUAGE];
|
||||||
|
|
||||||
@ -229,27 +229,22 @@ public sealed partial class PluginInstallService
|
|||||||
if (plugin.IsInternal)
|
if (plugin.IsInternal)
|
||||||
return TB("Internal assistant plugins cannot be deleted.");
|
return TB("Internal assistant plugins cannot be deleted.");
|
||||||
|
|
||||||
if (plugin.IsManagedByConfigServer)
|
|
||||||
return TB("Config Server managed assistant plugins cannot be deleted.");
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(plugin.LocalPath))
|
if (string.IsNullOrWhiteSpace(plugin.LocalPath))
|
||||||
return TB("The assistant plugin has no local directory.");
|
return TB("The assistant plugin has no local directory.");
|
||||||
|
|
||||||
var assistantPlugin = PluginFactory.RunningPlugins
|
//
|
||||||
.OfType<PluginAssistants>()
|
// Like for every other plugin type, the plugin path decides, not what the plugin declares
|
||||||
.FirstOrDefault(candidate => candidate.Id == plugin.Id && IsSameDirectory(candidate.PluginPath, plugin.LocalPath));
|
// about itself. Neither DEPLOYED_USING_CONFIG_SERVER nor the Assistant Builder metadata is
|
||||||
|
// suitable here: a locally placed assistant could declare itself as deployed by an
|
||||||
if (assistantPlugin is null || assistantPlugin.IsInternal || !assistantPlugin.IsAssistantBuilderGenerated)
|
// organization, or simply omit the builder metadata, and would then be impossible to remove
|
||||||
return TB("Only assistants generated by the Assistant Builder can be deleted.");
|
// through the user interface. Editing, revising, and sharing an assistant already follow the
|
||||||
|
// path, so deleting one must not be the single action that trusts the plugin's own claims.
|
||||||
if (assistantPlugin.IsManagedByConfigServer)
|
//
|
||||||
|
if (PluginFactory.IsEnterpriseConfigurationPath(plugin.LocalPath))
|
||||||
return TB("Config Server managed assistant plugins cannot be deleted.");
|
return TB("Config Server managed assistant plugins cannot be deleted.");
|
||||||
|
|
||||||
if (!TryGetPluginRoot(PluginType.ASSISTANT, out var assistantPluginsRoot, out var rootIssue))
|
if (!PluginFactory.IsInsidePluginsRoot(plugin.LocalPath) || PluginFactory.IsPluginsRoot(plugin.LocalPath))
|
||||||
return rootIssue;
|
return TB("The assistant plugin directory is outside the plugins directory.");
|
||||||
|
|
||||||
if (!IsPathInsideDirectory(assistantPluginsRoot, plugin.LocalPath) || IsSameDirectory(assistantPluginsRoot, plugin.LocalPath))
|
|
||||||
return TB("The assistant plugin directory is outside the local assistant plugin directory.");
|
|
||||||
|
|
||||||
return Directory.Exists(plugin.LocalPath)
|
return Directory.Exists(plugin.LocalPath)
|
||||||
? string.Empty
|
? string.Empty
|
||||||
@ -276,7 +271,7 @@ public sealed partial class PluginInstallService
|
|||||||
if (PluginFactory.IsEnterpriseConfigurationPath(plugin.LocalPath))
|
if (PluginFactory.IsEnterpriseConfigurationPath(plugin.LocalPath))
|
||||||
return TB("Plugins deployed by your organization cannot be deleted.");
|
return TB("Plugins deployed by your organization cannot be deleted.");
|
||||||
|
|
||||||
if (!PluginFactory.IsInsidePluginsRoot(plugin.LocalPath))
|
if (!PluginFactory.IsInsidePluginsRoot(plugin.LocalPath) || PluginFactory.IsPluginsRoot(plugin.LocalPath))
|
||||||
return TB("The plugin directory is outside the plugins directory.");
|
return TB("The plugin directory is outside the plugins directory.");
|
||||||
|
|
||||||
return Directory.Exists(plugin.LocalPath)
|
return Directory.Exists(plugin.LocalPath)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user