From fbeb202d6c24ec2c5324c62f2d9e94bec4b2a729 Mon Sep 17 00:00:00 2001 From: "Slai.life" Date: Fri, 30 Oct 2026 17:49:18 +0800 Subject: [PATCH] Skip approved archive scans before loading large ZIPs --- .../1.31/6632-local-archive-scan-override.md | 5 +++ src/AppInstallerCLICore/Resources.h | 2 +- .../Workflows/ArchiveFlow.cpp | 43 ++++++++++--------- .../Shared/Strings/en-us/winget.resw | 4 +- src/AppInstallerCLITests/InstallFlow.cpp | 6 ++- src/AppInstallerCLITests/TestHooks.h | 22 ++++++++++ src/AppInstallerCommonCore/Archive.cpp | 11 +++++ 7 files changed, 67 insertions(+), 26 deletions(-) create mode 100644 doc/release-notes/1.31/6632-local-archive-scan-override.md diff --git a/doc/release-notes/1.31/6632-local-archive-scan-override.md b/doc/release-notes/1.31/6632-local-archive-scan-override.md new file mode 100644 index 0000000000..ab52ed1542 --- /dev/null +++ b/doc/release-notes/1.31/6632-local-archive-scan-override.md @@ -0,0 +1,5 @@ +## Bug Fixes + +### Minor Bug Fixes + +* Skip the local archive malware scan immediately when its approved override is requested, avoiding unnecessary memory use for large archive installs. \ No newline at end of file diff --git a/src/AppInstallerCLICore/Resources.h b/src/AppInstallerCLICore/Resources.h index 4b574f5155..4c93ecd812 100644 --- a/src/AppInstallerCLICore/Resources.h +++ b/src/AppInstallerCLICore/Resources.h @@ -31,7 +31,7 @@ namespace AppInstaller::CLI::Resource WINGET_DEFINE_RESOURCE_STRINGID(AllowRebootArgumentDescription); WINGET_DEFINE_RESOURCE_STRINGID(ArchitectureArgumentDescription); WINGET_DEFINE_RESOURCE_STRINGID(ArchiveFailedMalwareScan); - WINGET_DEFINE_RESOURCE_STRINGID(ArchiveFailedMalwareScanOverridden); + WINGET_DEFINE_RESOURCE_STRINGID(ArchiveMalwareScanSkipped); WINGET_DEFINE_RESOURCE_STRINGID(ArgumentForSinglePackageProvidedWithMultipleQueries); WINGET_DEFINE_RESOURCE_STRINGID(AuthenticationAccountArgumentDescription); WINGET_DEFINE_RESOURCE_STRINGID(AuthenticationModeArgumentDescription); diff --git a/src/AppInstallerCLICore/Workflows/ArchiveFlow.cpp b/src/AppInstallerCLICore/Workflows/ArchiveFlow.cpp index 912b394ee2..3e1925f190 100644 --- a/src/AppInstallerCLICore/Workflows/ArchiveFlow.cpp +++ b/src/AppInstallerCLICore/Workflows/ArchiveFlow.cpp @@ -19,29 +19,30 @@ namespace AppInstaller::CLI::Workflow void ScanArchiveFromLocalManifest(Execution::Context& context) { - if (context.Args.Contains(Execution::Args::Type::Manifest)) + if (!context.Args.Contains(Execution::Args::Type::Manifest)) { - bool scanResult = Archive::ScanZipFile(context.Get()); + return; + } - if (scanResult) - { - AICLI_LOG(CLI, Info, << "Archive malware scan passed"); - } - else - { - if (context.Args.Contains(Execution::Args::Type::IgnoreLocalArchiveMalwareScan) && - Settings::IsAdminSettingEnabled(Settings::BoolAdminSetting::LocalArchiveMalwareScanOverride)) - { - AICLI_LOG(CLI, Warning, << "Archive scan detected malware. Proceeding due to --ignore-local-archive-malware-scan"); - context.Reporter.Warn() << Resource::String::ArchiveFailedMalwareScanOverridden << std::endl; - } - else - { - AICLI_LOG(CLI, Error, << "Archive malware scan failed"); - context.Reporter.Error() << Resource::String::ArchiveFailedMalwareScan << std::endl; - AICLI_TERMINATE_CONTEXT(APPINSTALLER_CLI_ERROR_ARCHIVE_SCAN_FAILED); - } - } + if (context.Args.Contains(Execution::Args::Type::IgnoreLocalArchiveMalwareScan) && + Settings::IsAdminSettingEnabled(Settings::BoolAdminSetting::LocalArchiveMalwareScanOverride)) + { + AICLI_LOG(CLI, Warning, << "Skipping local archive malware scan due to --ignore-local-archive-malware-scan"); + context.Reporter.Warn() << Resource::String::ArchiveMalwareScanSkipped << std::endl; + return; + } + + bool scanResult = Archive::ScanZipFile(context.Get()); + + if (scanResult) + { + AICLI_LOG(CLI, Info, << "Archive malware scan passed"); + } + else + { + AICLI_LOG(CLI, Error, << "Archive malware scan failed"); + context.Reporter.Error() << Resource::String::ArchiveFailedMalwareScan << std::endl; + AICLI_TERMINATE_CONTEXT(APPINSTALLER_CLI_ERROR_ARCHIVE_SCAN_FAILED); } } diff --git a/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw b/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw index af04b9f319..40c0cc1d01 100644 --- a/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw +++ b/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw @@ -1618,8 +1618,8 @@ Please specify one of them using the --source option to proceed. Archive scan detected malware. To override this check use --ignore-local-archive-malware-scan {Locked="--ignore-local-archive-malware-scan"} - - Archive scan detected malware. Proceeding due to --ignore-local-archive-malware-scan + + Archive malware scan skipped due to --ignore-local-archive-malware-scan {Locked="--ignore-local-archive-malware-scan"} diff --git a/src/AppInstallerCLITests/InstallFlow.cpp b/src/AppInstallerCLITests/InstallFlow.cpp index 30bf3da050..a9eee5fd8d 100644 --- a/src/AppInstallerCLITests/InstallFlow.cpp +++ b/src/AppInstallerCLITests/InstallFlow.cpp @@ -486,13 +486,15 @@ TEST_CASE("InstallFlow_Zip_ArchiveScanOverride_AdminSettingEnabled", "[InstallFl EnableAdminSetting(AppInstaller::Settings::BoolAdminSetting::LocalArchiveMalwareScanOverride); TestHook::SetScanArchiveResult_Override scanArchiveResultOverride(false); + TestHook::SetScanArchiveCalled_Override scanArchiveCalled; InstallCommand install({}); install.Execute(context); INFO(installOutput.str()); - // Verify override message is displayed to the user. - REQUIRE(installOutput.str().find(Resource::LocString(Resource::String::ArchiveFailedMalwareScanOverridden).get()) != std::string::npos); + // Verify the scan is skipped and the user is notified. + REQUIRE_FALSE(scanArchiveCalled.WasCalled()); + REQUIRE(installOutput.str().find(Resource::LocString(Resource::String::ArchiveMalwareScanSkipped).get()) != std::string::npos); // Verify Installer is called and parameters are passed in. REQUIRE(std::filesystem::exists(installResultPath.GetPath())); diff --git a/src/AppInstallerCLITests/TestHooks.h b/src/AppInstallerCLITests/TestHooks.h index 87415beb0a..083140f857 100644 --- a/src/AppInstallerCLITests/TestHooks.h +++ b/src/AppInstallerCLITests/TestHooks.h @@ -82,6 +82,7 @@ namespace AppInstaller namespace Archive { void TestHook_SetScanArchiveResult_Override(bool* status); + void TestHook_SetScanArchiveCalled_Override(bool* status); } namespace CLI::Execution @@ -166,6 +167,27 @@ namespace TestHook bool m_status; }; + struct SetScanArchiveCalled_Override + { + SetScanArchiveCalled_Override() + { + AppInstaller::Archive::TestHook_SetScanArchiveCalled_Override(&m_status); + } + + ~SetScanArchiveCalled_Override() + { + AppInstaller::Archive::TestHook_SetScanArchiveCalled_Override(nullptr); + } + + bool WasCalled() const + { + return m_status; + } + + private: + bool m_status = false; + }; + // Makes every source package validate as trusted, so that the pre-indexed stores can be driven // against packages built by the test rather than against signed test data. struct SetSourcePackageTrustValidation_Override diff --git a/src/AppInstallerCommonCore/Archive.cpp b/src/AppInstallerCommonCore/Archive.cpp index 7b5980e501..c34bccb6ff 100644 --- a/src/AppInstallerCommonCore/Archive.cpp +++ b/src/AppInstallerCommonCore/Archive.cpp @@ -51,16 +51,27 @@ namespace AppInstaller::Archive #ifndef AICLI_DISABLE_TEST_HOOKS static bool* s_ScanArchiveResult_TestHook_Override = nullptr; + static bool* s_ScanArchiveCalled_TestHook_Override = nullptr; void TestHook_SetScanArchiveResult_Override(bool* status) { s_ScanArchiveResult_TestHook_Override = status; } + + void TestHook_SetScanArchiveCalled_Override(bool* status) + { + s_ScanArchiveCalled_TestHook_Override = status; + } #endif bool ScanZipFile(const std::filesystem::path& zipPath) { #ifndef AICLI_DISABLE_TEST_HOOKS + if (s_ScanArchiveCalled_TestHook_Override) + { + *s_ScanArchiveCalled_TestHook_Override = true; + } + if (s_ScanArchiveResult_TestHook_Override) { return *s_ScanArchiveResult_TestHook_Override;