Addresses come from the command line rather than a file in the repo, because a list of testers is a
list of people's email addresses and this repository is public.
Defaults to the external group. The internal one only accepts people who already have an App Store
Connect account on the team, which is a much bigger thing to hand somebody than a build.
Claude-Session: https://claude.ai/code/session_018HwEWvoE1NkkUjJCMLSnup
The listing copy lives in text files rather than in a web form, so changing a description is a diff
someone can read and the store listing is reviewable next to the code it describes. Field lengths
are checked before sending, because Apple rejects an over-length field with an error that never
names the limit.
apple-provision.rb drives the Developer Portal through spaceship and is find-or-create throughout.
That matters most for the Developer ID certificate: an account may hold only a handful, they cannot
be un-revoked, and every copy of the app already signed by one stops verifying if it goes away.
Both scripts pin the App Store Connect team. This Apple ID can see more than one, and the other
belongs to somebody else entirely, so letting spaceship choose is how a listing ends up on the
wrong account.
The reviewer phone number and email are deliberately not in here. Apple requires a real number and
this repo is public.
Claude-Session: https://claude.ai/code/session_018HwEWvoE1NkkUjJCMLSnup
Tauri has no App Store target, so mas-package.sh covers the distance between the .app and something
App Store Connect will take. The order is load-bearing: the provisioning profile goes in before
codesign runs because the signature covers it, which is also why Tauri's own signing is switched
off for this build.
The sandbox costs three things, all Apple's rules rather than choices. The updater is gone, and
falls out for free because the plugin was already conditional on the config declaring it; only the
release overlay does. The Check for Updates menu item is gated on the same condition, since a menu
item that errors when clicked is its own rejection risk. The library moves into the container, and
the system spelling dictionary becomes unreadable.
Two things the first upload taught us. The profile is kept owner-only where it lives next to the
signing keys, and cp carried that mode into the bundle; Apple rejects a package containing anything
a non-root user cannot read. And altool exits 0 after printing UPLOAD FAILED, so its exit status
cannot be trusted and the transcript is the only reliable signal.
Claude-Session: https://claude.ai/code/session_018HwEWvoE1NkkUjJCMLSnup