#!/bin/bash # Formal direct-download release guardrail for Aligner. # This script is intentionally separate from package-app.sh, which remains the # local QA package entry and may use ad-hoc or local-only signing. set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" OUTPUT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" SOURCE_ROOT="$OUTPUT_ROOT/C1.source" INFO_PLIST="$SOURCE_ROOT/Resources/Aligner-Info.plist" fail() { echo "release-app.sh failed: $*" >&2 exit 1 } usage() { cat <<'USAGE' Usage: 03-O/C3.tools/release-app.sh --check-tools 03-O/C3.tools/release-app.sh --check-config 03-O/C3.tools/release-app.sh --check-notary-profile Required environment for a real public release: ALIGNER_DEVELOPER_IDENTITY="Developer ID Application: ..." ALIGNER_NOTARY_PROFILE="" ALIGNER_RELEASE_GITHUB_REPOSITORY="" Phase 1 currently establishes release-chain guardrails only. It refuses to produce a public release until Developer ID signing, notarization, stapling, Gatekeeper validation, manifest generation, and upload policy are all wired. USAGE } read_plist_value() { /usr/libexec/PlistBuddy -c "Print :$1" "$INFO_PLIST" 2>/dev/null \ || fail "unable to read $1 from $INFO_PLIST" } assert_tool() { command -v "$1" >/dev/null 2>&1 || fail "missing required tool: $1" } assert_xcrun_tool() { xcrun --find "$1" >/dev/null 2>&1 || fail "missing required xcrun tool: $1" } assert_tools() { assert_tool codesign assert_tool hdiutil assert_tool shasum assert_tool spctl assert_tool xcrun assert_xcrun_tool notarytool assert_xcrun_tool stapler echo "Release tools OK" } assert_config() { local version local build local minimum_macos assert_tools version="$(read_plist_value CFBundleShortVersionString)" build="$(read_plist_value CFBundleVersion)" minimum_macos="$(read_plist_value LSMinimumSystemVersion)" [[ "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] \ || fail "CFBundleShortVersionString must be MAJOR.MINOR.PATCH, got: $version" [[ "$build" =~ ^[0-9]{8}\.[0-9]{4}$ ]] \ || fail "CFBundleVersion must be YYYYMMDD.HHMM, got: $build" [[ "$minimum_macos" =~ ^[0-9]+(\.[0-9]+)?$ ]] \ || fail "LSMinimumSystemVersion must be numeric, got: $minimum_macos" [ "$minimum_macos" = "14.0" ] \ || fail "LSMinimumSystemVersion must be 14.0 for Round01.5 macOS 14 compatibility, got: $minimum_macos" if [ -z "${ALIGNER_DEVELOPER_IDENTITY:-}" ]; then fail "missing ALIGNER_DEVELOPER_IDENTITY; formal releases must use Developer ID Application signing" fi if [[ "${ALIGNER_DEVELOPER_IDENTITY:-}" != Developer\ ID\ Application:* ]]; then fail "ALIGNER_DEVELOPER_IDENTITY must start with 'Developer ID Application:'" fi if [ -z "${ALIGNER_NOTARY_PROFILE:-}" ]; then fail "missing ALIGNER_NOTARY_PROFILE; formal releases must use notarytool" fi if [ -z "${ALIGNER_RELEASE_GITHUB_REPOSITORY:-}" ]; then fail "missing ALIGNER_RELEASE_GITHUB_REPOSITORY; expected owner/repo for GitHub Releases" fi if [[ "${ALIGNER_RELEASE_GITHUB_REPOSITORY:-}" != */* ]]; then fail "ALIGNER_RELEASE_GITHUB_REPOSITORY must use owner/repo format" fi echo "Release config OK for Aligner $version build $build, minimum macOS $minimum_macos" } assert_notary_profile() { assert_config xcrun notarytool history \ --keychain-profile "$ALIGNER_NOTARY_PROFILE" \ --output-format json >/dev/null 2>&1 \ || fail "notarytool profile is not usable: $ALIGNER_NOTARY_PROFILE" echo "Notary profile OK: $ALIGNER_NOTARY_PROFILE" } case "${1:-}" in --check-tools) assert_tools ;; --check-config) assert_config ;; --check-notary-profile) assert_notary_profile ;; -h|--help) usage ;; "") assert_config fail "formal release packaging is not enabled in Phase 1 skeleton yet" ;; *) usage fail "unknown argument: $1" ;; esac