mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-05-19 19:32:15 +00:00
making the audit fully automatic
This commit is contained in:
parent
054481abcf
commit
820c9e2596
@ -1,4 +1,5 @@
|
|||||||
using AIStudio.Components;
|
using AIStudio.Components;
|
||||||
|
using AIStudio.Agents.AssistantAudit;
|
||||||
using AIStudio.Tools.PluginSystem;
|
using AIStudio.Tools.PluginSystem;
|
||||||
using AIStudio.Tools.PluginSystem.Assistants;
|
using AIStudio.Tools.PluginSystem.Assistants;
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
@ -7,22 +8,85 @@ namespace AIStudio.Pages;
|
|||||||
|
|
||||||
public partial class Assistants : MSGComponentBase
|
public partial class Assistants : MSGComponentBase
|
||||||
{
|
{
|
||||||
|
private bool isAutoAuditing;
|
||||||
|
|
||||||
|
[Inject]
|
||||||
|
private AssistantPluginAuditService AssistantPluginAuditService { get; init; } = null!;
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
this.ApplyFilters([], [ Event.CONFIGURATION_CHANGED, Event.PLUGINS_RELOADED ]);
|
this.ApplyFilters([], [ Event.CONFIGURATION_CHANGED, Event.PLUGINS_RELOADED ]);
|
||||||
await base.OnInitializedAsync();
|
await base.OnInitializedAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||||
|
{
|
||||||
|
if (firstRender)
|
||||||
|
await this.TryAutoAuditAssistantsAsync();
|
||||||
|
}
|
||||||
|
|
||||||
private IReadOnlyCollection<PluginAssistants> AssistantPlugins =>
|
private IReadOnlyCollection<PluginAssistants> AssistantPlugins =>
|
||||||
PluginFactory.RunningPlugins.OfType<PluginAssistants>()
|
PluginFactory.RunningPlugins.OfType<PluginAssistants>()
|
||||||
.Where(plugin => this.SettingsManager.IsPluginEnabled(plugin))
|
.Where(plugin => this.SettingsManager.IsPluginEnabled(plugin))
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
protected override Task ProcessIncomingMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data) where T : default
|
private async Task TryAutoAuditAssistantsAsync()
|
||||||
{
|
{
|
||||||
if (triggeredEvent is Event.CONFIGURATION_CHANGED or Event.PLUGINS_RELOADED)
|
if (this.isAutoAuditing || !this.SettingsManager.ConfigurationData.AssistantPluginAudit.AutomaticallyAuditAssistants)
|
||||||
return this.InvokeAsync(this.StateHasChanged);
|
return;
|
||||||
|
|
||||||
return Task.CompletedTask;
|
this.isAutoAuditing = true;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var wasConfigurationChanged = false;
|
||||||
|
var assistantPlugins = PluginFactory.RunningPlugins.OfType<PluginAssistants>().ToList();
|
||||||
|
foreach (var assistantPlugin in assistantPlugins)
|
||||||
|
{
|
||||||
|
var securityState = PluginAssistantSecurityResolver.Resolve(this.SettingsManager, assistantPlugin);
|
||||||
|
if (!securityState.RequiresAudit)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var audit = await this.AssistantPluginAuditService.RunAuditAsync(assistantPlugin);
|
||||||
|
if (audit.Level is AssistantAuditLevel.UNKNOWN)
|
||||||
|
{
|
||||||
|
await MessageBus.INSTANCE.SendError(new (Icons.Material.Filled.SettingsSuggest, string.Format(this.T("The automatic security audit for the assistant plugin '{0}' failed. Please run it manually from the plugins page."), assistantPlugin.Name)));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.UpsertAuditCard(audit);
|
||||||
|
wasConfigurationChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!wasConfigurationChanged)
|
||||||
|
return;
|
||||||
|
|
||||||
|
await this.SettingsManager.StoreSettings();
|
||||||
|
await this.MessageBus.SendMessage<bool>(this, Event.CONFIGURATION_CHANGED);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
this.isAutoAuditing = false;
|
||||||
|
await this.InvokeAsync(this.StateHasChanged);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpsertAuditCard(PluginAssistantAudit audit)
|
||||||
|
{
|
||||||
|
var audits = this.SettingsManager.ConfigurationData.AssistantPluginAudits;
|
||||||
|
var existingIndex = audits.FindIndex(x => x.PluginId == audit.PluginId);
|
||||||
|
if (existingIndex >= 0)
|
||||||
|
audits[existingIndex] = audit;
|
||||||
|
else
|
||||||
|
audits.Add(audit);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task ProcessIncomingMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data) where T : default
|
||||||
|
{
|
||||||
|
if (triggeredEvent is Event.PLUGINS_RELOADED)
|
||||||
|
await this.TryAutoAuditAssistantsAsync();
|
||||||
|
|
||||||
|
if (triggeredEvent is Event.CONFIGURATION_CHANGED or Event.PLUGINS_RELOADED)
|
||||||
|
await this.InvokeAsync(this.StateHasChanged);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,6 +15,7 @@ public partial class Plugins : MSGComponentBase
|
|||||||
private const string GROUP_ENABLED = "Enabled";
|
private const string GROUP_ENABLED = "Enabled";
|
||||||
private const string GROUP_DISABLED = "Disabled";
|
private const string GROUP_DISABLED = "Disabled";
|
||||||
private const string GROUP_INTERNAL = "Internal";
|
private const string GROUP_INTERNAL = "Internal";
|
||||||
|
private bool isAutoAuditing;
|
||||||
|
|
||||||
private DataAssistantPluginAudit AssistantPluginAuditSettings => this.SettingsManager.ConfigurationData.AssistantPluginAudit;
|
private DataAssistantPluginAudit AssistantPluginAuditSettings => this.SettingsManager.ConfigurationData.AssistantPluginAudit;
|
||||||
|
|
||||||
@ -50,6 +51,12 @@ public partial class Plugins : MSGComponentBase
|
|||||||
await base.OnInitializedAsync();
|
await base.OnInitializedAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||||
|
{
|
||||||
|
if (firstRender)
|
||||||
|
await this.TryAutoAuditAssistantsAsync();
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
private async Task PluginActivationStateChanged(IPluginMetadata pluginMeta)
|
private async Task PluginActivationStateChanged(IPluginMetadata pluginMeta)
|
||||||
@ -75,31 +82,6 @@ public partial class Plugins : MSGComponentBase
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var securityState = PluginAssistantSecurityResolver.Resolve(this.SettingsManager, assistantPlugin);
|
var securityState = PluginAssistantSecurityResolver.Resolve(this.SettingsManager, assistantPlugin);
|
||||||
if (securityState.RequiresAudit)
|
|
||||||
{
|
|
||||||
if (this.AssistantPluginAuditSettings.AutomaticallyAuditAssistants)
|
|
||||||
{
|
|
||||||
var audit = await this.AssistantPluginAuditService.RunAuditAsync(assistantPlugin);
|
|
||||||
if (audit.Level is AssistantAuditLevel.UNKNOWN)
|
|
||||||
{
|
|
||||||
await MessageBus.INSTANCE.SendError(new (Icons.Material.Filled.SettingsSuggest, string.Format(T("The Security Audit returned an invalid result, please try again manually."))));
|
|
||||||
await this.OpenAssistantAuditDialogAsync(pluginMeta.Id);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.UpsertAuditCard(audit);
|
|
||||||
await this.SettingsManager.StoreSettings();
|
|
||||||
await this.MessageBus.SendMessage<bool>(this, Event.CONFIGURATION_CHANGED);
|
|
||||||
|
|
||||||
securityState = PluginAssistantSecurityResolver.Resolve(this.SettingsManager, assistantPlugin);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await this.OpenAssistantAuditDialogAsync(pluginMeta.Id);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (securityState.RequiresAudit)
|
if (securityState.RequiresAudit)
|
||||||
{
|
{
|
||||||
await this.OpenAssistantAuditDialogAsync(pluginMeta.Id);
|
await this.OpenAssistantAuditDialogAsync(pluginMeta.Id);
|
||||||
@ -204,6 +186,47 @@ public partial class Plugins : MSGComponentBase
|
|||||||
|
|
||||||
private PluginAssistants? TryGetAssistantPlugin(Guid pluginId) => PluginFactory.RunningPlugins.OfType<PluginAssistants>().FirstOrDefault(x => x.Id == pluginId);
|
private PluginAssistants? TryGetAssistantPlugin(Guid pluginId) => PluginFactory.RunningPlugins.OfType<PluginAssistants>().FirstOrDefault(x => x.Id == pluginId);
|
||||||
|
|
||||||
|
private async Task TryAutoAuditAssistantsAsync()
|
||||||
|
{
|
||||||
|
if (this.isAutoAuditing || !this.AssistantPluginAuditSettings.AutomaticallyAuditAssistants)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.isAutoAuditing = true;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var wasConfigurationChanged = false;
|
||||||
|
var assistantPlugins = PluginFactory.RunningPlugins.OfType<PluginAssistants>().ToList();
|
||||||
|
foreach (var assistantPlugin in assistantPlugins)
|
||||||
|
{
|
||||||
|
var securityState = PluginAssistantSecurityResolver.Resolve(this.SettingsManager, assistantPlugin);
|
||||||
|
if (!securityState.RequiresAudit)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var audit = await this.AssistantPluginAuditService.RunAuditAsync(assistantPlugin);
|
||||||
|
if (audit.Level is AssistantAuditLevel.UNKNOWN)
|
||||||
|
{
|
||||||
|
await MessageBus.INSTANCE.SendError(new (Icons.Material.Filled.SettingsSuggest, string.Format(this.T("The automatic security audit for the assistant plugin '{0}' failed. Please run it manually."), assistantPlugin.Name)));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.UpsertAuditCard(audit);
|
||||||
|
wasConfigurationChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!wasConfigurationChanged)
|
||||||
|
return;
|
||||||
|
|
||||||
|
await this.SettingsManager.StoreSettings();
|
||||||
|
await this.MessageBus.SendMessage<bool>(this, Event.CONFIGURATION_CHANGED);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
this.isAutoAuditing = false;
|
||||||
|
await this.InvokeAsync(this.StateHasChanged);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void UpsertAuditCard(PluginAssistantAudit audit)
|
private void UpsertAuditCard(PluginAssistantAudit audit)
|
||||||
{
|
{
|
||||||
var audits = this.SettingsManager.ConfigurationData.AssistantPluginAudits;
|
var audits = this.SettingsManager.ConfigurationData.AssistantPluginAudits;
|
||||||
@ -220,7 +243,12 @@ public partial class Plugins : MSGComponentBase
|
|||||||
{
|
{
|
||||||
switch (triggeredEvent)
|
switch (triggeredEvent)
|
||||||
{
|
{
|
||||||
case Event.PLUGINS_RELOADED or Event.CONFIGURATION_CHANGED:
|
case Event.PLUGINS_RELOADED:
|
||||||
|
await this.TryAutoAuditAssistantsAsync();
|
||||||
|
await this.InvokeAsync(this.StateHasChanged);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Event.CONFIGURATION_CHANGED:
|
||||||
await this.InvokeAsync(this.StateHasChanged);
|
await this.InvokeAsync(this.StateHasChanged);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -181,8 +181,8 @@ public static class PluginAssistantSecurityResolver
|
|||||||
BadgeIcon = GetSecurityBadgeIcon(requiresAudit: false, hasAudit, hasHashMismatch: false, isBlockedByMinimum, canOverride),
|
BadgeIcon = GetSecurityBadgeIcon(requiresAudit: false, hasAudit, hasHashMismatch: false, isBlockedByMinimum, canOverride),
|
||||||
Headline = isBlockedByMinimum ? TB("This assistant is currently locked.") : TB("This assistant can still be used because your settings allow it."),
|
Headline = isBlockedByMinimum ? TB("This assistant is currently locked.") : TB("This assistant can still be used because your settings allow it."),
|
||||||
Description = isBlockedByMinimum
|
Description = isBlockedByMinimum
|
||||||
? string.Format(TB("The current audit result \"{0}\" is below your required minimum level \"{1}\". Your security settings therefore block this assistant plugin."), auditLevel.GetName(), auditSettings.MinimumLevel.GetName())
|
? string.Format(TB("The current audit result '{0}' is below your required minimum level '{1}'. Your security settings therefore block this assistant plugin."), auditLevel.GetName(), auditSettings.MinimumLevel.GetName())
|
||||||
: string.Format(TB("The current audit result is \"{0}\", which is below your required minimum level \"{1}\". Your settings still allow manual activation, but the assistant keeps this security status and should be reviewed carefully."), auditLevel.GetName(), auditSettings.MinimumLevel.GetName()),
|
: string.Format(TB("The current audit result is '{0}', which is below your required minimum level '{1}'. Your settings still allow manual activation, but the assistant keeps this security status and should be reviewed carefully."), auditLevel.GetName(), auditSettings.MinimumLevel.GetName()),
|
||||||
StatusColor = GetAvailabilityColor(requiresAudit: false, hasAudit, hasHashMismatch: false, isBlockedByMinimum, canOverride),
|
StatusColor = GetAvailabilityColor(requiresAudit: false, hasAudit, hasHashMismatch: false, isBlockedByMinimum, canOverride),
|
||||||
StatusIcon = GetAvailabilityIcon(requiresAudit: false, hasAudit, hasHashMismatch: false, isBlockedByMinimum, canOverride),
|
StatusIcon = GetAvailabilityIcon(requiresAudit: false, hasAudit, hasHashMismatch: false, isBlockedByMinimum, canOverride),
|
||||||
ActionLabel = TB("Open Security Check"),
|
ActionLabel = TB("Open Security Check"),
|
||||||
@ -215,7 +215,7 @@ public static class PluginAssistantSecurityResolver
|
|||||||
StatusLabel = GetAvailabilityLabel(requiresAudit: false, hasAudit, hasHashMismatch: false, isBlocked: false, canOverride: false),
|
StatusLabel = GetAvailabilityLabel(requiresAudit: false, hasAudit, hasHashMismatch: false, isBlocked: false, canOverride: false),
|
||||||
BadgeIcon = GetSecurityBadgeIcon(requiresAudit: false, hasAudit, hasHashMismatch: false, isBlocked: false, canOverride: false),
|
BadgeIcon = GetSecurityBadgeIcon(requiresAudit: false, hasAudit, hasHashMismatch: false, isBlocked: false, canOverride: false),
|
||||||
Headline = TB("This assistant is currently unlocked."),
|
Headline = TB("This assistant is currently unlocked."),
|
||||||
Description = string.Format(TB("The stored audit matches the current plugin code and meets your required minimum level \"{0}\"."), auditSettings.MinimumLevel.GetName()),
|
Description = string.Format(TB("The stored audit matches the current plugin code and meets your required minimum level '{0}'."), auditSettings.MinimumLevel.GetName()),
|
||||||
StatusColor = GetAvailabilityColor(requiresAudit: false, hasAudit, hasHashMismatch: false, isBlocked: false, canOverride: false),
|
StatusColor = GetAvailabilityColor(requiresAudit: false, hasAudit, hasHashMismatch: false, isBlocked: false, canOverride: false),
|
||||||
StatusIcon = GetAvailabilityIcon(requiresAudit: false, hasAudit, hasHashMismatch: false, isBlocked: false, canOverride: false),
|
StatusIcon = GetAvailabilityIcon(requiresAudit: false, hasAudit, hasHashMismatch: false, isBlocked: false, canOverride: false),
|
||||||
ActionLabel = TB("Open Security Check"),
|
ActionLabel = TB("Open Security Check"),
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user