apple signing: every signable target (extensions, App Group check), build keychain unlock over SSH, api confirm docs

This commit is contained in:
CRTkafa 2026-10-24 13:02:35 +08:00
parent 2e1c7cdc3c
commit 779cbdfcfd
17 changed files with 829 additions and 42 deletions

View file

@ -1229,8 +1229,13 @@ that fails without the fix (see CONTRIBUTING.md).
(and read relative to the working directory, not the project).
- **Do:** run the build in the Mac's logged-in session: a CI agent started there, or from SSH a `.command` file opened
with `open -a Terminal <file>` (unset SSH_CONNECTION SSH_CLIENT SSH_TTY inside). `--allow-ssh` after
`security unlock-keychain` skips the check.
- **Guard:** `remoteBuildSession` in `cli/lib/xcode.ts` stops `apple build` before the archive; `credPath` in
`security unlock-keychain` skips the check. To build over SSH or in CI anyway: export `STOREBOUND_KEYCHAIN_PASSWORD`
(never printed, never an argument of storebound) and add `--keychain-unlock` (unlocks the login keychain and runs
`security set-key-partition-list -S apple-tool:,apple:,codesign:`), or `--keychain <path> --keychain-unlock` for a
build keychain that holds the Apple Distribution key + certificate (`apple signing ensure --keychain <path>` imports
them); `--keychain` also signs the archive with `OTHER_CODE_SIGN_FLAGS=--keychain <path>` and puts the keychain on the search list.
- **Guard:** `remoteBuildSession` in `cli/lib/xcode.ts` stops `apple build` before the archive, and its message names
these fixes (`sshBuildRefusal`, `cli/lib/keychain.ts`; `tests/signing-targets.test.ts`); `credPath` in
`cli/lib/credentials.ts` resolves relative credential paths from the project and `ascKeyFile` hands xcodebuild an
absolute path (`tests/build-sign.test.ts`).
@ -1441,3 +1446,29 @@ that fails without the fix (see CONTRIBUTING.md).
--platform macos` refuses an unsigned .pkg or one not signed with an installer certificate before any network call
(`tests/mas-build.test.ts`). The `com.apple.pkg` file type of the API build upload is taken from Apple's schema and has not
been exercised against the live API yet; `--via altool` (`--type macos`) is the fallback.
## 120. An app extension (share extension, widget, watch app) could not be signed: bundle id not registered, capabilities missing, App Group not in the profile
- **Symptom:** an iOS app with a share extension archived, then failed at export / codesign: "No profile for team 'X'
matching 'com.example.app.share' found", "Provisioning profile ... doesn't include the App Groups capability" or
"doesn't match the entitlements file's value for the com.apple.security.application-groups entitlement". `apple
signing ensure` knew only the app's bundle id and refused (`not registered`) for `extraBundleIds`.
- **Cause:** every signable target of the archive (app, app extension, widget, watch app, App Clip) is its own bundle id
with its own capabilities and profile. And Apple's API can switch the APP_GROUPS capability on for a bundle id but
cannot assign a group container to it: the profile carries `com.apple.security.application-groups` only after the
group was ticked in the developer portal (Identifiers > the bundle id > App Groups > Configure).
- **Do:** `storebound apple signing ensure --dry` lists every target found in the Xcode project (PRODUCT_BUNDLE_IDENTIFIER
and CODE_SIGN_ENTITLEMENTS of the Release configuration) and what it would register, enable and create; without
`--dry` it registers the extension bundle ids, enables the capabilities its entitlements need (the entitlement-to-
capability table; `keychain-access-groups` needs none) and, for manual signing, creates an App Store profile per
target. It then decodes each profile and compares its App Groups with the target's entitlements: a gap fails with
the developer portal deep link `https://developer.apple.com/account/resources/identifiers/bundleId/edit/<id>` and the
steps to tick the group (drive it in the signed-in browser; never press Remove / Delete / Revoke). After that
`storebound apple signing ensure --refresh-profile` makes the profile again (a normal run reuses the active one, so it
does not pile up profiles while the group is unassigned). `apple build` (manual signing) stops before the archive on the
same gap (`--allow-app-group-gap` overrides). A variable bundle id (set in an xcconfig) is not resolvable: list the
extension in `apple.signing.extensions` (`bundleId`, `capabilities`, `appGroups`), which replaces the detected ones.
- **Guard:** `cli/lib/targets.ts` (pbxproj targets, App Group comparison, portal link and steps), `discoverTargets` in
`cli/apple/signing.ts`, `tests/signing-targets.test.ts` (fixture pbxproj with an app, a share extension and app group
entitlements, a decoded profile plist, a fake App Store Connect). There is no `console plan` form for the portal page:
the steps are in the error and the warning.