apple signing: App Group association fails early under automatic signing too (API capability + newest profile, steps and deep link, exit before the archive); console plan/verify apple-app-group

This commit is contained in:
CRTkafa 2026-10-25 22:34:14 +07:00
parent d978bb7a8b
commit 304407e523
20 changed files with 590 additions and 60 deletions

View file

@ -19,7 +19,7 @@ when the owner said so for this run). The MCP server offers only `apple_signing_
1. **Read.** `storebound apple signing status`: is the bundle id registered (else `storebound apple bundle`), which
capabilities it has vs `apple.signing.capabilities`, the distribution certificates of the team and whether this
Mac holds a private key for one (a key file in `.storebound/signing/` or an identity in the keychain), App Store
profiles per bundle id (the app and every extension / widget / watch app / App Clip found in the Xcode project, or `apple.signing.extensions`; `extraBundleIds` adds more) and whether Xcode has them installed. `signing ensure` registers the extensions' bundle ids, enables the capabilities their entitlements need and (manual style) makes their profiles; an App Group the profile lacks is reported with the developer portal link and steps (the API cannot assign a group; then `signing ensure --refresh-profile`, store-pitfalls 121).
profiles per bundle id (the app and every extension / widget / watch app / App Clip found in the Xcode project, or `apple.signing.extensions`; `extraBundleIds` adds more) and whether Xcode has them installed. `signing ensure` registers the extensions' bundle ids, enables the capabilities their entitlements need and (manual style) makes their profiles; an App Group not proven on the App ID (manual: the profile; automatic: the capability and the newest profile the API lists) is reported with the developer portal link and steps (the API cannot assign a group): `storebound console plan apple-app-group --bundle-id <id> --lookup`, drive it, then `signing ensure --refresh-profile` and `console verify apple-app-group` (store-pitfalls 121).
It also compares three places a capability must be and names what is missing where: the App ID, the config's
`apple.signing.capabilities` and the iOS project's `.entitlements` (`aps-environment` = PUSH_NOTIFICATIONS,
`com.apple.developer.game-center` = GAME_CENTER, associated domains, Sign in with Apple, iCloud, app groups, ...;
@ -61,8 +61,9 @@ when the owner said so for this run). The MCP server offers only `apple_signing_
`apple build` stops first and names the fixes. `STOREBOUND_KEYCHAIN_PASSWORD=... storebound apple build
--keychain-unlock` unlocks the login keychain and sets its key partition list (the password is read from the
environment and never printed); `--keychain <path>` signs with a build keychain (`--keychain <path> --keychain-unlock`
unlocks that one; `signing ensure --keychain <path>` imports the key + certificate into it). With manual signing it
also stops when a target's App Group is missing from its installed profile (store-pitfalls 121).
unlocks that one; `signing ensure --keychain <path>` imports the key + certificate into it). It
also stops before the archive when a target's App Group is missing (manual: its installed profile; automatic: the profile
the API lists; store-pitfalls 121; `--allow-app-group-gap` overrides).
- Capacitor: the archive ships the web assets `npx cap sync` copied last. Set `build.prebuild` (e.g.
`"npm run build && npx cap sync"`; per store `apple.prebuild` / `play.prebuild`) and `apple build` / `play build`
run it first (once per `flow run`; `--no-prebuild` skips it). Then the copied `public/index.html` must be newer

View file

@ -45,7 +45,7 @@ the UI shows. This is the primary mode.
`--all` / MCP `all: true` puts every card's steps inline in fix order and ends with the one owner list: tick the
IARC Terms of Use box (before), Send changes for review (after)), its cards `play-privacy-policy`, `play-ads`, `play-sign-in-details`, `play-advertising-id`,
`play-government-apps`, `play-financial-features`, `play-health-apps`, and the first production release:
`play-production-countries`, `play-production-release` and `play-publish-changes` (managed publishing). `storebound console plan` lists them.
`play-production-countries`, `play-production-release` and `play-publish-changes` (managed publishing), and the Apple developer portal step `apple-app-group` (assign an App Group to an extension's App ID, which the API cannot do; its final Save is yours, `buttons.finalByAgent`; `console verify apple-app-group` reads the API). `storebound console plan` lists them.
2. Send the owner the `ownerBatch` of every form you will fill in ONE message before you start (AGENTS.md rule 5): the
`ask-owner` answers (write them into the config, so the plan has them; never guess them) and the `before` steps
(Play content rating: tick the IARC Terms of Use box on the questionnaire's page 1 first; page 1's Next does

View file

@ -1465,7 +1465,6 @@ that fails without the fix (see CONTRIBUTING.md).
attributes first, `text=` last); `shots capture --dry` prints them per size, `--dry --probe` opens the pages and
names the MISS with the size and every candidate's match count.
- **Guard:** `tests/shots-gaps.test.ts`, `tests/browser/feature-fit.browser.ts` (rotate), `cli/shots/selectors.ts`.
||||||| parent of ae8d773 (apple signing: every signable target (extensions, App Group check), build keychain unlock over SSH, api confirm docs)
## 121. An app extension (share extension, widget, watch app) could not be signed: bundle id not registered, capabilities missing, App Group not in the profile
@ -1481,14 +1480,21 @@ that fails without the fix (see CONTRIBUTING.md).
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
target. It then compares each target's App Groups with what the API shows (manual signing: the decoded profile; automatic
signing: the App ID's APP_GROUPS capability settings and the newest profile the API lists for the bundle id, an
Xcode-managed one too; a profile that carries no group, or the capability off, is a gap; nothing readable is
"cannot be proven" and only warns with the same steps): 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
does not pile up profiles while the group is unassigned). `apple build` stops before the archive on the same gap in both
signing styles (manual: the installed profile; automatic: read through the API; `--allow-app-group-gap` overrides, e.g.
when the group was just ticked and Xcode will renew its managed profile at archive time). The agent-first plan is
`storebound console plan apple-app-group --bundle-id <id>` (`--lookup` adds the deep link; its Save is the agent's own, not a
store submission) and `storebound console verify apple-app-group` re-reads the App ID and the newest profile (after the
portal Save the old profiles are invalid: run `signing ensure --refresh-profile` first). 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.
entitlements, a decoded profile plist, a fake App Store Connect), `cli/lib/console-apple-group-plan.ts` (the plan),
`verifyAppGroupsApi` in `cli/lib/console-verify.ts`, `appGroupVerdicts` in `cli/lib/targets.ts` (gap / unproven / ok).