Skip to content

fix(mobile): give the widget and notification-service targets a team id - #109

Merged
GSTJ merged 2 commits into
mainfrom
fix/ios-extension-target-signing
Jul 28, 2026
Merged

fix(mobile): give the widget and notification-service targets a team id#109
GSTJ merged 2 commits into
mainfrom
fix/ios-extension-target-signing

Conversation

@GSTJ

@GSTJ GSTJ commented Jul 27, 2026

Copy link
Copy Markdown
Owner

This sets ios.appleTeamId from a new EXPO_APPLE_TEAM_ID secret, rewrites release-mobile.yml's CREDENTIALS block, and makes the iOS build step name the target that's missing credentials. It doesn't unblock rc1 on its own; the credentials themselves need an interactive run only you can do, listed at the bottom.

Why rc1 failed

EAS sets iOS signing up per target. rc1 enumerated three:

- Target: Pegada                     app.pegada
- Target: PegadaWidgets              app.pegada.widgets
- Target: PegadaNotificationService  app.pegada.notificationservice

app.pegada reused its stored certificate and profile fine. app.pegada.widgets has never had credentials stored, and SetUpDistributionCertificate.runNonInteractiveAsync (eas-cli 21.3.0) is four lines:

async runNonInteractiveAsync(_ctx, currentCertificate) {
  Log.warn('Distribution Certificate is not validated for non-interactive builds.');
  if (!currentCertificate) {
    throw new MissingCredentialsNonInteractiveError();
  }
  return currentCertificate;
}

currentCertificate comes from getDistributionCertificateForAppAsync, which queries by that target's own bundle id. No branch adopts the account's existing certificate (6ZL5FHSFHB), and none creates one. That throw prints as "Credentials are not set up. Run this command again in interactive mode."

Option 2 from the issue wouldn't have fixed it. rc1 was already authenticated with an ASC API key (Using App Store Connect API Key from EAS credentials service) and still died at the certificate lookup, which runs before any profile work. The key also can't finish the job on its own: syncCapabilityIdentifiersForEntitlementsAsync bails out on token auth with Skipping capability identifier syncing because the current Apple authentication session is not using Cookies, and app.pegada.widgets needs group.app.pegada linked to its App ID. Apple ID auth is what links App Groups.

So option 1, and I rewrote the CREDENTIALS comment block that predicted option 2.

Missing team id

@bacons/apple-targets has warned about this on every prebuild we've run, CI included:

[bacons/apple-targets] Expo config is missing required ios.appleTeamId property.
Find this in Xcode and add to the Expo Config to correct. iOS builds may fail
until this is corrected.

applyDevelopmentTeamIdToTargets falls back to any DEVELOPMENT_TEAM already present on a target, and a prebuild-generated project has none, so it takes the else branch: removeBuildSetting("DEVELOPMENT_TEAM") across every target, then writes DevelopmentTeam: undefined into TargetAttributes, which serializes into the pbxproj as that literal string.

app.config.ts claimed "Team ID comes from EAS credentials at build time". Prebuild runs long before the signing step. Both expo-target.config.js files repeated the claim, so I fixed it in all three.

I pulled the value from EXPO_APPLE_TEAM_ID instead of hardcoding it, since the repo is public. Setting it on the build step is enough, because env vars reach eas build --local's isolated working copy.

Error message

eas-cli's error names neither the target nor a command, and it lands ~40s into a job whose release notes already published. #104's first read blamed the ASC key. The build step translates it now.

Proof

expo prebuild -p ios on main vs this branch. DevelopmentTeam = undefined becomes a real id on both extension targets, and DEVELOPMENT_TEAM lands on all six build configurations (Pegada, PegadaWidgets, PegadaNotificationService, Debug and Release each). ABCDE12345 is a placeholder; the real id lives in the secret.

prebuild diff

Full diff: prebuild-development-team.diff

Warning's gone:

prebuild warning

The new failure branch, against a stubbed eas replaying rc1's output. I checked the other two paths too: exit 0 passes straight through, and a non-credentials failure exits 1 with no annotation and an empty step summary.

ci annotation

What I couldn't verify

No iOS release build ran. Signing needs the certificate and the Expo account, so the credentials half of #104 stays unproven until someone with App Store Connect access runs it. Verified locally: the prebuild output above, the three shell paths, oxfmt, oxlint, tsc --noEmit.

Left for you

  1. gh secret set EXPO_APPLE_TEAM_ID -R GSTJ/pegada, the 10-character id under Membership in App Store Connect. Until it exists the build just warns.
  2. From apps/mobile: eas credentials -p ios, production profile, once for PegadaWidgets and once for PegadaNotificationService. Sign in with the Apple ID rather than the API key or the App Group won't link. Reuse certificate 6ZL5FHSFHB and let EAS mint each profile.
  3. Re-run the workflow on v1.5.0-rc1.

A fourth target later costs step 2 again. eas credentials:configure-build hardcodes nonInteractive: false, so there's nothing to automate against.

Refs #104

Claude-Session: https://claude.ai/code/session_01QsVEsfkynXpJWK4t33exG9

@bacons/apple-targets reads ios.appleTeamId to stamp DEVELOPMENT_TEAM onto
the targets it generates. The field was never set, so prebuild took the "no
team anywhere" branch: it strips DEVELOPMENT_TEAM from every target and
writes the literal `DevelopmentTeam = undefined;` into TargetAttributes.
It also warns "iOS builds may fail until this is corrected" on every CI
prebuild. Sourced from EXPO_APPLE_TEAM_ID so the id stays out of the repo.

Also corrects release-mobile.yml's CREDENTIALS block, which predicted the
wrong failure. EAS sets iOS credentials up per target, and in non-interactive
mode SetUpDistributionCertificate can only reuse a certificate already
assigned to that target: no branch adopts an unassigned account certificate
and none creates one. An ASC API key does not help, since the rc1 run was
already using one when it failed at the certificate lookup, and it cannot
link App Group identifiers at all. The build step now names the target and
the command to run instead of leaving eas-cli's bare "run this command again
in interactive mode".

Refs #104

Claude-Session: https://claude.ai/code/session_01QsVEsfkynXpJWK4t33exG9
…ne is absent

pipefail plus the job shell's -e meant a no-match grep would kill the step
before it printed the annotation it exists to print.

Refs #104

Claude-Session: https://claude.ai/code/session_01QsVEsfkynXpJWK4t33exG9
@GSTJ
GSTJ merged commit 2777a62 into main Jul 28, 2026
9 checks passed
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