From a3ea51ed156df8903b9ebfb11ee8f80edbd03a6b Mon Sep 17 00:00:00 2001
From: "Austin S. Hemmelgarn" <austin@netdata.cloud>
Date: Thu, 8 Aug 2024 07:24:54 -0400
Subject: [PATCH] Add code signing for Windows executables. (#18222)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* Add code signing for Windows executables.

* Fix typos and add failure notification.

* Use full version for trusted signing action.

Because MS isn’t publishing it with proper semver tags.

* Avoid reinstalling dependencies that are already installed.

* Fix CMake 3.30 compatibility.

* Don’t let BUILD_DIR propagate to cmake.

* Fix JSON-C build warning.

* Fix handling of externally specified build directories.

While regular Windows paths do actually work under MSYS2, they seem to
confuse CMake, so we need to convert to a standard MSYS2 path if
`BUILD_DIR` is set to a Windows path.

* Fix typo.

* Fix build directory handling.
---
 .github/workflows/build.yml                   | 62 +++++++++++++++++++
 .../Modules/NetdataFetchContentExtra.cmake    | 15 ++++-
 packaging/cmake/Modules/NetdataJSONC.cmake    |  2 +-
 packaging/windows/compile-on-windows.sh       | 19 ++----
 packaging/windows/msys2-dependencies.sh       |  2 +-
 packaging/windows/package-windows.sh          | 21 ++-----
 packaging/windows/win-build-dir.sh            | 20 ++++++
 7 files changed, 105 insertions(+), 36 deletions(-)
 create mode 100644 packaging/windows/win-build-dir.sh

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 86a2590e91..f642d792d8 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -1082,11 +1082,47 @@ jobs:
       - name: Build Netdata
         id: build
         if: needs.file-check.outputs.run == 'true'
+        env:
+          BUILD_DIR: ${{ github.workspace }}\build
         run: ./packaging/windows/build.ps1
+      - name: Sign Agent Code
+        id: sign-agent
+        if: needs.file-check.outputs.run == 'true' && github.event_name != 'pull_request'
+        uses: azure/trusted-signing-action@v0.4.0
+        with:
+          azure-tennant-id: ${{ secrets.CODE_SIGNING_TENNANT_ID }}
+          azure-client-id: ${{ secrets.CODE_SIGNING_CLIENT_ID }}
+          azure-client-secret: ${{ secrets.CODE_SIGNING_CLIENT_SECRET }}
+          endpoint: "https://eus.codesigning.azure.net/"
+          trusted-signing-account-name: Netdata
+          certificate-profile-name: Netdata
+          files-folder: ${{ github.workspace }}\build
+          files-folder-filter: exe,dll
+          files-recurse: true
+          file-digest: SHA256
+          timestamp-rfc3161: "http://timestamp.acs.microsoft.com"
+          timestamp-digest: SHA256
       - name: Package Netdata
         id: package
         if: needs.file-check.outputs.run == 'true'
+        env:
+          BUILD_DIR: ${{ github.workspace }}\build
         run: ./packaging/windows/package.ps1
+      - name: Sign Installer
+        id: sign-installer
+        if: needs.file-check.outputs.run == 'true' && github.event_name != 'pull_request'
+        uses: azure/trusted-signing-action@v0.4.0
+        with:
+          azure-tennant-id: ${{ secrets.CODE_SIGNING_TENNANT_ID }}
+          azure-client-id: ${{ secrets.CODE_SIGNING_CLIENT_ID }}
+          azure-client-secret: ${{ secrets.CODE_SIGNING_CLIENT_SECRET }}
+          endpoint: "https://eus.codesigning.azure.net/"
+          trusted-signing-account-name: Netdata
+          certificate-profile-name: Netdata
+          files: ${{ github.workspace }}\packaging\windows\netdata-installer.exe
+          file-digest: SHA256
+          timestamp-rfc3161: "http://timestamp.acs.microsoft.com"
+          timestamp-digest: SHA256
       - name: Upload Installer
         id: upload
         uses: actions/upload-artifact@v4
@@ -1094,6 +1130,32 @@ jobs:
           name: windows-x86_64-installer
           path: packaging\windows\netdata-installer.exe
           retention-days: 30
+      - name: Failure Notification
+        uses: rtCamp/action-slack-notify@v2
+        env:
+          SLACK_COLOR: 'danger'
+          SLACK_FOOTER: ''
+          SLACK_ICON_EMOJI: ':github-actions:'
+          SLACK_TITLE: 'Windows build failed:'
+          SLACK_USERNAME: 'GitHub Actions'
+          SLACK_MESSAGE: |-
+              ${{ github.repository }}: Updater checks for ${{ matrix.distro }} failed.
+              Checkout: ${{ steps.checkout.outcome }}
+              Set Up Dependencies: ${{ steps.deps.outcome }}
+              Build Netdata: ${{ steps.build.outcome }}
+              Sign Agent Code: ${{ steps.sign-agent.outcome }}
+              Package Netdata: ${{ steps.package.outcome }}
+              Sign Installer: ${{ steps.sign-installer.outcome }}
+              Upload Installer: ${{ steps.upload.outcome }}
+          SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}
+        if: >-
+          ${{
+            failure()
+            && startsWith(github.ref, 'refs/heads/master')
+            && github.event_name != 'pull_request'
+            && github.repository == 'netdata/netdata'
+            && needs.file-check.outputs.run == 'true'
+          }}
 
   updater-check: # Test the generated dist archive using the updater code.
     name: Test Generated Distfile and Updater Code
diff --git a/packaging/cmake/Modules/NetdataFetchContentExtra.cmake b/packaging/cmake/Modules/NetdataFetchContentExtra.cmake
index 6601b6d95e..e82fe413b7 100644
--- a/packaging/cmake/Modules/NetdataFetchContentExtra.cmake
+++ b/packaging/cmake/Modules/NetdataFetchContentExtra.cmake
@@ -38,8 +38,17 @@ endmacro()
 #
 # This needs to be explicitly included for any sub-project that needs
 # to be built for the target system.
+#
+# This also needs to _NOT_ have any generator expressions, as they are not
+# supported for the required usage of this variable in CMake 3.30 or newer.
 set(NETDATA_PROPAGATE_TOOLCHAIN_ARGS
     "-DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}
-     -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
-     $<$<BOOL:${CMAKE_C_COMPILER_TARGET}>:-DCMAKE_C_COMPILER_TARGET=${CMAKE_C_COMPILER_TARGET}
-     $<$<BOOL:${CMAKE_CXX_COMPILER_TARGET}>:-DCMAKE_CXX_COMPILER_TARGET=${CMAKE_CXX_COMPILER_TARGET}")
+     -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}")
+
+if(DEFINED CMAKE_C_COMPILER_TARGET)
+  set(NETDATA_PROPAGATE_TOOLCHAIN_ARGS "${NETDATA_PROPAGATE_TOOLCHAIN_ARGS} -DCMAKE_C_COMPILER_TARGET=${CMAKE_C_COMPILER_TARGET}")
+endif()
+
+if(DEFINED CMAKE_CXX_COMPILER_TARGET)
+  set(NETDATA_PROPAGATE_TOOLCHAIN_ARGS "${NETDATA_PROPAGATE_TOOLCHAIN_ARGS} -DCMAKE_CXX_COMPILER_TARGET=${CMAKE_CXX_COMPILER_TARGET}")
+endif()
diff --git a/packaging/cmake/Modules/NetdataJSONC.cmake b/packaging/cmake/Modules/NetdataJSONC.cmake
index 2f500b2c50..89ec702650 100644
--- a/packaging/cmake/Modules/NetdataJSONC.cmake
+++ b/packaging/cmake/Modules/NetdataJSONC.cmake
@@ -75,7 +75,7 @@ macro(netdata_detect_jsonc)
         endif()
 
         if(NOT JSONC_FOUND)
-                set(ENABLE_BUNDLED_JSONC True PARENT_SCOPE)
+                set(ENABLE_BUNDLED_JSONC True)
                 netdata_bundle_jsonc()
                 set(NETDATA_JSONC_LDFLAGS json-c)
                 set(NETDATA_JSONC_INCLUDE_DIRS ${PROJECT_BINARY_DIR}/include)
diff --git a/packaging/windows/compile-on-windows.sh b/packaging/windows/compile-on-windows.sh
index 44266bf5fd..ceb4f5502f 100755
--- a/packaging/windows/compile-on-windows.sh
+++ b/packaging/windows/compile-on-windows.sh
@@ -1,21 +1,10 @@
 #!/bin/bash
 
-repo_root="$(dirname "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" > /dev/null && pwd -P)")")"
+REPO_ROOT="$(dirname "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" > /dev/null && pwd -P)")")"
 CMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE:-RelWithDebInfo}"
 
-if [ -n "${BUILD_DIR}" ]; then
-    build="${BUILD_DIR}"
-elif [ -n "${OSTYPE}" ]; then
-    if [ -n "${MSYSTEM}" ]; then
-        build="${repo_root}/build-${OSTYPE}-${MSYSTEM}"
-    else
-        build="${repo_root}/build-${OSTYPE}"
-    fi
-elif [ "$USER" = "vk" ]; then
-    build="${repo_root}/build"
-else
-    build="${repo_root}/build"
-fi
+# shellcheck source=./win-build-dir.sh
+. "${REPO_ROOT}/packaging/windows/win-build-dir.sh"
 
 set -exu -o pipefail
 
@@ -42,7 +31,7 @@ fi
 ${GITHUB_ACTIONS+echo "::group::Configuring"}
 # shellcheck disable=SC2086
 CFLAGS="${BUILD_CFLAGS}" /usr/bin/cmake \
-    -S "${repo_root}" \
+    -S "${REPO_ROOT}" \
     -B "${build}" \
     -G "${generator}" \
     -DCMAKE_INSTALL_PREFIX="/opt/netdata" \
diff --git a/packaging/windows/msys2-dependencies.sh b/packaging/windows/msys2-dependencies.sh
index e31b7e0de9..95a1952df8 100755
--- a/packaging/windows/msys2-dependencies.sh
+++ b/packaging/windows/msys2-dependencies.sh
@@ -11,7 +11,7 @@ pacman -Syuu --noconfirm
 ${GITHUB_ACTIONS+echo "::endgroup::"}
 
 ${GITHUB_ACTIONS+echo "::group::Installing dependencies"}
-pacman -S --noconfirm \
+pacman -S --noconfirm --needed \
     base-devel \
     cmake \
     git \
diff --git a/packaging/windows/package-windows.sh b/packaging/windows/package-windows.sh
index 08749d82c8..4c62e0c08f 100755
--- a/packaging/windows/package-windows.sh
+++ b/packaging/windows/package-windows.sh
@@ -1,20 +1,9 @@
 #!/bin/bash
 
-repo_root="$(dirname "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" > /dev/null && pwd -P)")")"
+REPO_ROOT="$(dirname "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" > /dev/null && pwd -P)")")"
 
-if [ -n "${BUILD_DIR}" ]; then
-    build="${BUILD_DIR}"
-elif [ -n "${OSTYPE}" ]; then
-    if [ -n "${MSYSTEM}" ]; then
-        build="${repo_root}/build-${OSTYPE}-${MSYSTEM}"
-    else
-        build="${repo_root}/build-${OSTYPE}"
-    fi
-elif [ "$USER" = "vk" ]; then
-    build="${repo_root}/build"
-else
-    build="${repo_root}/build"
-fi
+# shellcheck source=./win-build-dir.sh
+. "${REPO_ROOT}/packaging/windows/win-build-dir.sh"
 
 set -exu -o pipefail
 
@@ -24,7 +13,7 @@ ${GITHUB_ACTIONS+echo "::endgroup::"}
 
 if [ ! -f "/msys2-installer.exe" ]; then
     ${GITHUB_ACTIONS+echo "::group::Fetching MSYS2 installer"}
-    "${repo_root}/packaging/windows/fetch-msys2-installer.py" /msys2-installer.exe
+    "${REPO_ROOT}/packaging/windows/fetch-msys2-installer.py" /msys2-installer.exe
     ${GITHUB_ACTIONS+echo "::endgroup::"}
 fi
 
@@ -33,5 +22,5 @@ NDVERSION=$"$(grep 'CMAKE_PROJECT_VERSION:STATIC' "${build}/CMakeCache.txt"| cut
 NDMAJORVERSION=$"$(grep 'CMAKE_PROJECT_VERSION_MAJOR:STATIC' "${build}/CMakeCache.txt"| cut -d= -f2)"
 NDMINORVERSION=$"$(grep 'CMAKE_PROJECT_VERSION_MINOR:STATIC' "${build}/CMakeCache.txt"| cut -d= -f2)"
 
-/mingw64/bin/makensis.exe -DCURRVERSION="${NDVERSION}" -DMAJORVERSION="${NDMAJORVERSION}" -DMINORVERSION="${NDMINORVERSION}" "${repo_root}/packaging/windows/installer.nsi"
+/mingw64/bin/makensis.exe -DCURRVERSION="${NDVERSION}" -DMAJORVERSION="${NDMAJORVERSION}" -DMINORVERSION="${NDMINORVERSION}" "${REPO_ROOT}/packaging/windows/installer.nsi"
 ${GITHUB_ACTIONS+echo "::endgroup::"}
diff --git a/packaging/windows/win-build-dir.sh b/packaging/windows/win-build-dir.sh
new file mode 100644
index 0000000000..09dd6b9772
--- /dev/null
+++ b/packaging/windows/win-build-dir.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+if [ -n "${BUILD_DIR}" ]; then
+    if (echo "${BUILD_DIR}" | grep -q -E "^[A-Z]:\\\\"); then
+        build="$(echo "${BUILD_DIR}" | sed -e 's/\\/\//g' -e 's/^\([A-Z]\):\//\/\1\//' -)"
+    else
+        build="${BUILD_DIR}"
+    fi
+elif [ -n "${OSTYPE}" ]; then
+    if [ -n "${MSYSTEM}" ]; then
+        build="${REPO_ROOT}/build-${OSTYPE}-${MSYSTEM}"
+    else
+        build="${REPO_ROOT}/build-${OSTYPE}"
+    fi
+elif [ "$USER" = "vk" ]; then
+    build="${REPO_ROOT}/build"
+else
+    # shellcheck disable=SC2034
+    build="${REPO_ROOT}/build"
+fi