From 7670296a5c7fdec624e0a45dbde51059a7d735a8 Mon Sep 17 00:00:00 2001 From: Don Ho Date: Wed, 17 Jun 2026 16:43:20 +0200 Subject: [PATCH 1/7] Fix Path Traversal (Zip Slip) issue Close #106 --- .github/workflows/CI_build.yml | 2 +- src/winmain.cpp | 27 ++++++++++++++++----------- vcproj/GUP.vcxproj | 30 +----------------------------- 3 files changed, 18 insertions(+), 41 deletions(-) diff --git a/.github/workflows/CI_build.yml b/.github/workflows/CI_build.yml index 105de395..61127752 100644 --- a/.github/workflows/CI_build.yml +++ b/.github/workflows/CI_build.yml @@ -2,7 +2,7 @@ name: CI_build on: [push, pull_request] jobs: build: - runs-on: windows-latest + runs-on: windows-2022 strategy: fail-fast: false matrix: diff --git a/src/winmain.cpp b/src/winmain.cpp index 137b36fc..48dc49d8 100644 --- a/src/winmain.cpp +++ b/src/winmain.cpp @@ -542,6 +542,22 @@ bool decompress(const wstring& zipFullFilePath, const wstring& unzipDestTo) wstring extraitFullFilePath = unzipDestTo; PathAppend(extraitFullFilePath, file2extrait); + // Zip slip fix: canonicalize and verify path stays within unzipDestTo + wchar_t canonicalDest[MAX_PATH]; + wchar_t canonicalRoot[MAX_PATH]; + if (!GetFullPathNameW(extraitFullFilePath.c_str(), MAX_PATH, canonicalDest, nullptr) || + !GetFullPathNameW(unzipDestTo.c_str(), MAX_PATH, canonicalRoot, nullptr)) + return false; + + // Ensure canonicalDest starts with canonicalRoot + backslash + wstring destStr(canonicalDest); + wstring rootStr(canonicalRoot); + if (rootStr.back() != L'\\') rootStr += L'\\'; + if (destStr.substr(0, rootStr.size()) != rootStr) + { + // Path traversal attempt - skip this entry + continue; + } // file2extrait be separated into an array vector strArray = tokenizeString(file2extrait, '/'); @@ -1284,17 +1300,6 @@ bool isAppProcess(const wchar_t* wszAppMutex) int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR lpszCmdLine, int) { - /* - { - wstring destPath = L"C:\\tmp\\res\\TagsView"; - wstring dlDest = L"C:\\tmp\\pb\\TagsView_Npp_03beta.zip"; - bool isSuccessful = decompress(dlDest, destPath); - if (isSuccessful) - { - return 0; - } - } - */ // Debug use - stop here so we can attach this process for debugging //::MessageBox(NULL, L"And do something dirty to me ;)", L"Attach me!", MB_OK); diff --git a/vcproj/GUP.vcxproj b/vcproj/GUP.vcxproj index a3071c99..06d3d0c5 100644 --- a/vcproj/GUP.vcxproj +++ b/vcproj/GUP.vcxproj @@ -34,35 +34,7 @@ true - - Application - v143 - Unicode - true - - - Application - v143 - Unicode - true - - - Application - v143 - Unicode - true - - - Application - v143 - Unicode - - - Application - v143 - Unicode - - + Application v143 Unicode From f44afa31e66409e4d704ed7a280fa0bfa7573ac7 Mon Sep 17 00:00:00 2001 From: Don Ho Date: Mon, 6 Jul 2026 18:34:56 +0200 Subject: [PATCH 2/7] WinGUp (for Notepad++) v5.4.2 release --- src/change.log | 6 ++---- src/resource.h | 4 ++-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/change.log b/src/change.log index c9623ee8..3a160288 100644 --- a/src/change.log +++ b/src/change.log @@ -1,5 +1,3 @@ -WinGup (for Notepad++) v5.4.1 new featurs: +WinGup (for Notepad++) v5.4.2 new featurs: -1. Fix regression of launching notepad++.exe with admin privilege. -2. Fix WinGUp downloading fail regression behind corporate MITM proxies. -3. Update cURL to v8.19.0 to fix its security issue (CVE-2025-14819) +1. Fix updater path traversal (Zip Slip) issue. diff --git a/src/resource.h b/src/resource.h index 2a48d697..6fd6c8ca 100644 --- a/src/resource.h +++ b/src/resource.h @@ -19,8 +19,8 @@ #pragma once -#define VERSION_VALUE L"5.41\0" -#define VERSION_DIGITALVALUE 5, 4, 1, 0 +#define VERSION_VALUE L"5.42\0" +#define VERSION_DIGITALVALUE 5, 4, 2, 0 #define IDD_PROGRESS_DLG 1001 #define IDD_PROXY_DLG 1002 From 54cec7e30a5feded18942b6b550c170cc371494e Mon Sep 17 00:00:00 2001 From: bms Date: Mon, 13 Jul 2026 02:22:40 +0300 Subject: [PATCH 3/7] Add "-moveFolder" command line option for plugin deactivation in Notepad++ Usage: gup -moveFolder APP_PATH SRC_ROOT DEST_ROOT folderName1 [folderName2 ...] Ref: https://github.com/notepad-plus-plus/notepad-plus-plus/pull/18206 Close #107 --- src/winmain.cpp | 105 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 102 insertions(+), 3 deletions(-) diff --git a/src/winmain.cpp b/src/winmain.cpp index 48dc49d8..078c16d0 100644 --- a/src/winmain.cpp +++ b/src/winmain.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -88,6 +89,7 @@ static constexpr wchar_t FLAG_HELP[] = L"--help"; static constexpr wchar_t FLAG_UUZIP[] = L"-unzipTo"; static constexpr wchar_t FLAG_CLEANUP[] = L"-clean"; +static constexpr wchar_t FLAG_MOVEFOLDER[] = L"-moveFolder"; static constexpr wchar_t FLAG_INFOURL[] = L"-infoUrl="; static constexpr wchar_t FLAG_FORCEDOMAIN[] = L"-forceDomain="; @@ -164,13 +166,21 @@ gup [-vVERSION_VALUE] [-infoUrl=URL] [-chkCertKeyId=CERT_KEYID]\r\n\ \r\n\ Download & unzip mode:\r\n\ \r\n\ -gup -clean FOLDER_TO_ACTION\r\n\ -gup -unzipTo [-clean] FOLDER_TO_ACTION ZIP_URL\r\n\ +gup -clean APP_PATH FOLDER_TO_ACTION\r\n\ +gup -unzipTo [-clean] APP_PATH FOLDER_TO_ACTION ZIP_URL\r\n\ \r\n\ -clean : Delete all files in FOLDER_TO_ACTION.\r\n\ -unzipTo : Download zip file from ZIP_URL then unzip it into FOLDER_TO_ACTION.\r\n\ + APP_PATH: application path to launch after the operation.\r\n\ ZIP_URL : The URL to download zip file.\r\n\ FOLDER_TO_ACTION : The folder where we clean or/and unzip to.\r\n\ +\r\n\ +Move folder mode:\r\n\ +\r\n\ +gup -moveFolder APP_PATH SRC_ROOT DEST_ROOT folderName1 [folderName2 ...]\r\n\ +\r\n\ + -moveFolder: Move the given folder names from SRC_ROOT to DEST_ROOT.\r\n\ + APP_PATH: application path to launch after the operation.\r\n\ "; HFONT hCmdLineEditFont = nullptr; @@ -508,6 +518,36 @@ bool deleteFileOrFolder(const wstring& f2delete) return (res == 0); }; +// Moves a file or folder using std::filesystem::rename. +// If overwriteIfExists is true and fTo already exists, fTo is removed first: +// fs::rename (like the underlying Win32 MoveFileEx) is unable to replace a +// non-empty directory, so an explicit removal is required before the rename +// (plugin folders normally contain a .dll and other resources, so they are +// non-empty in practice). +// Conflict resolution (asking the user Yes/No/Yes to all/No to all) is expected +// to happen upstream (in Notepad++, before it exits and launches gup), since +// gup itself runs headless after the host application has already closed. +bool moveFileOrFolder(const wstring& fFrom, const wstring& fTo, bool overwriteIfExists) +{ + namespace fs = std::filesystem; + std::error_code ec; + + if (overwriteIfExists && fs::exists(fTo, ec)) + { + fs::remove_all(fTo, ec); + ec.clear(); + } + + fs::rename(fFrom, fTo, ec); + if (ec) + { + WRITE_LOG(GUP_LOG_FILENAME, L"moveFileOrFolder, fs::rename failed with error code: ", std::to_wstring(ec.value()).c_str()); + return false; + } + + return true; +}; + // unzipDestTo should be plugin home root + plugin folder name // ex: %APPDATA%\..\local\Notepad++\plugins\myAwesomePlugin @@ -1320,6 +1360,7 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR lpszCmdLine, int) bool isHelp = isInList(FLAG_HELP, params); bool isCleanUp = isInList(FLAG_CLEANUP, params); bool isUnzip = isInList(FLAG_UUZIP, params); + bool isMoveFolder = isInList(FLAG_MOVEFOLDER, params); getParamVal('v', params, version); getParamVal('p', params, customParam); @@ -1512,7 +1553,65 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR lpszCmdLine, int) return 0; } - + + // move folder(s) from SRC_ROOT to DEST_ROOT + // gup.exe -moveFolder "appPath2Launch" "src_root" "dest_root" "fold1" "fold2" ... + if (isMoveFolder) + { + if (nbParam < 4) + { + WRITE_LOG(GUP_LOG_FILENAME, L"-1 in plugin updater's part - if (isMoveFolder): ", L"nbParam < 4"); + return -1; + } + + wstring prog2Launch = params[0]; + wstring srcRoot = params[1]; + wstring destRoot = params[2]; + +#ifdef _DEBUG + // Don't check any thing in debug mode +#else + // Check signature of the launched program, with the same certif as gup.exe + SecurityGuard securityGuard4PluginsInstall; + + if (!securityGuard4PluginsInstall.initFromSelfCertif()) + { + securityGuard.writeSecurityError(L"Above certificate init error from \"gup -moveFolder\" (move folder)", L""); + return -1; + } + + bool isSecured = securityGuard4PluginsInstall.verifySignedBinary(prog2Launch.c_str()); + if (!isSecured) + { + securityGuard.writeSecurityError(L"Above certificate verification error from \"gup -moveFolder\" (move folder)", L""); + return -1; + } +#endif + + if (!::PathFileExists(destRoot.c_str())) + { + ::CreateDirectory(destRoot.c_str(), NULL); + } + + for (size_t i = 3; i < nbParam; ++i) + { + wstring srcPath = srcRoot; + ::PathAppend(srcPath, params[i]); + + wstring destPath = destRoot; + ::PathAppend(destPath, params[i]); + + // Overwrite conflicts are already resolved by the caller (Notepad++) before + // invoking gup: every folder name reaching this point has been confirmed by + // the user, so it is safe (and necessary) to overwrite an existing destination. + moveFileOrFolder(srcPath, destPath, true); + } + + safeLaunchAsUser(prog2Launch); + + return 0; + } + // update: // gup.exe -unzip -clean "appPath2Launch" "dest_folder" "pluginFolderName1 http://pluginFolderName1/pluginFolderName1.zip sha256Hash1" "pluginFolderName2 http://pluginFolderName2/pluginFolderName2.zip sha256Hash2" "plugin Folder Name3 http://plugin_Folder_Name3/plugin_Folder_Name3.zip sha256Hash3" // gup.exe -unzip -clean "c:\npp\notepad++.exe" "c:\donho\notepad++\plugins" "toto http://toto/toto.zip 7c31a97b..." "ti et ti http://ti_ti/ti_ti.zip 087a0591..." "tata http://tata/tata.zip 2e9766c..." From afe6242a68608c2bd6f2ec21c626cc74e285ba84 Mon Sep 17 00:00:00 2001 From: Don Ho Date: Wed, 12 Aug 2026 20:35:57 +0200 Subject: [PATCH 4/7] Fix a TOCTOU issue --- src/verifySignedfile.cpp | 11 ++++--- src/verifySignedfile.h | 10 +++--- src/winmain.cpp | 68 ++++++++++++++++++++++++++++++++++++++-- 3 files changed, 77 insertions(+), 12 deletions(-) diff --git a/src/verifySignedfile.cpp b/src/verifySignedfile.cpp index 31d168ef..e147782a 100644 --- a/src/verifySignedfile.cpp +++ b/src/verifySignedfile.cpp @@ -118,7 +118,7 @@ std::vector computeSHA256(const std::vector& data) } // Verify certificate chain and validity -bool SecurityGuard::verifyXmlCertificate(PCCERT_CONTEXT pCertContext) +bool SecurityGuard::verifyXmlCertificate(PCCERT_CONTEXT pCertContext) const { // Check certificate validity period FILETIME currentTime; @@ -204,7 +204,7 @@ std::wstring rawDataToHexString(PCRYPT_DATA_BLOB pDataBlob) // Verify that the certificate matches expected identity // You can verify by thumbprint (SHA1 hash of entire cert) or Key ID (SHA1 hash of public key) -bool SecurityGuard::verifyXmlTrustedCertificate(PCCERT_CONTEXT pCertContext, const std::wstring& expectedThumbprint/* = L""*/) +bool SecurityGuard::verifyXmlTrustedCertificate(PCCERT_CONTEXT pCertContext, const std::wstring& expectedThumbprint/* = L""*/) const { // Method 1: Verify by SHA1 thumbprint (most secure - identifies exact certificate) if (!expectedThumbprint.empty()) @@ -328,7 +328,7 @@ bool SecurityGuard::verifyXmlTrustedCertificate(PCCERT_CONTEXT pCertContext, con return true; // No verification requested } -bool SecurityGuard::verifyXmlSignature(const std::string& xmlData, const std::wstring& trustedThumbprint) +bool SecurityGuard::verifyXmlSignature(const std::string& xmlData, const std::wstring& trustedThumbprint) const { ScopedCOMInit com; if (!com.isInitialized()) @@ -612,7 +612,7 @@ bool SecurityGuard::initFromSelfCertif() return verifySignatureAndGetInfo(codeSigedBinPath, _signer_display_name, _signer_key_id, _signer_subject, _authority_key_id); } -bool SecurityGuard::verifySignatureAndGetInfo(const std::wstring& codeSigedBinPath, wstring& display_name, wstring& key_id_hex, wstring& subject, wstring& authority_key_id_hex) +bool SecurityGuard::verifySignatureAndGetInfo(const std::wstring& codeSigedBinPath, wstring& display_name, wstring& key_id_hex, wstring& subject, wstring& authority_key_id_hex) const { // // Signature verification @@ -630,6 +630,7 @@ bool SecurityGuard::verifySignatureAndGetInfo(const std::wstring& codeSigedBinPa winTEXTrust_data.dwUnionChoice = WTD_CHOICE_FILE; // we are not checking catalog signed files winTEXTrust_data.dwStateAction = WTD_STATEACTION_VERIFY; // only checking winTEXTrust_data.fdwRevocationChecks = WTD_REVOKE_WHOLECHAIN; // verify the whole certificate chain + winTEXTrust_data.dwProvFlags = WTD_CACHE_ONLY_URL_RETRIEVAL; // look only in the cached CRL when verifying embedded signature winTEXTrust_data.pFile = &file_data; if (!_doCheckRevocation) @@ -840,7 +841,7 @@ bool SecurityGuard::verifySignatureAndGetInfo(const std::wstring& codeSigedBinPa return status; } -bool SecurityGuard::verifySignedBinary(const std::wstring& filepath) +bool SecurityGuard::verifySignedBinary(const std::wstring& filepath) const { wstring display_name; wstring key_id_hex; diff --git a/src/verifySignedfile.h b/src/verifySignedfile.h index cc8566cd..65aca7f8 100644 --- a/src/verifySignedfile.h +++ b/src/verifySignedfile.h @@ -55,8 +55,8 @@ class SecurityGuard final SecurityGuard(){}; bool initFromSelfCertif(); - bool verifySignatureAndGetInfo(const std::wstring& codeSigedBinPath, std::wstring& display_name, std::wstring& key_id_hex, std::wstring& subject, std::wstring& authority_key_id_hex); - bool verifySignedBinary(const std::wstring& filepath); + bool verifySignatureAndGetInfo(const std::wstring& codeSigedBinPath, std::wstring& display_name, std::wstring& key_id_hex, std::wstring& subject, std::wstring& authority_key_id_hex) const; + bool verifySignedBinary(const std::wstring& filepath) const; void enableChkRevoc() { _doCheckRevocation = true; } void enableChkTrustChain() { _doCheckChainOfTrust = true; } @@ -71,7 +71,7 @@ class SecurityGuard final void writeSecurityError(const std::wstring& prefix, const std::wstring& log2write) const; - bool verifyXmlSignature(const std::string& xmlData, const std::wstring& trustedThumbprint = L""); + bool verifyXmlSignature(const std::string& xmlData, const std::wstring& trustedThumbprint = L"") const; private: // Code signing certificate @@ -85,8 +85,8 @@ class SecurityGuard final bool _doCheckChainOfTrust = false; // For xml signature verification - bool verifyXmlTrustedCertificate(PCCERT_CONTEXT pCertContext, const std::wstring& expectedThumbprint = L""); - bool verifyXmlCertificate(PCCERT_CONTEXT pCertContext); + bool verifyXmlTrustedCertificate(PCCERT_CONTEXT pCertContext, const std::wstring& expectedThumbprint = L"") const; + bool verifyXmlCertificate(PCCERT_CONTEXT pCertContext) const; std::wstring _errLogPath = L"%LOCALAPPDATA%\\WinGUp\\log\\securityError.log"; // By default, but overrideable }; diff --git a/src/winmain.cpp b/src/winmain.cpp index 078c16d0..34d0fabf 100644 --- a/src/winmain.cpp +++ b/src/winmain.cpp @@ -1197,16 +1197,33 @@ bool getUpdateInfo(const string& info2get, const GupParameters& gupParams, const return true; } -int runInstaller(const wstring& app2runPath, const wstring& binWindowsClassName, const wstring& closeMsg, const wstring& closeMsgTitle) +int runInstaller(const wstring& app2runPath, const wstring& binWindowsClassName, const wstring& closeMsg, const wstring& closeMsgTitle, bool doCheckSignature, const SecurityGuard& securityGuard) { + // Lock the downloaded binary to prevent write/modification during user interaction + HANDLE hLockedFile = ::CreateFileW( + app2runPath.c_str(), + GENERIC_READ, + FILE_SHARE_READ, // Deny write sharing to prevent TOCTOU file swap + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if (hLockedFile == INVALID_HANDLE_VALUE) + { + return (int)ERROR_ACCESS_DENIED; + } + if (!binWindowsClassName.empty()) { HWND h = ::FindWindowEx(NULL, NULL, binWindowsClassName.c_str(), NULL); if (h) { int installAnswer = ::MessageBox(h, closeMsg.c_str(), closeMsgTitle.c_str(), MB_YESNO | MB_APPLMODAL); + if (installAnswer == IDNO) { + ::CloseHandle(hLockedFile); return (int)NO_ERROR; } } @@ -1219,8 +1236,51 @@ int runInstaller(const wstring& app2runPath, const wstring& binWindowsClassName, } } + // + // Check the code signing signature again if demanded, for avoiding TOCTOU + // + if (doCheckSignature) + { + bool isSecured = securityGuard.verifySignedBinary(app2runPath); + + if (!isSecured) + { + wstring dlFileSha256; + + std::string content = getFileContentA(ws2s(app2runPath).c_str()); + if (content.empty()) + { + dlFileSha256 = L"No SHA-256: the file is empty."; + } + else + { + char sha2hashStr[65]{}; + uint8_t sha2hash[32]; + calc_sha_256(sha2hash, reinterpret_cast(content.c_str()), content.length()); + + for (size_t i = 0; i < 32; i++) + { + sprintf(sha2hashStr + i * 2, "%02x", sha2hash[i]); + } + + dlFileSha256 = L"Tampered file SHA-256: "; + dlFileSha256 += s2ws(sha2hashStr); + } + + securityGuard.writeSecurityError(L"The 2nd certificate signature verification failed - you might have TOCTOU problem.", dlFileSha256); + + // Delete the unverified/tampered binary file sitting in the TEMP folder + ::CloseHandle(hLockedFile); + deleteFileOrFolder(app2runPath); + + return -1; + } + } + // execute the installer intptr_t result = (intptr_t)::ShellExecute(NULL, L"open", app2runPath.c_str(), nsisSilentInstallParam.c_str(), L".", SW_SHOW); + ::CloseHandle(hLockedFile); + if (result <= 32) // There's a problem (Don't ask me why, ask Microsoft) { WRITE_LOG(GUP_LOG_FILENAME, L"runInstaller, ShellExecute failed with error code: ", std::to_wstring(result).c_str()); @@ -1959,6 +2019,10 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR lpszCmdLine, int) dlUrl += downloadURL; securityGuard.writeSecurityError(dlUrl, dlFileSha256); + + // Delete the unverified/tampered binary file sitting in the TEMP folder + deleteFileOrFolder(dlDest); + return -1; } } @@ -1971,7 +2035,7 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR lpszCmdLine, int) closeApp = MSGID_CLOSEAPP; msg += closeApp; - return runInstaller(dlDest, gupParams.getClassName(), msg, gupParams.getMessageBoxTitle().c_str()); + return runInstaller(dlDest, gupParams.getClassName(), msg, gupParams.getMessageBoxTitle().c_str(), doCheckSignature, securityGuard); } catch (exception ex) { if (!isSilentMode) From 80b6e0ff669c9a173a112035d8a08ef06a972b22 Mon Sep 17 00:00:00 2001 From: Don Ho Date: Thu, 13 Aug 2026 17:51:38 +0200 Subject: [PATCH 5/7] WinGUp (for Notepad++) v5.4.3 release --- src/change.log | 5 +++-- src/resource.h | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/change.log b/src/change.log index 3a160288..61b48474 100644 --- a/src/change.log +++ b/src/change.log @@ -1,3 +1,4 @@ -WinGup (for Notepad++) v5.4.2 new featurs: +WinGup (for Notepad++) v5.4.3 new featurs: -1. Fix updater path traversal (Zip Slip) issue. +1. Fix a TOCTOU issue. +2. Add "-moveFolder" command line option for plugin deactivation in Notepad++. diff --git a/src/resource.h b/src/resource.h index 6fd6c8ca..736e4888 100644 --- a/src/resource.h +++ b/src/resource.h @@ -19,8 +19,8 @@ #pragma once -#define VERSION_VALUE L"5.42\0" -#define VERSION_DIGITALVALUE 5, 4, 2, 0 +#define VERSION_VALUE L"5.43\0" +#define VERSION_DIGITALVALUE 5, 4, 3, 0 #define IDD_PROGRESS_DLG 1001 #define IDD_PROXY_DLG 1002 From 0563a59fb20cd1488a305ea2ab98652b3f5b3de9 Mon Sep 17 00:00:00 2001 From: Don Ho Date: Sat, 5 Sep 2026 18:36:26 +0200 Subject: [PATCH 6/7] Make new config compilable --- README.md | 3 ++- buildCurlAll.bat | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5a38efd3..8e26693d 100644 --- a/README.md +++ b/README.md @@ -65,8 +65,9 @@ How to build it? * Step 1: You have to build cURL before building WinGUp: + 0. Install [CMake](https://cmake.org/), if it is not yet installed in your system. 1. Open Visual Studio Native Tool Command. - 2. Go to WinGUp source directory and run "buildCurlAll.bat". + 2. Go to WinGUp source root directory and run "buildCurlAll.bat". * Step 2: Open [`vcproj\GUP.sln`](https://github.com/gup4win/wingup/blob/master/vcproj/GUP.sln) with VS2022. diff --git a/buildCurlAll.bat b/buildCurlAll.bat index 51a14f85..9ecfce6b 100644 --- a/buildCurlAll.bat +++ b/buildCurlAll.bat @@ -5,7 +5,7 @@ set RELEASE=-DCMAKE_BUILD_TYPE=Release set DEBUG=-DCMAKE_BUILD_TYPE=Debug echo [1/6] Configuring ARM64... -cmake curl -B curl\build\ARM64 -A ARM64 %COMMON% %RELEASE% +cmake curl -B curl\build\ARM64 -A ARM64 -T v143 %COMMON% %RELEASE% echo [2/6] Building ARM64 Release... cmake --build curl\build\ARM64 --config Release echo [3/6] Building ARM64 Debug... From e01affe45f21babd1ab49156f3dcb05ef35c6e40 Mon Sep 17 00:00:00 2001 From: PeterCJ Date: Thu, 3 Sep 2026 16:21:47 -0700 Subject: [PATCH 7/7] Add debug builds to push, pull, and release - edit the existing CI_build to add debug artifacts to each push/pull(PR) build - replicate to CD_release and store those debug zips as Assets on the Release Fix #109, close #110 --- .github/workflows/CD_release.yml | 94 ++++++++++++++++++++++++++++++++ .github/workflows/CI_build.yml | 21 +++++++ 2 files changed, 115 insertions(+) create mode 100644 .github/workflows/CD_release.yml diff --git a/.github/workflows/CD_release.yml b/.github/workflows/CD_release.yml new file mode 100644 index 00000000..c6ccca65 --- /dev/null +++ b/.github/workflows/CD_release.yml @@ -0,0 +1,94 @@ +name: CD_release +on: + release: + types: [published] + +jobs: + build: + runs-on: windows-2022 + permissions: + contents: write + strategy: + fail-fast: false + matrix: + build_platform: [x64, x86, ARM64] + steps: + - name: Checkout repo + uses: actions/checkout@v4 + + - name: Add msbuild to PATH + uses: microsoft/setup-msbuild@v2 + + - name: Configure curl (${{ matrix.build_platform }}) + run: | + $arch = "${{ matrix.build_platform }}" -eq "x86" ? "Win32" : "${{ matrix.build_platform }}" + cmake curl -B curl/build/${{ matrix.build_platform }} -A $arch ` + -DBUILD_SHARED_LIBS=OFF ` + -DCURL_STATIC_CRT=ON ` + -DBUILD_CURL_EXE=OFF ` + -DCURL_USE_SCHANNEL=ON ` + -DCURL_USE_OPENSSL=OFF ` + -DBUILD_TESTING=OFF ` + -DUSE_LIBPSL=OFF ` + -DCURL_USE_LIBPSL=OFF ` + -DUSE_NGHTTP2=OFF ` + -DUSE_LIBIDN2=OFF + + - name: Build curl Release (${{ matrix.build_platform }}) + run: cmake --build curl/build/${{ matrix.build_platform }} --config Release + + - name: Build curl Debug (${{ matrix.build_platform }}) + run: cmake --build curl/build/${{ matrix.build_platform }} --config Debug + + - name: Build GUP Release (${{ matrix.build_platform }}) + working-directory: vcproj + run: msbuild GUP.sln /m /p:configuration="Release" /p:platform="${{ matrix.build_platform }}" + + - name: Build GUP Debug (${{ matrix.build_platform }}) + working-directory: vcproj + run: msbuild GUP.sln /m /p:configuration="Debug" /p:platform="${{ matrix.build_platform }}" + + - name: build debug zipfile x64 + if: matrix.build_platform == 'x64' + run: Compress-Archive -Path ".\vcproj\x64\Debug\*" -DestinationPath "${{ github.workspace }}\gup_dbg_exe_x64.zip" + + - name: Store gup_dbg_exe_x64.zip as Release Asset + uses: svenstaro/upload-release-action@v2 + if: matrix.build_platform == 'x64' + with: + repo_token: ${{ secrets.GITHUB_TOKEN }} + file: gup_dbg_exe_x64.zip + asset_name: gup_dbg_exe_x64.zip + tag: ${{ github.ref }} + overwrite: true + body: ${{ github.event.release.body }} + + - name: build debug zipfile x86 + if: matrix.build_platform == 'x86' + run: Compress-Archive -Path ".\vcproj\Debug\*" -DestinationPath "${{ github.workspace }}\gup_dbg_exe_Win32.zip" + + - name: Store gup_dbg_exe_Win32.zip as Release Asset + if: matrix.build_platform == 'x86' + uses: svenstaro/upload-release-action@v2 + with: + repo_token: ${{ secrets.GITHUB_TOKEN }} + file: gup_dbg_exe_Win32.zip + asset_name: gup_dbg_exe_Win32.zip + tag: ${{ github.ref }} + overwrite: true + body: ${{ github.event.release.body }} + + - name: build debug zipfile ARM64 + if: matrix.build_platform == 'ARM64' + run: Compress-Archive -Path ".\vcproj\ARM64\Debug\*" -DestinationPath "${{ github.workspace }}\gup_dbg_exe_ARM64.zip" + + - name: Store gup_dbg_exe_ARM64.zip as Release Asset + if: matrix.build_platform == 'ARM64' + uses: svenstaro/upload-release-action@v2 + with: + repo_token: ${{ secrets.GITHUB_TOKEN }} + file: gup_dbg_exe_ARM64.zip + asset_name: gup_dbg_exe_ARM64.zip + tag: ${{ github.ref }} + overwrite: true + body: ${{ github.event.release.body }} diff --git a/.github/workflows/CI_build.yml b/.github/workflows/CI_build.yml index 61127752..c1b6b7ef 100644 --- a/.github/workflows/CI_build.yml +++ b/.github/workflows/CI_build.yml @@ -50,6 +50,13 @@ jobs: name: gup_exe_x64 path: bin64\ + - name: Archive artifacts for x64_dbg + if: matrix.build_platform == 'x64' + uses: actions/upload-artifact@v4 + with: + name: gup_exe_x64_dbg + path: vcproj\x64\Debug\ + - name: Archive artifacts for x86 if: matrix.build_platform == 'x86' uses: actions/upload-artifact@v4 @@ -57,9 +64,23 @@ jobs: name: gup_exe_x86 path: bin\ + - name: Archive artifacts for x86_dbg + if: matrix.build_platform == 'x86' + uses: actions/upload-artifact@v4 + with: + name: gup_exe_x86_dbg + path: vcproj\Debug\ + - name: Archive artifacts for ARM64 if: matrix.build_platform == 'ARM64' uses: actions/upload-artifact@v4 with: name: gup_exe_arm64 path: binarm64\ + + - name: Archive artifacts for ARM64_dbg + if: matrix.build_platform == 'ARM64' + uses: actions/upload-artifact@v4 + with: + name: gup_exe_arm64_dbg + path: vcproj\ARM64\Debug\