Skip to content

Merge pull request #52 from ledhed2222/mac-code-signing-fix #6

Merge pull request #52 from ledhed2222/mac-code-signing-fix

Merge pull request #52 from ledhed2222/mac-code-signing-fix #6

name: Build Native Installers
on:
push:
tags:
- 'v*' # Only builds on version tags like v2.4.3
workflow_dispatch: # Manual trigger from the GitHub UI
jobs:
macos:
runs-on: macos-latest # ARM runner (Apple Silicon, works on Intel via Rosetta 2)
steps:
- uses: actions/checkout@v4
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 21
- name: Extract version from pom.xml
id: version
run: |
VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "Building version: $VERSION"
- name: Import Code Signing Certificate
env:
CERTIFICATE_BASE64: ${{ secrets.MACOS_CERTIFICATE }}
CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PWD }}
KEYCHAIN_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PWD }}
run: |
# Create variables
CERTIFICATE_PATH=$RUNNER_TEMP/certificate.p12
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
# Decode certificate
echo -n "$CERTIFICATE_BASE64" | base64 --decode -o $CERTIFICATE_PATH
# Create temporary keychain
security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
# Import certificate to keychain
security import $CERTIFICATE_PATH -P "$CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
security list-keychain -d user -s $KEYCHAIN_PATH
# Enable codesigning from a non user interactive shell
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
- name: Build .jar
run: mvn clean package
- name: Build app bundle with jpackage
env:
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
run: |
# Get the certificate identity name
CERT_IDENTITY=$(security find-identity -v -p codesigning | grep "Developer ID Application" | head -1 | sed -n 's/.*"\(.*\)"/\1/p')
echo "Using certificate: $CERT_IDENTITY"
# First create just the app-image (app bundle), not DMG yet
jpackage \
--type app-image \
--name EWItool \
--input target \
--main-jar EWItool-${{ steps.version.outputs.version }}.jar \
--main-class com.github.ledhed2222.ewitool.Main \
--dest target \
--app-version ${{ steps.version.outputs.version }} \
--vendor "Ledhed2222" \
--icon src/main/resources/logo.icns
- name: Sign app bundle with hardened runtime
run: |
CERT_IDENTITY=$(security find-identity -v -p codesigning | grep "Developer ID Application" | head -1 | sed -n 's/.*"\(.*\)"/\1/p')
# Sign all nested binaries, libraries, and frameworks with hardened runtime
find target/EWItool.app/Contents -type f \( -name "*.dylib" -o -name "*.jnilib" -o -perm +111 \) | while read file; do
echo "Signing: $file"
codesign --force --sign "$CERT_IDENTITY" --timestamp --options runtime "$file" || true
done
# Sign the app bundle itself
codesign --force --sign "$CERT_IDENTITY" --timestamp --options runtime --deep target/EWItool.app
# Verify signature
codesign --verify --deep --strict --verbose=2 target/EWItool.app
- name: Create and sign DMG
run: |
CERT_IDENTITY=$(security find-identity -v -p codesigning | grep "Developer ID Application" | head -1 | sed -n 's/.*"\(.*\)"/\1/p')
# Create DMG from signed app bundle
hdiutil create -volname EWItool -srcfolder target/EWItool.app -ov -format UDZO target/EWItool-${{ steps.version.outputs.version }}.dmg
# Sign the DMG
codesign --force --sign "$CERT_IDENTITY" --timestamp target/EWItool-${{ steps.version.outputs.version }}.dmg
# Verify DMG signature
codesign --verify --verbose=4 target/EWItool-${{ steps.version.outputs.version }}.dmg
- name: Notarize DMG
env:
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_APP_PASSWORD: ${{ secrets.APPLE_APP_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
run: |
# Submit for notarization and capture submission ID
SUBMIT_OUTPUT=$(xcrun notarytool submit target/EWItool-${{ steps.version.outputs.version }}.dmg \
--apple-id "$APPLE_ID" \
--password "$APPLE_APP_PASSWORD" \
--team-id "$APPLE_TEAM_ID" \
--wait 2>&1)
echo "$SUBMIT_OUTPUT"
# Extract submission ID
SUBMISSION_ID=$(echo "$SUBMIT_OUTPUT" | grep "id:" | head -1 | awk '{print $2}')
echo "Submission ID: $SUBMISSION_ID"
# Check if notarization succeeded
if echo "$SUBMIT_OUTPUT" | grep -q "status: Accepted"; then
echo "Notarization succeeded!"
# Staple the notarization ticket
xcrun stapler staple target/EWItool-${{ steps.version.outputs.version }}.dmg
# Verify notarization
xcrun stapler validate target/EWItool-${{ steps.version.outputs.version }}.dmg
else
echo "Notarization failed. Getting log..."
xcrun notarytool log "$SUBMISSION_ID" \
--apple-id "$APPLE_ID" \
--password "$APPLE_APP_PASSWORD" \
--team-id "$APPLE_TEAM_ID"
exit 1
fi
- name: Rename DMG
run: |
mv target/EWItool-${{ steps.version.outputs.version }}.dmg target/EWItool-${{ steps.version.outputs.version }}-macos.dmg
- name: Upload to gh release
uses: softprops/action-gh-release@v1
with:
files: target/*-macos.dmg
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
windows:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 21
- name: Extract version from pom.xml
id: version
shell: pwsh
run: |
[xml]$pom = Get-Content pom.xml
$VERSION = $pom.project.version
echo "version=$VERSION" >> $env:GITHUB_OUTPUT
echo "Building version: $VERSION"
- name: Build .jar
run: mvn clean package
- name: Convert PNG to ICO for Windows
run: |
# jpackage will use PNG on Windows if ICO not available
# We'll use the PNG file directly
- name: Run jpackage for Windows
run: |
jpackage `
--type exe `
--name EWItool `
--input target `
--main-jar EWItool-${{ steps.version.outputs.version }}.jar `
--main-class com.github.ledhed2222.ewitool.Main `
--dest target `
--app-version ${{ steps.version.outputs.version }} `
--vendor "Ledhed2222" `
--icon src/main/resources/logo.png `
--win-dir-chooser `
--win-menu `
--win-shortcut
- name: Upload to gh release
uses: softprops/action-gh-release@v1
with:
files: target/*.exe
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
linux:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 21
- name: Extract version from pom.xml
id: version
run: |
VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "Building version: $VERSION"
- name: Install jpackage dependencies
run: |
sudo apt-get update
sudo apt-get install -y libfreetype6-dev libasound2-dev fakeroot rpm
- name: Build .jar
run: mvn clean package
- name: Run jpackage for Linux (DEB)
run: |
jpackage \
--type deb \
--name ewitool \
--input target \
--main-jar EWItool-${{ steps.version.outputs.version }}.jar \
--main-class com.github.ledhed2222.ewitool.Main \
--dest target \
--app-version ${{ steps.version.outputs.version }} \
--vendor "Ledhed2222" \
--icon src/main/resources/logo.png \
--linux-shortcut
- name: Run jpackage for Linux (RPM)
run: |
jpackage \
--type rpm \
--name ewitool \
--input target \
--main-jar EWItool-${{ steps.version.outputs.version }}.jar \
--main-class com.github.ledhed2222.ewitool.Main \
--dest target \
--app-version ${{ steps.version.outputs.version }} \
--vendor "Ledhed2222" \
--icon src/main/resources/logo.png \
--linux-shortcut
- name: Upload to gh release
uses: softprops/action-gh-release@v1
with:
files: |
target/*.deb
target/*.rpm
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}