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>
4 changed files +60 −2
modified
Makefile
+6 −1
@@ -27,12 +27,13 @@ BUILD_NUM := 1 | |||||
| 27 | MIN_MACOS := 13.0 | 27 | MIN_MACOS := 13.0 | ||
| 28 | DIST := dist | 28 | DIST := dist | ||
| 29 | APP_DIR := $(DIST)/$(APP_NAME).app | 29 | APP_DIR := $(DIST)/$(APP_NAME).app | ||
| 30 | +DMG_PATH := $(DIST)/ZyquoAtlas.dmg | ||||
| 30 | IDENTITY := Developer ID Application: Simon-Pierre Boucher (3YM54G49SN) | 31 | IDENTITY := Developer ID Application: Simon-Pierre Boucher (3YM54G49SN) | ||
| 31 | NOTARY_PROFILE:= MacLustr-Notarize | 32 | NOTARY_PROFILE:= MacLustr-Notarize | ||
| 32 | ENTITLEMENTS := Resources/ZyquoAtlas.entitlements | 33 | ENTITLEMENTS := Resources/ZyquoAtlas.entitlements | ||
| 33 | VERIFY_ARGS ?= | 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 | dev: build bundle | 38 | dev: build bundle | ||
| 38 | @echo "=== Ad-hoc signing (dev) ===" | 39 | @echo "=== Ad-hoc signing (dev) ===" | ||
@@ -78,6 +79,10 @@ release: universal | |||||
| 78 | scripts/write-info-plist.sh "$(APP_DIR)" "$(APP_NAME)" "$(EXEC_NAME)" "$(BUNDLE_ID)" "$(VERSION)" "$(BUILD_NUM)" "$(MIN_MACOS)" | 79 | scripts/write-info-plist.sh "$(APP_DIR)" "$(APP_NAME)" "$(EXEC_NAME)" "$(BUNDLE_ID)" "$(VERSION)" "$(BUILD_NUM)" "$(MIN_MACOS)" | ||
| 79 | scripts/notarize.sh "$(APP_DIR)" "$(IDENTITY)" "$(NOTARY_PROFILE)" "$(ENTITLEMENTS)" | 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 | icon: | 86 | icon: | ||
| 82 | scripts/generate-icon.sh | 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 | make run # make dev, then launch the app | 20 | make run # make dev, then launch the app | ||
| 21 | make test # run the test suite | 21 | make test # run the test suite | ||
| 22 | make release # universal (arm64+x86_64), Developer ID signed, notarized, stapled | 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 | make icon # regenerate AppIcon.icns from assets/icon/zyquo-atlas.svg | 24 | make icon # regenerate AppIcon.icns from assets/icon/zyquo-atlas.svg | ||
| 24 | make verify # API verification with real keys (source .env.keys) | 25 | make verify # API verification with real keys (source .env.keys) | ||
| 25 | make clean | 26 | make clean | ||
modified
docs/PLAN.md
+1 −1
@@ -176,7 +176,7 @@ launchable, single window; browser core is Phase 2). | |||||
| 176 | 176 | ||||
| 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.** | 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 | |||||