Skip to content

feat(desktop): automate Mac App Store packaging and App Store Connect delivery #2199

Description

@chrisbbreuer

Goal

Make a Stacks desktop app publishable to the Mac App Store through Buddy and a reusable GitHub Actions workflow. The repeatable path should be automated from a clean macOS runner; account enrollment, legal agreements, and one-time secret creation remain explicit human steps.

Related distribution work: pantry-pm/pantry#219.

Confirmed current gaps

buddy build:desktop currently emits a launcher, craft-runtime, desktop.json, provenance, and checksums under storage/framework/desktop-dist. It does not yet produce or validate the App Store deliverable:

  • no .app bundle with a complete Info.plist;
  • no embedded Mac App Store provisioning profile;
  • no parent/helper App Sandbox entitlement split;
  • no Mac App Distribution or Mac Installer Distribution signing;
  • no signed installer .pkg;
  • no App Store Connect validation/upload command;
  • no reusable workflow for importing certificates and secrets;
  • no automated certificate/profile reconciliation through the App Store Connect API;
  • no universal arm64+x64 merge for a single dual-architecture Store binary;
  • no listing metadata, screenshots, privacy, pricing, agreements, or review submission automation.

Apple requires App Sandbox for Mac App Store distribution and supports API-key/JWT build upload automation:

Phase 1: deterministic Buddy package/sign/upload path

  • Add buddy desktop:apple:doctor to check macOS/Xcode tooling, bundle metadata, certificate identities, profile presence, API credentials, and Craft compatibility without mutating Apple or GitHub state.
  • Add buddy desktop:apple:init to generate a documented reusable-workflow caller without overwriting an existing workflow.
  • Add buddy desktop:apple:package to build the desktop payload, create a valid .app, embed the profile, sign the helper/runtime before the parent app, produce a signed installer .pkg, verify signatures and entitlements, and write provenance/checksums.
  • Add buddy desktop:apple:publish with package-only, --validate-only, and upload modes using App Store Connect API key auth.
  • Derive app name/version from the project and require explicit bundle ID, team ID, signing identities, and provisioning profile.
  • Default entitlements to App Sandbox plus outbound network access; allow an audited app-owned entitlement file for additional capabilities.
  • Ensure the embedded Craft runtime inherits the parent sandbox and cannot escape it.
  • Add a reusable workflow_call workflow that builds Craft from an immutable revision, imports signing material into an ephemeral keychain, runs Buddy validation/package/upload, and uploads the resulting package/provenance/checksums as workflow artifacts.
  • Ensure every secret is passed through environment/files with restrictive permissions and is absent from logs and artifacts.

Phase 2: Apple resource reconciliation

Use the App Store Connect API where Apple exposes the resource:

  • Register or reconcile the explicit bundle ID and capabilities.
  • Create/download/rotate Mac App Distribution and Mac Installer Distribution certificates from a caller-provided CSR/private key strategy.
  • Create/download/refresh the Mac App Store provisioning profile.
  • Add buddy desktop:apple:provision --plan and --apply, with idempotent diffs and no certificate revocation unless explicitly requested.
  • Upload the binary with JWT authentication and poll until processing completes.
  • Synchronize version metadata and attach the processed build.
  • Add a prepare-only mode for metadata and a separate explicit App Review submission action.

Do not attempt to automate unavailable or legally sensitive actions: Developer Program enrollment, paid-app banking/tax setup, contract acceptance, export-compliance attestations requiring owner judgment, privacy answers, age rating answers, or final release policy decisions.

Phase 3: Store readiness and multi-architecture quality

  • Build arm64 and x64 launcher/runtime pairs from the same revisions and merge compatible Mach-O binaries with lipo into one universal app.
  • Validate minimum macOS version, architecture set, bundle ID, marketing version, build number, category, icon, copyright, and usage descriptions.
  • Run a sandboxed launch smoke test before upload.
  • Verify the actual signed entitlements with codesign -d --entitlements :-.
  • Add Store rejection preflight checks for forbidden paths, unsigned nested code, mutable executables, private frameworks, and missing privacy declarations.
  • Generate and validate required App Store screenshots from deterministic UI fixtures, while keeping human approval before upload.
  • Attach Store delivery receipts to the corresponding GitHub Release through Pantry once feat(release): add macOS App Store and S3-compatible distribution targets pantry-pm/pantry#219 lands.

Required secrets and variables

Secrets:

  • APPLE_APP_CERTIFICATE_BASE64
  • APPLE_INSTALLER_CERTIFICATE_BASE64
  • APPLE_CERTIFICATE_PASSWORD
  • APPLE_PROVISIONING_PROFILE_BASE64
  • APP_STORE_CONNECT_API_KEY
  • APP_STORE_CONNECT_API_KEY_ID
  • APP_STORE_CONNECT_API_ISSUER_ID
  • an ephemeral keychain password (generated in CI when possible)

Variables/inputs:

  • app name
  • bundle ID
  • Apple team ID
  • Mac App Distribution signing identity
  • Mac Installer Distribution signing identity
  • minimum macOS version
  • category
  • release tag/version/build number
  • validate-only vs upload vs submit-for-review

Tests and evidence

  • Pure unit tests for plist/entitlement/workflow rendering and required-input diagnostics.
  • Command tests with an injected process runner so no test invokes Apple services.
  • macOS CI fixture that creates an unsigned app/package and verifies layout/provenance.
  • Signed private fixture proving nested code order, profile embedding, sandbox inheritance, package signature, and App Store validation.
  • Secret-redaction regression tests.
  • Protocol evidence updated from pending only after signed validation artifacts exist.

Acceptance criteria

  • A new Stacks app can generate a caller workflow with one Buddy command.
  • A configured repository can produce a signed Mac App Store .pkg from a clean pinned runner.
  • Validation and upload use API-key auth and can be retried without rebuilding or duplicating versions.
  • All non-secret inputs and exact source/Craft revisions are recorded in provenance.
  • Manual Apple account/legal steps are clearly listed and never presented as automated.
  • GitHub Release artifacts, Pantry receipts, and App Store delivery records identify the same package SHA-256.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions