Skip to content

Commit bf9aae8

Browse files
fix(windows): don't fail uninstall when the configuration directory is unresolved
Co-authored-by: chouetz <24426034+chouetz@users.noreply.github.com>
1 parent 115e86d commit bf9aae8

4 files changed

Lines changed: 67 additions & 6 deletions

File tree

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Each section from every release note are combined when the
2+
# CHANGELOG.rst is rendered. So the text needs to be worded so that
3+
# it does not depend on any information only available in another
4+
# section. This may mean repeating some details, but each section
5+
# must be readable independently of the other.
6+
#
7+
# Each section note must be formatted as reStructuredText.
8+
---
9+
fixes:
10+
- |
11+
On Windows, fixed an issue where uninstalling the Agent could fail with MSI error code 1603
12+
when the Agent's install state in the registry had been removed or corrupted. The configuration
13+
directory owner check no longer blocks the operation when the configuration directory cannot be
14+
resolved, since there is nothing to secure in that case.

tools/windows/DatadogAgentInstaller/CustomActions.Tests/CustomActions.Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@
8383
<Compile Include="IntegrationTests\TestConfig.cs" />
8484
<Compile Include="Logs\ProcessConfigTests.cs" />
8585
<Compile Include="Native\SecureDirectoryTests.cs" />
86+
<Compile Include="Prerequisites\EnsureSecureConfigRootTests.cs" />
8687
<Compile Include="ProcessUserCustomActions\TestDelegate.cs" />
8788
<Compile Include="Process\ProcessConfigTests.cs" />
8889
<Compile Include="Proxy\ProcessConfigTests.cs" />
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
using Datadog.CustomActions;
2+
using FluentAssertions;
3+
using WixToolset.Dtf.WindowsInstaller;
4+
using Xunit;
5+
6+
namespace CustomActions.Tests.Prerequisites
7+
{
8+
public class EnsureSecureConfigRootTests : SessionTestBaseSetup
9+
{
10+
// Uninstalling an Agent whose install state (the registry values that record the configuration
11+
// directory) was removed or corrupted leaves APPLICATIONDATADIRECTORY unset. The configuration
12+
// directory owner check must not fail in that case, otherwise the custom action returns Failure
13+
// and the MSI aborts with exit code 1603, making a broken install impossible to uninstall.
14+
// See incident 58787.
15+
[Fact]
16+
public void EnsureSecureConfigRoot_Succeeds_When_ConfigRoot_Is_Not_Set()
17+
{
18+
PrerequisitesCustomActions.EnsureSecureConfigRoot(Session.Object)
19+
.Should()
20+
.Be(ActionResult.Success);
21+
}
22+
23+
[Fact]
24+
public void EnsureSecureConfigRootUI_Reports_Valid_When_ConfigRoot_Is_Not_Set()
25+
{
26+
PrerequisitesCustomActions.EnsureSecureConfigRoot(Session.Object, calledFromUIControl: true)
27+
.Should()
28+
.Be(ActionResult.Success);
29+
30+
Properties.Should()
31+
.Contain(PrerequisitesCustomActions.ConfigRootValidProperty, "True");
32+
}
33+
}
34+
}

tools/windows/DatadogAgentInstaller/CustomActions/PrerequisitesCustomActions.cs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public static ActionResult EnsureAdminCaller(Session session)
6666
/// dialog cannot send a message to the user, and returning failure exits the installer.
6767
/// https://learn.microsoft.com/en-us/windows/win32/msi/sending-messages-to-windows-installer-using-msiprocessmessage
6868
/// </remarks>
69-
private static ActionResult EnsureSecureConfigRoot(ISession session, bool calledFromUIControl = false)
69+
internal static ActionResult EnsureSecureConfigRoot(ISession session, bool calledFromUIControl = false)
7070
{
7171
if (calledFromUIControl)
7272
{
@@ -78,15 +78,27 @@ private static ActionResult EnsureSecureConfigRoot(ISession session, bool called
7878
// Read outside the try so that the messages below can name the directory
7979
var configRoot = session.Property("APPLICATIONDATADIRECTORY");
8080

81-
try
81+
if (string.IsNullOrEmpty(configRoot))
8282
{
83-
if (string.IsNullOrEmpty(configRoot))
83+
// On a fresh install or a maintenance (Change/Repair) run, CostFinalize resolves this
84+
// property to a concrete path before this action runs, so an empty value means the
85+
// install state that records the configuration directory is unavailable. That happens
86+
// when operating on an install whose registry state was removed or corrupted - for
87+
// example uninstalling it. There is no directory to verify or secure in that case, and
88+
// returning Failure would fail the MSI (exit code 1603) and make a broken-but-removable
89+
// install impossible to uninstall. Treat it as nothing to verify and let the operation
90+
// proceed. See incident 58787.
91+
session.Log("APPLICATIONDATADIRECTORY is not set, skipping the configuration directory owner check");
92+
if (calledFromUIControl)
8493
{
85-
// Resolved by CostFinalize, which runs before this action in both sequences, so an
86-
// empty value means something is wrong. Fail rather than skip the check.
87-
throw new InvalidOperationException("APPLICATIONDATADIRECTORY is not set");
94+
session[ConfigRootValidProperty] = "True";
8895
}
8996

97+
return ActionResult.Success;
98+
}
99+
100+
try
101+
{
90102
SecureDirectory.AssertSecureOwner(session, configRoot);
91103
}
92104
catch (SecureDirectoryException e)

0 commit comments

Comments
 (0)