Skip to content

signing: automatic certificate, device and profile setup through App Store Connect - #21

Closed
Interlap01 wants to merge 7 commits into
feat/asc-clientfrom
feat/signing-auto
Closed

Interlap01 wants to merge 7 commits into
feat/asc-clientfrom
feat/signing-auto

Conversation

@Interlap01

@Interlap01 Interlap01 commented Sep 16, 2026

Copy link
Copy Markdown
Collaborator

Summary

Stacked on #20 (App Store Connect client). builder signing setup without --certificate/--profile now does the whole Apple portal flow with the API key from builder auth apple; the manual path is unchanged and remains the fallback.

  • Resolves the bundle ID from --bundle-id, a new optional ios.bundleId in builder.json (filled by init when the Xcode project has exactly one app target), the newest IPA in ./dist/, or a prompt.
  • Finds or creates the bundle ID, issues a certificate from a locally generated CSR (--type development|ad-hoc|app-store), registers devices from --device or --devices-from-mobai (cloud and simulator entries are skipped, UDID shape enforced), creates the profile, writes the key, .p12 and .mobileprovision to --out-dir with 0600, then uploads the three IOS_* secrets to GitHub and flips ios.signing. For Codemagic/Bitrise it prints the file paths and links the provider secrets doc.
  • Idempotent re-runs: a valid certificate is reused only when its private key is local and matches; profiles named Builder <type> <bundle id> are reused when active and matching, otherwise recreated with the reason printed. Nothing is ever revoked; Apple's certificate and device quota errors get hints.
  • Order of operations avoids orphaned certificates: devices are checked and the key is written before the certificate request, since a certificate whose key is lost burns one of Apple's two slots for a year.
  • Without a TTY, --yes is required and a generated .p12 password is printed once; --json output for agents.
  • Endpoint helpers in internal/asc/{bundleids,certificates,devices,profiles}.go with httptest tests; the orchestration is tested against an in-memory portal that issues real certificates from the CSR.
  • Ad Hoc and App Store material becomes usable by the export step once workflow: derive the IPA export method from the provisioning profile #17 lands (export method follows the profile type).

Test plan

  • go build ./... && go vet ./... && go test ./..., gofmt -l . clean, golangci-lint v2.12.2 0 issues
  • builder signing setup --type development --devices-from-mobai on a fresh bundle ID creates cert, device and profile, then builder ios build produces a signed IPA
  • Second run reports everything valid and changes nothing
  • --type app-store with ios.configuration: Release produces an IPA that builder ios upload accepts

The provisioning resources behind automatic signing: find/register App IDs
(filter[identifier] also matches prefixes, so the exact identifier is
checked), list/issue certificates with the CSR as csrContent and the DER
decoded from certificateContent, list/register iOS devices, and list by
name, create and delete profiles. Profile membership is read from the
paginated relationships endpoints rather than include=, which caps the
linkage arrays.
… API

signing.Auto finds or registers the App ID, reuses a valid certificate
only when the matching private key is on this machine (otherwise no .p12
can be built, so a new one is issued; nothing is ever revoked), registers
missing devices and puts every enabled iOS device into the profile, and
recreates the Builder-managed profile only when it is missing, INVALID,
expired, forced, or its certificate or device set changed. Apple's quota
refusals for certificates and devices get an explanatory hint.

CreateCSR is split out of GenerateKeyAndCSR so a CSR can be made for an
existing key, and KeyMatchesCertificate exposes the check BuildP12 does.
builder signing setup without --certificate/--profile now provisions
everything through signing.Auto: --bundle-id (else ios.bundleId, else the
newest IPA in ./dist, else a prompt on a TTY), --type development|ad-hoc|
app-store, --device / --devices-from-mobai, --key or the ios-signing.key a
previous run left in --out-dir, --force, --yes, --password and --json. One
confirmation shows the plan before anything is created; without a TTY
--yes is required and the .p12 password is generated and printed once.

GitHub gets the three IOS_* secrets and ios.signing flips as before;
Codemagic and Bitrise get the file paths and docs/provider-secrets.md.
The resolved bundle ID is saved as ios.bundleId, which init now also
fills from PRODUCT_BUNDLE_IDENTIFIER when the Xcode project has exactly
one app target. The manual --certificate/--profile path is unchanged.
README's Code Signing section leads with builder signing setup through the
App Store Connect API (bundle ID resolution, certificate reuse rule,
device and profile handling, idempotent reruns, --type app-store) and
keeps the portal steps as the manual fallback. CLAUDE.md gains the
command, flow diagram, module notes, the ios.bundleId field and the
still-hardcoded development export method; provider-secrets.md points
Codemagic/Bitrise users at automatic setup with --out-dir.
Auto issued the certificate before looking at devices and wrote the private
key only after the profile existed. A development run with no device to
cover, or any failure between the certificate POST and the file write,
left a certificate on the account whose key was gone: Builder never
revokes, so it occupied one of the two Development slots for a year.

Devices are now resolved first, and a generated key is on disk before the
CSR goes to Apple, so a failed run can be retried with the same key and
the certificate it may have produced is reused.
MobAI also lists cloud farm devices (cloud: true) as physical iOS devices;
their IDs are farm handles like awsdevicefarm:Apple_iPhone_16:26.0, which
--devices-from-mobai would have sent to Apple as UDIDs. Decode the cloud
flag, skip those, and require a UDID shape (40 hex, or 8-16 hex) for both
MobAI-sourced and --device values so a typo fails here, not as an ASC 409.
The note described the hardcoded development export method as current;
PR #17 derives it from the profile, so say what must hold and point there.
@Interlap01

Copy link
Copy Markdown
Collaborator Author

Folded into #23; the automatic flow was reworked there.

@Interlap01 Interlap01 closed this Sep 16, 2026
@Interlap01
Interlap01 deleted the feat/signing-auto branch September 17, 2026 18:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant