From 70bd15e50a5a35281058b1cd045b90586c3ccd0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20CORTIER?= Date: Fri, 18 Sep 2026 15:37:18 +0900 Subject: [PATCH] refactor(agent-installer): deduplicate helper registry values Centralize the PolicyConsentHelper discovery values so native and WOW6432Node registry views stay synchronized without changing installer behavior. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../PolicyConsentDiscoveryTests.cs | 62 +++++++++++-- package/AgentWindowsManaged/Program.cs | 89 +++++++------------ 2 files changed, 89 insertions(+), 62 deletions(-) diff --git a/package/AgentWindowsManaged.Tests/PolicyConsentDiscoveryTests.cs b/package/AgentWindowsManaged.Tests/PolicyConsentDiscoveryTests.cs index c7c38d3a6..81d027f3b 100644 --- a/package/AgentWindowsManaged.Tests/PolicyConsentDiscoveryTests.cs +++ b/package/AgentWindowsManaged.Tests/PolicyConsentDiscoveryTests.cs @@ -43,17 +43,22 @@ public void DiscoveryUsesTheConsumerNativeRegistryView(Platform platform, bool e } [Theory] - [InlineData(Platform.x86, 0)] - [InlineData(Platform.x64, 7)] - [InlineData(Platform.arm64, 7)] - public void NativeAgentMsiPublishesDiscoveryFor32BitConsumers(Platform platform, int expectedCount) + [InlineData(Platform.x86, 7)] + [InlineData(Platform.x64, 14)] + [InlineData(Platform.arm64, 14)] + public void AgentMsiPublishesDiscoveryInRequiredRegistryViews( + Platform platform, + int expectedCount) { Type program = System.Reflection.Assembly .Load("DevolutionsAgent") .GetType("DevolutionsAgent.Program", throwOnError: true); MethodInfo method = program.GetMethod( - "CreatePolicyConsentRegistryValuesFor32BitConsumers", - BindingFlags.Static | BindingFlags.NonPublic); + "CreatePolicyConsentRegistryValues", + BindingFlags.Static | BindingFlags.NonPublic, + binder: null, + types: [typeof(Platform?), typeof(Version)], + modifiers: null); RegValue[] values = Assert.IsAssignableFrom>( method.Invoke(null, [platform, new Version(2026, 3, 0)])) @@ -62,9 +67,52 @@ public void NativeAgentMsiPublishesDiscoveryFor32BitConsumers(Platform platform, Assert.Equal(expectedCount, values.Length); Assert.All(values, value => { - Assert.False(value.Win64); Assert.Equal(RegistryKeyAction.createAndRemoveOnUninstall, value.RegistryKeyAction); }); + Assert.Equal( + new[] + { + "ProtocolVersion", + "ExecutableName", + "ExecutablePath", + "ProductName", + "ProductVersion", + "BrokerPipeName", + "CurrentUiSignerSpkiSha256", + }, + values.Take(7).Select(value => value.Name)); + Assert.Equal( + new[] + { + "2.0", + "DevolutionsAgentPolicyConsent.exe", + "[INSTALLDIR]DevolutionsAgentPolicyConsent.exe", + "Devolutions Agent Policy Consent", + "2026.3.0", + @"\\.\pipe\Devolutions.Now.PackageBroker.v1", + "e43ed3368eaabff61abc79eb338cba9da88a80d93b751735ff417f26afa579a8", + }, + values.Take(7).Select(value => value.Value)); + Assert.All(values.Take(7), value => + { + Assert.Equal(platform != Platform.x86, value.Win64); + Assert.Equal( + platform == Platform.x86 ? "Type=string" : "Type=string; Component:Win64=yes", + value.AttributesDefinition); + }); + + if (platform == Platform.x86) + { + return; + } + + Assert.Equal(values.Take(7).Select(value => value.Name), values.Skip(7).Select(value => value.Name)); + Assert.Equal(values.Take(7).Select(value => value.Value), values.Skip(7).Select(value => value.Value)); + Assert.All(values.Skip(7), value => + { + Assert.False(value.Win64); + Assert.Equal("Type=string", value.AttributesDefinition); + }); } [Fact] diff --git a/package/AgentWindowsManaged/Program.cs b/package/AgentWindowsManaged/Program.cs index 7df0ddab1..c48f23579 100644 --- a/package/AgentWindowsManaged/Program.cs +++ b/package/AgentWindowsManaged/Program.cs @@ -339,34 +339,6 @@ static void Main() Win64 = project.Platform == Platform.x64, RegistryKeyAction = RegistryKeyAction.create, }, - CreatePolicyConsentRegistryValue( - "ProtocolVersion", - Includes.POLICY_CONSENT_PROTOCOL_VERSION, - Use64BitRegistryView(project.Platform)), - CreatePolicyConsentRegistryValue( - "ExecutableName", - Includes.POLICY_CONSENT_EXECUTABLE_NAME, - Use64BitRegistryView(project.Platform)), - CreatePolicyConsentRegistryValue( - "ExecutablePath", - $"[{AgentProperties.InstallDir}]{Includes.POLICY_CONSENT_EXECUTABLE_NAME}", - Use64BitRegistryView(project.Platform)), - CreatePolicyConsentRegistryValue( - "ProductName", - Includes.POLICY_CONSENT_PRODUCT_NAME, - Use64BitRegistryView(project.Platform)), - CreatePolicyConsentRegistryValue( - "ProductVersion", - DevolutionsAgentProductVersion.ToString(), - Use64BitRegistryView(project.Platform)), - CreatePolicyConsentRegistryValue( - "BrokerPipeName", - Includes.POLICY_CONSENT_DEFAULT_BROKER_PIPE_NAME, - Use64BitRegistryView(project.Platform)), - CreatePolicyConsentRegistryValue( - "CurrentUiSignerSpkiSha256", - Includes.POLICY_CONSENT_CURRENT_UI_SIGNER_SPKI_SHA256, - Use64BitRegistryView(project.Platform)), new (RegistryHive.LocalMachine, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", Includes.SERVICE_NAME, $"[{AgentProperties.InstallDir}]{Includes.DESKTOP_DIRECTORY_NAME}\\{Includes.DESKTOP_EXECUTABLE_NAME}") { Win64 = project.Platform == Platform.x64, @@ -394,7 +366,7 @@ static void Main() CreateEventLogSourceRegistryValue(project.Platform == Platform.x64), }; project.RegValues = project.RegValues - .Concat(CreatePolicyConsentRegistryValuesFor32BitConsumers(project.Platform, DevolutionsAgentProductVersion)) + .Concat(CreatePolicyConsentRegistryValues(project.Platform, DevolutionsAgentProductVersion)) .ToArray(); List projectProperties = AgentProperties.Properties.Select(x => x.ToWixSharpProperty()).ToList(); @@ -498,47 +470,54 @@ internal static RegValue CreatePolicyConsentRegistryValue(string name, string va internal static bool Use64BitRegistryView(Platform? platform) => platform is Platform.x64 or Platform.arm64; - internal static IEnumerable CreatePolicyConsentRegistryValuesFor32BitConsumers( + internal static IEnumerable CreatePolicyConsentRegistryValues( Platform? platform, Version productVersion) { - if (!Use64BitRegistryView(platform)) + bool nativeRegistryViewIs64Bit = Use64BitRegistryView(platform); + IEnumerable nativeRegistryValues = CreatePolicyConsentRegistryValues( + productVersion, + nativeRegistryViewIs64Bit); + + if (!nativeRegistryViewIs64Bit) { - return []; + return nativeRegistryValues; } - return + return nativeRegistryValues.Concat(CreatePolicyConsentRegistryValues(productVersion, false)); + } + + private static IEnumerable CreatePolicyConsentRegistryValues( + Version productVersion, + bool win64) => + CreatePolicyConsentDiscoveryValues(productVersion) + .Select(value => CreatePolicyConsentRegistryValue(value.Name, value.Value, win64)); + + private static IEnumerable<(string Name, string Value)> CreatePolicyConsentDiscoveryValues( + Version productVersion) => [ - CreatePolicyConsentRegistryValue( + ( "ProtocolVersion", - Includes.POLICY_CONSENT_PROTOCOL_VERSION, - false), - CreatePolicyConsentRegistryValue( + Includes.POLICY_CONSENT_PROTOCOL_VERSION), + ( "ExecutableName", - Includes.POLICY_CONSENT_EXECUTABLE_NAME, - false), - CreatePolicyConsentRegistryValue( + Includes.POLICY_CONSENT_EXECUTABLE_NAME), + ( "ExecutablePath", - $"[{AgentProperties.InstallDir}]{Includes.POLICY_CONSENT_EXECUTABLE_NAME}", - false), - CreatePolicyConsentRegistryValue( + $"[{AgentProperties.InstallDir}]{Includes.POLICY_CONSENT_EXECUTABLE_NAME}"), + ( "ProductName", - Includes.POLICY_CONSENT_PRODUCT_NAME, - false), - CreatePolicyConsentRegistryValue( + Includes.POLICY_CONSENT_PRODUCT_NAME), + ( "ProductVersion", - productVersion.ToString(), - false), - CreatePolicyConsentRegistryValue( + productVersion.ToString()), + ( "BrokerPipeName", - Includes.POLICY_CONSENT_DEFAULT_BROKER_PIPE_NAME, - false), - CreatePolicyConsentRegistryValue( + Includes.POLICY_CONSENT_DEFAULT_BROKER_PIPE_NAME), + ( "CurrentUiSignerSpkiSha256", - Includes.POLICY_CONSENT_CURRENT_UI_SIGNER_SPKI_SHA256, - false), + Includes.POLICY_CONSENT_CURRENT_UI_SIGNER_SPKI_SHA256), ]; - } private static void Project_UnhandledException(ExceptionEventArgs e) {