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

Yaml manifest schemaheader validation for V.1.10.0 and above #5126

Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
8b9fce6
Add schema header validation for YAML manifests V.1.10.0 and above
Madhusudhan-MSFT Jan 12, 2025
4db7583
Treat schema header validation errors as warnings for 'winget validat…
Madhusudhan-MSFT Jan 12, 2025
c60d267
Add tests for YAML Manifest schema header validations
Madhusudhan-MSFT Jan 12, 2025
c8e69e3
Extend Add schema header validation tests for WinGet CLI Validation c…
Madhusudhan-MSFT Jan 12, 2025
8065a7a
Update error message in ManifestV1_10 test case
Madhusudhan-MSFT Jan 12, 2025
f594f1b
Fix typo in test manifest file path in two test files
Madhusudhan-MSFT Jan 12, 2025
1d27243
Enhance YAML manifest schema header validation
Madhusudhan-MSFT Jan 12, 2025
bd4fd24
Fix casing in YAML language server schema URL comment
Madhusudhan-MSFT Jan 12, 2025
4b18e9e
Fix casing in YAML language server schema URL to address ValidateV1_1…
Madhusudhan-MSFT Jan 12, 2025
097ee92
Addressing PR review comments: Simplify schema header validation erro…
Madhusudhan-MSFT Jan 14, 2025
7d9c4f2
Fix formatting issues in ValidateCommand.cs
Madhusudhan-MSFT Jan 14, 2025
ea00978
[PRFeedback:] Refactor YAML schema header handling
Madhusudhan-MSFT Jan 15, 2025
8607fbb
Fix typo in AddSchemaHeader parameter name
Madhusudhan-MSFT Jan 15, 2025
91f1fb2
Fix visual studio editor introduced encoding character issue with the…
Madhusudhan-MSFT Jan 15, 2025
ad62417
Revert chagnes ValidateCommand.cs and replacing it with orginal file …
Madhusudhan-MSFT Jan 15, 2025
001e610
Bring back validatecommand schema header tests.
Jan 15, 2025
812f547
PRFeedback: Refactor YAML schema handling and improve maintainability
Madhusudhan-MSFT Jan 17, 2025
db264b6
Optimize YamlParser with move semantics
Madhusudhan-MSFT Jan 17, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/AppInstallerCLICore/Commands/ValidateCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ namespace AppInstaller::CLI
{
ManifestValidateOption validateOption;
validateOption.FullValidation = true;
validateOption.SchemaHeaderValidationAsWarning = true;
Madhusudhan-MSFT marked this conversation as resolved.
Show resolved Hide resolved
validateOption.ThrowOnWarning = !(context.Args.Contains(Execution::Args::Type::IgnoreWarnings));
auto manifest = YamlParser::CreateFromPath(inputFile, validateOption);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# yaml-language-server: $schema=https://aka.ms/winget-manifest.singleton.1.10.0.schema.json
PackageIdentifier: AppInstallerCliTest.SchemaHeader
PackageVersion: 1.0.0.0
PackageLocale: en-US
PackageName: AppInstaller Test Schema Header
Publisher: Microsoft Corporation
License: Test
ShortDescription: This manifest with schema header

Installers:
- Architecture: x86
InstallerUrl: https://ThisIsNotUsed
InstallerType: msi
InstallerSha256: 65DB2F2AC2686C7F2FD69D4A4C6683B888DC55BFA20A0E32CA9F838B51689A3B
ManifestType: singleton
ManifestVersion: 1.10.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# yaml-language-server= $schema=https://aka.ms/winget-manifest.singleton.1.10.0.schema.json
PackageIdentifier: AppInstallerCliTest.SchemaHeaderInvalid
PackageVersion: 1.0.0.0
PackageLocale: en-US
PackageName: AppInstaller Test Schema Header Invalid
Publisher: Microsoft Corporation
License: Test
ShortDescription: This manifest has an invalid schema header

Installers:
- Architecture: x86
InstallerUrl: https://ThisIsNotUsed
InstallerType: msi
InstallerSha256: 65DB2F2AC2686C7F2FD69D4A4C6683B888DC55BFA20A0E32CA9F838B51689A3B
ManifestType: singleton
ManifestVersion: 1.10.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# yaml-language-server: $schema=https://aka.ms/winget-manifest.installer.1.10.0.schema.json
PackageIdentifier: AppInstallerCliTest.SchemaHeaderManifestTypeMismatch
PackageVersion: 1.0.0.0
PackageLocale: en-US
PackageName: AppInstaller Test Schema Header ManifestType Mismatch
Publisher: Microsoft Corporation
License: Test
ShortDescription: This manifest has a mismatched ManisfestType in the schema header

Installers:
- Architecture: x86
InstallerUrl: https://ThisIsNotUsed
InstallerType: msi
InstallerSha256: 65DB2F2AC2686C7F2FD69D4A4C6683B888DC55BFA20A0E32CA9F838B51689A3B
ManifestType: singleton
ManifestVersion: 1.10.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
PackageIdentifier: AppInstallerCliTest.SchemaHeaderNotFound
PackageVersion: 1.0.0.0
PackageLocale: en-US
PackageName: AppInstaller Test Schema Header Not Found
Publisher: Microsoft Corporation
License: Test
ShortDescription: This manifest has a missing schema header

Installers:
- Architecture: x86
InstallerUrl: https://ThisIsNotUsed
InstallerType: msi
InstallerSha256: 65DB2F2AC2686C7F2FD69D4A4C6683B888DC55BFA20A0E32CA9F838B51689A3B
ManifestType: singleton
ManifestVersion: 1.10.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# yaml-language-server: $schema=https://aka.ms/winget-manifest-invalid.singleton.1.10.0.schema.json
PackageIdentifier: AppInstallerCliTest.SchemaHeaderURLPatternMismatch
PackageVersion: 1.0.0.0
PackageLocale: en-US
PackageName: AppInstaller Test Schema Header URL Pattern Mismatch
Publisher: Microsoft Corporation
License: Test
ShortDescription: This manifest has a mismatched schema header URL pattern

Installers:
- Architecture: x86
InstallerUrl: https://ThisIsNotUsed
InstallerType: msi
InstallerSha256: 65DB2F2AC2686C7F2FD69D4A4C6683B888DC55BFA20A0E32CA9F838B51689A3B
ManifestType: singleton
ManifestVersion: 1.10.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# yaml-language-server: $schema=https://aka.ms/winget-manifest.singleton.1.9.0.schema.json
PackageIdentifier: AppInstallerCliTest.SchemaHeaderVersionMismatch
PackageVersion: 1.0.0.0
PackageLocale: en-US
PackageName: AppInstaller Test Schema Header ManifestVersion Mismatch
Publisher: Microsoft Corporation
License: Test
ShortDescription: This manifest has a mismatched ManisfestVersion in the schema header

Installers:
- Architecture: x86
InstallerUrl: https://ThisIsNotUsed
InstallerType: msi
InstallerSha256: 65DB2F2AC2686C7F2FD69D4A4C6683B888DC55BFA20A0E32CA9F838B51689A3B
ManifestType: singleton
ManifestVersion: 1.10.0
46 changes: 44 additions & 2 deletions src/AppInstallerCLIE2ETests/ValidateCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public void ValidateManifest()
[Test]
public void ValidateManifestWithExtendedCharacter()
{
var result = TestCommon.RunAICLICommand("validate", TestCommon.GetTestDataFile("Manifests\\TëstExeInstaller.yaml"));
var result = TestCommon.RunAICLICommand("validate", TestCommon.GetTestDataFile("Manifests\\TëstExeInstaller.yaml"));
Madhusudhan-MSFT marked this conversation as resolved.
Show resolved Hide resolved
Assert.AreEqual(Constants.ErrorCode.S_OK, result.ExitCode);
Assert.True(result.StdOut.Contains("Manifest validation succeeded."));
}
Expand Down Expand Up @@ -80,5 +80,47 @@ public void ValidateManifestDoesNotExist()
Assert.AreEqual(Constants.ErrorCode.ERROR_PATH_NOT_FOUND, result.ExitCode);
Assert.True(result.StdOut.Contains("Path does not exist"));
}

/// <summary>
/// Test validate manifest with invalid schema and expect warnings.
/// </summary>
[Test]
public void ValidateManifestV1_10_SchemaHeaderExpectWarnings()
{
var result = TestCommon.RunAICLICommand("validate", TestCommon.GetTestDataFile("Manifests\\TestWarningManifestV1_10-SchemaHeaderNotFound.yaml"));
Assert.AreEqual(Constants.ErrorCode.ERROR_MANIFEST_VALIDATION_WARNING, result.ExitCode);
Assert.True(result.StdOut.Contains("Manifest validation succeeded with warnings."));
Assert.True(result.StdOut.Contains("Manifest Warning: Schema header not found."));

result = TestCommon.RunAICLICommand("validate", TestCommon.GetTestDataFile("Manifests\\TestWarningManifestV1_10-SchemaHeaderInvalid.yaml"));
Assert.AreEqual(Constants.ErrorCode.ERROR_MANIFEST_VALIDATION_WARNING, result.ExitCode);
Assert.True(result.StdOut.Contains("Manifest validation succeeded with warnings."));
Assert.True(result.StdOut.Contains("Manifest Warning: The schema header is invalid. Please verify that the schema header is present and formatted correctly as a valid YAML node with the appropriate commented syntax."));

result = TestCommon.RunAICLICommand("validate", TestCommon.GetTestDataFile("Manifests\\TestWarningManifestV1_10-SchemaHeaderURLPatternMismatch.yaml"));
Assert.AreEqual(Constants.ErrorCode.ERROR_MANIFEST_VALIDATION_WARNING, result.ExitCode);
Assert.True(result.StdOut.Contains("Manifest validation succeeded with warnings."));
Assert.True(result.StdOut.Contains("Manifest Warning: The schema header URL does not match the expected pattern"));

result = TestCommon.RunAICLICommand("validate", TestCommon.GetTestDataFile("Manifests\\TestWarningManifestV1_10-SchemaHeaderManifestTypeMismatch.yaml"));
Assert.AreEqual(Constants.ErrorCode.ERROR_MANIFEST_VALIDATION_WARNING, result.ExitCode);
Assert.True(result.StdOut.Contains("Manifest validation succeeded with warnings."));
Assert.True(result.StdOut.Contains("Manifest Warning: The manifest type in the schema header does not match the ManifestType property value in the manifest."));

result = TestCommon.RunAICLICommand("validate", TestCommon.GetTestDataFile("Manifests\\TestWarningManifestV1_10-SchemaHeaderVersionMismatch.yaml"));
Assert.AreEqual(Constants.ErrorCode.ERROR_MANIFEST_VALIDATION_WARNING, result.ExitCode);
Assert.True(result.StdOut.Contains("Manifest validation succeeded with warnings."));
Assert.True(result.StdOut.Contains("Manifest Warning: The manifest version in the schema header does not match the ManifestVersion property value in the manifest."));
}

/// <summary>
/// Test validate manifest with valid schema header.
/// </summary>
[Test]
public void ValidateManifestV1_10_SchemaHeaderExpectNoWarning()
{
var result = TestCommon.RunAICLICommand("validate", TestCommon.GetTestDataFile("Manifests\\TestGoodManifestV1_10-SchemaHeader.yaml"));
Assert.AreEqual(Constants.ErrorCode.S_OK, result.ExitCode);
}
}
}
}
85 changes: 82 additions & 3 deletions src/AppInstallerCLIE2ETests/WinGetUtil/WinGetUtilManifest.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// <copyright file="WinGetUtilManifest.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation. Licensed under the MIT License.
// </copyright>
Expand Down Expand Up @@ -80,6 +80,85 @@ public void WinGetUtil_ValidateManifest_Success(WinGetUtilWrapper.CreateManifest

// Close manifest
WinGetUtilWrapper.WinGetCloseManifest(manifestHandle);
}
}
}

/// <summary>
/// Test validate manifest with schema header.
/// </summary>
/// <param name="createManifestOption">Create manifest options.</param>
[Test]
[TestCase(WinGetUtilWrapper.CreateManifestOption.NoValidation)]
[TestCase(WinGetUtilWrapper.CreateManifestOption.SchemaAndSemanticValidation)]
public void WinGetUtil_ValidateManifest_V1_10_WithSchemaHeader_Success(WinGetUtilWrapper.CreateManifestOption createManifestOption)
{
string manifestsFilePath = TestCommon.GetTestDataFile(@"Manifests\TestGoodManifestV1_10-SchemaHeader.yaml");

// Create manifest
WinGetUtilWrapper.WinGetCreateManifest(
manifestsFilePath,
out bool succeeded,
out IntPtr manifestHandle,
out string createFailureMessage,
string.Empty,
createManifestOption);

Assert.True(succeeded);
Assert.AreNotEqual(IntPtr.Zero, manifestHandle);
Assert.IsNull(createFailureMessage);

// Close manifest
WinGetUtilWrapper.WinGetCloseManifest(manifestHandle);
}

/// <summary>
/// Test validate manifest with schema header for failure scenarios.
/// </summary>
/// <param name="createManifestOption">Create manifest options.</param>
[Test]
[TestCase(WinGetUtilWrapper.CreateManifestOption.SchemaAndSemanticValidation)]
public void WinGetUtil_ValidateManifest_V1_10_WithSchemaHeader_Failure(WinGetUtilWrapper.CreateManifestOption createManifestOption)
{
// Schema header not found
string manifestsFilePath = TestCommon.GetTestDataFile(@"Manifests\TestWarningManifestV1_10-SchemaHeaderNotFound.yaml");
string expectedError = "Manifest Error: Schema header not found.";
this.ValidateSchemaHeaderFailure(manifestsFilePath, createManifestOption, expectedError);

// Schema header invalid
manifestsFilePath = TestCommon.GetTestDataFile(@"Manifests\TestWarningManifestV1_10-SchemaHeaderInvalid.yaml");
expectedError = "Manifest Error: The schema header is invalid. Please verify that the schema header is present and formatted correctly as a valid YAML node with the appropriate commented syntax.";
this.ValidateSchemaHeaderFailure(manifestsFilePath, createManifestOption, expectedError);

// Schema header URL pattern mismatch
manifestsFilePath = TestCommon.GetTestDataFile(@"Manifests\TestWarningManifestV1_10-SchemaHeaderURLPatternMismatch.yaml");
expectedError = "Manifest Error: The schema header URL does not match the expected pattern.";
this.ValidateSchemaHeaderFailure(manifestsFilePath, createManifestOption, expectedError);

// Schema header manifest type mismatch
manifestsFilePath = TestCommon.GetTestDataFile(@"Manifests\TestWarningManifestV1_10-SchemaHeaderManifestTypeMismatch.yaml");
expectedError = "Manifest Error: The manifest type in the schema header does not match the ManifestType property value in the manifest.";
this.ValidateSchemaHeaderFailure(manifestsFilePath, createManifestOption, expectedError);

// Schema header version mismatch
manifestsFilePath = TestCommon.GetTestDataFile(@"Manifests\TestWarningManifestV1_10-SchemaHeaderVersionMismatch.yaml");
expectedError = "Manifest Error: The manifest version in the schema header does not match the ManifestVersion property value in the manifest.";
this.ValidateSchemaHeaderFailure(manifestsFilePath, createManifestOption, expectedError);
}

private void ValidateSchemaHeaderFailure(string manifestsFilePath, WinGetUtilWrapper.CreateManifestOption createManifestOption, string expectedError)
{
// Create manifest
WinGetUtilWrapper.WinGetCreateManifest(
manifestsFilePath,
out bool succeeded,
out IntPtr manifestHandle,
out string createFailureMessage,
string.Empty,
createManifestOption);

Assert.False(succeeded);
Assert.AreEqual(IntPtr.Zero, manifestHandle);
Assert.IsNotNull(createFailureMessage);
Assert.IsTrue(createFailureMessage.Contains(expectedError));
}
}
}
17 changes: 16 additions & 1 deletion src/AppInstallerCLITests/AppInstallerCLITests.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1033,6 +1033,21 @@
<CopyFileToFolders Include="TestData\ContainsEscapeControlCode.yaml">
<DeploymentContent>true</DeploymentContent>
</CopyFileToFolders>
<CopyFileToFolders Include="TestData\ManifestV1_10-Bad-SchemaHeaderInvalid.yaml">
<DeploymentContent>true</DeploymentContent>
</CopyFileToFolders>
<CopyFileToFolders Include="TestData\ManifestV1_10-Bad-SchemaHeaderManifestTypeMismatch.yaml">
<DeploymentContent>true</DeploymentContent>
</CopyFileToFolders>
<CopyFileToFolders Include="TestData\ManifestV1_10-Bad-SchemaHeaderManifestVersionMismatch.yaml">
<DeploymentContent>true</DeploymentContent>
</CopyFileToFolders>
<CopyFileToFolders Include="TestData\ManifestV1_10-Bad-SchemaHeaderNotFound.yaml">
<DeploymentContent>true</DeploymentContent>
</CopyFileToFolders>
<CopyFileToFolders Include="TestData\ManifestV1_10-Bad-SchemaHeaderURLPatternMismatch.yaml">
<DeploymentContent>true</DeploymentContent>
</CopyFileToFolders>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AppInstallerCLICore\AppInstallerCLICore.vcxproj">
Expand Down Expand Up @@ -1076,4 +1091,4 @@
<Error Condition="!Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.230706.1\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.230706.1\build\native\Microsoft.Windows.CppWinRT.props'))" />
<Error Condition="!Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.230706.1\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.230706.1\build\native\Microsoft.Windows.CppWinRT.targets'))" />
</Target>
</Project>
</Project>
15 changes: 15 additions & 0 deletions src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -1044,5 +1044,20 @@
<CopyFileToFolders Include="TestData\ContainsEscapeControlCode.yaml">
<Filter>TestData</Filter>
</CopyFileToFolders>
<CopyFileToFolders Include="TestData\ManifestV1_10-Bad-SchemaHeaderInvalid.yaml">
<Filter>TestData</Filter>
</CopyFileToFolders>
<CopyFileToFolders Include="TestData\ManifestV1_10-Bad-SchemaHeaderManifestTypeMismatch.yaml">
<Filter>TestData</Filter>
</CopyFileToFolders>
<CopyFileToFolders Include="TestData\ManifestV1_10-Bad-SchemaHeaderManifestVersionMismatch.yaml">
<Filter>TestData</Filter>
</CopyFileToFolders>
<CopyFileToFolders Include="TestData\ManifestV1_10-Bad-SchemaHeaderNotFound.yaml">
<Filter>TestData</Filter>
</CopyFileToFolders>
<CopyFileToFolders Include="TestData\ManifestV1_10-Bad-SchemaHeaderURLPatternMismatch.yaml">
<Filter>TestData</Filter>
</CopyFileToFolders>
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# yaml-language-server= $schema=https://aka.ms/winget-manifest.singleton.1.10.0.schema.json
PackageIdentifier: AppInstallerCliTest.SchemaHeaderInvalid
PackageVersion: 1.0.0.0
PackageLocale: en-US
PackageName: AppInstaller Test Schema Header Invalid
Publisher: Microsoft Corporation
License: Test
ShortDescription: This manifest has an invalid schema header

Installers:
- Architecture: x86
InstallerUrl: https://ThisIsNotUsed
InstallerType: msi
InstallerSha256: 65DB2F2AC2686C7F2FD69D4A4C6683B888DC55BFA20A0E32CA9F838B51689A3B
ManifestType: singleton
ManifestVersion: 1.10.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# yaml-language-server: $schema=https://aka.ms/winget-manifest.installer.1.10.0.schema.json
PackageIdentifier: AppInstallerCliTest.SchemaHeaderManifestTypeMismatch
PackageVersion: 1.0.0.0
PackageLocale: en-US
PackageName: AppInstaller Test Schema Header ManifestType Mismatch
Publisher: Microsoft Corporation
License: Test
ShortDescription: This manifest has a mismatched ManisfestType in the schema header

Installers:
- Architecture: x86
InstallerUrl: https://ThisIsNotUsed
InstallerType: msi
InstallerSha256: 65DB2F2AC2686C7F2FD69D4A4C6683B888DC55BFA20A0E32CA9F838B51689A3B
ManifestType: singleton
ManifestVersion: 1.10.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# yaml-language-server: $schema=https://aka.ms/winget-manifest.singleton.1.9.0.schema.json
PackageIdentifier: AppInstallerCliTest.SchemaHeaderVersionMismatch
PackageVersion: 1.0.0.0
PackageLocale: en-US
PackageName: AppInstaller Test Schema Header ManifestVersion Mismatch
Publisher: Microsoft Corporation
License: Test
ShortDescription: This manifest has a mismatched ManisfestVersion in the schema header

Installers:
- Architecture: x86
InstallerUrl: https://ThisIsNotUsed
InstallerType: msi
InstallerSha256: 65DB2F2AC2686C7F2FD69D4A4C6683B888DC55BFA20A0E32CA9F838B51689A3B
ManifestType: singleton
ManifestVersion: 1.10.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
PackageIdentifier: AppInstallerCliTest.SchemaHeaderNotFound
PackageVersion: 1.0.0.0
PackageLocale: en-US
PackageName: AppInstaller Test Schema Header Not Found
Publisher: Microsoft Corporation
License: Test
ShortDescription: This manifest has a missing schema header

Installers:
- Architecture: x86
InstallerUrl: https://ThisIsNotUsed
InstallerType: msi
InstallerSha256: 65DB2F2AC2686C7F2FD69D4A4C6683B888DC55BFA20A0E32CA9F838B51689A3B
ManifestType: singleton
ManifestVersion: 1.10.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# yaml-language-server: $schema=https://aka.ms/winget-manifest-invalid.singleton.1.10.0.schema.json
PackageIdentifier: AppInstallerCliTest.SchemaHeaderURLPatternMismatch
PackageVersion: 1.0.0.0
PackageLocale: en-US
PackageName: AppInstaller Test Schema Header URL Pattern Mismatch
Publisher: Microsoft Corporation
License: Test
ShortDescription: This manifest has a mismatched schema header URL pattern

Installers:
- Architecture: x86
InstallerUrl: https://ThisIsNotUsed
InstallerType: msi
InstallerSha256: 65DB2F2AC2686C7F2FD69D4A4C6683B888DC55BFA20A0E32CA9F838B51689A3B
ManifestType: singleton
ManifestVersion: 1.10.0
Loading
Loading