- The App Store variant was only signed ad hoc to run locally, so nothing it produced could be submitted; with a Mac App Store Connect provisioning profile in .signing/app-store.provisionprofile it now embeds the profile, adds the profile's App ID and team to the app's entitlements, signs both executables with the keychain's Apple Distribution identity, and wraps the app in an installer package signed with Mac Installer Distribution. - A profile whose App ID is not the bundle's is refused, and a missing distribution or installer certificate stops the build rather than producing an unsubmittable package. - CFBundleVersion becomes the build's UTC time to the minute, since App Store Connect rejects a build number it has seen, while CFBundleShortVersionString stays VERSION; ITSAppUsesNonExemptEncryption is false, as the build's only cryptography is hashing and random numbers. - The bundled daemon keeps only the sandbox and inherit entitlements, which a helper inheriting its parent's sandbox requires. - Without a profile the variant builds as before, ad hoc or with MIDI_HARBOR_SIGNING_IDENTITY, to run on the building Mac.
59 lines
2.5 KiB
Markdown
59 lines
2.5 KiB
Markdown
# Feature Specification: App Store Submission
|
|
|
|
**Created**: 2026-09-28
|
|
|
|
**Status**: Implemented; built and checked on 2026-09-28 with the owner's certificates and
|
|
profile, not yet uploaded
|
|
|
|
**Input**: User request: "How do I build for the app store?", then the certificates and the
|
|
provisioning profile, and "Okay, added."
|
|
|
|
014 built the sandboxed App Store variant, signed ad hoc to run on the building Mac, and left the
|
|
package App Store Connect takes to the owner. `make appstore` now builds that package when the
|
|
owner's provisioning profile is in `.signing/`.
|
|
|
|
## User Scenarios & Testing *(mandatory)*
|
|
|
|
### User Story 1 - Building a submission (Priority: P1)
|
|
|
|
The owner runs `make appstore` and gets `Midi-Harbor-<version>.pkg`, which Transporter uploads
|
|
to App Store Connect as a new build of Midi Harbor.
|
|
|
|
**Why this priority**: it is the whole request.
|
|
|
|
**Independent Test**: With the certificates and profile in place, run `make appstore` and check
|
|
the signatures, entitlements, embedded profile, architectures and Info.plist of what it makes.
|
|
|
|
**Acceptance Scenarios**:
|
|
|
|
1. **Given** the profile and both certificates, **When** `make appstore` runs, **Then** it makes
|
|
a universal app signed with Apple Distribution, the profile embedded and its identifiers in
|
|
the app's entitlements, and a package signed with Mac Installer Distribution.
|
|
2. **Given** two builds of one version, **When** both are uploaded, **Then** the second is
|
|
accepted, its build number being higher.
|
|
3. **Given** a profile for another App ID, **When** `make appstore` runs, **Then** it stops,
|
|
naming both.
|
|
4. **Given** no profile, **When** `make appstore` runs, **Then** it builds the app to run on this
|
|
Mac, as before.
|
|
|
|
## Requirements *(mandatory)*
|
|
|
|
### Functional Requirements
|
|
|
|
- **FR-S01**: `make appstore` MUST build an installer package App Store Connect accepts, from the
|
|
profile and certificates alone, with nothing else to set.
|
|
- **FR-S02**: Each build MUST carry a build number higher than any before it.
|
|
- **FR-S03**: The build MUST refuse a profile whose App ID is not the bundle's.
|
|
|
|
## Success Criteria *(mandatory)*
|
|
|
|
### Measurable Outcomes
|
|
|
|
- **SC-S01**: A new build reaches App Store Connect with one command and one upload.
|
|
|
|
## Assumptions
|
|
|
|
- Uploading stays with Transporter: an API key upload needs the App Store Connect key that
|
|
notarization is also waiting for, and can be added with it.
|
|
- The build number is the build's time in UTC to the minute; two submissions within one minute
|
|
are not expected.
|