mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-10-17 06:38:00 +00:00
Added priorities for configuration plugins and fixed how they collide (#899)
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-pc-windows-msvc.exe, win-x64, windows-latest, x86_64-pc-windows-msvc, nsis,updater, nsis) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-unknown-linux-gnu, linux-x64, ubuntu-22.04, x86_64-unknown-linux-gnu, appimage,updater, appimage) (push) Blocked by required conditions
Build and Release / Prepare & create release (push) Blocked by required conditions
Build and Release / Publish release (push) Blocked by required conditions
Build and Release / Determine run mode (push) Waiting to run
Build and Release / Read metadata (push) Blocked by required conditions
Build and Release / Sync Flatpak repo (push) Blocked by required conditions
Build and Release / Collect Flatpak artifacts (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-apple-darwin, osx-arm64, macos-latest, aarch64-apple-darwin, dmg,app,updater, dmg) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-pc-windows-msvc.exe, win-arm64, windows-latest, aarch64-pc-windows-msvc, nsis,updater, nsis) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-unknown-linux-gnu, linux-arm64, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, appimage,updater, appimage) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-apple-darwin, osx-x64, macos-latest, x86_64-apple-darwin, dmg,app,updater, dmg) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-pc-windows-msvc.exe, win-x64, windows-latest, x86_64-pc-windows-msvc, nsis,updater, nsis) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-unknown-linux-gnu, linux-x64, ubuntu-22.04, x86_64-unknown-linux-gnu, appimage,updater, appimage) (push) Blocked by required conditions
Build and Release / Prepare & create release (push) Blocked by required conditions
Build and Release / Publish release (push) Blocked by required conditions
Build and Release / Determine run mode (push) Waiting to run
Build and Release / Read metadata (push) Blocked by required conditions
Build and Release / Sync Flatpak repo (push) Blocked by required conditions
Build and Release / Collect Flatpak artifacts (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-apple-darwin, osx-arm64, macos-latest, aarch64-apple-darwin, dmg,app,updater, dmg) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-pc-windows-msvc.exe, win-arm64, windows-latest, aarch64-pc-windows-msvc, nsis,updater, nsis) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-unknown-linux-gnu, linux-arm64, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, appimage,updater, appimage) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-apple-darwin, osx-x64, macos-latest, x86_64-apple-darwin, dmg,app,updater, dmg) (push) Blocked by required conditions
This commit is contained in:
1 parent
d1a6781ea6
commit
0eb747b386
17 files changed
+562
-104
No files matched your search
@@ -33,26 +33,29 @@ public record ConfigMeta<TClass, TValue> : ConfigMetaBase
|
||||
public required TValue Default { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The additive value contribution provided by a configuration plugin.
|
||||
/// The additive value contributions, one per contributing configuration plugin.
|
||||
/// </summary>
|
||||
public TValue PluginContribution { get; private set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Stores an additive plugin contribution.
|
||||
/// </summary>
|
||||
public void SetPluginContribution(TValue value, Guid pluginId)
|
||||
{
|
||||
this.PluginContribution = value;
|
||||
this.PluginContributionByConfigPluginId = pluginId;
|
||||
this.HasPluginContribution = true;
|
||||
}
|
||||
/// <remarks>
|
||||
/// Every configuration plugin keeps its own contribution, so removing one of them leaves the
|
||||
/// contributions of the others intact. Callers that need the overall contribution combine the
|
||||
/// values themselves: only they know how to combine the concrete type.
|
||||
/// </remarks>
|
||||
public IReadOnlyDictionary<Guid, TValue> PluginContributions => this.pluginContributions;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void ClearPluginContribution()
|
||||
{
|
||||
this.PluginContribution = default!;
|
||||
base.ClearPluginContribution();
|
||||
}
|
||||
public override IReadOnlyCollection<Guid> ContributingConfigPluginIds => this.pluginContributions.Keys;
|
||||
|
||||
private readonly Dictionary<Guid, TValue> pluginContributions = [];
|
||||
|
||||
/// <summary>
|
||||
/// Stores the additive contribution of one configuration plugin, replacing its previous one.
|
||||
/// </summary>
|
||||
/// <param name="value">The contributed value.</param>
|
||||
/// <param name="pluginId">The contributing configuration plugin.</param>
|
||||
public void SetPluginContribution(TValue value, Guid pluginId) => this.pluginContributions[pluginId] = value;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool RemovePluginContribution(Guid configPluginId) => this.pluginContributions.Remove(configPluginId);
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Reset()
|
||||
|
||||
@@ -38,14 +38,19 @@ public abstract record ConfigMetaBase(string SettingName) : IConfig
|
||||
public Guid EditableDefaultByConfigPluginId { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether a plugin contribution is available.
|
||||
/// The configuration plugins which contribute to this setting.
|
||||
/// </summary>
|
||||
public bool HasPluginContribution { get; protected set; }
|
||||
/// <remarks>
|
||||
/// Contributions are additive, so several configuration plugins may contribute at the same time
|
||||
/// and each of them keeps its own contribution. An organization might enable one preview feature
|
||||
/// for everybody and another one for a single department, for example.
|
||||
/// </remarks>
|
||||
public abstract IReadOnlyCollection<Guid> ContributingConfigPluginIds { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The ID of the plugin that provided the additive value contribution.
|
||||
/// Indicates whether at least one configuration plugin contributes to this setting.
|
||||
/// </summary>
|
||||
public Guid PluginContributionByConfigPluginId { get; protected set; }
|
||||
public bool HasPluginContribution => this.ContributingConfigPluginIds.Count > 0;
|
||||
|
||||
/// <summary>
|
||||
/// Locks the configuration state, indicating that it is controlled by a specific plugin.
|
||||
@@ -133,13 +138,11 @@ public abstract record ConfigMetaBase(string SettingName) : IConfig
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the additive plugin contribution without changing the current value.
|
||||
/// Removes the contribution of one configuration plugin without changing the current value.
|
||||
/// </summary>
|
||||
public virtual void ClearPluginContribution()
|
||||
{
|
||||
this.PluginContributionByConfigPluginId = Guid.Empty;
|
||||
this.HasPluginContribution = false;
|
||||
}
|
||||
/// <param name="configPluginId">The configuration plugin whose contribution is removed.</param>
|
||||
/// <returns>True when that plugin had a contribution, otherwise false.</returns>
|
||||
public abstract bool RemovePluginContribution(Guid configPluginId);
|
||||
|
||||
/// <summary>
|
||||
/// Resets the configuration property to its default value.
|
||||
|
||||
@@ -654,6 +654,11 @@ public static partial class ManagedConfiguration
|
||||
if (dryRun)
|
||||
return successful;
|
||||
|
||||
//
|
||||
// Contributions need no protection against a takeover: every configuration plugin has its
|
||||
// own contribution, so no plugin can replace or drop the contribution of another one. This
|
||||
// is also why a local configuration plugin may contribute next to one of an organization.
|
||||
//
|
||||
if (successful)
|
||||
{
|
||||
var configInstance = configSelection.Compile().Invoke(SettingsManagerAccess.ConfigurationData);
|
||||
@@ -663,10 +668,8 @@ public static partial class ManagedConfiguration
|
||||
configMeta.SetValue(merged);
|
||||
configMeta.SetPluginContribution(new HashSet<TValue>(configuredValue), configPluginId);
|
||||
}
|
||||
else if (configMeta.HasPluginContribution && configMeta.PluginContributionByConfigPluginId == configPluginId)
|
||||
{
|
||||
configMeta.ClearPluginContribution();
|
||||
}
|
||||
else
|
||||
configMeta.RemovePluginContribution(configPluginId);
|
||||
|
||||
if (configMeta.IsLocked && configMeta.LockedByConfigPluginId == configPluginId)
|
||||
configMeta.UnlockConfiguration();
|
||||
@@ -905,6 +908,11 @@ public static partial class ManagedConfiguration
|
||||
if(dryRun)
|
||||
return successful;
|
||||
|
||||
// The setting might belong to the IT department of an organization. In that case, no local
|
||||
// configuration plugin may touch it, no matter what it declares:
|
||||
if (!MayManageSetting(configPluginId, configMeta))
|
||||
return false;
|
||||
|
||||
switch (successful)
|
||||
{
|
||||
case true:
|
||||
@@ -954,6 +962,11 @@ public static partial class ManagedConfiguration
|
||||
if (dryRun)
|
||||
return successful;
|
||||
|
||||
// The setting might belong to the IT department of an organization. In that case, no local
|
||||
// configuration plugin may touch it, no matter what it declares:
|
||||
if (!MayManageSetting(configPluginId, configMeta))
|
||||
return false;
|
||||
|
||||
switch (successful)
|
||||
{
|
||||
case true when managedMode is ManagedConfigurationMode.LOCKED:
|
||||
|
||||
@@ -257,6 +257,51 @@ public static partial class ManagedConfiguration
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether a configuration plugin may manage a setting, or whether that setting belongs
|
||||
/// to the IT department of an organization.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A local configuration plugin must not take over a setting an organization manages. Otherwise,
|
||||
/// anyone could hand out a configuration plugin that quietly replaces parts of the organization
|
||||
/// configuration, e.g. the address of a self-hosted provider.<br/><br/>
|
||||
/// Between two configuration plugins of the same organization, we do not interfere: both belong
|
||||
/// to the IT department, so the one processed later wins, as before.
|
||||
/// </remarks>
|
||||
/// <param name="configPluginId">The configuration plugin which wants to manage the setting.</param>
|
||||
/// <param name="configMeta">The configuration metadata of the setting.</param>
|
||||
/// <returns>True when the plugin may manage this setting, otherwise false.</returns>
|
||||
private static bool MayManageSetting(Guid configPluginId, ConfigMetaBase configMeta)
|
||||
{
|
||||
var owningConfigPluginId = GetSettingOwner(configMeta);
|
||||
if (owningConfigPluginId == Guid.Empty || owningConfigPluginId == configPluginId)
|
||||
return true;
|
||||
|
||||
if (!PluginFactory.IsEnterpriseConfigurationPlugin(owningConfigPluginId))
|
||||
return true;
|
||||
|
||||
if (PluginFactory.IsEnterpriseConfigurationPlugin(configPluginId))
|
||||
return true;
|
||||
|
||||
Log.LogWarning($"The configuration plugin '{configPluginId}' tried to manage the setting '{configMeta.SettingName}', which is managed by the configuration plugin '{owningConfigPluginId}' of your organization. Ignoring the attempt: configurations deployed by your organization's IT take precedence.");
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines the configuration plugin which currently manages a setting, if any.
|
||||
/// </summary>
|
||||
private static Guid GetSettingOwner(ConfigMetaBase configMeta)
|
||||
{
|
||||
if (configMeta.IsLocked && configMeta.LockedByConfigPluginId != Guid.Empty)
|
||||
return configMeta.LockedByConfigPluginId;
|
||||
|
||||
// The editable default is persisted as well, so we prefer it over the in-memory state:
|
||||
if (TryGetEditableDefaultState(configMeta.SettingName, out var editableDefaultState) && editableDefaultState.ConfigPluginId != Guid.Empty)
|
||||
return editableDefaultState.ConfigPluginId;
|
||||
|
||||
return configMeta.EditableDefaultByConfigPluginId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all managed states whose configuration plugin is not available anymore.
|
||||
/// </summary>
|
||||
@@ -269,12 +314,13 @@ public static partial class ManagedConfiguration
|
||||
/// change it at all.
|
||||
/// </remarks>
|
||||
/// <param name="availablePlugins">The collection of available plugins to check against.</param>
|
||||
/// <param name="deployedConfigPluginIds">
|
||||
/// The IDs of all configuration plugins which are deployed on this machine, including those which
|
||||
/// could not be loaded. A deployed plugin was not removed, so its settings must stay untouched.
|
||||
/// <param name="deployedEnterpriseConfigPluginIds">
|
||||
/// The IDs of the configuration plugins which an organization deployed on this machine, including
|
||||
/// those which could not be loaded. A deployed plugin was not removed, so its settings must stay
|
||||
/// untouched.
|
||||
/// </param>
|
||||
/// <returns>True when at least one setting was changed, otherwise false.</returns>
|
||||
public static bool CleanupLeftOverManagedConfigurations(IReadOnlyCollection<IAvailablePlugin> availablePlugins, IReadOnlySet<Guid> deployedConfigPluginIds)
|
||||
public static bool CleanupLeftOverManagedConfigurations(IReadOnlyCollection<IAvailablePlugin> availablePlugins, IReadOnlySet<Guid> deployedEnterpriseConfigPluginIds)
|
||||
{
|
||||
var wasChanged = false;
|
||||
var registeredSettingNames = new HashSet<string>(StringComparer.Ordinal);
|
||||
@@ -293,7 +339,7 @@ public static partial class ManagedConfiguration
|
||||
configMeta.RestoreLockedConfiguration();
|
||||
|
||||
// Check the locked state:
|
||||
if (configMeta.IsLocked && configMeta.LockedByConfigPluginId != Guid.Empty && !IsPluginPresent(configMeta.LockedByConfigPluginId, availablePlugins, deployedConfigPluginIds))
|
||||
if (configMeta.IsLocked && configMeta.LockedByConfigPluginId != Guid.Empty && !IsPluginPresent(configMeta.LockedByConfigPluginId, availablePlugins, deployedEnterpriseConfigPluginIds))
|
||||
{
|
||||
Log.LogInformation($"Resetting the setting '{configMeta.SettingName}': it was locked by the configuration plugin '{configMeta.LockedByConfigPluginId}', which is not available anymore.");
|
||||
configMeta.ResetLockedConfiguration();
|
||||
@@ -301,14 +347,18 @@ public static partial class ManagedConfiguration
|
||||
}
|
||||
|
||||
// Check the editable default state:
|
||||
if (CleanupEditableDefaultState(configMeta, availablePlugins, deployedConfigPluginIds))
|
||||
if (CleanupEditableDefaultState(configMeta, availablePlugins, deployedEnterpriseConfigPluginIds))
|
||||
wasChanged = true;
|
||||
|
||||
// Check the additive plugin contribution:
|
||||
if (configMeta.HasPluginContribution && configMeta.PluginContributionByConfigPluginId != Guid.Empty && !IsPluginPresent(configMeta.PluginContributionByConfigPluginId, availablePlugins, deployedConfigPluginIds))
|
||||
// Check the additive plugin contributions. Every contributing plugin is checked on its
|
||||
// own, so one removed plugin does not take the contributions of the others with it:
|
||||
foreach (var contributingConfigPluginId in configMeta.ContributingConfigPluginIds.ToList())
|
||||
{
|
||||
Log.LogInformation($"Clearing the plugin contribution for the setting '{configMeta.SettingName}': the configuration plugin '{configMeta.PluginContributionByConfigPluginId}' is not available anymore.");
|
||||
configMeta.ClearPluginContribution();
|
||||
if (contributingConfigPluginId != Guid.Empty && IsPluginPresent(contributingConfigPluginId, availablePlugins, deployedEnterpriseConfigPluginIds))
|
||||
continue;
|
||||
|
||||
Log.LogInformation($"Clearing the contribution of the configuration plugin '{contributingConfigPluginId}' to the setting '{configMeta.SettingName}': the plugin is not available anymore.");
|
||||
configMeta.RemovePluginContribution(contributingConfigPluginId);
|
||||
wasChanged = true;
|
||||
}
|
||||
}
|
||||
@@ -328,7 +378,7 @@ public static partial class ManagedConfiguration
|
||||
/// The latter matters for organizations: a broken configuration plugin is still in charge, so we
|
||||
/// must not treat its settings as left over.
|
||||
/// </remarks>
|
||||
private static bool IsPluginPresent(Guid configPluginId, IReadOnlyCollection<IAvailablePlugin> availablePlugins, IReadOnlySet<Guid> deployedConfigPluginIds) => deployedConfigPluginIds.Contains(configPluginId) || availablePlugins.Any(x => x.Id == configPluginId);
|
||||
private static bool IsPluginPresent(Guid configPluginId, IReadOnlyCollection<IAvailablePlugin> availablePlugins, IReadOnlySet<Guid> deployedEnterpriseConfigPluginIds) => deployedEnterpriseConfigPluginIds.Contains(configPluginId) || availablePlugins.Any(x => x.Id == configPluginId);
|
||||
|
||||
/// <summary>
|
||||
/// Removes persisted managed states which belong to settings that are not registered anymore.
|
||||
@@ -390,7 +440,7 @@ public static partial class ManagedConfiguration
|
||||
|
||||
private static bool ClearEditableDefaultState(string settingName) => SettingsManagerAccess.ConfigurationData.ManagedEditableDefaults.Remove(settingName);
|
||||
|
||||
private static bool CleanupEditableDefaultState(ConfigMetaBase configMeta, IReadOnlyCollection<IAvailablePlugin> availablePlugins, IReadOnlySet<Guid> deployedConfigPluginIds)
|
||||
private static bool CleanupEditableDefaultState(ConfigMetaBase configMeta, IReadOnlyCollection<IAvailablePlugin> availablePlugins, IReadOnlySet<Guid> deployedEnterpriseConfigPluginIds)
|
||||
{
|
||||
if (!TryGetEditableDefaultState(configMeta.SettingName, out var editableDefaultState))
|
||||
{
|
||||
@@ -401,7 +451,7 @@ public static partial class ManagedConfiguration
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IsPluginPresent(editableDefaultState.ConfigPluginId, availablePlugins, deployedConfigPluginIds))
|
||||
if (IsPluginPresent(editableDefaultState.ConfigPluginId, availablePlugins, deployedEnterpriseConfigPluginIds))
|
||||
return false;
|
||||
|
||||
Log.LogInformation($"Clearing the editable default of the setting '{configMeta.SettingName}': the configuration plugin '{editableDefaultState.ConfigPluginId}' is not available anymore.");
|
||||
|
||||
Reference in new issue
Block a user