Skip to content

--no-auto-testflight-setup is ignored when the submit profile has no ascAppId: Team (Expo) is still created and all Admins enrolled (opt-out lost in 22.0.0) #4397

Description

@kbrandwijk

Build/Submit details page URL

No response

Summary

eas submit -p ios --no-auto-testflight-setup still creates the internal TestFlight group Team (Expo) and adds every Admin on the Apple team to it as a tester, whenever the submit profile has no ascAppId. The flag is only honoured on the ascAppId code path; the default path (app resolved by bundle identifier through ensureAppStoreConnectAppExistsAsync) calls the group setup unconditionally.

Expected: --no-auto-testflight-setup disables the group creation and the tester enrolment on every path, as its description says ("Set up an internal TestFlight group for the app (iOS only)", allowNo: true). On a team where the Admins are not the testers, enrolling them without being asked is a change to the team's TestFlight configuration that the user explicitly opted out of.

Managed or bare?

Managed (continuous native generation; ios/ and android/ are gitignored prebuild output, which is why expo-env-info prints Expo Workflow: bare below).

Environment

eas-cli/24.0.0 darwin-arm64 node-v20.19.4 (global install via bun; expo-env-info does not see the bun global registry, so its npmGlobalPackages line is corrected by hand below).

expo-env-info 2.1.0 environment info:
    System:
      OS: macOS 26.5.2
      Shell: 5.9 - /bin/zsh
    Binaries:
      Node: 20.19.4 - ~/.nvm/versions/node/v20.19.4/bin/node
      Yarn: 1.22.22 - ~/.nvm/versions/node/v20.19.4/bin/yarn
      npm: 10.8.2 - ~/.nvm/versions/node/v20.19.4/bin/npm
    Managers:
      CocoaPods: 1.16.2 - /opt/homebrew/bin/pod
    SDKs:
      iOS SDK:
        Platforms: DriverKit 25.5, iOS 26.5, macOS 26.5, tvOS 26.5, visionOS 26.5, watchOS 26.5
    IDEs:
      Android Studio: 2025.2 AI-252.25557.131.2521.14344949
      Xcode: 26.5/17F42 - /usr/bin/xcodebuild
    npmPackages:
      expo: ~57.0.20 => 57.0.20
      expo-router: ~57.0.19 => 57.0.19
      react: 19.2.3 => 19.2.3
      react-dom: 19.2.3 => 19.2.3
      react-native: 0.86.3 => 0.86.3
      react-native-web: ~0.21.0 => 0.21.2
    npmGlobalPackages:
      eas-cli: 24.0.0 (bun global install)
    Expo Workflow: bare   <- see above; the project is managed

Error output

No error. After a successful eas submit --platform ios --profile <profile> (submit profile {}, no ascAppId, key on the EAS credentials service), App Store Connect > TestFlight shows a new internal group Team (Expo) with automatic distribution on and every Admin of the team enrolled as a tester. That run did not pass --no-auto-testflight-setup; that the flag would not have changed the outcome on this path is established from the source below, and the steps to observe it are in the repro section. (The messages for this step are TestFlight group created: Team (Expo) and TestFlight access enabled for: ..., from ensureTestFlightGroup.ts.)

Where it happens (eas-cli main)

packages/eas-cli/src/submit/ios/IosSubmitCommand.ts, resolveAscAppIdentifierAsync, has two branches:

  • With ascAppId in the profile (L175): ensureTestFlightSetupForExistingAppAsync(this.ctx, ascAppId). That function checks the flag first (packages/eas-cli/src/submit/ios/ensureTestFlightSetup.ts L28: if (!ctx.autoTestFlightSetup) return;). Correct.
  • Without ascAppId (L194): ensureAppStoreConnectAppExistsAsync(this.ctx) in packages/eas-cli/src/submit/ios/AppProduce.ts, which resolves or creates the app and then, at L97, calls ensureTestFlightGroupExistsAsync(app, { nonInteractive }) inside a try/catch. Nothing on this path reads ctx.autoTestFlightSetup.

ensureTestFlightGroupExistsAsync (packages/eas-cli/src/credentials/ios/appstore/ensureTestFlightGroup.ts) then creates the Team (Expo) group with hasAccessToAllBuilds: true when the app has no groups, lists the team's users, filters to UserRole.ADMIN, and bulk-assigns them as beta testers.

The flag is plumbed into SubmissionContext (packages/eas-cli/src/commands/submit.ts L111-L113, L162, L233; submit/context.ts), so ctx.autoTestFlightSetup is available in AppProduce.ts; it is just not consulted there.

How it got here (regression in 22.0.0)

So since 22.0.0 the default path has no opt-out at all: the env var is gone and the flag is not read. The 22.0.0 changelog entry ("with --no-auto-testflight-setup to disable it") reads as if the flag disables the behaviour; it disables it on one of the two paths.

Docs

The behaviour is not described anywhere a user reads before their first submit. Submit to the Apple App Store does not mention it. Distribute an iOS app with TestFlight says to create internal groups by hand in App Store Connect and target them with --groups, and does not mention that eas submit will create one and enrol the Admins on its own. The only mention is the flag's one-line description in the CLI reference.

Reproducible demo or steps to reproduce from a blank project

  1. npx create-expo-app repro && cd repro && eas init && eas build:configure. Set ios.bundleIdentifier to a bundle id on your Apple team whose App Store Connect app has no TestFlight groups yet (a fresh app record, or one where you removed the groups). Add "submit": { "production": {} } and do not set ascAppId.
  2. Set up an App Store Connect API key for EAS Submit (eas credentials -p ios).
  3. eas build -p ios --profile production.
  4. eas submit -p ios --profile production --latest --no-auto-testflight-setup.
  5. Observe TestFlight group created: Team (Expo) in the output and the group, with the team's Admins enrolled, in App Store Connect.

Control: add "ascAppId": "<the app's numeric id>" to the submit profile, delete the group, and run step 4 again. No group is created; the flag is honoured on that path.

Suggested fix

Move the check back into ensureTestFlightGroupExistsAsync (where the env var used to be) so every caller respects it (commands/go.ts L45 calls it too), or read ctx.autoTestFlightSetup in createAppStoreConnectAppAsync (AppProduce.ts L97). Restoring EAS_NO_AUTO_TESTFLIGHT_SETUP alongside the flag would also help CI, where a flag has to be threaded through every invocation and an env var does not.

Docs: a sentence in the TestFlight guide saying that the first eas submit creates Team (Expo) and enrols all Admins unless a group already exists or --no-auto-testflight-setup is passed.

The default itself

Beyond the flag bug: as far as we could find, this default is undocumented, and it is an undesirable one. Every other thing eas submit does is scoped to the build it is submitting. This step reaches into the team: it creates a distribution group the user did not ask for, with automatic access to every future build, and enrols people by role rather than by choice, so each Admin gets a TestFlight invitation for an app they may have no part in testing, on the first submit, when whoever is running it is least likely to know a flag exists. Reading the Admin list also needs an Admin-role key, so the step silently depends on the key's role in a way the submission itself does not.

The behaviour the TestFlight guide describes is the right one: the team creates the groups it wants and eas submit --groups targets them. Please consider making the automatic group opt-in (--auto-testflight-setup, default off), or at least asking before creating it in interactive mode; and in either case documenting it in the TestFlight guide, not only as a flag description.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions