Fix macos signing and clean up CI (#4020)

* Fix macos signing and clean up CI

* Get version on mac similar to windows
This commit is contained in:
borgmanJeremy
2025-06-23 20:04:25 -05:00
committed by GitHub
parent ef93ad9481
commit 7e3f2901f3
9 changed files with 172 additions and 255 deletions

View File

@@ -4,7 +4,6 @@ on:
push:
branches:
- master
- fix*
paths-ignore:
- 'README.md'
- 'LICENSE'
@@ -36,25 +35,7 @@ jobs:
runs-on: ${{ matrix.dist.os }}
env:
APP_NAME: flameshot
DIR_BULD: build
DIR_PKG: build/src
HELPERS_SCRIPTS_PATH: ../../packaging/macos
# Apple developer identity, example: "Developer ID Application: <user name> (code)"
# Note: no signing and notarization will be proceed if this variable is not set
APPLE_DEV_IDENTITY: ${{ secrets.APPLE_DEV_IDENTITY }}
# Apple ID user
APPLE_DEV_USER: ${{ secrets.APPLE_DEV_USER }}
# Apple ID user password
APPLE_DEV_PASS: ${{ secrets.APPLE_DEV_PASS }}
# Apple certificate with private and public keys in base64 format
APPLE_DEVELOPER_ID_APPLICATION_CERT_DATA: ${{ secrets.APPLE_DEVELOPER_ID_APPLICATION_CERT_DATA }}
# Apple certificate password
APPLE_DEVELOPER_ID_APPLICATION_CERT_PASS: ${{ secrets.APPLE_DEVELOPER_ID_APPLICATION_CERT_PASS }}
# Any temporary password for keychain, which will be created on github actions CI
APPLE_TEMP_CI_KEYCHAIN_PASS: ${{ secrets.APPLE_TEMP_CI_KEYCHAIN_PASS }}
# Temporary variable for internal use, it will be set on the "Build dmg" step
NOTARIZATION_CHECK: false
DIR_BUILD: build
steps:
- name: Checkout Source code
if: github.event_name == 'push'
@@ -83,6 +64,9 @@ jobs:
echo ${last_committed_tag:1}
echo "Details: ${ver_info}"
echo "================================"
# This will allow to build pre-preleases without git tag
# echo "VERSION=${last_committed_tag:1}" >> $GITHUB_ENV
echo "VERSION=$(cat CMakeLists.txt |grep 'set.*(.*FLAMESHOT_VERSION' | sed 's/[^0-9.]*//' |sed 's/)//g')" >> $GITHUB_ENV
echo "VER_INFO=${ver_info}" >> $GITHUB_ENV
- name: Install Qt
@@ -90,36 +74,21 @@ jobs:
- name: Configure
run: |
rm -rf "${DIR_BULD}"/src/flameshot.dmg "${DIR_BULD}"/src/flameshot.app/
cmake -S . -B "${DIR_BULD}" -DQt6_DIR=$(brew --prefix qt6)/lib/cmake/Qt6 -DUSE_MONOCHROME_ICON=True
rm -rf "${DIR_BUILD}"/src/flameshot.dmg "${DIR_BUILD}"/src/flameshot.app/
cmake -GNinja -S . -B "${DIR_BUILD}" -DQt6_DIR=$(brew --prefix qt6)/lib/cmake/Qt6 -DUSE_MONOCHROME_ICON=True
- name: Compile
run: |
cmake --build "${DIR_BULD}"
- name: Create key-chain and import certificate
run: |
cd "${DIR_PKG}"
${HELPERS_SCRIPTS_PATH}/create_keychain.sh flameshot
cmake --build "${DIR_BUILD}"
- name: Build dmg package
run: |
cd "${DIR_PKG}"
${HELPERS_SCRIPTS_PATH}/sign_qtapp.sh flameshot
cd "${DIR_BUILD}"
ninja create_dmg
- name: Artifact Upload
uses: actions/upload-artifact@v4
with:
name: ${{ env.PRODUCT }}-${{ env.VER_INFO }}-artifact-macos-${{ matrix.dist.arch }}
path: ${{ github.workspace }}/build/src/flameshot.dmg
overwrite: true
- name: Notarization status
shell: bash
run: |
if [[ "${NOTARIZATION_CHECK}" == "true" ]]; then
echo "Notarization check succeed"
else
echo "::warning Notarization check failed"
# exit 1
fi
path: ${{ github.workspace }}/build/src/Flameshot-${{ env.VERSION }}.dmg
overwrite: true

View File

@@ -80,8 +80,6 @@ if(WIN32)
add_definitions(-DFLAMESHOT_VERSION_STRING="${PROJECT_VERSION}")
elseif(APPLE)
set(Qt6_DIR "$(brew --prefix qt6)/lib/cmake/Qt6/" CACHE PATH "directory where Qt6Config.cmake exists.")
set(CMAKE_MACOSX_BUNDLE ON)
set(CMAKE_MACOSX_RPATH ON)
endif()
set(RUN_IN_PLACE
${DEFAULT_RUN_IN_PLACE}

View File

@@ -1,24 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleExecutable</key>
<string>Flameshot</string>
<key>CFBundleIconFile</key>
<string>flameshot</string>
<key>CFBundleIdentifier</key>
<string>com.Flameshot.flameshot</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>LSMinimumSystemVersion</key>
<string>10.13</string>
<key>NOTE</key>
<string>This file was generated by Qt/QMake.</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>NSSupportsAutomaticGraphicsSwitching</key>
<true/>
</dict>
</plist>

96
packaging/macos/create_dmg.sh Executable file
View File

@@ -0,0 +1,96 @@
#!/bin/bash
# Script to create and optionally sign a DMG file
# Usage: create_dmg.sh <app_path> <dmg_path> <app_sign_identity> <dmg_sign_identity>
# If signing identities are empty, DMG will be created unsigned
APP_PATH="$1"
DMG_PATH="$2"
APP_SIGN_IDENTITY="$3"
DMG_SIGN_IDENTITY="$4"
if [ $# -ne 4 ]; then
echo "Usage: create_dmg.sh <app_path> <dmg_path> <app_sign_identity> <dmg_sign_identity>"
echo "Note: Leave signing identities empty to create unsigned DMG"
exit 1
fi
echo "Creating DMG from: $APP_PATH"
echo "Output DMG: $DMG_PATH"
rm -f "$DMG_PATH"
TEMP_DIR=$(mktemp -d)
echo "Using temp directory: $TEMP_DIR"
cp -R "$APP_PATH" "$TEMP_DIR/"
# Create Applications symlink
ln -s /Applications "$TEMP_DIR/Applications"
# Calculate size needed for DMG (in KB)
SIZE=$(du -sk "$TEMP_DIR" | cut -f1)
SIZE=$((SIZE + 1000)) # Add some padding
echo "Creating DMG with size: ${SIZE}k"
# Create DMG
hdiutil create -srcfolder "$TEMP_DIR" \
-volname "Flameshot" \
-fs HFS+ \
-fsargs "-c c=64,a=16,e=16" \
-format UDZO \
-size ${SIZE}k \
"$DMG_PATH"
if [ $? -ne 0 ]; then
echo "Failed to create DMG"
rm -rf "$TEMP_DIR"
exit 1
fi
echo "DMG created successfully"
# Sign the DMG (either with identity or ad hoc)
if [ -n "$DMG_SIGN_IDENTITY" ] && [ "$DMG_SIGN_IDENTITY" != "" ]; then
echo "Signing DMG with identity: $DMG_SIGN_IDENTITY"
codesign --force --sign "$DMG_SIGN_IDENTITY" --timestamp "$DMG_PATH"
if [ $? -eq 0 ]; then
echo "DMG signed with Developer ID"
# Verify signature
echo "Verifying DMG signature..."
codesign --verify --verbose "$DMG_PATH"
else
echo "Failed to sign DMG with identity"
rm -rf "$TEMP_DIR"
exit 1
fi
else
echo "Signing DMG with ad hoc signature (no identity required)"
codesign --force --sign - "$DMG_PATH"
if [ $? -eq 0 ]; then
echo "DMG signed with ad hoc signature"
else
echo "Failed to ad hoc sign DMG"
rm -rf "$TEMP_DIR"
exit 1
fi
fi
# Clean up
rm -rf "$TEMP_DIR"
echo "DMG creation complete: $DMG_PATH"
if [ -z "$DMG_SIGN_IDENTITY" ] || [ "$DMG_SIGN_IDENTITY" = "" ]; then
echo ""
echo "NOTE: This DMG uses ad hoc signing (no Developer ID required)."
echo "Users will see a security warning but can still run the app by:"
echo "1. Right-clicking the app and selecting 'Open'"
echo "2. Or going to System Preferences > Security & Privacy and clicking 'Open Anyway'"
echo "3. The warning only appears on first launch"
echo ""
echo "The app and DMG are properly signed for Apple Silicon requirements."
fi

View File

@@ -1,33 +0,0 @@
#!/bin/bash
# Inspired by
# https://localazy.com/blog/how-to-automatically-sign-macos-apps-using-github-actions
TEMP_CI_CERT_FILENAME="temp_ci_appleDistribution.p12"
# Get the following variables from MacOS-pack.yaml:
# APP_NAME
# APPLE_DEV_IDENTITY
# APPLE_DEVELOPER_ID_APPLICATION_CERT_PASS
# APPLE_DEVELOPER_ID_APPLICATION_CERT_DATA
# APPLE_TEMP_CI_KEYCHAIN_PASS
# For the Community (if no Apple Developer ID available)
if [[ "${APPLE_DEV_IDENTITY}" == "" ]]; then
echo "WARNING: No credentials for signing found"
echo "WARNING: Cannot create keychain for signing"
echo "WARNING: dmg package won't be signed and notarized"
exit 0
fi
# create keychain
security create-keychain -p "${APPLE_TEMP_CI_KEYCHAIN_PASS}" build.keychain
security default-keychain -s build.keychain
security unlock-keychain -p "${APPLE_TEMP_CI_KEYCHAIN_PASS}" build.keychain
# import certificate
[ -r "${TEMP_CI_CERT_FILENAME}" ] && rm "${TEMP_CI_CERT_FILENAME}"
echo "${APPLE_DEVELOPER_ID_APPLICATION_CERT_DATA}" | base64 --decode > "${TEMP_CI_CERT_FILENAME}"
security import "${TEMP_CI_CERT_FILENAME}" -P "${APPLE_DEVELOPER_ID_APPLICATION_CERT_PASS}" -k build.keychain -T /usr/bin/codesign
[ -r "${TEMP_CI_CERT_FILENAME}" ] && rm "${TEMP_CI_CERT_FILENAME}"
security find-identity -v
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "${APPLE_TEMP_CI_KEYCHAIN_PASS}" build.keychain

Binary file not shown.

View File

@@ -1,80 +0,0 @@
#!/bin/bash
# Inspired by
# https://localazy.com/blog/how-to-automatically-sign-macos-apps-using-github-actions
# https://forum.qt.io/topic/96652/how-to-notarize-qt-application-on-macos/18
# Get the following variables from the MacOS-pack.yaml:
# APP_NAME
# APPLE_DEV_IDENTITY
# APPLE_DEV_USER
# APPLE_DEV_PASS
# For the Community (if no Apple Developer ID available)
if [[ "${APPLE_DEV_IDENTITY}" == "" ]]; then
echo "WARNING: No credentials for signing found"
echo "WARNING: dmg package won't be signed and notarized"
echo "--> Start packaging process"
"$(brew --prefix qt6)/bin/macdeployqt" "${APP_NAME}.app" -dmg
echo "--> Update dmg package links"
"./${HELPERS_SCRIPTS_PATH}/update_package.sh"
exit 0
fi
echo "--> Start application signing process"
codesign --sign "${APPLE_DEV_IDENTITY}" --verbose --deep "${APP_NAME}.app"
echo "--> Start packaging process"
"$(brew --prefix qt6)/bin/macdeployqt" "${APP_NAME}.app" -dmg -sign-for-notarization="${APPLE_DEV_IDENTITY}"
echo "--> Update dmg package links"
"./${HELPERS_SCRIPTS_PATH}/update_package.sh"
echo "--> Start dmg signing process"
codesign --sign "${APPLE_DEV_IDENTITY}" --verbose --deep "${APP_NAME}.dmg"
echo "--> Start Notarization process"
response=$(xcrun altool -t osx -f "${APP_NAME}.dmg" --primary-bundle-id "org.namecheap.${APP_NAME}" --notarize-app -u "${APPLE_DEV_USER}" -p "${APPLE_DEV_PASS}")
requestUUID=$(echo "${response}" | tr ' ' '\n' | tail -1)
for ((ATTEMPT=5; ATTEMPT>=1; ATTEMPT--))
do
echo "--> Checking notarization status"
statusCheckResponse=$(xcrun altool --notarization-info "${requestUUID}" -u "${APPLE_DEV_USER}" -p "${APPLE_DEV_PASS}")
isSuccess=$(echo "${statusCheckResponse}" | grep "success")
isFailure=$(echo "${statusCheckResponse}" | grep "invalid")
if [[ "${isSuccess}" != "" ]]; then
echo "Notarization done!"
xcrun stapler staple "${APP_NAME}.dmg"
EXIT_CODE=$?
if [ ${EXIT_CODE} -ne 0 ]; then
echo "Stapler failed!"
exit ${EXIT_CODE}
fi
echo "Stapler done!"
break
fi
if [[ "${isFailure}" != "" ]]; then
echo "${statusCheckResponse}"
echo "Notarization failed"
exit 1
fi
echo "Notarization not finished yet, sleep 2m then check again..."
for num in {1..12}
do
sleep 10
echo "Elapsed: ${num}0 sec"
done
done
if [[ "${ATTEMPT}" == 0 ]]; then
export NOTARIZATION_CHECK="false"
echo "::warning Notarization check failed"
else
export NOTARIZATION_CHECK="true"
fi
echo "--> Start verify signing process"
codesign -dv --verbose=4 "${APP_NAME}.dmg"

View File

@@ -1,55 +0,0 @@
#!/bin/bash
echo "Change the permission of .dmg file"
hdiutil convert "flameshot.dmg" -format UDRW -o "flameshot_rw.dmg"
echo "Mount it and save the device"
DEVICE=$(hdiutil attach -readwrite -noverify "flameshot_rw.dmg" | grep -E '^/dev/' | sed 1q | awk '{print $1}')
sleep 5
echo "Create the sysmbolic link to application folder"
PATH_AT_VOLUME="/Volumes/flameshot/"
CURRENT_PATH="$(pwd)"
cd "${PATH_AT_VOLUME}"
ln -s /Applications
cd "${CURRENT_PATH}"
# TODO - add background and icon location.
# https://forum.qt.io/topic/94987/how-can-i-add-symbolic-link-application-and-background-image-in-dmg-package/3
#echo "copy the background image in to package"
#mkdir -p "${PATH_AT_VOLUME}".background/
#cp backgroundImage.png "${PATH_AT_VOLUME}".background/
#echo "done"
#
## tell the Finder to resize the window, set the background,
## change the icon size, place the icons in the right position, etc.
#echo '
# tell application "Finder"
# tell disk "/Volumes/src:flameshot"
# open
# set current view of container window to icon view
# set toolbar visible of container window to false
# set statusbar visible of container window to false
# set the bounds of container window to {400, 100, 1110, 645}
# set viewOptions to the icon view options of container window
# set arrangement of viewOptions to not arranged
# set icon size of viewOptions to 72
# set background picture of viewOptions to file ".background:backgroundImage.png"
# set position of item "flameshot.app" of container window to {160, 325}
# set position of item "Applications" of container window to {560, 320}
# close
# open
# update without registering applications
# delay 2
# end tell
# end tell
#' | osascript
#
#sync
# unmount it
hdiutil detach "${DEVICE}"
rm -f "flameshot.dmg"
hdiutil convert "flameshot_rw.dmg" -format UDZO -o "flameshot.dmg"
rm -f "flameshot_rw.dmg"

View File

@@ -229,12 +229,14 @@ if (USE_WAYLAND_CLIPBOARD)
endif()
if (APPLE)
set(MACOSX_BUNDLE_IDENTIFIER "org.flameshot")
set_target_properties(
flameshot
PROPERTIES
XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER ${MACOSX_BUNDLE_IDENTIFIER}
)
set_target_properties(flameshot PROPERTIES
MACOSX_BUNDLE TRUE
MACOSX_BUNDLE_BUNDLE_NAME "Flameshot"
MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION}
MACOSX_BUNDLE_IDENTIFIER "org.flameshot.Flameshot"
MACOSX_BUNDLE_GUI_IDENTIFIER "org.flameshot.Flameshot"
)
target_link_libraries(
flameshot
qhotkey
@@ -443,18 +445,62 @@ endif ()
# macdeployqt
if (APPLE)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
execute_process(COMMAND brew --prefix qt5 OUTPUT_VARIABLE QTDIR)
string(REGEX REPLACE "\n$" "" QTDIR "${QTDIR}")
set(MAC_DEPLOY_QT ${QTDIR}/bin/macdeployqt)
if (EXISTS ${MAC_DEPLOY_QT})
set_source_files_properties(resources/icon.icns PROPERTIES
MACOSX_PACKAGE_LOCATION Resources)
# Code signing settings - optional, set to empty string to skip signing
set(CODE_SIGN_IDENTITY "" CACHE STRING "Code signing identity (leave empty to skip signing)")
set(DMG_SIGN_IDENTITY "" CACHE STRING "DMG signing identity (leave empty to skip signing)")
# Custom target to create DMG (signed or unsigned)
add_custom_target(create_dmg
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/../packaging/macos/create_dmg.sh
"${CMAKE_CURRENT_BINARY_DIR}/Flameshot.app"
"${CMAKE_CURRENT_BINARY_DIR}/Flameshot-${PROJECT_VERSION}.dmg"
"${CODE_SIGN_IDENTITY}"
"${DMG_SIGN_IDENTITY}"
DEPENDS flameshot
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Creating DMG"
VERBATIM
)
# Always sign the app bundle (either with identity or ad hoc)
if(CODE_SIGN_IDENTITY AND NOT CODE_SIGN_IDENTITY STREQUAL "")
# Identity-based signing (requires Developer ID)
add_custom_command(TARGET flameshot POST_BUILD
COMMAND codesign --force --deep --sign "${CODE_SIGN_IDENTITY}"
--options runtime --timestamp "$<TARGET_BUNDLE_DIR:flameshot>"
COMMENT "Code signing app bundle with ${CODE_SIGN_IDENTITY}"
)
else()
# Ad hoc signing
add_custom_command(TARGET flameshot POST_BUILD
COMMAND codesign --force --deep --sign - "$<TARGET_BUNDLE_DIR:flameshot>"
COMMENT "Ad hoc code signing app bundle (no identity required)"
)
endif()
# Deploy Qt libraries and dependencies
find_program(MACDEPLOYQT_EXECUTABLE macdeployqt HINTS ${Qt6_DIR}/../../../bin)
if(MACDEPLOYQT_EXECUTABLE)
add_custom_command(TARGET flameshot POST_BUILD
COMMAND ${MACDEPLOYQT_EXECUTABLE} "$<TARGET_BUNDLE_DIR:flameshot>" -verbose=2
COMMENT "Deploying Qt libraries"
)
# Re-sign after macdeployqt (it modifies the bundle)
if(CODE_SIGN_IDENTITY AND NOT CODE_SIGN_IDENTITY STREQUAL "")
add_custom_command(TARGET flameshot POST_BUILD
COMMAND codesign --force --deep --sign "${CODE_SIGN_IDENTITY}"
--options runtime --timestamp "$<TARGET_BUNDLE_DIR:flameshot>"
COMMENT "Re-signing app bundle after Qt deployment"
)
else()
add_custom_command(TARGET flameshot POST_BUILD
COMMAND codesign --force --deep --sign - "$<TARGET_BUNDLE_DIR:flameshot>"
COMMENT "Re-signing app bundle after Qt deployment (ad hoc)"
)
endif()
else()
message(WARNING "macdeployqt not found. App may not run on systems without Qt installed.")
endif()
set_target_properties(${target} PROPERTIES
MACOSX_BUNDLE TRUE
)
else ()
message("Unable to find executable ${MAC_DEPLOY_QT}.")
endif ()
endif ()