Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 doc/ReleaseNotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,4 @@ The PowerShell module now automatically uses `GH_TOKEN` or `GITHUB_TOKEN` enviro
* `SignFile` in `WinGetSourceCreator` now supports an optional RFC 3161 timestamp server via the new `TimestampServer` property on the `Signature` model. When set, `signtool.exe` is called with `/tr <url> /td sha256`, embedding a countersignature timestamp so that signed packages remain valid after the signing certificate expires.
* File and directory paths passed to `signtool.exe` and `makeappx.exe` are now quoted, fixing failures when paths contain spaces.
* DSC export now correctly exports WinGet Admin Settings
* `winget validate` now performs case-insensitive comparison for file extensions where applicable
3 changes: 3 additions & 0 deletions src/AppInstallerCLITests/AppInstallerCLITests.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1048,6 +1048,9 @@
<CopyFileToFolders Include="TestData\Manifest-Good-InstallerTypeZip-PortableExe.yaml">
<DeploymentContent>true</DeploymentContent>
</CopyFileToFolders>
<CopyFileToFolders Include="TestData\Manifest-Good-InstallerTypeZip-PortableExeUppercase.yaml">
<DeploymentContent>true</DeploymentContent>
</CopyFileToFolders>
<CopyFileToFolders Include="TestData\Manifest-Bad-InstallerTypeZip-PortableNotExe.yaml">
<DeploymentContent>true</DeploymentContent>
</CopyFileToFolders>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1119,6 +1119,9 @@
<CopyFileToFolders Include="TestData\Manifest-Good-InstallerTypeZip-PortableExe.yaml">
<Filter>TestData</Filter>
</CopyFileToFolders>
<CopyFileToFolders Include="TestData\Manifest-Good-InstallerTypeZip-PortableExeUppercase.yaml">
<Filter>TestData</Filter>
</CopyFileToFolders>
<CopyFileToFolders Include="TestData\Manifest-Bad-InstallerTypeZip-PortableNotExe.yaml">
<Filter>TestData</Filter>
</CopyFileToFolders>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Good manifest. Installer type zip with NestedInstallerType portable should allow uppercase .EXE files
# yaml-language-server: $schema=https://aka.ms/winget-manifest.singleton.1.9.0.schema.json

PackageIdentifier: microsoft.msixsdk
PackageVersion: 1.0.0.0
PackageLocale: en-US
PackageName: AppInstaller Test Installer
Publisher: Microsoft Corporation
Moniker: AICLITestExe
License: Test
ShortDescription: Test installer for zip with uppercase .EXE extension
Installers:
- Architecture: x64
InstallerUrl: https://ThisIsNotUsed
InstallerType: zip
NestedInstallerType: portable
InstallerSha256: 65DB2F2AC2686C7F2FD69D4A4C6683B888DC55BFA20A0E32CA9F838B51689A3B
NestedInstallerFiles:
- RelativeFilePath: GoodApplication.EXE
ManifestType: singleton
ManifestVersion: 1.9.0
6 changes: 6 additions & 0 deletions src/AppInstallerCLITests/YamlManifest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -842,6 +842,7 @@ TEST_CASE("ReadGoodManifests", "[ManifestValidation]")
{ "Manifest-Good-Switches.yaml" },
{ "Manifest-Good-DefaultExpectedReturnCodeInInstallerSuccessCodes.yaml" },
{ "Manifest-Good-InstallerTypeZip-PortableExe.yaml" },
{ "Manifest-Good-InstallerTypeZip-PortableExeUppercase.yaml" },
};

for (auto const& testCase : TestCases)
Expand Down Expand Up @@ -1348,6 +1349,7 @@ TEST_CASE("PortableFileTypeValidation", "[ManifestValidation]")
{
Manifest installerManifest = YamlParser::CreateFromPath(TestDataFile("Manifest-Bad-InstallerTypeZip-PortableNotExe.yaml"));
Manifest rootManifest = YamlParser::CreateFromPath(TestDataFile("Manifest-Bad-InstallerTypeZip-PortableNotExe_Root.yaml"));
Manifest uppercaseManifest = YamlParser::CreateFromPath(TestDataFile("Manifest-Good-InstallerTypeZip-PortableExeUppercase.yaml"));

// Regular validation should detect as error
auto errors = ValidateManifest(installerManifest, true);
Expand All @@ -1364,6 +1366,10 @@ TEST_CASE("PortableFileTypeValidation", "[ManifestValidation]")

errors = ValidateManifest(rootManifest, false);
REQUIRE(errors.size() == 0);

// Uppercase file extension should be accepted (case-insensitive comparison)
errors = ValidateManifest(uppercaseManifest, true);
REQUIRE(errors.size() == 0);
}

TEST_CASE("WindowsFeatureNameValidation", "[ManifestValidation][111981]")
Expand Down
6 changes: 4 additions & 2 deletions src/AppInstallerCommonCore/Manifest/ManifestValidation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -370,17 +370,19 @@ namespace AppInstaller::Manifest
// If running full validation, check filetype
if (options.FullValidation)
{
const std::wstring lowerExtension = Utility::ToLower(fullPath.extension().wstring());

if (isPortable)
{
if (fullPath.has_extension() && std::find(s_AllowedPortableFiletypes.begin(), s_AllowedPortableFiletypes.end(), fullPath.extension()) == s_AllowedPortableFiletypes.end())
if (fullPath.has_extension() && std::find(s_AllowedPortableFiletypes.begin(), s_AllowedPortableFiletypes.end(), lowerExtension) == s_AllowedPortableFiletypes.end())
{
resultErrors.emplace_back(ManifestError::InvalidPortableFiletype, "RelativeFilePath", nestedInstallerFile.RelativeFilePath);
}
}

if (isFont)
{
if (fullPath.has_extension() && std::find(s_AllowedFontFiletypes.begin(), s_AllowedFontFiletypes.end(), fullPath.extension()) == s_AllowedFontFiletypes.end())
if (fullPath.has_extension() && std::find(s_AllowedFontFiletypes.begin(), s_AllowedFontFiletypes.end(), lowerExtension) == s_AllowedFontFiletypes.end())
{
resultErrors.emplace_back(ManifestError::InvalidFontFiletype, "RelativeFilePath", nestedInstallerFile.RelativeFilePath);
}
Expand Down