diff --git a/.github/workflows/create-release.yml b/.github/workflows/create-release.yml
index 3a10ca3e3c..19ca1146e8 100644
--- a/.github/workflows/create-release.yml
+++ b/.github/workflows/create-release.yml
@@ -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.
diff --git a/BUILDING.md b/BUILDING.md
index 1fd7b61bf5..120a23172a 100644
--- a/BUILDING.md
+++ b/BUILDING.md
@@ -662,12 +662,19 @@ by any other channel.
| OS | App location | State directories |
|---|---|---|
-| macOS | `/Applications/Amethyst.app` | `~/Library/Application Support/Amethyst`
`~/Library/Preferences/com.vitorpamplona.amethyst.desktop.plist`
`~/Library/Caches/Amethyst` |
+| macOS | `/Applications/Amethyst.app` | `~/.amethyst` (accounts + keys)
`~/Library/Application Support/Amethyst` (Tor)
`~/Library/Caches/AmethystDesktop` (image cache)
`~/Library/Preferences/com.apple.java.util.prefs.plist` (**shared** — see below) |
| Windows | `%LOCALAPPDATA%\Amethyst` or `C:\Program Files\Amethyst` | `%APPDATA%\Amethyst`
`%LOCALAPPDATA%\Amethyst` |
| Linux (deb/rpm) | `/opt/amethyst` | `~/.config/amethyst`
`~/.local/share/amethyst`
`~/.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`
diff --git a/desktopApp/packaging/homebrew/amethyst-nostr.rb b/desktopApp/packaging/homebrew/amethyst-nostr.rb
index c63eef6ec1..0e0ae12854 100644
--- a/desktopApp/packaging/homebrew/amethyst-nostr.rb
+++ b/desktopApp/packaging/homebrew/amethyst-nostr.rb
@@ -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