diff --git a/.github/releasers/macos/Info.plist b/.github/releasers/macos/Info.plist
index 30fb8745a..812fd4ab6 100644
--- a/.github/releasers/macos/Info.plist
+++ b/.github/releasers/macos/Info.plist
@@ -5,7 +5,7 @@
CFBundlePackageType
APPL
CFBundleIdentifier
- com.github.pactus-project.pactus.pactus-gui
+ org.pactus.pacgui
CFBundleExecutable
pactus-gui
CFBundleName
diff --git a/.github/releasers/releaser_gui_macos.sh b/.github/releasers/releaser_gui_macos.sh
index 2b953f048..29dbe289b 100644
--- a/.github/releasers/releaser_gui_macos.sh
+++ b/.github/releasers/releaser_gui_macos.sh
@@ -77,17 +77,113 @@ ${BUNDLER} ${GUI_BUNDLE}/gui.bundle
# Removing Cellar as workaround
rm -rf ${ROOT_DIR}/pactus-gui.app/Contents/Resources/Cellar
+
+# After gtk-mac-bundler and your fix-install-names script...
+
+if [ ! -z "${MACOS_CERT_IDENTITY}" ]; then
+ echo "=== Signing all Mach-O files inside the app bundle (dylibs, .so, executables, etc.)..."
+
+ # Create a temporary file to list all Mach-O binaries
+ find ${ROOT_DIR}/pactus-gui.app/Contents -type f -exec file {} \; | grep "Mach-O" | cut -d: -f1 > /tmp/macho_files.txt
+
+ # First, sign only the .dylib and .so files (if any)
+ grep -E '\.(dylib|so)$' /tmp/macho_files.txt | while read binary; do
+ echo "Signing library: $binary"
+ codesign --force --timestamp --verbose --sign "${MACOS_CERT_IDENTITY}" "$binary"
+ if [ $? -ne 0 ]; then exit 1; fi
+ done
+
+ # Then sign all other Mach-O binaries (executables, helpers, etc.)
+ grep -v -E '\.(dylib|so)$' /tmp/macho_files.txt | while read binary; do
+ echo "Signing binary: $binary"
+ codesign --force --timestamp --verbose --sign "${MACOS_CERT_IDENTITY}" "$binary"
+ if [ $? -ne 0 ]; then exit 1; fi
+ done
+
+ # Sign standalone binaries outside the app (if any)
+ for bin in pactus-daemon pactus-wallet pactus-shell pactus-gui; do
+ if [ -f "${BUILD_DIR}/${bin}" ]; then
+ echo "Signing standalone binary: ${BUILD_DIR}/${bin}"
+ codesign --force --timestamp --verbose --sign "${MACOS_CERT_IDENTITY}" "${BUILD_DIR}/${bin}"
+ fi
+ done
+
+ echo "=== Signing the whole app bundle (top-level)..."
+ codesign --force --timestamp --verbose --sign "${MACOS_CERT_IDENTITY}" ${ROOT_DIR}/pactus-gui.app
+
+ echo "=== Verification: checking the final app bundle..."
+ codesign --verify --verbose --deep --strict ${ROOT_DIR}/pactus-gui.app
+ if [ $? -ne 0 ]; then
+ echo "ERROR: App bundle verification failed!"
+ exit 1
+ fi
+fi
+
+# if [ ! -z "${MACOS_CERT_IDENTITY}" ]; then
+# echo "=== Signing artifacts..."
+# codesign --force --timestamp --sign "${MACOS_CERT_IDENTITY}" ${BUILD_DIR}/pactus-daemon
+# codesign --force --timestamp --sign "${MACOS_CERT_IDENTITY}" ${BUILD_DIR}/pactus-wallet
+# codesign --force --timestamp --sign "${MACOS_CERT_IDENTITY}" ${BUILD_DIR}/pactus-shell
+# codesign --force --timestamp --sign "${MACOS_CERT_IDENTITY}" ${BUILD_DIR}/pactus-gui
+
+# echo "=== Signing app bundle..."
+# codesign --force --timestamp --sign "${MACOS_CERT_IDENTITY}" ${ROOT_DIR}/pactus-gui.app
+# fi
+
echo "Creating dmg"
# https://github.com/create-dmg/create-dmg
-
create-dmg --version
-
create-dmg --skip-jenkins \
--volname "Pactus GUI" \
"${FILE_NAME}.dmg" \
"${ROOT_DIR}/pactus-gui.app"
-echo "Creating archive"
+
+
+if [ ! -z "${APPLE_ID}" ]; then
+ echo "=== Submitting for notarization..."
+
+ # Capture submission ID and check final status
+ SUBMISSION_ID=$(xcrun notarytool submit "${FILE_NAME}.dmg" \
+ --apple-id "${APPLE_ID}" \
+ --password "${APPLE_PASSWORD}" \
+ --team-id "${APPLE_TEAM_ID}" \
+ --wait --output-format json | jq -r '.id')
+
+ STATUS=$(xcrun notarytool info "$SUBMISSION_ID" \
+ --apple-id "${APPLE_ID}" \
+ --password "${APPLE_PASSWORD}" \
+ --team-id "${APPLE_TEAM_ID}" \
+ --output-format json | jq -r '.status')
+
+ if [ "$STATUS" != "Accepted" ]; then
+ echo "Notarization failed with status: $STATUS"
+ xcrun notarytool log "$SUBMISSION_ID" \
+ --apple-id "${APPLE_ID}" \
+ --password "${APPLE_PASSWORD}" \
+ --team-id "${APPLE_TEAM_ID}" \
+ notarization.log
+ cat notarization.log
+ exit 1
+ fi
+
+
+
+ # xcrun notarytool submit "${FILE_NAME}.dmg" \
+ # --apple-id "${APPLE_ID}" \
+ # --password "${APPLE_PASSWORD}" \
+ # --team-id "${APPLE_TEAM_ID}" \
+ # --wait
+
+ # echo "Stapling DMG only (the app inside gets the ticket automatically)..."
+ # # ✅ FIX: Only staple the DMG – the .app was not notarized separately, so stapling it would cause error 65.
+ # xcrun stapler staple "${FILE_NAME}.dmg"
+
+ # # ❌ REMOVED: Stapling the standalone .app
+ # # xcrun stapler staple "${ROOT_DIR}/pactus-gui.app"
+fi
+
+echo "Creating tar.gz archive"
cp ${BUILD_DIR}/pactus-daemon ${PACKAGE_DIR}
cp ${BUILD_DIR}/pactus-wallet ${PACKAGE_DIR}
cp ${BUILD_DIR}/pactus-shell ${PACKAGE_DIR}
diff --git a/.github/workflows/releaser.yml b/.github/workflows/releaser.yml
index de1a87fd9..1d85ea6c2 100644
--- a/.github/workflows/releaser.yml
+++ b/.github/workflows/releaser.yml
@@ -121,8 +121,22 @@ jobs:
with:
go-version: "1.26.2"
+ - name: Import macOS Certificates
+ uses: apple-actions/import-codesign-certs@v1
+ with:
+ p12-file-base64: ${{ secrets.MACOS_CERTIFICATE }}
+ p12-password: ${{ secrets.MACOS_CERTIFICATE_PWD }}
+
+ - name: List Identities
+ run: security find-identity -v -p codesigning
+
- name: Create release files
run: bash ./.github/releasers/releaser_gui_macos.sh
+ env:
+ MACOS_CERT_IDENTITY: ${{ secrets.MACOS_CERT_IDENTITY }}
+ APPLE_ID: ${{ secrets.APPLE_ID }}
+ APPLE_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
+ APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
- name: Calculate sha256sum
run: sha256sum pactus-*.dmg pactus-*.tar.gz > checksum-${{ matrix.name }}.txt
diff --git a/.github/workflows/test-macos-signing.yml b/.github/workflows/test-macos-signing.yml
new file mode 100644
index 000000000..6f6789c56
--- /dev/null
+++ b/.github/workflows/test-macos-signing.yml
@@ -0,0 +1,60 @@
+name: Test macOS Signing
+
+on:
+ pull_request:
+ workflow_dispatch:
+
+jobs:
+ test-gui-macos:
+ runs-on: ${{ matrix.runner }}
+ strategy:
+ matrix:
+ name: [macos-amd64, macos-arm64]
+ include:
+ - name: macos-amd64
+ runner: macos-15-intel
+ lib_home: /usr/local
+ - name: macos-arm64
+ runner: macos-15
+ lib_home: /opt/homebrew
+
+ env:
+ LIB_HOME: ${{ matrix.lib_home }}
+
+ steps:
+ - uses: actions/checkout@v6
+ with:
+ fetch-depth: 0 # Required for git describe
+
+ - name: Install Dependencies
+ run: brew install gtk+3 librsvg create-dmg coreutils gdk-pixbuf glib-networking pkg-config
+
+ - name: Install Go
+ uses: actions/setup-go@v6
+ with:
+ go-version: "1.26.2"
+
+ - name: Import macOS Certificates
+ uses: apple-actions/import-codesign-certs@v6
+ with:
+ p12-file-base64: ${{ secrets.MACOS_CERTIFICATE }}
+ p12-password: ${{ secrets.MACOS_CERTIFICATE_PWD }}
+
+ - name: List Identities
+ run: security find-identity -v -p codesigning
+
+ - name: Create release files
+ run: bash ./.github/releasers/releaser_gui_macos.sh
+ env:
+ MACOS_CERT_IDENTITY: ${{ secrets.MACOS_CERT_IDENTITY }}
+ APPLE_ID: ${{ secrets.APPLE_ID }}
+ APPLE_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
+ APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
+
+ - name: Upload Artifacts
+ uses: actions/upload-artifact@v6
+ with:
+ name: pactus-gui-test-${{ matrix.name }}
+ path: |
+ pactus-*.dmg
+ pactus-*.tar.gz