diff --git a/.github/workflows/release-packages.yml b/.github/workflows/release-packages.yml index 70019455..82e91c81 100644 --- a/.github/workflows/release-packages.yml +++ b/.github/workflows/release-packages.yml @@ -122,46 +122,91 @@ jobs: APPLE_API_KEY_BASE64: ${{ secrets.GWS_APPLE_API_KEY_BASE64 }} APPLE_API_KEY: ${{ secrets.GWS_APPLE_API_KEY }} - - name: Configure macOS installer signing + - name: Import signing certificates env: - APPLE_SIGN_IDENTITY: ${{ secrets.GWS_APPLE_SIGN_IDENTITY }} + APPLICATION_P12: ${{ secrets.GWS_APPLE_SIGN_APPLICATION_P12 }} + INSTALLER_P12: ${{ secrets.GWS_APPLE_SIGN_INSTALLER_P12 }} + P12_PASSWORD: ${{ secrets.GWS_APPLE_SIGN_PW }} run: | - cat <> src/Cargo.toml - - [package.metadata.packager.macos] - signing-identity = "${APPLE_SIGN_IDENTITY}" - entitlements = "entitlements.plist" - EOF - - - name: Install cargo-packager - run: cargo install cargo-packager --locked + KEYCHAIN_PATH="$RUNNER_TEMP/signing.keychain-db" + KEYCHAIN_PW="$(openssl rand -hex 32)" + security create-keychain -p "$KEYCHAIN_PW" "$KEYCHAIN_PATH" + security set-keychain-settings "$KEYCHAIN_PATH" + security unlock-keychain -p "$KEYCHAIN_PW" "$KEYCHAIN_PATH" + echo -n "$APPLICATION_P12" | base64 --decode -o "$RUNNER_TEMP/app.p12" + echo -n "$INSTALLER_P12" | base64 --decode -o "$RUNNER_TEMP/inst.p12" + security import "$RUNNER_TEMP/app.p12" -P "$P12_PASSWORD" -k "$KEYCHAIN_PATH" -T /usr/bin/codesign -T /usr/bin/pkgbuild + security import "$RUNNER_TEMP/inst.p12" -P "$P12_PASSWORD" -k "$KEYCHAIN_PATH" -T /usr/bin/codesign -T /usr/bin/pkgbuild + security set-key-partition-list -S apple-tool:,apple: -s -k "$KEYCHAIN_PW" "$KEYCHAIN_PATH" + security list-keychains -d user -s "$KEYCHAIN_PATH" $(security list-keychains -d user | tr -d '"') + + - name: Compute version from tag + run: | + VERSION="${GITHUB_REF_NAME#v}" + echo "VERSION=$VERSION" >> "$GITHUB_ENV" - name: Build ggsql binary (x86_64) run: cargo build --release --bin ggsql --bin ggsql-jupyter - - name: Bundle and sign dynamic library dependencies + - name: Bundle dynamic library dependencies run: | - dylibbundler -cd -of -b -x target/release/ggsql -d ./libs/ -p @executable_path/../Resources/libs/ - dylibbundler -cd -of -b -x target/release/ggsql-jupyter -d ./libs/ -p @executable_path/../Resources/libs/ + dylibbundler -cd -of -b -x target/release/ggsql -d ./libs/ -p "@executable_path/../lib/ggsql$VERSION/" + dylibbundler -cd -of -b -x target/release/ggsql-jupyter -d ./libs/ -p "@executable_path/../lib/ggsql$VERSION/" - - name: Ad-hoc sign binaries + - name: Sign binaries and dylibs (Developer ID Application) + env: + SIGN_ID: "Developer ID Application: ${{ secrets.GWS_APPLE_SIGN_IDENTITY }}" run: | - codesign --force --sign - target/release/ggsql - codesign --force --sign - target/release/ggsql-jupyter - - - name: Build DMG installer (x86_64) - run: cargo packager --release --formats dmg + # Sign bundled dylibs first (inside-out), replacing dylibbundler's ad-hoc sigs + find ./libs -type f \( -name "*.dylib" -o -name "*.so" \) -print0 | \ + xargs -0 -I{} codesign --force --options runtime --timestamp --sign "$SIGN_ID" "{}" + # Then sign the executables with hardened runtime + entitlements + codesign --force --options runtime --timestamp \ + --entitlements src/entitlements.plist \ + --sign "$SIGN_ID" target/release/ggsql + codesign --force --options runtime --timestamp \ + --entitlements src/entitlements.plist \ + --sign "$SIGN_ID" target/release/ggsql-jupyter + + - name: Build and notarize PKG installer (x86_64) + # NOTE: --sign uses the Developer ID *Installer* cert (signs .pkg only), + # distinct from the Developer ID Application cert used to sign Mach-O above. env: - APPLE_CERTIFICATE: ${{ secrets.GWS_APPLE_SIGN_P12 }} - APPLE_CERTIFICATE_PASSWORD: ${{ secrets.GWS_APPLE_SIGN_PW }} + SIGN_ID: "Developer ID Installer: ${{ secrets.GWS_APPLE_SIGN_IDENTITY }}" APPLE_API_KEY: ${{ secrets.GWS_APPLE_API_KEY }} APPLE_API_ISSUER: ${{ secrets.GWS_APPLE_API_ISSUER }} - - - name: Upload DMG installer (x86_64) + run: | + PKG_NAME="ggsql_${VERSION}_x86_64.pkg" + mkdir -p pkg-payload/usr/local/bin "pkg-payload/usr/local/lib/ggsql$VERSION" + cp target/release/ggsql pkg-payload/usr/local/bin/ + cp target/release/ggsql-jupyter pkg-payload/usr/local/bin/ + cp -R ./libs/. "pkg-payload/usr/local/lib/ggsql$VERSION/" + mkdir -p pkg-scripts + cat > pkg-scripts/postinstall <> src/Cargo.toml - - [package.metadata.packager.macos] - signing-identity = "${APPLE_SIGN_IDENTITY}" - entitlements = "entitlements.plist" - EOF - - - name: Install cargo-packager - run: cargo install cargo-packager --locked + KEYCHAIN_PATH="$RUNNER_TEMP/signing.keychain-db" + KEYCHAIN_PW="$(openssl rand -hex 32)" + security create-keychain -p "$KEYCHAIN_PW" "$KEYCHAIN_PATH" + security set-keychain-settings "$KEYCHAIN_PATH" + security unlock-keychain -p "$KEYCHAIN_PW" "$KEYCHAIN_PATH" + echo -n "$APPLICATION_P12" | base64 --decode -o "$RUNNER_TEMP/app.p12" + echo -n "$INSTALLER_P12" | base64 --decode -o "$RUNNER_TEMP/inst.p12" + security import "$RUNNER_TEMP/app.p12" -P "$P12_PASSWORD" -k "$KEYCHAIN_PATH" -T /usr/bin/codesign -T /usr/bin/pkgbuild + security import "$RUNNER_TEMP/inst.p12" -P "$P12_PASSWORD" -k "$KEYCHAIN_PATH" -T /usr/bin/codesign -T /usr/bin/pkgbuild + security set-key-partition-list -S apple-tool:,apple: -s -k "$KEYCHAIN_PW" "$KEYCHAIN_PATH" + security list-keychains -d user -s "$KEYCHAIN_PATH" $(security list-keychains -d user | tr -d '"') + + - name: Compute version from tag + run: | + VERSION="${GITHUB_REF_NAME#v}" + echo "VERSION=$VERSION" >> "$GITHUB_ENV" - name: Build ggsql binary (aarch64) run: cargo build --release --bin ggsql --bin ggsql-jupyter - - name: Bundle and sign dynamic library dependencies + - name: Bundle dynamic library dependencies run: | - dylibbundler -cd -of -b -x target/release/ggsql -d ./libs/ -p @executable_path/../Resources/libs/ - dylibbundler -cd -of -b -x target/release/ggsql-jupyter -d ./libs/ -p @executable_path/../Resources/libs/ + dylibbundler -cd -of -b -x target/release/ggsql -d ./libs/ -p "@executable_path/../lib/ggsql$VERSION/" + dylibbundler -cd -of -b -x target/release/ggsql-jupyter -d ./libs/ -p "@executable_path/../lib/ggsql$VERSION/" - - name: Build DMG installer (aarch64) - run: cargo packager --release --formats dmg + - name: Sign binaries and dylibs (Developer ID Application) env: - APPLE_CERTIFICATE: ${{ secrets.GWS_APPLE_SIGN_P12 }} - APPLE_CERTIFICATE_PASSWORD: ${{ secrets.GWS_APPLE_SIGN_PW }} + SIGN_ID: "Developer ID Application: ${{ secrets.GWS_APPLE_SIGN_IDENTITY }}" + run: | + # Sign bundled dylibs first (inside-out), replacing dylibbundler's ad-hoc sigs + find ./libs -type f \( -name "*.dylib" -o -name "*.so" \) -print0 | \ + xargs -0 -I{} codesign --force --options runtime --timestamp --sign "$SIGN_ID" "{}" + # Then sign the executables with hardened runtime + entitlements + codesign --force --options runtime --timestamp \ + --entitlements src/entitlements.plist \ + --sign "$SIGN_ID" target/release/ggsql + codesign --force --options runtime --timestamp \ + --entitlements src/entitlements.plist \ + --sign "$SIGN_ID" target/release/ggsql-jupyter + + - name: Build and notarize PKG installer (aarch64) + # NOTE: --sign uses the Developer ID *Installer* cert (signs .pkg only), + # distinct from the Developer ID Application cert used to sign Mach-O above. + env: + SIGN_ID: "Developer ID Installer: ${{ secrets.GWS_APPLE_SIGN_IDENTITY }}" APPLE_API_KEY: ${{ secrets.GWS_APPLE_API_KEY }} APPLE_API_ISSUER: ${{ secrets.GWS_APPLE_API_ISSUER }} - - - name: Upload DMG installer (aarch64) + run: | + PKG_NAME="ggsql_${VERSION}_aarch64.pkg" + mkdir -p pkg-payload/usr/local/bin "pkg-payload/usr/local/lib/ggsql$VERSION" + cp target/release/ggsql pkg-payload/usr/local/bin/ + cp target/release/ggsql-jupyter pkg-payload/usr/local/bin/ + cp -R ./libs/. "pkg-payload/usr/local/lib/ggsql$VERSION/" + mkdir -p pkg-scripts + cat > pkg-scripts/postinstall <