Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tests for configure mixed elevation #4487

Merged
merged 14 commits into from
Jun 14, 2024
42 changes: 39 additions & 3 deletions src/AppInstallerCLICore/ConfigurationDynamicRuntimeFactory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,27 @@ namespace AppInstaller::CLI::ConfigurationRemoting
{
namespace anonymous
{
#ifndef DISABLE_TEST_HOOKS
constexpr std::wstring_view DisableRunAsTestGuid = L"1e62d683-2999-44e7-81f7-6f8f35e8d731";
constexpr std::wstring_view DisableHighIntegritySetSerializationTestGuid = L"02f64b7d-6c2e-43fa-87dd-1f265800681d";

// Checks the configuration set metadata for a specific test guid that controls the behavior flow.
bool GetTestBehavior(const ConfigurationSet& configurationSet, const std::wstring_view& testGuid)
{
auto testBehavior = configurationSet.Metadata().TryLookup(testGuid);
if (testBehavior)
{
auto testBehaviorProperty = testBehavior.try_as<IPropertyValue>();
if (testBehaviorProperty && testBehaviorProperty.Type() == PropertyType::Boolean)
{
return testBehaviorProperty.GetBoolean();
}
}

return false;
}
#endif

struct DynamicProcessorInfo
{
IConfigurationSetProcessorFactory Factory;
Expand Down Expand Up @@ -138,9 +159,15 @@ namespace AppInstaller::CLI::ConfigurationRemoting
std::vector<ConfigurationUnit> highIntegrityUnits;
auto units = m_configurationSet.Units();

for (auto unit : units)
for (auto unit : units)
{
if (unit.IsActive() && GetIntegrityLevelForUnit(unit) == Security::IntegrityLevel::High)
if (unit.IsActive() && GetIntegrityLevelForUnit(unit) == Security::IntegrityLevel::High &&
#ifndef DISABLE_TEST_HOOKS
!GetTestBehavior(m_configurationSet, DisableHighIntegritySetSerializationTestGuid)
#elif
true
#endif
)
{
highIntegrityUnits.emplace_back(unit);
}
Expand Down Expand Up @@ -172,7 +199,16 @@ namespace AppInstaller::CLI::ConfigurationRemoting
// If we got here, the only option is that the current integrity level is not High.
if (integrityLevel == Security::IntegrityLevel::High)
{
factory = CreateOutOfProcessFactory(true, SerializeSetProperties(), SerializeHighIntegrityLevelSet());
bool useRunAs = true;

#ifndef DISABLE_TEST_HOOKS
if (GetTestBehavior(m_configurationSet, DisableRunAsTestGuid))
{
useRunAs = false;
}
#endif

factory = CreateOutOfProcessFactory(useRunAs, SerializeSetProperties(), SerializeHighIntegrityLevelSet());
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,7 @@ namespace AppInstaller::CLI::ConfigurationRemoting

IConfigurationSetProcessorFactory CreateOutOfProcessFactory(bool useRunAs, const std::string& properties, const std::string& restrictions)
{
AICLI_LOG(CLI, Info, << restrictions);
return winrt::make<RemoteFactory>(useRunAs, properties, restrictions);
}
}
Expand Down
3 changes: 1 addition & 2 deletions src/AppInstallerCLICore/Workflows/ConfigurationFlow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,7 @@ namespace AppInstaller::CLI::Workflow
IConfigurationSetProcessorFactory factory;

// Since downgrading is not currently supported, only use dynamic if not running as admin.
if (Settings::ExperimentalFeature::IsEnabled(Settings::ExperimentalFeature::Feature::ConfigureSelfElevation) &&
!Runtime::IsRunningAsAdmin())
if (Settings::ExperimentalFeature::IsEnabled(Settings::ExperimentalFeature::Feature::ConfigureSelfElevation) && !Runtime::IsRunningAsAdmin())
{
factory = ConfigurationRemoting::CreateDynamicRuntimeFactory();
// TODO: Implement SetProcessorFactory::IPwshConfigurationSetProcessorFactoryProperties on dynamic factory
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@ namespace Microsoft.Management.Configuration.Processor
{
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Management.Automation;
using System.Runtime.CompilerServices;
using System.Text;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// <copyright file="Constants.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation. Licensed under the MIT License.
// </copyright>
Expand All @@ -20,5 +20,20 @@
/// The namespace where xUnit traits will be defined.
/// </summary>
public const string NamespaceNameForTraits = "Microsoft.Management.Configuration.UnitTests.Helpers";

/// <summary>
/// The dynamic runtime factory handler identifier.
/// </summary>
public const string DynamicRuntimeHandlerIdentifier = "{73fea39f-6f4a-41c9-ba94-6fd14d633e40}";

/// <summary>
/// Test guid for disabling the dynamic factory from setting the 'RunAs' start process verb.
/// </summary>
public const string DisableRunAsTestGuid = "1e62d683-2999-44e7-81f7-6f8f35e8d731";

/// <summary>
/// Test guid for disabling the serialization of high integrity units.
/// </summary>
public const string DisableHighIntegriySerializationTestGuid = "02f64b7d-6c2e-43fa-87dd-1f265800681d";

Check failure on line 37 in src/Microsoft.Management.Configuration.UnitTests/Helpers/Constants.cs

View workflow job for this annotation

GitHub Actions / Check Spelling

`Integriy` is not a recognized word. (unrecognized-spelling)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
// -----------------------------------------------------------------------------
// <copyright file="ConfigurationMixedElevationTests.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation. Licensed under the MIT License.
// </copyright>
// -----------------------------------------------------------------------------

namespace Microsoft.Management.Configuration.UnitTests.Tests
{
using System;
using System.Threading.Tasks;
using Microsoft.Management.Configuration.UnitTests.Fixtures;
using Microsoft.Management.Configuration.UnitTests.Helpers;
using Microsoft.VisualBasic;
using Xunit;
using Xunit.Abstractions;

/// <summary>
/// Unit tests for verifying the processor behavior for handling mixed elevation scenarios.
/// </summary>
[Collection("UnitTestCollection")]
[OutOfProc]
public class ConfigurationMixedElevationTests : ConfigurationProcessorTestBase
{
private readonly UnitTestFixture fixture;
private readonly ITestOutputHelper log;

/// <summary>
/// Initializes a new instance of the <see cref="ConfigurationMixedElevationTests"/> class.
/// </summary>
/// <param name="fixture">Unit test fixture.</param>
/// <param name="log">Log helper.</param>
public ConfigurationMixedElevationTests(UnitTestFixture fixture, ITestOutputHelper log)
: base(fixture, log)
{
this.fixture = fixture;
this.log = log;
}

/// <summary>
/// Verifies that a set of units with mixed elevation can run successfully.
/// </summary>
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
[Fact]
public async Task ApplyUnitsWithMixedElevation()
{
string resourceName = "E2ETestResource";
string moduleName = "xE2ETestResource";
Version version = new Version("0.0.0.1");

ConfigurationSet configurationSet = this.ConfigurationSet();
configurationSet.Metadata.Add(Helpers.Constants.DisableRunAsTestGuid, true);

ConfigurationUnit elevationRequiredUnit = this.ConfigurationUnit();
elevationRequiredUnit.Metadata.Add("securityContext", "elevated");
elevationRequiredUnit.Metadata.Add("version", version.ToString());
elevationRequiredUnit.Metadata.Add("module", moduleName);

elevationRequiredUnit.Settings.Add("secretCode", "123456789");
elevationRequiredUnit.Type = resourceName;
elevationRequiredUnit.Intent = ConfigurationUnitIntent.Apply;

ConfigurationUnit unit = this.ConfigurationUnit();
unit.Metadata.Add("version", version.ToString());
unit.Metadata.Add("module", moduleName);
unit.Settings.Add("secretCode", "123456789");
unit.Type = resourceName;
unit.Intent = ConfigurationUnitIntent.Apply;

configurationSet.Units = new ConfigurationUnit[] { elevationRequiredUnit, unit };

IConfigurationSetProcessorFactory dynamicFactory = await this.fixture.ConfigurationStatics.CreateConfigurationSetProcessorFactoryAsync(Helpers.Constants.DynamicRuntimeHandlerIdentifier);

ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics(dynamicFactory);

ApplyConfigurationSetResult result = processor.ApplySet(configurationSet, ApplyConfigurationSetFlags.None);
Assert.NotNull(result);
Assert.Null(result.ResultCode);
Assert.Equal(2, result.UnitResults.Count);

foreach (var unitResult in result.UnitResults)
{
Assert.NotNull(unitResult);
Assert.False(unitResult.PreviouslyInDesiredState);
Assert.False(unitResult.RebootRequired);
Assert.NotNull(unitResult.ResultInformation);
Assert.Null(unitResult.ResultInformation.ResultCode);
Assert.Equal(ConfigurationUnitResultSource.None, unitResult.ResultInformation.ResultSource);
}
}

/// <summary>
/// Verifies that a unit not in the limitation set will fail.
/// </summary>
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
[Fact]
public async Task ApplyUnitNotInLimitationSet()
{
string resourceName = "E2ETestResource";
string moduleName = "xE2ETestResource";
Version version = new Version("0.0.0.1");

ConfigurationSet configurationSet = this.ConfigurationSet();
configurationSet.Metadata.Add(Helpers.Constants.DisableRunAsTestGuid, true);
configurationSet.Metadata.Add(Helpers.Constants.DisableHighIntegriySerializationTestGuid, true);

Check failure on line 104 in src/Microsoft.Management.Configuration.UnitTests/Tests/ConfigurationMixedElevationTests.cs

View workflow job for this annotation

GitHub Actions / Check Spelling

`Integriy` is not a recognized word. (unrecognized-spelling)

ConfigurationUnit elevationRequiredUnit1 = this.ConfigurationUnit();
elevationRequiredUnit1.Metadata.Add("securityContext", "elevated");
elevationRequiredUnit1.Metadata.Add("version", version.ToString());
elevationRequiredUnit1.Metadata.Add("module", moduleName);

elevationRequiredUnit1.Settings.Add("secretCode", "123456789");
elevationRequiredUnit1.Type = resourceName;
elevationRequiredUnit1.Intent = ConfigurationUnitIntent.Apply;

configurationSet.Units = new ConfigurationUnit[] { elevationRequiredUnit1 };

IConfigurationSetProcessorFactory dynamicFactory = await this.fixture.ConfigurationStatics.CreateConfigurationSetProcessorFactoryAsync(Helpers.Constants.DynamicRuntimeHandlerIdentifier);

ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics(dynamicFactory);

ApplyConfigurationSetResult result = processor.ApplySet(configurationSet, ApplyConfigurationSetFlags.None);
Assert.NotNull(result);
Assert.NotNull(result.ResultCode);
Assert.Equal(Errors.WINGET_CONFIG_ERROR_SET_APPLY_FAILED, result.ResultCode.HResult);
Assert.Equal(1, result.UnitResults.Count);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests
using Microsoft.Management.Configuration.Processor;
using Microsoft.Management.Configuration.Processor.Set;
using Microsoft.Management.Configuration.UnitTests.Fixtures;
using Moq;
using WinRT;
using Xunit;
using Xunit.Abstractions;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// <copyright file="ConfigurationProcessorGetTests.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation. Licensed under the MIT License.
// </copyright>
// -----------------------------------------------------------------------------

namespace Microsoft.Management.Configuration.UnitTests.Tests
{
using System.Collections.Generic;
using System.IO;
using Microsoft.Management.Configuration.UnitTests.Fixtures;
using Microsoft.Management.Configuration.UnitTests.Helpers;
Expand Down
3 changes: 2 additions & 1 deletion src/nuget.config
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
<add key="AppInstallerCLIE2ETestsRepo" value="file:///C:/Users/ryfu/AppData/Local/Temp/efe9569e-e036-47b3-b4b7-31444da84fe1" />
</packageSources>
<disabledPackageSources>
<clear />
Expand Down
Loading