build(cmake): add code signing

This commit is contained in:
Oleg Shparber 2023-09-10 23:15:22 -04:00
parent a81b3f500f
commit 9e213078a6
6 changed files with 246 additions and 118 deletions

View File

@ -155,28 +155,23 @@ jobs:
if: matrix.config.publishArtifacts
run: cmake --build build --preset ${{ matrix.config.buildPreset }} --target package
- name: Sign Artifacts
if: matrix.config.publishArtifacts && github.repository == 'zealdocs/zeal' && github.event_name == 'push'
uses: dlemstra/code-sign-action@v1
with:
certificate: '${{ secrets.CODESIGN_CERTIFICATE }}'
password: '${{ secrets.CODESIGN_PASSWORD }}'
files: |
build/${{ matrix.config.configurePreset }}/bin/RelWithDebInfo/zeal.exe
build/${{ matrix.config.configurePreset }}/bin/RelWithDebInfo/archive.dll
build/${{ matrix.config.configurePreset }}/bin/RelWithDebInfo/sqlite3.dll
build/${{ matrix.config.configurePreset }}/bin/RelWithDebInfo/zlib1.dll
- name: Upload Artifacts
- name: Upload ZIP Artifacts
if: matrix.config.publishArtifacts
uses: actions/upload-artifact@v3
with:
name: zeal-${{ env.ZEAL_VERSION }}${{ matrix.config.configurePreset == 'ninja-multi-vcpkg-portable' && '-portable' || '' }}-windows-x64
name: zeal-${{ env.ZEAL_VERSION }}${{ matrix.config.configurePreset == 'ninja-multi-vcpkg-portable' && '-portable' || '' }}-windows-x64.zip
path: |
build/${{ matrix.config.configurePreset }}/bin/RelWithDebInfo
!**/*.idl
!**/*.ilk
!**/*.pdb
build/${{ matrix.config.configurePreset }}/zeal-*.zip
build/${{ matrix.config.configurePreset }}/zeal-*.zip.sha256
- name: Upload MSI Artifacts
if: matrix.config.publishArtifacts && matrix.config.configurePreset == 'ninja-multi-vcpkg'
uses: actions/upload-artifact@v3
with:
name: zeal-${{ env.ZEAL_VERSION }}-windows-x64.msi
path: |
build/${{ matrix.config.configurePreset }}/zeal-*.msi
build/${{ matrix.config.configurePreset }}/zeal-*.msi.sha256
build-appimage:
name: AppImage

185
cmake/CodeSign.cmake Normal file
View File

@ -0,0 +1,185 @@
#
# CodeSign.cmake
#
# Copyright (c) 2023 Oleg Shparber and contributors. All rights reserved.
# Licensed under the MIT License.
#
include_guard()
# codesign(FILES <files>...
# [DESCRIPTION] <description-string>
# [URL] <url-string>
# [CERTIFICATE_FILE] <filename>
# [CERTIFICATE_PASSWORD] <password-string>
# [TIMESTAMP_URL] <url-string>
# [QUIET]
# [VERBOSE]
# [DEBUG])
function(codesign)
if(NOT WIN32)
message(FATAL_ERROR "Code signing is only supported on Windows.")
endif()
cmake_parse_arguments(_ARG
"QUIET;VERBOSE;DEBUG" # Options.
"DESCRIPTION;URL;CERTIFICATE_FILE;CERTIFICATE_PASSWORD;TIMESTAMP_URL" # Single-value keywords.
"FILES" # Multi-value keywords.
${ARGN}
)
if(NOT _ARG_FILES)
message(FATAL_ERROR "FILES argument is required.")
endif()
# Find signtool executable.
# TODO: Add option for path to signtool.exe.
# Add Windows 10 SDK paths.
get_filename_component(_w10sdk_root_path
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots;KitsRoot10]"
ABSOLUTE CACHE
)
if(_w10sdk_root_path)
file(GLOB _w10sdk_paths "${_w10sdk_root_path}/bin/10.*")
list(REVERSE _w10sdk_paths) # Newest version first.
# Detect target architecture.
# https://learn.microsoft.com/en-us/windows/win32/winprog64/wow64-implementation-details#environment-variables
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64")
set(_w10sdk_arch "x64")
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "IA64")
set(_w10sdk_arch "x64")
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "X86")
set(_w10sdk_arch "x86")
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "ARM64")
set(_w10sdk_arch "arm64")
else()
message(DEBUG "Unknown architecture: ${CMAKE_SYSTEM_PROCESSOR}.")
endif()
endif()
# TODO: Add microsoft.windows.sdk.buildtools path.
find_program(_cmd
NAMES signtool
PATHS ${_w10sdk_paths}
PATH_SUFFIXES ${_w10sdk_arch}
)
if(NOT _cmd)
message(NOTICE "signtool.exe was not found, no binaries will be signed.")
return()
endif()
message(DEBUG "Found signtool.exe: ${_cmd}")
# Start constructing command.
set(_cmd_args "sign")
list(APPEND _cmd_args "/fd" "sha256")
# Set certificate file.
if(NOT _ARG_CERTIFICATE_FILE)
if(CODESIGN_CERTIFICATE_FILE)
set(_ARG_CERTIFICATE_FILE ${CODESIGN_CERTIFICATE_FILE})
elseif(DEFINED ENV{CODESIGN_CERTIFICATE_FILE})
set(_ARG_CERTIFICATE_FILE $ENV{CODESIGN_CERTIFICATE_FILE})
elseif(DEFINED ENV{CODESIGN_CERTIFICATE})
# Read the whole certificate from environment variable and store it
# in a temporary file for signtool to use.
# Determine temporary file location. Try to keep it local to the build.
if(CMAKE_BINARY_DIR)
set(_temp_path ${CMAKE_BINARY_DIR})
elseif(CPACK_TEMPORARY_DIRECTORY)
set(_temp_path ${CPACK_TEMPORARY_DIRECTORY})
else()
set(_temp_path $ENV{TEMP})
endif()
set(_certificate_file "${_temp_path}/codesign.pem")
file(WRITE ${_certificate_file} $ENV{CODESIGN_CERTIFICATE})
set(_ARG_CERTIFICATE_FILE ${_certificate_file})
else()
message(NOTICE "Certificate is not provided, no binaries will be signed.")
return()
endif()
endif()
list(APPEND _cmd_args "/f" ${_ARG_CERTIFICATE_FILE})
# Set password.
if(NOT _ARG_CERTIFICATE_PASSWORD)
if(CODESIGN_CERTIFICATE_PASSWORD)
set(_ARG_CERTIFICATE_PASSWORD ${CODESIGN_CERTIFICATE_PASSWORD})
elseif(DEFINED ENV{CODESIGN_CERTIFICATE_PASSWORD})
set(_ARG_CERTIFICATE_PASSWORD $ENV{CODESIGN_CERTIFICATE_PASSWORD})
endif()
endif()
if(_ARG_CERTIFICATE_PASSWORD)
list(APPEND _cmd_args "/p" ${_ARG_CERTIFICATE_PASSWORD})
endif()
# Set description.
if(NOT _ARG_DESCRIPTION AND PROJECT_DESCRIPTION)
set(_ARG_DESCRIPTION ${PROJECT_DESCRIPTION})
endif()
if(_ARG_DESCRIPTION)
list(APPEND _cmd_args "/d" ${_ARG_DESCRIPTION})
endif()
# Set project URL.
if(NOT _ARG_URL AND PROJECT_HOMEPAGE_URL)
set(_ARG_URL ${PROJECT_HOMEPAGE_URL})
endif()
if(_ARG_URL)
list(APPEND _cmd_args "/du" ${_ARG_URL})
endif()
# Set timestamp server.
if(NOT _ARG_TIMESTAMP_URL)
set(_ARG_TIMESTAMP_URL "http://timestamp.digicert.com")
endif()
if(_ARG_TIMESTAMP_URL)
list(APPEND _cmd_args "/t" ${_ARG_TIMESTAMP_URL})
endif()
# Set quiet, verbose, or debug options.
if(_ARG_QUIET)
list(APPEND _cmd_args "/q")
endif()
if(_ARG_VERBOSE)
list(APPEND _cmd_args "/v")
endif()
if(_ARG_DEBUG)
list(APPEND _cmd_args "/debug")
endif()
foreach(_file ${_ARG_FILES})
message(STATUS "Signing ${_file}...")
execute_process(COMMAND ${_cmd} ${_cmd_args} ${_file}
RESULT_VARIABLE _rc
OUTPUT_VARIABLE _stdout
ERROR_VARIABLE _stderr
)
if(NOT _rc EQUAL 0)
message(NOTICE "Signing failed: ${_stderr}")
endif()
if(NOT _ARG_QUIET)
message(NOTICE ${_stdout})
endif()
endforeach()
# Cleanup
if(_certificate_file)
file(REMOVE ${_certificate_file})
endif()
endfunction()

View File

@ -1,77 +0,0 @@
# TODO: This script should be replaced with wixproj and/or CPack.
# Sample command:
# .\build.ps1 -Arch x64 -Version 0.4.0 -PackagePath "c:\tmp\zeal-0.4.0-windows-x64" -SignMsi
param(
[Parameter(Mandatory=$True)]
[ValidatePattern("[0-9].[0-9].[0-9]")]
[string]$Version,
[Parameter(Mandatory=$True)]
[ValidateSet('x86', 'x64')]
[string]$Arch,
[Parameter(Mandatory=$True)]
[string]$PackagePath,
[Switch]$DevBuild,
[Switch]$SignMsi
)
$BaseFilename = "zeal-$Version-windows-$Arch"
$WixobjFilename = "$BaseFilename.wixobj"
$MsiFilename = "$BaseFilename.msi"
function CleanUp {
Remove-Item -ErrorAction Ignore -Path "$WixobjFilename"
# We are not going to build patches for now.
# More infor about wixpdb: https://www.firegiant.com/wix/tutorial/upgrades-and-modularization/patchwork/
Remove-Item -ErrorAction Ignore "$BaseFilename.wixpdb"
}
Write-Output "Building $MsiFilename..."
if ($DevBuild) {
$compressionLevelArg = '-dCompressionLevel="none"'
}
$VCRedistPath = 'C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Redist\MSVC\v142\MergeModules'
$VCRedistFile = "Microsoft_VC142_CRT_$Arch.msm"
Write-Output "Running candle..."
& candle.exe -nologo -pedantic -wx -arch "$Arch" `
-dAppVersion="$Version" `
-dAppPackageDir="$PackagePath" `
-dVCRedistPath="$VCRedistPath" `
-dVCRedistFile="$VCRedistFile" `
$compressionLevelArg `
-o "$WixobjFilename" zeal.wxs
if ($LastExitCode -ne 0) {
CleanUp
throw "candle failed with exit code $LastExitCode."
}
Write-Output "Running light..."
# Supressing LGHT1076, see https://wixtoolset.org/documentation/manual/v3/howtos/redistributables_and_install_checks/install_vcredist.html
& light.exe -nologo -pedantic -wx -sw1076 -ext WixUIExtension -o "$MsiFilename" "$WixobjFilename"
if ($LastExitCode -ne 0) {
CleanUp
throw "light failed with exit code $LastExitCode."
}
if ($SignMsi) {
$KeyName = "Open Source Developer, Oleg Shparber"
$Description = "Zeal $Version Installer"
$Url = "https://zealdocs.org"
$TimestampServerUrl = "http://timestamp.comodoca.com/authenticode"
Write-Output "Signing $MsiFilename..."
& signtool sign /v /n "$KeyName" /d "$Description" /du "$Url" /t "$TimestampServerUrl" "$MsiFilename"
if ($LastExitCode -ne 0) {
CleanUp
throw "signtool failed with exit code $LastExitCode."
}
}
CleanUp

View File

@ -0,0 +1,7 @@
if(NOT CPACK_GENERATOR STREQUAL "WIX")
message(DEBUG "Skipping package signing for ${CPACK_GENERATOR} generator.")
return()
endif()
include(CodeSign)
codesign(FILES ${CPACK_PACKAGE_FILES} QUIET)

View File

@ -0,0 +1,13 @@
# TODO: Automatically generate list.
set(_file_list
"zeal.exe"
"archive.dll"
"zlib1.dll"
"sqlite3.dll"
)
include(CodeSign)
foreach(_file ${_file_list})
codesign(FILES "${CPACK_TEMPORARY_DIRECTORY}/${_file}" QUIET)
endforeach()

View File

@ -46,8 +46,8 @@ endif()
target_link_libraries(App PRIVATE Core Util Qt${QT_VERSION_MAJOR}::Widgets)
set_target_properties(App PROPERTIES
OUTPUT_NAME "${PROJECT_OUTPUT_NAME}"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
OUTPUT_NAME ${PROJECT_OUTPUT_NAME}
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}
)
# Install Qt runtime dependencies on Windows.
@ -56,15 +56,15 @@ if(WIN32 AND use_qt_cmake_commands)
TARGET App
OUTPUT_SCRIPT qt_deploy_script
CONTENT "
# TODO: Run windeployqt after build.
# Override deployment script's working directory.
set(QT_DEPLOY_PREFIX \"$<TARGET_FILE_DIR:App>\")
# set(QT_DEPLOY_PREFIX \"$<TARGET_FILE_DIR:App>\")
qt_deploy_runtime_dependencies(
EXECUTABLE \"$<TARGET_FILE:App>\"
BIN_DIR .
NO_TRANSLATIONS
NO_COMPILER_RUNTIME
VERBOSE
)")
endif()
@ -98,11 +98,7 @@ endif()
#
# CPack configuration.
#
if(ZEAL_PORTABLE_BUILD)
set(CPACK_GENERATOR "ZIP")
else()
set(CPACK_GENERATOR "ZIP;WIX")
endif()
set(CPACK_GENERATOR "ZIP")
set(CPACK_VERBATIM_VARIABLES YES)
@ -125,20 +121,29 @@ set(CPACK_RESOURCE_FILE_README "${CMAKE_SOURCE_DIR}/README.md")
set(CPACK_PACKAGE_CHECKSUM SHA256)
# CPack WiX configuration.
set(CPACK_WIX_UPGRADE_GUID "5C4B6030-A1B4-4EFE-A5AF-28F6FA2E7978")
set(CPACK_WIX_PROPERTY_ARPURLINFOABOUT "${CMAKE_PROJECT_HOMEPAGE_URL}")
set(CPACK_WIX_PRODUCT_ICON "${CMAKE_SOURCE_DIR}/src/app/resources/zeal.ico")
#set(CPACK_WIX_UI_BANNER "${CMAKE_SOURCE_DIR}/pkg/wix/banner.png")
#set(CPACK_WIX_UI_DIALOG "${CMAKE_SOURCE_DIR}/pkg/wix/dialog.png")
set(CPACK_WIX_EXTENSIONS "WixUtilExtension.dll")
set(CPACK_WIX_UI_REF "Zeal_InstallDir")
set(CPACK_WIX_TEMPLATE "${CMAKE_SOURCE_DIR}/pkg/wix/template.xml")
set(CPACK_WIX_PATCH_FILE "${CMAKE_SOURCE_DIR}/pkg/wix/patch.xml")
set(CPACK_WIX_EXTRA_SOURCES
"${CMAKE_SOURCE_DIR}/pkg/wix/ui.wxs"
"${CMAKE_SOURCE_DIR}/pkg/wix/exitdialog.wxs"
)
if(WIN32)
# CPack WiX configuration.
set(CPACK_WIX_UPGRADE_GUID "5C4B6030-A1B4-4EFE-A5AF-28F6FA2E7978")
set(CPACK_WIX_PROPERTY_ARPURLINFOABOUT "${CMAKE_PROJECT_HOMEPAGE_URL}")
set(CPACK_WIX_PRODUCT_ICON "${CMAKE_SOURCE_DIR}/src/app/resources/zeal.ico")
#set(CPACK_WIX_UI_BANNER "${CMAKE_SOURCE_DIR}/pkg/wix/banner.png")
#set(CPACK_WIX_UI_DIALOG "${CMAKE_SOURCE_DIR}/pkg/wix/dialog.png")
set(CPACK_WIX_EXTENSIONS "WixUtilExtension.dll")
set(CPACK_WIX_UI_REF "Zeal_InstallDir")
set(CPACK_WIX_TEMPLATE "${CMAKE_SOURCE_DIR}/pkg/wix/template.xml")
set(CPACK_WIX_PATCH_FILE "${CMAKE_SOURCE_DIR}/pkg/wix/patch.xml")
set(CPACK_WIX_EXTRA_SOURCES
"${CMAKE_SOURCE_DIR}/pkg/wix/ui.wxs"
"${CMAKE_SOURCE_DIR}/pkg/wix/exitdialog.wxs"
)
set(CPACK_PRE_BUILD_SCRIPTS "${CMAKE_SOURCE_DIR}/pkg/wix/cpack_pre_build.cmake")
if(NOT ZEAL_PORTABLE_BUILD)
list(APPEND CPACK_GENERATOR "WIX")
set(CPACK_POST_BUILD_SCRIPTS "${CMAKE_SOURCE_DIR}/pkg/wix/cpack_post_build.cmake")
endif()
endif()
# Set options for the source package.
# Usage: cmake --build <build> --target package_source