commit 984b7c13c138a25bb587c74c3128e2d529059d6b
parent c17110b97e72079739e3425fd7a8fc22f2c16168
Author: yao-msft <50888816+yao-msft@users.noreply.github.com>
Date: Fri, 24 Sep 2021 18:51:50 -0700
Add option to check fields requiring verified publisher in manifest p… (#1487)
Diffstat:
12 files changed, 145 insertions(+), 76 deletions(-)
diff --git a/src/AppInstallerCLICore/Commands/ValidateCommand.cpp b/src/AppInstallerCLICore/Commands/ValidateCommand.cpp
@@ -9,6 +9,7 @@
namespace AppInstaller::CLI
{
using namespace std::string_view_literals;
+ using namespace AppInstaller::Manifest;
std::vector<Argument> ValidateCommand::GetArguments() const
{
@@ -42,7 +43,10 @@ namespace AppInstaller::CLI
try
{
- auto manifest = Manifest::YamlParser::CreateFromPath(inputFile, true, true);
+ ManifestValidateOption validateOption;
+ validateOption.FullValidation = true;
+ validateOption.ThrowOnWarning = true;
+ auto manifest = YamlParser::CreateFromPath(inputFile, validateOption);
context.Add<Execution::Data::Manifest>(manifest);
context <<
@@ -51,7 +55,7 @@ namespace AppInstaller::CLI
context.Reporter.Info() << Resource::String::ManifestValidationSuccess << std::endl;
}
- catch (const Manifest::ManifestException& e)
+ catch (const ManifestException& e)
{
HRESULT hr = S_OK;
if (e.IsWarningOnly())
diff --git a/src/AppInstallerCLITests/TestData/InstallFlowTest_LicenseAgreement.yaml b/src/AppInstallerCLITests/TestData/InstallFlowTest_LicenseAgreement.yaml
@@ -1,10 +1,11 @@
-PackageIdentifier: TestInstallerWithLicenseAgreement
+PackageIdentifier: TestInstaller.WithLicenseAgreement
PackageVersion: 1.0.0.0
PackageLocale: en-US
PackageName: AppInstaller Test Installer
Publisher: Microsoft Corporation
Moniker: AICLITestExe
License: Test
+ShortDescription: TestInstallerWithLicenseAgreement
Agreements:
- AgreementLabel: Agreement with text
Agreement: This is the text of the agreement.
diff --git a/src/AppInstallerCLITests/YamlManifest.cpp b/src/AppInstallerCLITests/YamlManifest.cpp
@@ -168,16 +168,33 @@ private:
bool m_expectedWarningOnly;
};
-void TestManifest(const std::filesystem::path& manifestPath, const std::string& expectedMessage = {}, bool expectedWarningOnly = false)
+ManifestValidateOption GetTestManifestValidateOption(
+ bool schemaValidationOnly = false,
+ bool errorOnVerifiedPublisher = false)
+{
+ ManifestValidateOption validateOption;
+ validateOption.FullValidation = true;
+ validateOption.ThrowOnWarning = true;
+ validateOption.SchemaValidationOnly = schemaValidationOnly;
+ validateOption.ErrorOnVerifiedPublisherFields = errorOnVerifiedPublisher;
+ return validateOption;
+}
+
+void TestManifest(
+ const std::filesystem::path& manifestPath,
+ const std::string& expectedMessage = {},
+ bool expectedWarningOnly = false,
+ ManifestValidateOption validateOption = GetTestManifestValidateOption())
{
INFO(manifestPath.u8string());
+
if (expectedMessage.empty())
{
- CHECK_NOTHROW(YamlParser::CreateFromPath(TestDataFile(manifestPath), true, true));
+ CHECK_NOTHROW(YamlParser::CreateFromPath(TestDataFile(manifestPath), validateOption));
}
else
{
- CHECK_THROWS_MATCHES(YamlParser::CreateFromPath(TestDataFile(manifestPath), true, true), ManifestException, ManifestExceptionMatcher(expectedMessage, expectedWarningOnly));
+ CHECK_THROWS_MATCHES(YamlParser::CreateFromPath(TestDataFile(manifestPath), validateOption), ManifestException, ManifestExceptionMatcher(expectedMessage, expectedWarningOnly));
}
}
@@ -186,6 +203,7 @@ struct ManifestTestCase
std::string TestFile;
std::string ExpectedMessage = {};
bool IsWarningOnly = false;
+ ManifestValidateOption ValidateOption = GetTestManifestValidateOption();
};
TEST_CASE("ReadGoodManifests", "[ManifestValidation]")
@@ -256,12 +274,14 @@ TEST_CASE("ReadBadManifests", "[ManifestValidation]")
{ "Manifest-Bad-ProductCodeOnMSIX.yaml", "The specified installer type does not support ProductCode. Field: InstallerType Value: Msix" },
{ "Manifest-Bad-InvalidUpdateBehavior.yaml", "Invalid field value. Field: UpdateBehavior" },
{ "Manifest-Bad-InvalidLocale.yaml", "The locale value is not a well formed bcp47 language tag." },
- { "Manifest-Bad-AppsAndFeaturesEntriesOnMSIX.yaml", "The specified installer type does not write to Apps and Features entry." }
+ { "Manifest-Bad-AppsAndFeaturesEntriesOnMSIX.yaml", "The specified installer type does not write to Apps and Features entry." },
+ { "InstallFlowTest_LicenseAgreement.yaml", "Field usage requires verified publishers.", true },
+ { "InstallFlowTest_LicenseAgreement.yaml", "Field usage requires verified publishers.", false, GetTestManifestValidateOption(false, true) },
};
for (auto const& testCase : TestCases)
{
- TestManifest(testCase.TestFile, testCase.ExpectedMessage, testCase.IsWarningOnly);
+ TestManifest(testCase.TestFile, testCase.ExpectedMessage, testCase.IsWarningOnly, testCase.ValidateOption);
}
}
@@ -281,7 +301,7 @@ TEST_CASE("ManifestEncoding", "[ManifestValidation]")
for (auto const& testCase : TestCases)
{
INFO(testCase.TestFile);
- Manifest manifest = YamlParser::CreateFromPath(TestDataFile(testCase.TestFile), true, true);
+ Manifest manifest = YamlParser::CreateFromPath(TestDataFile(testCase.TestFile), GetTestManifestValidateOption());
REQUIRE(manifest.DefaultLocalization.Get<Localization::PackageName>() == u8"MSIX SDK\xA9");
}
}
@@ -540,14 +560,26 @@ void VerifyV1ManifestContent(const Manifest& manifest, bool isSingleton, Manifes
REQUIRE(localization1.Get<Localization::ShortDescription>() == "This is MSIX SDK UK");
REQUIRE(localization1.Get<Localization::Description>() == "The MSIX SDK project is an effort to enable developers UK");
REQUIRE(localization1.Get<Localization::Tags>() == MultiValue{ "appxsdkUK", "msixsdkUK" });
+
+ if (manifestVer >= ManifestVer{ s_ManifestVersionV1_1 })
+ {
+ REQUIRE(localization1.Get<Localization::ReleaseNotes>() == "Release notes");
+ REQUIRE(localization1.Get<Localization::ReleaseNotesUrl>() == "https://ReleaseNotes.net");
+ REQUIRE(localization1.Get<Localization::Agreements>().size() == 1);
+ REQUIRE(localization1.Get<Localization::Agreements>().at(0).Label == "Label");
+ REQUIRE(localization1.Get<Localization::Agreements>().at(0).AgreementText == "Text");
+ REQUIRE(localization1.Get<Localization::Agreements>().at(0).AgreementUrl == "https://AgreementUrl.net");
+ }
}
}
TEST_CASE("ValidateV1GoodManifestAndVerifyContents", "[ManifestValidation]")
{
+ ManifestValidateOption validateOption;
+ validateOption.FullValidation = true;
TempDirectory singletonDirectory{ "SingletonManifest" };
CopyTestDataFilesToFolder({ "ManifestV1-Singleton.yaml" }, singletonDirectory);
- Manifest singletonManifest = YamlParser::CreateFromPath(singletonDirectory, true, true);
+ Manifest singletonManifest = YamlParser::CreateFromPath(singletonDirectory, validateOption);
VerifyV1ManifestContent(singletonManifest, true);
TempDirectory multiFileDirectory{ "MultiFileManifest" };
@@ -558,7 +590,7 @@ TEST_CASE("ValidateV1GoodManifestAndVerifyContents", "[ManifestValidation]")
"ManifestV1-MultiFile-Locale.yaml" }, multiFileDirectory);
TempFile mergedManifestFile{ "merged.yaml" };
- Manifest multiFileManifest = YamlParser::CreateFromPath(multiFileDirectory, true, true, mergedManifestFile);
+ Manifest multiFileManifest = YamlParser::CreateFromPath(multiFileDirectory, validateOption, mergedManifestFile);
VerifyV1ManifestContent(multiFileManifest, false);
// Read from merged manifest should have the same content as multi file manifest
@@ -568,9 +600,11 @@ TEST_CASE("ValidateV1GoodManifestAndVerifyContents", "[ManifestValidation]")
TEST_CASE("ValidateV1_1GoodManifestAndVerifyContents", "[ManifestValidation]")
{
+ ManifestValidateOption validateOption;
+ validateOption.FullValidation = true;
TempDirectory singletonDirectory{ "SingletonManifest" };
CopyTestDataFilesToFolder({ "ManifestV1_1-Singleton.yaml" }, singletonDirectory);
- Manifest singletonManifest = YamlParser::CreateFromPath(singletonDirectory, true, true);
+ Manifest singletonManifest = YamlParser::CreateFromPath(singletonDirectory, validateOption);
VerifyV1ManifestContent(singletonManifest, true, ManifestVer{s_ManifestVersionV1_1});
TempDirectory multiFileDirectory{ "MultiFileManifest" };
@@ -581,7 +615,7 @@ TEST_CASE("ValidateV1_1GoodManifestAndVerifyContents", "[ManifestValidation]")
"ManifestV1_1-MultiFile-Locale.yaml" }, multiFileDirectory);
TempFile mergedManifestFile{ "merged.yaml" };
- Manifest multiFileManifest = YamlParser::CreateFromPath(multiFileDirectory, true, true, mergedManifestFile);
+ Manifest multiFileManifest = YamlParser::CreateFromPath(multiFileDirectory, validateOption, mergedManifestFile);
VerifyV1ManifestContent(multiFileManifest, false, ManifestVer{ s_ManifestVersionV1_1 });
// Read from merged manifest should have the same content as multi file manifest
diff --git a/src/AppInstallerCommonCore/Manifest/ManifestYamlPopulator.cpp b/src/AppInstallerCommonCore/Manifest/ManifestYamlPopulator.cpp
@@ -392,7 +392,7 @@ namespace AppInstaller::Manifest
{
std::vector<FieldProcessInfo> fields_v1_1 =
{
- { "Agreements", [this](const YAML::Node& value)->ValidationErrors { return ProcessAgreementsNode(value); } },
+ { "Agreements", [this](const YAML::Node& value)->ValidationErrors { return ProcessAgreementsNode(value); }, true },
{ "ReleaseNotes", [this](const YAML::Node& value)->ValidationErrors { m_p_localization->Add<Localization::ReleaseNotes>(value.as<std::string>()); return {}; } },
{ "ReleaseNotesUrl", [this](const YAML::Node& value)->ValidationErrors { m_p_localization->Add<Localization::ReleaseNotesUrl>(value.as<std::string>()); return {}; } },
};
@@ -543,6 +543,13 @@ namespace AppInstaller::Manifest
resultErrors.emplace_back(ManifestError::FieldDuplicate, fieldInfo.Name, "", m_isMergedManifest ? 0 : keyValuePair.first.Mark().line, m_isMergedManifest ? 0 : keyValuePair.first.Mark().column);
}
+ if (fieldInfo.RequireVerifiedPublisher)
+ {
+ resultErrors.emplace_back(ManifestError::FieldRequireVerifiedPublisher, fieldInfo.Name, "",
+ m_isMergedManifest ? 0 : keyValuePair.first.Mark().line, m_isMergedManifest ? 0 : keyValuePair.first.Mark().column,
+ m_validateOption.ErrorOnVerifiedPublisherFields ? ValidationError::Level::Error : ValidationError::Level::Warning);
+ }
+
if (!valueNode.IsNull())
{
try
@@ -559,7 +566,7 @@ namespace AppInstaller::Manifest
else
{
// For full validation, also reports unrecognized fields as warning
- if (m_fullValidation)
+ if (m_validateOption.FullValidation)
{
resultErrors.emplace_back(ManifestError::FieldUnknown, key, "", m_isMergedManifest ? 0 : keyValuePair.first.Mark().line, m_isMergedManifest ? 0 : keyValuePair.first.Mark().column, ValidationError::Level::Warning);
}
@@ -664,9 +671,13 @@ namespace AppInstaller::Manifest
return resultErrors;
}
- ValidationErrors ManifestYamlPopulator::PopulateManifestInternal(const YAML::Node& rootNode, Manifest& manifest, const ManifestVer& manifestVersion, bool fullValidation)
+ ValidationErrors ManifestYamlPopulator::PopulateManifestInternal(
+ const YAML::Node& rootNode,
+ Manifest& manifest,
+ const ManifestVer& manifestVersion,
+ ManifestValidateOption validateOption)
{
- m_fullValidation = fullValidation;
+ m_validateOption = validateOption;
m_isMergedManifest = !rootNode["ManifestType"sv].IsNull() && rootNode["ManifestType"sv].as<std::string>() == "merged";
ValidationErrors resultErrors;
@@ -772,9 +783,13 @@ namespace AppInstaller::Manifest
return resultErrors;
}
- ValidationErrors ManifestYamlPopulator::PopulateManifest(const YAML::Node& rootNode, Manifest& manifest, const ManifestVer& manifestVersion, bool fullValidation)
+ ValidationErrors ManifestYamlPopulator::PopulateManifest(
+ const YAML::Node& rootNode,
+ Manifest& manifest,
+ const ManifestVer& manifestVersion,
+ ManifestValidateOption validateOption)
{
ManifestYamlPopulator manifestPopulator;
- return manifestPopulator.PopulateManifestInternal(rootNode, manifest, manifestVersion, fullValidation);
+ return manifestPopulator.PopulateManifestInternal(rootNode, manifest, manifestVersion, validateOption);
}
}
\ No newline at end of file
diff --git a/src/AppInstallerCommonCore/Manifest/YamlParser.cpp b/src/AppInstallerCommonCore/Manifest/YamlParser.cpp
@@ -86,7 +86,7 @@ namespace AppInstaller::Manifest::YamlParser
// - Validate manifest type correctness
// - Allowed file type in multi file manifest: version, installer, defaultLocale, locale
// - Allowed file type in single file manifest: preview manifest, merged and singleton
- ManifestVer ValidateInput(std::vector<YamlManifestInfo>& input, bool fullValidation, bool schemaValidationOnly)
+ ManifestVer ValidateInput(std::vector<YamlManifestInfo>& input, ManifestValidateOption validateOption)
{
std::vector<ValidationError> errors;
@@ -253,7 +253,7 @@ namespace AppInstaller::Manifest::YamlParser
errors.emplace_back(ManifestError::InconsistentMultiFileManifestDefaultLocale);
}
- if (!schemaValidationOnly && !(isVersionManifestFound && isInstallerManifestFound && isDefaultLocaleManifestFound))
+ if (!validateOption.SchemaValidationOnly && !(isVersionManifestFound && isInstallerManifestFound && isDefaultLocaleManifestFound))
{
errors.emplace_back(ManifestError::IncompleteMultiFileManifest);
}
@@ -264,12 +264,12 @@ namespace AppInstaller::Manifest::YamlParser
ManifestTypeEnum manifestType = ConvertToManifestTypeEnum(manifestTypeStr);
firstYamlManifest.ManifestType = manifestType;
- if (fullValidation && manifestType == ManifestTypeEnum::Merged)
+ if (validateOption.FullValidation && manifestType == ManifestTypeEnum::Merged)
{
errors.emplace_back(ValidationError::MessageFieldValueWithFile(ManifestError::FieldValueNotSupported, "ManifestType", manifestTypeStr, firstYamlManifest.FileName));
}
- if (!schemaValidationOnly && manifestType != ManifestTypeEnum::Merged && manifestType != ManifestTypeEnum::Singleton)
+ if (!validateOption.SchemaValidationOnly && manifestType != ManifestTypeEnum::Merged && manifestType != ManifestTypeEnum::Singleton)
{
errors.emplace_back(ValidationError::MessageWithFile(ManifestError::IncompleteMultiFileManifest, firstYamlManifest.FileName));
}
@@ -405,24 +405,23 @@ namespace AppInstaller::Manifest::YamlParser
std::vector<ValidationError> ParseManifestImpl(
std::vector<YamlManifestInfo>& input,
Manifest& manifest,
- bool fullValidation,
const std::filesystem::path& mergedManifestPath,
- bool schemaValidationOnly)
+ ManifestValidateOption validateOption)
{
THROW_HR_IF_MSG(E_INVALIDARG, input.size() == 0, "No manifest file found");
- THROW_HR_IF_MSG(E_INVALIDARG, schemaValidationOnly && !mergedManifestPath.empty(), "Manifest cannot be merged if only schema validation is performed");
+ THROW_HR_IF_MSG(E_INVALIDARG, validateOption.SchemaValidationOnly && !mergedManifestPath.empty(), "Manifest cannot be merged if only schema validation is performed");
THROW_HR_IF_MSG(E_INVALIDARG, input.size() == 1 && !mergedManifestPath.empty(), "Manifest cannot be merged from a single manifest");
- auto manifestVersion = ValidateInput(input, fullValidation, schemaValidationOnly);
+ auto manifestVersion = ValidateInput(input, validateOption);
std::vector<ValidationError> resultErrors;
- if (fullValidation || schemaValidationOnly)
+ if (validateOption.FullValidation || validateOption.SchemaValidationOnly)
{
resultErrors = ValidateAgainstSchema(input, manifestVersion);
}
- if (schemaValidationOnly)
+ if (validateOption.SchemaValidationOnly)
{
return resultErrors;
}
@@ -430,11 +429,11 @@ namespace AppInstaller::Manifest::YamlParser
// Merge manifests in multi file manifest case
const YAML::Node& manifestDoc = (input.size() > 1) ? MergeMultiFileManifest(input) : input[0].Root;
- auto errors = ManifestYamlPopulator::PopulateManifest(manifestDoc, manifest, manifestVersion, fullValidation);
+ auto errors = ManifestYamlPopulator::PopulateManifest(manifestDoc, manifest, manifestVersion, validateOption);
std::move(errors.begin(), errors.end(), std::inserter(resultErrors, resultErrors.end()));
// Extra semantic validations after basic validation and field population
- if (fullValidation)
+ if (validateOption.FullValidation)
{
errors = ValidateManifest(manifest);
std::move(errors.begin(), errors.end(), std::inserter(resultErrors, resultErrors.end()));
@@ -458,10 +457,8 @@ namespace AppInstaller::Manifest::YamlParser
Manifest CreateFromPath(
const std::filesystem::path& inputPath,
- bool fullValidation,
- bool throwOnWarning,
- const std::filesystem::path& mergedManifestPath,
- bool schemaValidationOnly)
+ ManifestValidateOption validateOption,
+ const std::filesystem::path& mergedManifestPath)
{
std::vector<YamlManifestInfo> docList;
@@ -492,15 +489,13 @@ namespace AppInstaller::Manifest::YamlParser
THROW_EXCEPTION_MSG(ManifestException(), e.what());
}
- return ParseManifest(docList, fullValidation, throwOnWarning, mergedManifestPath, schemaValidationOnly);
+ return ParseManifest(docList, validateOption, mergedManifestPath);
}
Manifest Create(
const std::string& input,
- bool fullValidation,
- bool throwOnWarning,
- const std::filesystem::path& mergedManifestPath,
- bool schemaValidationOnly)
+ ManifestValidateOption validateOption,
+ const std::filesystem::path& mergedManifestPath)
{
std::vector<YamlManifestInfo> docList;
@@ -515,22 +510,20 @@ namespace AppInstaller::Manifest::YamlParser
THROW_EXCEPTION_MSG(ManifestException(), e.what());
}
- return ParseManifest(docList, fullValidation, throwOnWarning, mergedManifestPath, schemaValidationOnly);
+ return ParseManifest(docList, validateOption, mergedManifestPath);
}
Manifest ParseManifest(
std::vector<YamlManifestInfo>& input,
- bool fullValidation,
- bool throwOnWarning,
- const std::filesystem::path& mergedManifestPath,
- bool schemaValidationOnly)
+ ManifestValidateOption validateOption,
+ const std::filesystem::path& mergedManifestPath)
{
Manifest manifest;
std::vector<ValidationError> errors;
try
{
- errors = ParseManifestImpl(input, manifest, fullValidation, mergedManifestPath, schemaValidationOnly);
+ errors = ParseManifestImpl(input, manifest, mergedManifestPath, validateOption);
}
catch (const ManifestException&)
{
@@ -546,7 +539,7 @@ namespace AppInstaller::Manifest::YamlParser
{
ManifestException ex{ std::move(errors) };
- if (throwOnWarning || !ex.IsWarningOnly())
+ if (validateOption.ThrowOnWarning || !ex.IsWarningOnly())
{
THROW_EXCEPTION(ex);
}
diff --git a/src/AppInstallerCommonCore/Public/winget/ManifestCommon.h b/src/AppInstallerCommonCore/Public/winget/ManifestCommon.h
@@ -27,6 +27,16 @@ namespace AppInstaller::Manifest
// The manifest extension for the MS Store
constexpr std::string_view s_MSStoreExtension = "msstore"sv;
+ struct ManifestValidateOption
+ {
+ bool SchemaValidationOnly = false;
+ bool ErrorOnVerifiedPublisherFields = false;
+
+ // Options not exposed in winget util
+ bool FullValidation = false;
+ bool ThrowOnWarning = false;
+ };
+
// ManifestVer is inherited from Utility::Version and is a more restricted version.
// ManifestVer is used to specify the version of app manifest itself.
// ManifestVer is a 3 part version in the format of [0-65535].[0-65535].[0-65535]
diff --git a/src/AppInstallerCommonCore/Public/winget/ManifestValidation.h b/src/AppInstallerCommonCore/Public/winget/ManifestValidation.h
@@ -42,6 +42,7 @@ namespace AppInstaller::Manifest
const char* const InvalidBcp47Value = "The locale value is not a well formed bcp47 language tag.";
const char* const BothAllowedAndExcludedMarketsDefined = "Both AllowedMarkets and ExcludedMarkets defined.";
const char* const DuplicateReturnCodeEntry = "Duplicate installer return code found.";
+ const char* const FieldRequireVerifiedPublisher = "Field usage requires verified publishers.";
}
struct ValidationError
diff --git a/src/AppInstallerCommonCore/Public/winget/ManifestYamlParser.h b/src/AppInstallerCommonCore/Public/winget/ManifestYamlParser.h
@@ -24,29 +24,18 @@ namespace AppInstaller::Manifest::YamlParser
ManifestTypeEnum ManifestType = ManifestTypeEnum::Preview;
};
- // fullValidation: Bool to set if manifest creation should perform extra validation that client does not need.
- // e.g. Channel should be null. Client code does not need this check to work properly.
- // throwOnWarning: Bool to indicate if an exception should be thrown with only warnings detected in the manifest.
- // mergedManifestPath: Output file for merged manifest after processing a multi file manifest
- // schemaValidationOnly: Bool to indicate if only schema validation should be performed
Manifest CreateFromPath(
const std::filesystem::path& inputPath,
- bool fullValidation = false,
- bool throwOnWarning = false,
- const std::filesystem::path& mergedManifestPath = {},
- bool schemaValidationOnly = false);
+ ManifestValidateOption validateOption = {},
+ const std::filesystem::path& mergedManifestPath = {});
Manifest Create(
const std::string& input,
- bool fullValidation = false,
- bool throwOnWarning = false,
- const std::filesystem::path& mergedManifestPath = {},
- bool schemaValidationOnly = false);
+ ManifestValidateOption validateOption = {},
+ const std::filesystem::path& mergedManifestPath = {});
Manifest ParseManifest(
std::vector<YamlManifestInfo>& input,
- bool fullValidation = false,
- bool throwOnWarning = false,
- const std::filesystem::path& mergedManifestPath = {},
- bool schemaValidationOnly = false);
+ ManifestValidateOption validateOption = {},
+ const std::filesystem::path& mergedManifestPath = {});
}
\ No newline at end of file
diff --git a/src/AppInstallerCommonCore/Public/winget/ManifestYamlPopulator.h b/src/AppInstallerCommonCore/Public/winget/ManifestYamlPopulator.h
@@ -9,21 +9,26 @@ namespace AppInstaller::Manifest
{
struct ManifestYamlPopulator
{
- static std::vector<ValidationError> PopulateManifest(const YAML::Node& rootNode, Manifest& manifest, const ManifestVer& manifestVersion, bool fullValidation);
+ static std::vector<ValidationError> PopulateManifest(
+ const YAML::Node& rootNode,
+ Manifest& manifest,
+ const ManifestVer& manifestVersion,
+ ManifestValidateOption validateOption);
private:
- bool m_fullValidation = false;
bool m_isMergedManifest = false;
+ ManifestValidateOption m_validateOption;
// Struct mapping a manifest field to its population logic
struct FieldProcessInfo
{
- FieldProcessInfo(std::string name, std::function<std::vector<ValidationError>(const YAML::Node&)> func) :
- Name(std::move(name)), ProcessFunc(func) {}
+ FieldProcessInfo(std::string name, std::function<std::vector<ValidationError>(const YAML::Node&)> func, bool requireVerifiedPublisher = false) :
+ Name(std::move(name)), ProcessFunc(func), RequireVerifiedPublisher(requireVerifiedPublisher) {}
std::string Name;
std::function<std::vector<ValidationError>(const YAML::Node&)> ProcessFunc;
+ bool RequireVerifiedPublisher = false;
};
std::vector<FieldProcessInfo> RootFieldInfos;
@@ -79,6 +84,10 @@ namespace AppInstaller::Manifest
std::vector<ValidationError> ProcessAppsAndFeaturesEntriesNode(const YAML::Node& appsAndFeaturesEntriesNode);
std::vector<ValidationError> ProcessExpectedReturnCodesNode(const YAML::Node& returnCodesNode);
- std::vector<ValidationError> PopulateManifestInternal(const YAML::Node& rootNode, Manifest& manifest, const ManifestVer& manifestVersion, bool fullValidation);
+ std::vector<ValidationError> PopulateManifestInternal(
+ const YAML::Node& rootNode,
+ Manifest& manifest,
+ const ManifestVer& manifestVersion,
+ ManifestValidateOption validateOption);
};
}
\ No newline at end of file
diff --git a/src/WinGetUtil/Exports.cpp b/src/WinGetUtil/Exports.cpp
@@ -183,7 +183,12 @@ extern "C"
try
{
- (void)YamlParser::CreateFromPath(manifestPath, true, true);
+ ManifestValidateOption validateOption;
+ validateOption.FullValidation = true;
+ validateOption.ThrowOnWarning = true;
+
+ (void)YamlParser::CreateFromPath(manifestPath, validateOption);
+
*succeeded = TRUE;
}
catch (const ManifestException& e)
@@ -211,9 +216,14 @@ extern "C"
try
{
- (void)YamlParser::CreateFromPath(inputPath, true, true,
- mergedManifestPath ? mergedManifestPath : L"",
- option == WinGetValidateManifestOption::SchemaValidationOnly);
+ ManifestValidateOption validateOption;
+ validateOption.FullValidation = true;
+ validateOption.ThrowOnWarning = true;
+ validateOption.SchemaValidationOnly = WI_IsFlagSet(option, WinGetValidateManifestOption::SchemaValidationOnly);
+ validateOption.ErrorOnVerifiedPublisherFields = WI_IsFlagSet(option, WinGetValidateManifestOption::ErrorOnVerifiedPublisherFields);
+
+ (void)YamlParser::CreateFromPath(inputPath, validateOption, mergedManifestPath ? mergedManifestPath : L"");
+
*succeeded = TRUE;
}
catch (const ManifestException& e)
diff --git a/src/WinGetUtil/WinGetUtil.h b/src/WinGetUtil/WinGetUtil.h
@@ -19,10 +19,13 @@ extern "C"
enum WinGetValidateManifestOption
{
- Default,
- SchemaValidationOnly
+ Default = 0,
+ SchemaValidationOnly = 0x1,
+ ErrorOnVerifiedPublisherFields = 0x2,
};
+ DEFINE_ENUM_FLAG_OPERATORS(WinGetValidateManifestOption);
+
// Initializes the logging infrastructure.
WINGET_UTIL_API WinGetLoggingInit(
WINGET_STRING logPath);
diff --git a/src/WinGetYamlFuzzing/WinGetYamlFuzzing.cpp b/src/WinGetYamlFuzzing/WinGetYamlFuzzing.cpp
@@ -10,7 +10,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t * data, size_t size)
try
{
- AppInstaller::Manifest::Manifest manifest = AppInstaller::Manifest::YamlParser::Create(input, false);
+ AppInstaller::Manifest::Manifest manifest = AppInstaller::Manifest::YamlParser::Create(input);
}
catch (...) {}