phase8: signed+notarized DMG — scripts/make-dmg.sh + make dmg target; dist/ZyquoAtlas.dmg notarization Accepted, spctl = Notarized Developer ID
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Showing 4 changed files with +60 and −2
modified
Makefile
+6 −1
@@ -27,12 +27,13 @@ BUILD_NUM := 1 | ||
| 27 | 27 | MIN_MACOS := 13.0 |
| 28 | 28 | DIST := dist |
| 29 | 29 | APP_DIR := $(DIST)/$(APP_NAME).app |
| 30 | +DMG_PATH := $(DIST)/ZyquoAtlas.dmg | |
| 30 | 31 | IDENTITY := Developer ID Application: Simon-Pierre Boucher (3YM54G49SN) |
| 31 | 32 | NOTARY_PROFILE:= MacLustr-Notarize |
| 32 | 33 | ENTITLEMENTS := Resources/ZyquoAtlas.entitlements |
| 33 | 34 | VERIFY_ARGS ?= |
| 34 | 35 | |
| 35 | −.PHONY: dev build bundle release universal icon test clean run verify | |
| 36 | +.PHONY: dev build bundle release universal dmg icon test clean run verify | |
| 36 | 37 | |
| 37 | 38 | dev: build bundle |
| 38 | 39 | @echo "=== Ad-hoc signing (dev) ===" |
@@ -78,6 +79,10 @@ release: universal | ||
| 78 | 79 | scripts/write-info-plist.sh "$(APP_DIR)" "$(APP_NAME)" "$(EXEC_NAME)" "$(BUNDLE_ID)" "$(VERSION)" "$(BUILD_NUM)" "$(MIN_MACOS)" |
| 79 | 80 | scripts/notarize.sh "$(APP_DIR)" "$(IDENTITY)" "$(NOTARY_PROFILE)" "$(ENTITLEMENTS)" |
| 80 | 81 | |
| 82 | +# Signed + notarized distribution DMG from the notarized app (run `make release` first). | |
| 83 | +dmg: | |
| 84 | + scripts/make-dmg.sh "$(APP_DIR)" "$(IDENTITY)" "$(NOTARY_PROFILE)" "$(DMG_PATH)" | |
| 85 | + | |
| 81 | 86 | icon: |
| 82 | 87 | scripts/generate-icon.sh |
| 83 | 88 | |
modified
README.md
+1 −0
@@ -20,6 +20,7 @@ make dev # release build → dist/Zyquo Atlas.app, ad-hoc signed (local ite | ||
| 20 | 20 | make run # make dev, then launch the app |
| 21 | 21 | make test # run the test suite |
| 22 | 22 | make release # universal (arm64+x86_64), Developer ID signed, notarized, stapled |
| 23 | +make dmg # signed + notarized + stapled dist/ZyquoAtlas.dmg (run after make release) | |
| 23 | 24 | make icon # regenerate AppIcon.icns from assets/icon/zyquo-atlas.svg |
| 24 | 25 | make verify # API verification with real keys (source .env.keys) |
| 25 | 26 | make clean |
modified
docs/PLAN.md
+1 −1
@@ -176,7 +176,7 @@ launchable, single window; browser core is Phase 2). | ||
| 176 | 176 | |
| 177 | 177 | **Verified independently:** `lipo -archs` → `x86_64 arm64`; `codesign -dvv` → `flags=0x10000(runtime)`, Authority `Developer ID Application …`, `TeamIdentifier=3YM54G49SN`; `stapler validate` → worked; **`spctl -a -vv` → `accepted, source=Notarized Developer ID`**. **Phase 8 gate PASSED.** |
| 178 | 178 | |
| 179 | −Notes: `make dev` (ad-hoc) retained for iteration. Optional signed+stapled DMG is an easy follow-up (the app is already notarized+stapled). Vendored `Content/Readability*.js` (Mozilla, Apache-2.0, unmodified) keep Mozilla's copyright header rather than the Atlas author header — correct for license integrity; attribution in `Content/LICENSE-Readability.txt`. | |
| 179 | +Notes: `make dev` (ad-hoc) retained for iteration. Optional signed+stapled DMG delivered (`make dmg` → `dist/ZyquoAtlas.dmg`, notarization Accepted, `spctl` = Notarized Developer ID). Vendored `Content/Readability*.js` (Mozilla, Apache-2.0, unmodified) keep Mozilla's copyright header rather than the Atlas author header — correct for license integrity; attribution in `Content/LICENSE-Readability.txt`. | |
| 180 | 180 | |
| 181 | 181 | --- |
| 182 | 182 | |
added
scripts/make-dmg.sh
+52 −0
@@ -0,0 +1,52 @@ | ||
| 1 | +#!/bin/bash | |
| 2 | +# | |
| 3 | +# make-dmg.sh | |
| 4 | +# Zyquo Atlas | |
| 5 | +# | |
| 6 | +# Author: Simon-Pierre Boucher | |
| 7 | +# Mail: contact@spboucher.ai | |
| 8 | +# | |
| 9 | +# Builds a signed, notarized, stapled distribution DMG from an already | |
| 10 | +# notarized+stapled Zyquo Atlas.app (run `make release` first). Creates a | |
| 11 | +# compressed UDZO image with a drag-to-Applications symlink, signs it with the | |
| 12 | +# Developer ID, submits to notarytool --wait, and staples. Secrets never printed. | |
| 13 | +# | |
| 14 | +# Usage: make-dmg.sh <app-dir> <identity> <notary-profile> <dmg-path> | |
| 15 | +# | |
| 16 | +set -euo pipefail | |
| 17 | +cd "$(dirname "$0")/.." | |
| 18 | + | |
| 19 | +APP_DIR="$1" | |
| 20 | +IDENTITY="$2" | |
| 21 | +KEYCHAIN_PROFILE="$3" | |
| 22 | +DMG_PATH="$4" | |
| 23 | +APP_NAME="$(basename "${APP_DIR%.app}")" | |
| 24 | + | |
| 25 | +[ -d "$APP_DIR" ] || { echo "ERROR: $APP_DIR missing — run 'make release' first" >&2; exit 1; } | |
| 26 | + | |
| 27 | +echo "=== Staging DMG contents ===" | |
| 28 | +STAGE="$(mktemp -d)/dmg" | |
| 29 | +mkdir -p "$STAGE" | |
| 30 | +cp -R "$APP_DIR" "$STAGE/" | |
| 31 | +ln -s /Applications "$STAGE/Applications" | |
| 32 | + | |
| 33 | +echo "=== Creating compressed image ===" | |
| 34 | +rm -f "$DMG_PATH" | |
| 35 | +hdiutil create -volname "$APP_NAME" -srcfolder "$STAGE" -ov -format UDZO "$DMG_PATH" | |
| 36 | +rm -rf "$(dirname "$STAGE")" | |
| 37 | + | |
| 38 | +echo "=== Signing DMG (Developer ID) ===" | |
| 39 | +codesign --force --timestamp --sign "$IDENTITY" "$DMG_PATH" | |
| 40 | +codesign --verify --verbose=2 "$DMG_PATH" | |
| 41 | + | |
| 42 | +echo "=== Notarizing DMG (profile: $KEYCHAIN_PROFILE) ===" | |
| 43 | +xcrun notarytool submit "$DMG_PATH" --keychain-profile "$KEYCHAIN_PROFILE" --wait | |
| 44 | + | |
| 45 | +echo "=== Stapling DMG ===" | |
| 46 | +xcrun stapler staple "$DMG_PATH" | |
| 47 | +xcrun stapler validate "$DMG_PATH" | |
| 48 | + | |
| 49 | +echo "=== Gatekeeper assessment (DMG) ===" | |
| 50 | +spctl -a -t open --context context:primary-signature -vv "$DMG_PATH" | |
| 51 | + | |
| 52 | +echo "Done: $DMG_PATH is signed, notarized, and stapled." | |
| 53 | ||