mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-11-04 22:47:21 +00:00
Fixed local configuration plugins overriding the tool settings of an organization (#1139)
This commit is contained in:
1 parent
eef475581c
commit
2c2ad0dfde
5 files changed
+579
-80
No files matched your search
@@ -830,7 +830,7 @@ public static partial class ManagedConfiguration
|
||||
|
||||
var settingName = SettingName(propertyExpression);
|
||||
var managedMode = ReadManagedConfigurationMode(propertyExpression, settings);
|
||||
return HandleParsedDictionaryValue(configPluginId, dryRun, successful, configMeta, configuredValue, managedMode, settingName);
|
||||
return HandleParsedScalarValue(configPluginId, dryRun, successful, configMeta, configuredValue, managedMode, settingName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1080,9 +1080,14 @@ 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))
|
||||
// configuration plugin may touch it, no matter what it declares. A plugin which does not
|
||||
// declare the setting touches nothing below unless it owns the setting, so we ask only when it
|
||||
// declares the setting. Otherwise, the log would report every local plugin for every setting
|
||||
// of the organization:
|
||||
//
|
||||
if (successful && !MayManageSetting(configPluginId, configMeta))
|
||||
return false;
|
||||
|
||||
//
|
||||
@@ -1141,9 +1146,14 @@ 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))
|
||||
// configuration plugin may touch it, no matter what it declares. A plugin which does not
|
||||
// declare the setting touches nothing below unless it owns the setting, so we ask only when it
|
||||
// declares the setting. Otherwise, the log would report every local plugin for every setting
|
||||
// of the organization:
|
||||
//
|
||||
if (successful && !MayManageSetting(configPluginId, configMeta))
|
||||
return false;
|
||||
|
||||
//
|
||||
@@ -1204,67 +1214,6 @@ public static partial class ManagedConfiguration
|
||||
return successful;
|
||||
}
|
||||
|
||||
private static bool HandleParsedDictionaryValue<TClass>(
|
||||
Guid configPluginId,
|
||||
bool dryRun,
|
||||
bool successful,
|
||||
ConfigMeta<TClass, IDictionary<string, string>> configMeta,
|
||||
IDictionary<string, string> configuredValue,
|
||||
ManagedConfigurationMode managedMode,
|
||||
string settingName)
|
||||
{
|
||||
if (dryRun)
|
||||
return successful;
|
||||
|
||||
switch (successful)
|
||||
{
|
||||
case true when managedMode is ManagedConfigurationMode.LOCKED:
|
||||
ClearEditableDefaultState(settingName);
|
||||
configMeta.ClearEditableDefaultConfiguration();
|
||||
configMeta.SetValue(CloneStringDictionary(configuredValue));
|
||||
configMeta.LockConfiguration(configPluginId);
|
||||
break;
|
||||
|
||||
case true when managedMode is ManagedConfigurationMode.EDITABLE_DEFAULT:
|
||||
var currentValueSerialized = SerializeManagedStringDictionaryValue(configMeta.GetValue());
|
||||
var configuredValueSerialized = SerializeManagedStringDictionaryValue(configuredValue);
|
||||
|
||||
string lastAppliedValue;
|
||||
if (!TryGetEditableDefaultState(settingName, out var editableDefaultState))
|
||||
{
|
||||
configMeta.SetValue(CloneStringDictionary(configuredValue));
|
||||
lastAppliedValue = configuredValueSerialized;
|
||||
}
|
||||
else
|
||||
{
|
||||
lastAppliedValue = editableDefaultState.LastAppliedValue;
|
||||
if (string.Equals(currentValueSerialized, lastAppliedValue, StringComparison.Ordinal))
|
||||
{
|
||||
configMeta.SetValue(CloneStringDictionary(configuredValue));
|
||||
lastAppliedValue = configuredValueSerialized;
|
||||
}
|
||||
}
|
||||
|
||||
SetEditableDefaultState(settingName, configPluginId, lastAppliedValue);
|
||||
configMeta.UnlockConfiguration();
|
||||
configMeta.SetEditableDefaultConfiguration(configPluginId);
|
||||
break;
|
||||
|
||||
case false when configMeta.IsLocked && configMeta.LockedByConfigPluginId == configPluginId:
|
||||
configMeta.ResetLockedConfiguration();
|
||||
break;
|
||||
|
||||
case false when configMeta.ManagedMode is ManagedConfigurationMode.EDITABLE_DEFAULT
|
||||
&& TryGetEditableDefaultState(settingName, out var editableDefaultStateToRemove)
|
||||
&& editableDefaultStateToRemove.ConfigPluginId == configPluginId:
|
||||
configMeta.ClearEditableDefaultConfiguration();
|
||||
ClearEditableDefaultState(settingName);
|
||||
break;
|
||||
}
|
||||
|
||||
return successful;
|
||||
}
|
||||
|
||||
private static ManagedConfigurationMode ReadManagedConfigurationMode<TClass, TValue>(
|
||||
Expression<Func<TClass, TValue>> propertyExpression,
|
||||
LuaTable settings)
|
||||
@@ -1286,6 +1235,17 @@ public static partial class ManagedConfiguration
|
||||
{
|
||||
null => string.Empty,
|
||||
string text => text,
|
||||
|
||||
//
|
||||
// Tables of texts, i.e., the tool tables, keep the form they were stored in before they shared
|
||||
// this method with the other settings. The settings of installed versions hold the last applied
|
||||
// editable default in that form, and any other form would make each of them look as if the user
|
||||
// had changed it, so that the organization could never update it again:
|
||||
//
|
||||
IDictionary<string, string> texts => string.Join("\n", texts
|
||||
.OrderBy(pair => pair.Key, StringComparer.Ordinal)
|
||||
.Select(pair => $"{pair.Key}={pair.Value}")),
|
||||
|
||||
System.Collections.IDictionary dictionary => string.Join(";", dictionary.Keys
|
||||
.Cast<object>()
|
||||
.OrderBy(key => key.ToString(), StringComparer.Ordinal)
|
||||
@@ -1300,10 +1260,4 @@ public static partial class ManagedConfiguration
|
||||
};
|
||||
|
||||
private static Dictionary<string, string> CloneStringDictionary(IDictionary<string, string> values) => new(values, StringComparer.Ordinal);
|
||||
|
||||
private static string SerializeManagedStringDictionaryValue(IDictionary<string, string> values) => string.Join(
|
||||
"\n",
|
||||
values
|
||||
.OrderBy(pair => pair.Key, StringComparer.Ordinal)
|
||||
.Select(pair => $"{pair.Key}={pair.Value}"));
|
||||
}
|
||||
@@ -14,6 +14,17 @@ public static partial class ManagedConfiguration
|
||||
|
||||
private static ILogger Log => Program.LOGGER_FACTORY.CreateLogger(nameof(ManagedConfiguration));
|
||||
|
||||
/// <summary>
|
||||
/// Decides whether a configuration plugin speaks for an organization.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The plugin factory decides this by the directories of a running app, which a test does not
|
||||
/// have. Tests therefore replace this for their duration and restore it afterward, so that they
|
||||
/// can check what an organization owns against a local configuration plugin. The app itself
|
||||
/// never replaces it.
|
||||
/// </remarks>
|
||||
internal static Func<Guid, bool> IsOrganizationPlugin { get; set; } = PluginFactory.IsOrganizationConfigurationPlugin;
|
||||
|
||||
/// <summary>
|
||||
/// All registered settings, in no particular order.
|
||||
/// </summary>
|
||||
@@ -354,10 +365,10 @@ public static partial class ManagedConfiguration
|
||||
if (owningConfigPluginId == Guid.Empty || owningConfigPluginId == configPluginId)
|
||||
return true;
|
||||
|
||||
if (!PluginFactory.IsOrganizationConfigurationPlugin(owningConfigPluginId))
|
||||
if (!IsOrganizationPlugin(owningConfigPluginId))
|
||||
return true;
|
||||
|
||||
if (PluginFactory.IsOrganizationConfigurationPlugin(configPluginId))
|
||||
if (IsOrganizationPlugin(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.");
|
||||
|
||||
Reference in new issue
Block a user