Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

iOS signing

iOS Simulator builds use Xcode’s local ad-hoc identity (-). Xcode signs the framework and extensions before sealing the application. When WidgetKit is enabled, the pipeline then re-signs only the widget and containing application, inside-out and without --deep, so their generated application-group entitlements are embedded in the effective signatures. Artifact validation requires exact signature identifiers, sealed plists/resources, strict verification for every bundle, and recursive strict verification for the application. No Apple Account, team, certificate, or provisioning profile is needed.

Local physical-device signing

The local path uses the official Xcode development pipeline with an explicit user-selected Team. Provisioning updates are disabled unless requested, and manual signing can name a profile. After Xcode builds, RustFerry checks the expected executable and Cargo provenance, arm64 architecture, signatures, signing certificate, embedded profiles, expiration, Team and bundle identifiers, entitlement authorization, and embedded extensions before returning a validated artifact.

The implementation and deterministic tests do not establish a real signing or device result. The local environment had no Apple Development identity, Team, provisioning profile, signed physical artifact, or attached device. Widget application groups and other entitlements can require additional profile capabilities.

Remote manual-development signing

Manual-development signing is implemented for the GitHub remote provider. The source repository must be public. Signing runs in a distinct private execution repository through protected Environment rustferry-goal3-signing, with a required reviewer and exactly the rustferry/goal3/builds/* deployment policy.

Configure the unsigned remote provider first, then validate the signing assets without mutation:

cargo ferry signing setup manual \
  --certificate /private/signing/development.p12 \
  --profile weather=/private/signing/application.mobileprovision \
  --profile FerryWidgetExtension=/private/signing/widget.mobileprovision \
  --profile FerryLiveActivityExtension=/private/signing/live-activity.mobileprovision \
  --remote github \
  --device-sha256 <lowercase-sha256> \
  --dry-run

The files must remain outside every Git repository. Manual setup accepts at most three application and extension profiles. Projects with extensions require one exact, case-sensitive --profile TARGET=PATH for every generated target; use the preview’s target names. The legacy unkeyed --profile PATH form remains valid only for an extension-free single application, and the two forms cannot be mixed. All profiles must contain one common selected device. Omit --device-sha256 only when every profile contains the same single device.

The example uses the interactive no-echo prompt. Other password sources are --password-stdin, --password-env <NAME>, or --password-credential <ENTRY>. Select one. No password value is accepted on the command line. JSON, non-interactive, and stdin-password mutation require --yes; otherwise the command asks for confirmation after printing public certificate, profile, team, device-hash, and target metadata.

The protected Environment must contain no secrets before initial setup. RustFerry revalidates the retained asset bytes immediately before upload, then sends the PKCS#12 and profiles as canonical padded base64 and the password as raw UTF-8, with a 48 KiB limit per final value. The application keeps the legacy profile secret name; each extension receives a deterministic static secret derived from its target name and bundle identifier. RustFerry verifies the exact planned three-to-five-name set remotely before persisting the private local signing config. Multi-profile jobs use the bounded RFSIGNV2 stdin frame; the legacy frame remains single-application-only. See GitHub macOS provider security for the full preflight, failure, and cleanup contract.

The multi-profile setup and transport pass the affected-package integration suite locally. A real Apple Development certificate/profile upload and signed IPA acceptance run remain pending. No signing identity, private key, password, profile contents, or account token is stored in ferry.toml, public workflow files, or generated logs. See Physical iPhone development and STATUS for the current evidence level.