mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-08-08 23:54:39 +00:00
fix(release): actually notarize the macOS DMG, and verify it
The macOS leg ran only `packageReleaseDmg`, which SIGNS the DMG but does not
notarize it — notarization is a separate Compose task. The `notarization {}`
block in desktopApp/build.gradle.kts only supplies credentials; nothing invoked
it. So every release up to v1.13.1 shipped a signed but unnotarized DMG:
`xcrun stapler validate` reports no ticket on either the .app or the .dmg, and
Gatekeeper blocks it on first launch.
Append `:desktopApp:notarizeReleaseDmg` on the macOS leg. Compose 1.11.1's
AbstractNotarizationTask runs `notarytool submit --wait` and then `stapler
staple` in place, so the asset-collection step still finds the same file. Raise
that leg's inner timeout to 45m since the submit blocks on Apple.
Gate it on the cert AND all three notary secrets, so forks and credential-less
runs keep producing a plain unsigned DMG instead of failing.
Add a verify step that asserts the stapled ticket. The bug survived many
releases precisely because nothing ever checked the outcome.
Also update the reference cask to 1.13.1 and make it pass `brew audit --new
--cask` + `brew style` cleanly: add the missing conflicts_with (the tiling
window manager's cask installs the same Amethyst.app), add depends_on :macos,
fix stanza order, drop the unnecessary `verified:` (url and homepage share a
domain), and widen the zap to the state dirs the source actually uses.
Correct BUILDING.md's macOS state table, which listed a
com.vitorpamplona.amethyst.desktop.plist that does not exist and omitted
~/.amethyst. Note that Java's Preferences API writes to a SHARED
com.apple.java.util.prefs.plist, which is why the cask must not zap it.
This commit is contained in:
@@ -155,8 +155,44 @@ jobs:
|
||||
AMETHYST_NOTARY_TEAM_ID: ${{ secrets.MAC_NOTARY_TEAM_ID }}
|
||||
with:
|
||||
max_attempts: 2
|
||||
timeout_minutes: 15
|
||||
command: ./gradlew --no-daemon :desktopApp:${{ matrix.tasks }}
|
||||
# macOS needs far longer: notarizeReleaseDmg blocks on `notarytool
|
||||
# submit --wait`, which is minutes-to-tens-of-minutes on Apple's side.
|
||||
timeout_minutes: ${{ matrix.family == 'macos' && 45 || 15 }}
|
||||
# Append notarization on the macOS leg. `packageReleaseDmg` only SIGNS
|
||||
# the DMG — notarization is a separate Compose task, and because it was
|
||||
# never invoked every release up to v1.13.1 shipped a signed but
|
||||
# UNNOTARIZED DMG that Gatekeeper blocks on first launch. The task runs
|
||||
# `notarytool submit --wait` and then `stapler staple`, in place, so the
|
||||
# asset-collection step below still finds the same file.
|
||||
#
|
||||
# Gated on the cert AND all three notary secrets being present, so forks
|
||||
# and credential-less runs keep producing a plain unsigned DMG exactly as
|
||||
# before instead of failing.
|
||||
command: ./gradlew --no-daemon :desktopApp:${{ matrix.tasks }}${{ (matrix.family == 'macos' && steps.mac_keychain.outputs.signing == 'true' && secrets.MAC_NOTARY_APPLE_ID != '' && secrets.MAC_NOTARY_PASSWORD != '' && secrets.MAC_NOTARY_TEAM_ID != '') && ' :desktopApp:notarizeReleaseDmg' || '' }}
|
||||
|
||||
# Regression guard. The missing-notarization bug was invisible for many
|
||||
# releases precisely because nothing ever asserted the outcome; assert it
|
||||
# now so a silently-dropped notarization step can never ship again.
|
||||
- name: Verify the DMG is notarized and stapled (macOS leg)
|
||||
if: matrix.family == 'macos'
|
||||
env:
|
||||
EXPECT_NOTARIZED: ${{ (steps.mac_keychain.outputs.signing == 'true' && secrets.MAC_NOTARY_APPLE_ID != '' && secrets.MAC_NOTARY_PASSWORD != '' && secrets.MAC_NOTARY_TEAM_ID != '') && 'true' || 'false' }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
DMG=$(find desktopApp/build/compose/binaries -name "*.dmg" -print -quit)
|
||||
[[ -n "$DMG" ]] || { echo "::error::no DMG produced"; exit 1; }
|
||||
echo "Checking $DMG"
|
||||
|
||||
if [[ "$EXPECT_NOTARIZED" != "true" ]]; then
|
||||
echo "::warning::Apple signing/notary credentials are not configured; this DMG is unsigned and unnotarized. Gatekeeper will block it, and it is not eligible for the Homebrew cask."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if ! xcrun stapler validate "$DMG"; then
|
||||
echo "::error::$DMG has no stapled notarization ticket -- notarizeReleaseDmg did not run or failed"
|
||||
exit 1
|
||||
fi
|
||||
echo "notarization ticket stapled OK"
|
||||
|
||||
# jpackage pins libicu to the build host's version (libicu74 on
|
||||
# ubuntu-24.04). Rewrite the .deb so it installs across Debian/Ubuntu.
|
||||
|
||||
+8
-1
@@ -662,12 +662,19 @@ by any other channel.
|
||||
|
||||
| OS | App location | State directories |
|
||||
|---|---|---|
|
||||
| macOS | `/Applications/Amethyst.app` | `~/Library/Application Support/Amethyst`<br>`~/Library/Preferences/com.vitorpamplona.amethyst.desktop.plist`<br>`~/Library/Caches/Amethyst` |
|
||||
| macOS | `/Applications/Amethyst.app` | `~/.amethyst` (accounts + keys)<br>`~/Library/Application Support/Amethyst` (Tor)<br>`~/Library/Caches/AmethystDesktop` (image cache)<br>`~/Library/Preferences/com.apple.java.util.prefs.plist` (**shared** — see below) |
|
||||
| Windows | `%LOCALAPPDATA%\Amethyst` or `C:\Program Files\Amethyst` | `%APPDATA%\Amethyst`<br>`%LOCALAPPDATA%\Amethyst` |
|
||||
| Linux (deb/rpm) | `/opt/amethyst` | `~/.config/amethyst`<br>`~/.local/share/amethyst`<br>`~/.cache/amethyst` |
|
||||
| Linux (AppImage/tar.gz) | user-chosen | Same as above |
|
||||
| Linux (Flatpak) | `/var/lib/flatpak` or `~/.local/share/flatpak` | `~/.var/app/com.vitorpamplona.amethyst.Desktop/` |
|
||||
|
||||
**macOS preferences are in a SHARED file.** `DesktopPreferences` uses the Java
|
||||
Preferences API, which on macOS writes into
|
||||
`~/Library/Preferences/com.apple.java.util.prefs.plist` — one plist for *every*
|
||||
Java application on the machine, not a per-app file. Never delete it to "reset
|
||||
Amethyst": that wipes unrelated apps' settings. This is why the Homebrew cask's
|
||||
`zap` stanza deliberately omits it.
|
||||
|
||||
Uninstall:
|
||||
|
||||
- Homebrew: `brew uninstall --cask amethyst-nostr && brew zap amethyst-nostr`
|
||||
|
||||
@@ -16,13 +16,12 @@
|
||||
# https://github.com/vitorpamplona/amethyst/releases/download/vX.Y.Z/amethyst-desktop-X.Y.Z-macos-arm64.dmg
|
||||
# shasum -a 256 amethyst.dmg
|
||||
cask "amethyst-nostr" do
|
||||
version "1.12.6"
|
||||
sha256 "69882e83ebcec6723e1ad5655ec2c9d1fa151b9d1a8ae51b869a9d62feabf093"
|
||||
version "1.13.1"
|
||||
sha256 "ead8f4f6263417d661b0d24be3853ec3284b330abc14748ebd77a2c2afcd2789"
|
||||
|
||||
url "https://github.com/vitorpamplona/amethyst/releases/download/v#{version}/amethyst-desktop-#{version}-macos-arm64.dmg",
|
||||
verified: "github.com/vitorpamplona/amethyst/"
|
||||
url "https://github.com/vitorpamplona/amethyst/releases/download/v#{version}/amethyst-desktop-#{version}-macos-arm64.dmg"
|
||||
name "Amethyst"
|
||||
desc "Nostr client for desktop"
|
||||
desc "Nostr client"
|
||||
homepage "https://github.com/vitorpamplona/amethyst"
|
||||
|
||||
livecheck do
|
||||
@@ -30,9 +29,25 @@ cask "amethyst-nostr" do
|
||||
strategy :github_latest
|
||||
end
|
||||
|
||||
# The unrelated tiling window manager (cask `amethyst`, ianyh/Amethyst) also
|
||||
# installs `Amethyst.app`, so the two cannot coexist in /Applications.
|
||||
conflicts_with cask: "amethyst"
|
||||
depends_on arch: :arm64
|
||||
depends_on :macos
|
||||
|
||||
app "Amethyst.app"
|
||||
|
||||
zap trash: "~/.amethyst"
|
||||
# Verified against the source, not the docs:
|
||||
# ~/.amethyst DesktopAccountStorage (accounts + keys)
|
||||
# ~/Library/Application Support/Amethyst DesktopTorManager (tor/)
|
||||
# ~/Library/Caches/AmethystDesktop Coil image cache
|
||||
#
|
||||
# Deliberately NOT zapped: ~/Library/Preferences/com.apple.java.util.prefs.plist.
|
||||
# The app uses the Java Preferences API, which writes to that single SHARED
|
||||
# plist — deleting it would wipe every other Java app's preferences too.
|
||||
zap trash: [
|
||||
"~/.amethyst",
|
||||
"~/Library/Application Support/Amethyst",
|
||||
"~/Library/Caches/AmethystDesktop",
|
||||
]
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user