From 3f2d76337afcf86da472d5fec67d1e2d9153f2be Mon Sep 17 00:00:00 2001 From: nilsk Date: Tue, 31 Mar 2026 15:37:01 +0200 Subject: [PATCH] integrating the security rules and badge to the plugin overview page --- app/MindWork AI Studio/Pages/Plugins.razor | 15 +++- app/MindWork AI Studio/Pages/Plugins.razor.cs | 86 ++++++++++++++----- 2 files changed, 75 insertions(+), 26 deletions(-) diff --git a/app/MindWork AI Studio/Pages/Plugins.razor b/app/MindWork AI Studio/Pages/Plugins.razor index c1012744..26167b11 100644 --- a/app/MindWork AI Studio/Pages/Plugins.razor +++ b/app/MindWork AI Studio/Pages/Plugins.razor @@ -1,4 +1,5 @@ @using AIStudio.Tools.PluginSystem +@using AIStudio.Tools.PluginSystem.Assistants @inherits MSGComponentBase @attribute [Route(Routes.PLUGINS)] @@ -64,19 +65,25 @@ + @if (context.Type is PluginType.ASSISTANT) + { + var assistantPlugin = PluginFactory.RunningPlugins.OfType().FirstOrDefault(x => x.Id == context.Id); + + } @if (context is { IsInternal: false, Type: not PluginType.CONFIGURATION }) { var isEnabled = this.SettingsManager.IsPluginEnabled(context); - - + var activationSwitchDisabled = this.IsActivationSwitchDisabled(context, isEnabled); + + } - + @if (context is { IsInternal: false } && !string.IsNullOrWhiteSpace(context.SourceURL)) { var sourceUrl = context.SourceURL; var isSendingMail = IsSendingMail(sourceUrl); - if(isSendingMail) + if (isSendingMail) { diff --git a/app/MindWork AI Studio/Pages/Plugins.razor.cs b/app/MindWork AI Studio/Pages/Plugins.razor.cs index b0e9b9d7..ec2aee00 100644 --- a/app/MindWork AI Studio/Pages/Plugins.razor.cs +++ b/app/MindWork AI Studio/Pages/Plugins.razor.cs @@ -59,7 +59,7 @@ public partial class Plugins : MSGComponentBase return; } - if (pluginMeta.Type is not PluginType.ASSISTANT || !this.AssistantPluginAuditSettings.RequireAuditBeforeActivation) + if (pluginMeta.Type is not PluginType.ASSISTANT) { this.SettingsManager.ConfigurationData.EnabledPlugins.Add(pluginMeta.Id); await this.SettingsManager.StoreSettings(); @@ -71,31 +71,37 @@ public partial class Plugins : MSGComponentBase if (assistantPlugin is null) return; - var pluginHash = assistantPlugin.ComputeAuditHash(); - var cachedAudit = this.SettingsManager.ConfigurationData.AssistantPluginAudits.FirstOrDefault(x => x.PluginId == pluginMeta.Id); - if (cachedAudit is not null && cachedAudit.PluginHash == pluginHash) + var securityState = PluginAssistantSecurityResolver.Resolve(this.SettingsManager, assistantPlugin); + if (securityState.RequiresAudit) { - if (cachedAudit.Level < this.AssistantPluginAuditSettings.MinimumLevel && this.AssistantPluginAuditSettings.BlockActivationBelowMinimum) - { - await this.DialogService.ShowMessageBox(this.T("Assistant Audit"), $"{cachedAudit.Level.GetName()}: {cachedAudit.Summary}", this.T("Close")); - return; - } - - if (cachedAudit.Level < this.AssistantPluginAuditSettings.MinimumLevel && - !await this.ConfirmActivationBelowMinimumAsync(pluginMeta.Name, cachedAudit.Level)) - { - return; - } - - this.SettingsManager.ConfigurationData.EnabledPlugins.Add(pluginMeta.Id); - await this.SettingsManager.StoreSettings(); - await this.MessageBus.SendMessage(this, Event.CONFIGURATION_CHANGED); + await this.OpenAssistantAuditDialogAsync(pluginMeta.Id); return; } + if (securityState.IsBelowMinimum && securityState.IsBlocked) + { + var blockedAudit = securityState.Audit; + if (blockedAudit is not null) + await this.DialogService.ShowMessageBox(this.T("Assistant Audit"), $"{blockedAudit.Level.GetName()}: {blockedAudit.Summary}", this.T("Close")); + return; + } + + if (securityState.IsBelowMinimum && securityState.CanOverride && + !await this.ConfirmActivationBelowMinimumAsync(pluginMeta.Name, securityState.Audit!.Level)) + { + return; + } + + this.SettingsManager.ConfigurationData.EnabledPlugins.Add(pluginMeta.Id); + await this.SettingsManager.StoreSettings(); + await this.MessageBus.SendMessage(this, Event.CONFIGURATION_CHANGED); + } + + private async Task OpenAssistantAuditDialogAsync(Guid pluginId) + { var parameters = new DialogParameters { - { x => x.PluginId, pluginMeta.Id }, + { x => x.PluginId, pluginId }, }; var dialog = await this.DialogService.ShowAsync(this.T("Assistant Audit"), parameters, DialogOptions.FULLSCREEN); var result = await dialog.Result; @@ -106,7 +112,7 @@ public partial class Plugins : MSGComponentBase this.UpsertAuditCard(auditResult.Audit); if (auditResult.ActivatePlugin) - this.SettingsManager.ConfigurationData.EnabledPlugins.Add(pluginMeta.Id); + this.SettingsManager.ConfigurationData.EnabledPlugins.Add(pluginId); await this.SettingsManager.StoreSettings(); await this.MessageBus.SendMessage(this, Event.CONFIGURATION_CHANGED); @@ -132,8 +138,44 @@ public partial class Plugins : MSGComponentBase return dialogResult is not null && !dialogResult.Canceled; } + private bool IsActivationSwitchDisabled(IPluginMetadata pluginMeta, bool isEnabled) + { + if (isEnabled || pluginMeta.Type is not PluginType.ASSISTANT) + return false; + + var assistantPlugin = this.TryGetAssistantPlugin(pluginMeta.Id); + if (assistantPlugin is null) + return false; + + var securityState = PluginAssistantSecurityResolver.Resolve(this.SettingsManager, assistantPlugin); + return securityState.IsBlocked && !securityState.RequiresAudit; + } + + private string GetActivationTooltip(IPluginMetadata pluginMeta, bool isEnabled) + { + if (isEnabled) + return this.T("Disable plugin"); + + if (pluginMeta.Type is not PluginType.ASSISTANT) + return this.T("Enable plugin"); + + var assistantPlugin = this.TryGetAssistantPlugin(pluginMeta.Id); + if (assistantPlugin is null) + return this.T("Enable plugin"); + + var securityState = PluginAssistantSecurityResolver.Resolve(this.SettingsManager, assistantPlugin); + if (securityState.RequiresAudit) + return securityState.ActionLabel; + + return securityState.IsBlocked + ? securityState.Description + : this.T("Enable plugin"); + } + private static bool IsSendingMail(string sourceUrl) => sourceUrl.TrimStart().StartsWith("mailto:", StringComparison.OrdinalIgnoreCase); + private PluginAssistants? TryGetAssistantPlugin(Guid pluginId) => PluginFactory.RunningPlugins.OfType().FirstOrDefault(x => x.Id == pluginId); + private void UpsertAuditCard(PluginAssistantAudit audit) { var audits = this.SettingsManager.ConfigurationData.AssistantPluginAudits; @@ -150,7 +192,7 @@ public partial class Plugins : MSGComponentBase { switch (triggeredEvent) { - case Event.PLUGINS_RELOADED: + case Event.PLUGINS_RELOADED or Event.CONFIGURATION_CHANGED: await this.InvokeAsync(this.StateHasChanged); break; }