Skip to content

Commit

Permalink
Update configuration environment behavior (#5182)
Browse files Browse the repository at this point in the history
## Change
In response to some other discussions, update the configuration
environment behavior:
1. Add an environment at the set level
2. Don't inherit environment data into child units, and don't promote
environment data when serializing

Updated the one consumer of environment (dynamic factory) to be
responsible for the flow of the security context from the set to the
immediate child units.

Also improved serialization of groups to output the non-resource
properties.
  • Loading branch information
JohnMcPMS authored Feb 6, 2025
1 parent 586bcbc commit 71e3a17
Show file tree
Hide file tree
Showing 12 changed files with 243 additions and 71 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,9 @@ namespace AppInstaller::CLI::ConfigurationRemoting
m_currentIntegrityLevel = Security::GetEffectiveIntegrityLevel();
#endif

m_setIntegrityLevel = m_currentIntegrityLevel;
m_setIntegrityLevel = SecurityContextToIntegrityLevel(m_configurationSet.Environment().Context());

// Check for multiple integrity level requirements
bool multipleIntegrityLevels = false;
bool higherIntegrityLevelsThanCurrent = false;
Expand Down Expand Up @@ -211,13 +214,13 @@ namespace AppInstaller::CLI::ConfigurationRemoting
}

private:
// Converts the string representation of SecurityContext to the integrity level
// Converts the string representation of SecurityContext to the target integrity level for this instance
Security::IntegrityLevel SecurityContextToIntegrityLevel(SecurityContext securityContext)
{
switch (securityContext)
{
case SecurityContext::Current:
return m_currentIntegrityLevel;
return m_setIntegrityLevel;
case SecurityContext::Restricted:
#ifndef AICLI_DISABLE_TEST_HOOKS
if (m_enableRestrictedIntegrityLevel)
Expand Down Expand Up @@ -358,6 +361,7 @@ namespace AppInstaller::CLI::ConfigurationRemoting

winrt::com_ptr<DynamicFactory> m_dynamicFactory;
Security::IntegrityLevel m_currentIntegrityLevel;
Security::IntegrityLevel m_setIntegrityLevel;
ProcessorMap m_setProcessors;
ConfigurationSet m_configurationSet;
std::once_flag m_createUnitSetProcessorsOnce;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// -----------------------------------------------------------------------------
// <copyright file="ValueSetExtensions.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation. Licensed under the MIT License.
// </copyright>
// -----------------------------------------------------------------------------

namespace Microsoft.Management.Configuration.UnitTests.Helpers
{
using System;
using System.Text;
using Windows.Foundation.Collections;

/// <summary>
/// Extensions for ValueSet.
/// </summary>
internal static class ValueSetExtensions
{
/// <summary>
/// Converts the value set to YAML like output.
/// </summary>
/// <param name="set">The set to output.</param>
/// <returns>The string.</returns>
public static string ToYaml(this ValueSet set)
{
StringBuilder sb = new StringBuilder();
ToYaml(set, sb);
return sb.ToString();
}

private static void ToYaml(ValueSet set, StringBuilder sb, int indentation = 0)
{
foreach (var keyValuePair in set)
{
bool addLine = true;

sb.Append(' ', indentation);
sb.Append(keyValuePair.Key);
sb.Append(": ");

if (keyValuePair.Value == null)
{
sb.Append("null");
}
else
{
switch (keyValuePair.Value)
{
case int i:
sb.Append(i);
break;
case string s:
sb.Append(s);
break;
case bool b:
sb.Append(b);
break;
case ValueSet v:
sb.AppendLine();
ToYaml(v, sb, indentation + 2);
addLine = false;
break;
default:
throw new NotImplementedException($"Add ToYaml type `{keyValuePair.Value.GetType().Name}`");
}
}

if (addLine)
{
sb.AppendLine();
}
}
}
}
}

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions src/Microsoft.Management.Configuration/ConfigurationSet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,16 @@ namespace winrt::Microsoft::Management::Configuration::implementation
m_schemaUri = value;
}

Configuration::ConfigurationEnvironment ConfigurationSet::Environment()
{
return *m_environment;
}

implementation::ConfigurationEnvironment& ConfigurationSet::EnvironmentInternal()
{
return *m_environment;
}

std::vector<Configuration::ConfigurationEnvironment> ConfigurationSet::GetUnitEnvironmentsInternal()
{
std::vector<impl::EnvironmentData> uniqueEnvironments;
Expand Down
5 changes: 5 additions & 0 deletions src/Microsoft.Management.Configuration/ConfigurationSet.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the MIT License.
#pragma once
#include "ConfigurationSet.g.h"
#include "ConfigurationEnvironment.h"
#include "ConfigurationSetChangeData.h"
#include "ConfigurationStatus.h"
#include <winget/ILifetimeWatcher.h>
Expand All @@ -25,6 +26,7 @@ namespace winrt::Microsoft::Management::Configuration::implementation
void Units(std::vector<Configuration::ConfigurationUnit>&& units);
void Parameters(std::vector<Configuration::ConfigurationParameter>&& value);
void ConfigurationSetChange(com_ptr<ConfigurationSetChangeData>& data, const std::optional<guid>& unitInstanceIdentifier);
implementation::ConfigurationEnvironment& EnvironmentInternal();
std::vector<Configuration::ConfigurationEnvironment> GetUnitEnvironmentsInternal();
#endif

Expand Down Expand Up @@ -68,6 +70,8 @@ namespace winrt::Microsoft::Management::Configuration::implementation
Windows::Foundation::Uri SchemaUri();
void SchemaUri(const Windows::Foundation::Uri& value);

Configuration::ConfigurationEnvironment Environment();

Windows::Foundation::Collections::IVector<Configuration::ConfigurationEnvironment> GetUnitEnvironments();

HRESULT STDMETHODCALLTYPE SetLifetimeWatcher(IUnknown* watcher);
Expand All @@ -91,6 +95,7 @@ namespace winrt::Microsoft::Management::Configuration::implementation
Windows::Foundation::Uri m_schemaUri = nullptr;
std::string m_inputHash;
std::shared_ptr<ConfigurationStatus::SetChangeRegistration> m_setChangeRegistration;
com_ptr<implementation::ConfigurationEnvironment> m_environment{ make_self<implementation::ConfigurationEnvironment>() };
#endif
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,13 @@ namespace winrt::Microsoft::Management::Configuration::implementation

CHECK_ERROR(ParseValueSet(m_document, ConfigurationField::Metadata, false, result->Metadata()));

m_setEnvironment = make_self<implementation::ConfigurationEnvironment>();
CHECK_ERROR(ExtractEnvironmentFromMetadata(result->Metadata(), *m_setEnvironment));
CHECK_ERROR(ExtractEnvironmentFromMetadata(result->Metadata(), result->EnvironmentInternal()));

CHECK_ERROR(ParseParameters(result));
CHECK_ERROR(ParseValueSet(m_document, ConfigurationField::Variables, false, result->Variables()));

std::vector<Configuration::ConfigurationUnit> units;
CHECK_ERROR(ParseConfigurationUnitsFromField(m_document, ConfigurationField::Resources, *m_setEnvironment, units));
CHECK_ERROR(ParseConfigurationUnitsFromField(m_document, ConfigurationField::Resources, units));
result->Units(std::move(units));

result->SchemaVersion(GetSchemaVersion());
Expand Down Expand Up @@ -177,25 +176,25 @@ namespace winrt::Microsoft::Management::Configuration::implementation
}
}

void ConfigurationSetParser_0_3::ParseConfigurationUnitsFromField(const Node& document, ConfigurationField field, const ConfigurationEnvironment& defaultEnvironment, std::vector<Configuration::ConfigurationUnit>& result)
void ConfigurationSetParser_0_3::ParseConfigurationUnitsFromField(const Node& document, ConfigurationField field, std::vector<Configuration::ConfigurationUnit>& result)
{
ParseSequence(document, field, false, Node::Type::Mapping, [&](const Node& item)
{
auto configurationUnit = make_self<ConfigurationUnit>();
ParseConfigurationUnit(configurationUnit.get(), item, defaultEnvironment);
ParseConfigurationUnit(configurationUnit.get(), item);
result.emplace_back(*configurationUnit);
});
}

void ConfigurationSetParser_0_3::ParseConfigurationUnit(ConfigurationUnit* unit, const Node& unitNode, const ConfigurationEnvironment& defaultEnvironment)
void ConfigurationSetParser_0_3::ParseConfigurationUnit(ConfigurationUnit* unit, const Node& unitNode)
{
// Set unknown intent as the new schema doesn't express it directly
unit->Intent(ConfigurationUnitIntent::Unknown);

CHECK_ERROR(GetStringValueForUnit(unitNode, ConfigurationField::Name, true, unit, &ConfigurationUnit::Identifier));
CHECK_ERROR(GetStringValueForUnit(unitNode, ConfigurationField::Type, true, unit, &ConfigurationUnit::Type));
CHECK_ERROR(ParseValueSet(unitNode, ConfigurationField::Metadata, false, unit->Metadata()));
CHECK_ERROR(ExtractEnvironmentForUnit(unit, defaultEnvironment));
CHECK_ERROR(ExtractEnvironmentForUnit(unit));
CHECK_ERROR(ValidateType(unit, unitNode, ConfigurationField::Type, false, true));
CHECK_ERROR(GetStringArrayForUnit(unitNode, ConfigurationField::DependsOn, false, unit, &ConfigurationUnit::Dependencies));

Expand All @@ -212,7 +211,7 @@ namespace winrt::Microsoft::Management::Configuration::implementation
if (propertiesNode)
{
std::vector<Configuration::ConfigurationUnit> units;
CHECK_ERROR(ParseConfigurationUnitsFromField(propertiesNode, ConfigurationField::Resources, unit->EnvironmentInternal(), units));
CHECK_ERROR(ParseConfigurationUnitsFromField(propertiesNode, ConfigurationField::Resources, units));
unit->Units(std::move(units));
}
}
Expand Down Expand Up @@ -294,13 +293,10 @@ namespace winrt::Microsoft::Management::Configuration::implementation
}
}

void ConfigurationSetParser_0_3::ExtractEnvironmentForUnit(ConfigurationUnit* unit, const ConfigurationEnvironment& defaultEnvironment)
void ConfigurationSetParser_0_3::ExtractEnvironmentForUnit(ConfigurationUnit* unit)
{
auto& environmentInternal = unit->EnvironmentInternal();
environmentInternal.DeepCopy(defaultEnvironment);

// Get unnested security context
ExtractSecurityContext(unit, defaultEnvironment.Context());
ExtractSecurityContext(unit);

// Get nested environment
ExtractEnvironmentFromMetadata(unit->Metadata(), unit->EnvironmentInternal());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ namespace winrt::Microsoft::Management::Configuration::implementation
ConfigurationParameter* parameter,
void(ConfigurationParameter::* propertyFunction)(const Windows::Foundation::IInspectable& value));

void ParseConfigurationUnitsFromField(const AppInstaller::YAML::Node& document, ConfigurationField field, const ConfigurationEnvironment& defaultEnvironment, std::vector<Configuration::ConfigurationUnit>& result);
virtual void ParseConfigurationUnit(ConfigurationUnit* unit, const AppInstaller::YAML::Node& unitNode, const ConfigurationEnvironment& defaultEnvironment);
void ParseConfigurationUnitsFromField(const AppInstaller::YAML::Node& document, ConfigurationField field, std::vector<Configuration::ConfigurationUnit>& result);
virtual void ParseConfigurationUnit(ConfigurationUnit* unit, const AppInstaller::YAML::Node& unitNode);
// Determines if the given unit should be converted to a group.
bool ShouldConvertToGroup(ConfigurationUnit* unit);

Expand All @@ -63,10 +63,9 @@ namespace winrt::Microsoft::Management::Configuration::implementation
void ExtractEnvironmentFromMetadata(const Windows::Foundation::Collections::ValueSet& metadata, ConfigurationEnvironment& targetEnvironment);

// Extracts the environment for a unit.
void ExtractEnvironmentForUnit(ConfigurationUnit* unit, const ConfigurationEnvironment& defaultEnvironment);
void ExtractEnvironmentForUnit(ConfigurationUnit* unit);

AppInstaller::YAML::Node m_document;
com_ptr<ConfigurationEnvironment> m_setEnvironment;
};

std::optional<std::pair<Windows::Foundation::PropertyType, bool>> ParseWindowsFoundationPropertyType(std::string_view value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,13 @@ namespace winrt::Microsoft::Management::Configuration::implementation
{
emitter << BeginMap;

WriteValues(emitter, WriteYamlValue);

emitter << EndMap;
}

void WriteValues(AppInstaller::YAML::Emitter& emitter, void(*WriteYamlValue)(AppInstaller::YAML::Emitter& emitter, const winrt::Windows::Foundation::IInspectable& value))
{
if (m_valueSet)
{
for (const auto& [key, value] : m_valueSet)
Expand All @@ -100,8 +107,6 @@ namespace winrt::Microsoft::Management::Configuration::implementation
WriteYamlValue(emitter, override.second);
}
}

emitter << EndMap;
}

private:
Expand Down Expand Up @@ -171,6 +176,12 @@ namespace winrt::Microsoft::Management::Configuration::implementation
writer.Write(emitter, WriteYamlValue);
}

void ConfigurationSetSerializer::WriteYamlValueSetValues(AppInstaller::YAML::Emitter& emitter, const Windows::Foundation::Collections::ValueSet& valueSet, const std::vector<std::pair<ConfigurationField, Windows::Foundation::IInspectable>>& overrides)
{
anon::ValueSetWriter writer{ valueSet, overrides };
writer.WriteValues(emitter, WriteYamlValue);
}

void ConfigurationSetSerializer::WriteYamlStringArray(AppInstaller::YAML::Emitter& emitter, const Windows::Foundation::Collections::IVector<hstring>& values)
{
emitter << BeginSeq;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ namespace winrt::Microsoft::Management::Configuration::implementation
ConfigurationSetSerializer() = default;

static void WriteYamlValueSet(AppInstaller::YAML::Emitter& emitter, const Windows::Foundation::Collections::ValueSet& valueSet, const std::vector<std::pair<ConfigurationField, Windows::Foundation::IInspectable>>& overrides = {});
static void WriteYamlValueSetValues(AppInstaller::YAML::Emitter& emitter, const Windows::Foundation::Collections::ValueSet& valueSet, const std::vector<std::pair<ConfigurationField, Windows::Foundation::IInspectable>>& overrides = {});
static void WriteYamlValueSetIfNotEmpty(AppInstaller::YAML::Emitter& emitter, ConfigurationField key, const Windows::Foundation::Collections::ValueSet& valueSet, const std::vector<std::pair<ConfigurationField, Windows::Foundation::IInspectable>>& overrides = {});
static void WriteYamlValueSetAsArray(AppInstaller::YAML::Emitter& emitter, const Windows::Foundation::Collections::ValueSet& valueSetArray);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,12 +112,10 @@ namespace winrt::Microsoft::Management::Configuration::implementation

void AddEnvironmentToMetadata(
Windows::Foundation::Collections::ValueSet& metadata,
const Configuration::ConfigurationEnvironment& environment,
const Configuration::ConfigurationEnvironment& commonEnvironment)
const Configuration::ConfigurationEnvironment& environment)
{
AddEnvironmentToMetadata(metadata,
environment.Context(), environment.ProcessorIdentifier(), environment.ProcessorProperties(),
commonEnvironment.Context(), commonEnvironment.ProcessorIdentifier(), commonEnvironment.ProcessorProperties());
environment.Context(), environment.ProcessorIdentifier(), environment.ProcessorProperties());
}
}

Expand All @@ -131,8 +129,7 @@ namespace winrt::Microsoft::Management::Configuration::implementation

// Prepare an override if necessary
Collections::ValueSet wingetMetadataOverride = nullptr;
auto commonEnvironment = ConfigurationEnvironment::CalculateCommonEnvironment(configurationSet->GetUnitEnvironmentsInternal());
AddEnvironmentToMetadata(wingetMetadataOverride, commonEnvironment);
AddEnvironmentToMetadata(wingetMetadataOverride, configurationSet->EnvironmentInternal());

WriteYamlValueSetIfNotEmpty(emitter, ConfigurationField::Metadata, configurationSet->Metadata(),
{
Expand All @@ -142,7 +139,7 @@ namespace winrt::Microsoft::Management::Configuration::implementation

WriteYamlParameters(emitter, configurationSet->Parameters());
WriteYamlValueSetIfNotEmpty(emitter, ConfigurationField::Variables, configurationSet->Variables());
WriteYamlConfigurationUnits(emitter, configurationSet->Units(), *commonEnvironment);
WriteYamlConfigurationUnits(emitter, configurationSet->Units());

emitter << EndMap;

Expand Down Expand Up @@ -220,8 +217,7 @@ namespace winrt::Microsoft::Management::Configuration::implementation

void ConfigurationSetSerializer_0_3::WriteYamlConfigurationUnits(
AppInstaller::YAML::Emitter& emitter,
const Windows::Foundation::Collections::IVector<Configuration::ConfigurationUnit>& values,
const Configuration::ConfigurationEnvironment& commonEnvironment)
const Windows::Foundation::Collections::IVector<Configuration::ConfigurationUnit>& values)
{
emitter << Key << GetConfigurationFieldName(ConfigurationField::Resources);

Expand All @@ -242,7 +238,7 @@ namespace winrt::Microsoft::Management::Configuration::implementation
// Prepare an override if necessary
Collections::ValueSet wingetMetadataOverride = nullptr;
Configuration::ConfigurationEnvironment unitEnvironment = unit.Environment();
AddEnvironmentToMetadata(wingetMetadataOverride, unitEnvironment, commonEnvironment);
AddEnvironmentToMetadata(wingetMetadataOverride, unitEnvironment);

WriteYamlValueSetIfNotEmpty(emitter, ConfigurationField::Metadata, unit.Metadata(),
{ { ConfigurationField::WingetMetadataRoot, wingetMetadataOverride } });
Expand Down Expand Up @@ -272,7 +268,12 @@ namespace winrt::Microsoft::Management::Configuration::implementation
emitter << Key << GetConfigurationFieldName(ConfigurationField::Properties);
emitter << BeginMap;

WriteYamlConfigurationUnits(emitter, groupUnits, unitEnvironment);
// Write everything but the resources
WriteYamlValueSetValues(emitter, unit.Settings(),
{ { ConfigurationField::Resources, nullptr } });

// Write the resources from the individual units
WriteYamlConfigurationUnits(emitter, groupUnits);

emitter << EndMap;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ namespace winrt::Microsoft::Management::Configuration::implementation
void WriteYamlParameters(AppInstaller::YAML::Emitter& emitter, const Windows::Foundation::Collections::IVector<Configuration::ConfigurationParameter>& values);
void WriteYamlConfigurationUnits(
AppInstaller::YAML::Emitter& emitter,
const Windows::Foundation::Collections::IVector<Configuration::ConfigurationUnit>& values,
const Configuration::ConfigurationEnvironment& commonEnvironment);
const Windows::Foundation::Collections::IVector<Configuration::ConfigurationUnit>& values);
};
}
Loading

0 comments on commit 71e3a17

Please sign in to comment.