From e0d48e49e8002ada926088d1ee518e3bfb6f6998 Mon Sep 17 00:00:00 2001 From: kfattic <6775519+kfattic@users.noreply.github.com> Date: Wed, 16 Sep 2026 13:24:26 -0500 Subject: [PATCH] Package 1.1.0: one PKG installs the CLI and the notarized app Co-Authored-By: Claude Opus 5 (1M context) --- CLAUDE.md | 6 ++-- README.md | 8 ++--- build.sh | 86 ++++++++++++++++++++++++++++++++++--------------- pkg/postinstall | 27 ++++++++++++---- 4 files changed, 89 insertions(+), 38 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 1fd2e39..a255832 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -53,8 +53,10 @@ swift build # debug build of everything - Package: tools-version 6.0, Swift 5 language mode, macOS 14 minimum. - `build.sh` reads `CODESIGN_APP_IDENTITY`, `CODESIGN_PKG_IDENTITY`, `NOTARY_PROFILE` (and optional `CODESIGN_TEAM_ID`) from the environment or an untracked `build.env`. Never hard-code identities. -- The PKG is payload-free (`pkgbuild --nopayload --scripts`; `pkg/postinstall` copies the binary), because - any payload's "." entry would reset an existing `/usr/local/bin`'s ownership. +- The PKG is payload-free (`pkgbuild --nopayload --scripts`): `pkg/postinstall` installs the CLI to + `/usr/local/bin` and the notarized, stapled app to `/Applications`. A payload's "." entry is recorded as + root:wheel for its install location, which would reset an existing `/usr/local/bin` (Homebrew) or + `/Applications` (root:admin 775). The app is notarized and stapled before packaging; the PKG after. - The app icon master is `Icon/AppIcon-1024.png`; `build.sh` generates `AppIcon.icns` from it. Don't redraw it. - Live tests are opt-in and write to queues: `CUPSKIT_LIVE_QUEUE=`, `CUPSKIT_LIVE_JOBS=,`, `CUPSKIT_LIVE_QUICK=,`. Use throwaway queues (e.g. `lpd://127.0.0.1/…`, paused) and diff --git a/README.md b/README.md index 05447e0..34cd006 100644 --- a/README.md +++ b/README.md @@ -6,14 +6,14 @@ ## Install -> Status: the CLI is stable (1.0.x). The app is under active development — see [Releases](../../releases) for what's shipped. +> Status: the CLI is stable. The app (1.1) covers printers, jobs, queue options and quick actions; printer discovery, classes, the server page and the Attributes/Log tabs are still to come — see [Releases](../../releases). Download the signed, notarized PKG from the latest [release](../../releases). It installs: - `/usr/local/bin/cupsadmin` -- `/Applications/CUPS Admin.app` (once the app ships) +- `/Applications/CUPS Admin.app` -The package is payload-free and installs via a postinstall script, so it never changes the ownership of an existing `/usr/local/bin` (Homebrew on Intel Macs is safe). For Munki, use an `installs` array pointing at `/usr/local/bin/cupsadmin`; there is no payload file list to key off. +The package is payload-free and installs both via a postinstall script, so it never changes the ownership of an existing `/usr/local/bin` (Homebrew on Intel Macs is safe) or of `/Applications`. For Munki, use an `installs` array pointing at `/usr/local/bin/cupsadmin` and `/Applications/CUPS Admin.app`; there is no payload file list to key off. Requires macOS 14 or later. Universal (Apple silicon and Intel). @@ -98,7 +98,7 @@ VERSION=1.2.3 ./build.sh Or put those three lines (without `export`) in a `build.env` next to `build.sh`; it's read if present and gitignored. Variables already set in the environment win. -`build.sh` builds a universal binary (per-architecture `swift build` + `lipo`), signs with the hardened runtime, builds the payload-free PKG, notarizes, staples and verifies with `spctl`. Use `./build.sh --build-only` to skip signing and notarization. `./build.sh --screenshots` regenerates the README screenshot from three temporary demo queues. Run `./test.sh` for the test suite (`CUPSKIT_LIVE_QUEUE=` enables the live tests; `CUPSKIT_LIVE_JOBS` and `CUPSKIT_LIVE_QUICK` take two throwaway queues each for the job and quick-action tests). +`build.sh` builds a universal binary (per-architecture `swift build` + `lipo`), signs the CLI and app with the hardened runtime, notarizes and staples the app, builds the payload-free PKG, notarizes and staples it, and verifies both with `spctl`. Use `./build.sh --build-only` to skip signing and notarization. `./build.sh --screenshots` regenerates the README screenshot from three temporary demo queues. Run `./test.sh` for the test suite (`CUPSKIT_LIVE_QUEUE=` enables the live tests; `CUPSKIT_LIVE_JOBS` and `CUPSKIT_LIVE_QUICK` take two throwaway queues each for the job and quick-action tests). ## Notes for admins diff --git a/build.sh b/build.sh index bb271b1..0f14298 100755 --- a/build.sh +++ b/build.sh @@ -1,6 +1,6 @@ #!/bin/bash -# Universal release build -> signed CLI binary + signed "CUPS Admin.app" -> signed payload-free PKG -# (postinstall installs /usr/local/bin/cupsadmin) -> notarize -> staple -> spctl. +# Universal release build -> signed CLI + signed, notarized, stapled "CUPS Admin.app" -> signed payload-free PKG +# (postinstall installs /usr/local/bin/cupsadmin and /Applications/CUPS Admin.app) -> notarize -> staple -> spctl. # Usage: ./build.sh full pipeline (VERSION=1.2.0 ./build.sh to set the version) # ./build.sh --build-only build CLI and app, ad-hoc signed; no identities, no pkg, no notarization # ./build.sh --screenshots build like --build-only, then regenerate docs/screenshots/app-jobs.png @@ -113,7 +113,7 @@ SWIFT # --- configuration ------------------------------------------------------------- cd "$(dirname "$0")" -VERSION="${VERSION:-1.0.1}" +VERSION="${VERSION:-1.1.0}" IDENTIFIER="edu.wku.cupsadmin" # build.env fills in only what the environment doesn't already set. @@ -268,11 +268,53 @@ if [ $BUILD_ONLY -eq 1 ]; then exit 0 fi +# --- notarize helper -------------------------------------------------------------- +# notarize