From d07f6968dc74094940eada1b4583876736d39d8b Mon Sep 17 00:00:00 2001 From: Jake Date: Tue, 10 Mar 2026 15:16:29 -0400 Subject: [PATCH 1/6] [build-tools] Detect iOS Development provisioning profiles and set correct code signing identity Add DEVELOPMENT distribution type to distinguish Development profiles from Ad Hoc. Development profiles have get-task-allow=true in their entitlements; Ad Hoc profiles don't. When a Development profile is detected, override CODE_SIGN_IDENTITY to "Apple Development" instead of the "iPhone Distribution" that @expo/config-plugins hardcodes. This fixes builds that use credentialsSource: "local" with Development profiles (e.g., for Family Controls entitlement). Co-Authored-By: Claude Opus 4.6 --- .../src/ios/__tests__/configure.test.ts | 46 +++++++++++++++++++ packages/build-tools/src/ios/configure.ts | 25 ++++++++++ .../ios/credentials/provisioningProfile.ts | 5 ++ .../utils/ios/__tests__/configure.test.ts | 41 +++++++++++++++++ .../src/steps/utils/ios/configure.ts | 21 +++++++++ .../ios/credentials/provisioningProfile.ts | 5 ++ 6 files changed, 143 insertions(+) diff --git a/packages/build-tools/src/ios/__tests__/configure.test.ts b/packages/build-tools/src/ios/__tests__/configure.test.ts index b5ddd0a134..72034fade5 100644 --- a/packages/build-tools/src/ios/__tests__/configure.test.ts +++ b/packages/build-tools/src/ios/__tests__/configure.test.ts @@ -165,6 +165,52 @@ describe(configureXcodeProject, () => { 'Info.plist application target' ); }); + it('configures credentials with Apple Development identity for development profile', async () => { + vol.fromJSON( + { + 'ios/testapp.xcodeproj/project.pbxproj': originalFs.readFileSync( + path.join(__dirname, 'fixtures/simple-project.pbxproj'), + 'utf-8' + ), + 'ios/testapp/AppDelegate.m': 'placeholder', + }, + '/app' + ); + const options = { + credentials: { + keychainPath: 'fake/path', + targetProvisioningProfiles: { + testapp: { + path: 'fake/path.mobileprovision', + target: 'testapp', + bundleIdentifier: 'abc', + teamId: 'ABCDEFGH', + uuid: 'abc', + name: 'profile name', + developerCertificate: Buffer.from('test'), + certificateCommonName: 'Apple Development: Test User', + distributionType: DistributionType.DEVELOPMENT, + }, + }, + distributionType: DistributionType.DEVELOPMENT, + teamId: 'ABCDEFGH', + applicationTargetProvisioningProfile: {} as ProvisioningProfile, + }, + buildConfiguration: 'Release', + }; + const ctx = { + getReactNativeProjectDirectory: () => '/app', + logger: { info: jest.fn() }, + job: {}, + }; + await configureXcodeProject(ctx as any, options); + const pbxproj = vol.readFileSync( + '/app/ios/testapp.xcodeproj/project.pbxproj', + 'utf-8' + ) as string; + expect(pbxproj).toContain('CODE_SIGN_IDENTITY = "Apple Development"'); + expect(pbxproj).not.toContain('"iPhone Distribution"'); + }); it('configures credentials and versions for multi target project', async () => { vol.fromJSON( { diff --git a/packages/build-tools/src/ios/configure.ts b/packages/build-tools/src/ios/configure.ts index 15f36ef943..6c120f2826 100644 --- a/packages/build-tools/src/ios/configure.ts +++ b/packages/build-tools/src/ios/configure.ts @@ -6,6 +6,7 @@ import uniq from 'lodash/uniq'; import path from 'path'; import { Credentials } from './credentials/manager'; +import { DistributionType } from './credentials/provisioningProfile'; import { BuildContext } from '../context'; async function configureXcodeProject( @@ -59,6 +60,30 @@ async function configureCredentialsAsync( } ); } + + if (credentials.distributionType === DistributionType.DEVELOPMENT) { + overrideCodeSignIdentityForDevelopment( + ctx.getReactNativeProjectDirectory(), + targetNames, + buildConfiguration + ); + } +} + +function overrideCodeSignIdentityForDevelopment( + projectRoot: string, + targetNames: string[], + buildConfiguration: string +): void { + const project = IOSConfig.XcodeUtils.getPbxproj(projectRoot); + for (const targetName of targetNames) { + const xcBuildConfiguration = IOSConfig.Target.getXCBuildConfigurationFromPbxproj(project, { + targetName, + buildConfiguration, + }); + xcBuildConfiguration.buildSettings.CODE_SIGN_IDENTITY = '"Apple Development"'; + } + fs.writeFileSync(project.filepath, project.writeSync()); } async function updateVersionsAsync( diff --git a/packages/build-tools/src/ios/credentials/provisioningProfile.ts b/packages/build-tools/src/ios/credentials/provisioningProfile.ts index 4926e1d783..222c8948d2 100644 --- a/packages/build-tools/src/ios/credentials/provisioningProfile.ts +++ b/packages/build-tools/src/ios/credentials/provisioningProfile.ts @@ -24,6 +24,7 @@ export interface ProvisioningProfileData { export enum DistributionType { AD_HOC = 'ad-hoc', APP_STORE = 'app-store', + DEVELOPMENT = 'development', ENTERPRISE = 'enterprise', } @@ -137,6 +138,10 @@ export default class ProvisioningProfile { if (plistData.ProvisionsAllDevices) { return DistributionType.ENTERPRISE; } else if (plistData.ProvisionedDevices) { + const entitlements = plistData.Entitlements as plist.PlistObject | undefined; + if (entitlements?.['get-task-allow']) { + return DistributionType.DEVELOPMENT; + } return DistributionType.AD_HOC; } else { return DistributionType.APP_STORE; diff --git a/packages/build-tools/src/steps/utils/ios/__tests__/configure.test.ts b/packages/build-tools/src/steps/utils/ios/__tests__/configure.test.ts index 6cc2e47c68..df10f1586b 100644 --- a/packages/build-tools/src/steps/utils/ios/__tests__/configure.test.ts +++ b/packages/build-tools/src/steps/utils/ios/__tests__/configure.test.ts @@ -50,6 +50,47 @@ describe(configureCredentialsAsync, () => { vol.readFileSync('/app/ios/testapp.xcodeproj/project.pbxproj', 'utf-8') ).toMatchSnapshot(); }); + it('configures credentials with Apple Development identity for development profile', async () => { + vol.fromJSON( + { + 'ios/testapp.xcodeproj/project.pbxproj': originalFs.readFileSync( + path.join(__dirname, 'fixtures/simple-project.pbxproj'), + 'utf-8' + ), + 'ios/testapp/AppDelegate.m': 'placeholder', + }, + '/app' + ); + const options = { + credentials: { + keychainPath: 'fake/path', + targetProvisioningProfiles: { + testapp: { + path: 'fake/path.mobileprovision', + target: 'testapp', + bundleIdentifier: 'abc', + teamId: 'ABCDEFGH', + uuid: 'abc', + name: 'profile name', + developerCertificate: Buffer.from('test'), + certificateCommonName: 'Apple Development: Test User', + distributionType: DistributionType.DEVELOPMENT, + }, + }, + distributionType: DistributionType.DEVELOPMENT, + teamId: 'ABCDEFGH', + applicationTargetProvisioningProfile: {} as ProvisioningProfile, + }, + buildConfiguration: 'Release', + }; + await configureCredentialsAsync({ info: jest.fn() } as any, '/app', options); + const pbxproj = vol.readFileSync( + '/app/ios/testapp.xcodeproj/project.pbxproj', + 'utf-8' + ) as string; + expect(pbxproj).toContain('CODE_SIGN_IDENTITY = "Apple Development"'); + expect(pbxproj).not.toContain('"iPhone Distribution"'); + }); it('configures credentials for multi target project', async () => { vol.fromJSON( { diff --git a/packages/build-tools/src/steps/utils/ios/configure.ts b/packages/build-tools/src/steps/utils/ios/configure.ts index 1867e76a38..23b1063ef0 100644 --- a/packages/build-tools/src/steps/utils/ios/configure.ts +++ b/packages/build-tools/src/steps/utils/ios/configure.ts @@ -6,6 +6,7 @@ import uniq from 'lodash/uniq'; import path from 'path'; import { Credentials } from './credentials/manager'; +import { DistributionType } from './credentials/provisioningProfile'; export async function configureCredentialsAsync( logger: bunyan, @@ -31,6 +32,26 @@ export async function configureCredentialsAsync( buildConfiguration, }); } + + if (credentials.distributionType === DistributionType.DEVELOPMENT) { + overrideCodeSignIdentityForDevelopment(workingDir, targetNames, buildConfiguration); + } +} + +function overrideCodeSignIdentityForDevelopment( + projectRoot: string, + targetNames: string[], + buildConfiguration: string +): void { + const project = IOSConfig.XcodeUtils.getPbxproj(projectRoot); + for (const targetName of targetNames) { + const xcBuildConfiguration = IOSConfig.Target.getXCBuildConfigurationFromPbxproj(project, { + targetName, + buildConfiguration, + }); + xcBuildConfiguration.buildSettings.CODE_SIGN_IDENTITY = '"Apple Development"'; + } + fs.writeFileSync(project.filepath, project.writeSync()); } export async function updateVersionsAsync( diff --git a/packages/build-tools/src/steps/utils/ios/credentials/provisioningProfile.ts b/packages/build-tools/src/steps/utils/ios/credentials/provisioningProfile.ts index 6e07f02d77..42b31a2677 100644 --- a/packages/build-tools/src/steps/utils/ios/credentials/provisioningProfile.ts +++ b/packages/build-tools/src/steps/utils/ios/credentials/provisioningProfile.ts @@ -23,6 +23,7 @@ export interface ProvisioningProfileData { export enum DistributionType { AD_HOC = 'ad-hoc', APP_STORE = 'app-store', + DEVELOPMENT = 'development', ENTERPRISE = 'enterprise', } @@ -133,6 +134,10 @@ export default class ProvisioningProfile { if (plistData.ProvisionsAllDevices) { return DistributionType.ENTERPRISE; } else if (plistData.ProvisionedDevices) { + const entitlements = plistData.Entitlements as plist.PlistObject | undefined; + if (entitlements?.['get-task-allow']) { + return DistributionType.DEVELOPMENT; + } return DistributionType.AD_HOC; } else { return DistributionType.APP_STORE; From d46582ac4da750c7b400a88eaaa2dd939d115108 Mon Sep 17 00:00:00 2001 From: Jake Date: Tue, 10 Mar 2026 15:21:20 -0400 Subject: [PATCH 2/6] [eas-cli] Accept Development provisioning profiles for internal distribution Fix isAdHocProfile() to distinguish Development from Ad Hoc profiles by checking the get-task-allow entitlement. Add isDevelopmentProfile() for explicit detection. Update assertProvisioningProfileType() to accept Development profiles for internal distribution, and reject them for store distribution. This enables credentialsSource: "local" with Development profiles needed for entitlements like Family Controls (com.apple.developer.family-controls) that only work with Development provisioning profiles. Co-Authored-By: Claude Opus 4.6 --- .../credentials/ios/IosCredentialsProvider.ts | 20 ++++++++++++++----- .../ios/utils/provisioningProfile.ts | 16 ++++++++++++++- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/packages/eas-cli/src/credentials/ios/IosCredentialsProvider.ts b/packages/eas-cli/src/credentials/ios/IosCredentialsProvider.ts index a46b3bf738..b46648d690 100644 --- a/packages/eas-cli/src/credentials/ios/IosCredentialsProvider.ts +++ b/packages/eas-cli/src/credentials/ios/IosCredentialsProvider.ts @@ -10,7 +10,11 @@ import { getAppFromContextAsync } from './actions/BuildCredentialsUtils'; import { SetUpBuildCredentials } from './actions/SetUpBuildCredentials'; import { SetUpPushKey } from './actions/SetUpPushKey'; import { App, IosCredentials, Target } from './types'; -import { isAdHocProfile, isEnterpriseUniversalProfile } from './utils/provisioningProfile'; +import { + isAdHocProfile, + isDevelopmentProfile, + isEnterpriseUniversalProfile, +} from './utils/provisioningProfile'; import { CommonIosAppCredentialsFragment } from '../../graphql/generated'; import Log from '../../log'; import { findApplicationTarget } from '../../project/ios/target'; @@ -150,6 +154,7 @@ export default class IosCredentialsProvider { private assertProvisioningProfileType(provisioningProfile: string, targetName?: string): void { const isAdHoc = isAdHocProfile(provisioningProfile); + const isDevelopment = isDevelopmentProfile(provisioningProfile); const isEnterprise = isEnterpriseUniversalProfile(provisioningProfile); if (this.options.distribution === 'internal') { if (this.options.enterpriseProvisioning === 'universal' && !isEnterprise) { @@ -164,16 +169,21 @@ export default class IosCredentialsProvider { targetName ? ` (target '${targetName})'` : '' } for internal distribution if you specified "enterpriseProvisioning": "adhoc" in eas.json` ); - } else if (!this.options.enterpriseProvisioning && !isEnterprise && !isAdHoc) { + } else if ( + !this.options.enterpriseProvisioning && + !isEnterprise && + !isAdHoc && + !isDevelopment + ) { throw new Error( - `You must use an adhoc provisioning profile${ + `You must use an adhoc or development provisioning profile${ targetName ? ` (target '${targetName})'` : '' } for internal distribution.` ); } - } else if (isAdHoc) { + } else if (isAdHoc || isDevelopment) { throw new Error( - `You can't use an adhoc provisioning profile${ + `You can't use an ${isAdHoc ? 'adhoc' : 'development'} provisioning profile${ targetName ? ` (target '${targetName}')` : '' } for app store distribution.` ); diff --git a/packages/eas-cli/src/credentials/ios/utils/provisioningProfile.ts b/packages/eas-cli/src/credentials/ios/utils/provisioningProfile.ts index 74507389f4..315c8dcf45 100644 --- a/packages/eas-cli/src/credentials/ios/utils/provisioningProfile.ts +++ b/packages/eas-cli/src/credentials/ios/utils/provisioningProfile.ts @@ -23,7 +23,21 @@ export function readProfileName(dataBase64: string): string { export function isAdHocProfile(dataBase64: string): boolean { const profilePlist = parse(dataBase64); const provisionedDevices = profilePlist['ProvisionedDevices'] as string[] | undefined; - return Array.isArray(provisionedDevices); + if (!Array.isArray(provisionedDevices)) { + return false; + } + const entitlements = profilePlist['Entitlements'] as PlistObject | undefined; + return !entitlements?.['get-task-allow']; +} + +export function isDevelopmentProfile(dataBase64: string): boolean { + const profilePlist = parse(dataBase64); + const provisionedDevices = profilePlist['ProvisionedDevices'] as string[] | undefined; + if (!Array.isArray(provisionedDevices)) { + return false; + } + const entitlements = profilePlist['Entitlements'] as PlistObject | undefined; + return !!entitlements?.['get-task-allow']; } export function isEnterpriseUniversalProfile(dataBase64: string): boolean { From 6440712d1fa23841df1d7c56f6893c6c06fd7ee3 Mon Sep 17 00:00:00 2001 From: Jake Date: Thu, 12 Mar 2026 12:45:14 -0400 Subject: [PATCH 3/6] [build-tools] Use certificateCommonName for development code signing identity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Address review feedback: use the certificate common name from the provisioning profile instead of hardcoding "Apple Development", which doesn't cover all certificate types (e.g. "iPhone Developer", "iOS Development"). Also fix grammar in error message ("an development" โ†’ "a development"). Co-Authored-By: Claude Opus 4.6 --- .../src/ios/__tests__/configure.test.ts | 2 +- packages/build-tools/src/ios/configure.ts | 10 +++++----- .../steps/utils/ios/__tests__/configure.test.ts | 2 +- .../build-tools/src/steps/utils/ios/configure.ts | 14 +++++++++----- .../src/credentials/ios/IosCredentialsProvider.ts | 2 +- 5 files changed, 17 insertions(+), 13 deletions(-) diff --git a/packages/build-tools/src/ios/__tests__/configure.test.ts b/packages/build-tools/src/ios/__tests__/configure.test.ts index 72034fade5..175647c920 100644 --- a/packages/build-tools/src/ios/__tests__/configure.test.ts +++ b/packages/build-tools/src/ios/__tests__/configure.test.ts @@ -208,7 +208,7 @@ describe(configureXcodeProject, () => { '/app/ios/testapp.xcodeproj/project.pbxproj', 'utf-8' ) as string; - expect(pbxproj).toContain('CODE_SIGN_IDENTITY = "Apple Development"'); + expect(pbxproj).toContain('CODE_SIGN_IDENTITY = "Apple Development: Test User"'); expect(pbxproj).not.toContain('"iPhone Distribution"'); }); it('configures credentials and versions for multi target project', async () => { diff --git a/packages/build-tools/src/ios/configure.ts b/packages/build-tools/src/ios/configure.ts index 6c120f2826..807f661fd7 100644 --- a/packages/build-tools/src/ios/configure.ts +++ b/packages/build-tools/src/ios/configure.ts @@ -6,7 +6,7 @@ import uniq from 'lodash/uniq'; import path from 'path'; import { Credentials } from './credentials/manager'; -import { DistributionType } from './credentials/provisioningProfile'; +import { DistributionType, ProvisioningProfileData } from './credentials/provisioningProfile'; import { BuildContext } from '../context'; async function configureXcodeProject( @@ -64,7 +64,7 @@ async function configureCredentialsAsync( if (credentials.distributionType === DistributionType.DEVELOPMENT) { overrideCodeSignIdentityForDevelopment( ctx.getReactNativeProjectDirectory(), - targetNames, + credentials.targetProvisioningProfiles, buildConfiguration ); } @@ -72,16 +72,16 @@ async function configureCredentialsAsync( function overrideCodeSignIdentityForDevelopment( projectRoot: string, - targetNames: string[], + targetProvisioningProfiles: Record, buildConfiguration: string ): void { const project = IOSConfig.XcodeUtils.getPbxproj(projectRoot); - for (const targetName of targetNames) { + for (const [targetName, profile] of Object.entries(targetProvisioningProfiles)) { const xcBuildConfiguration = IOSConfig.Target.getXCBuildConfigurationFromPbxproj(project, { targetName, buildConfiguration, }); - xcBuildConfiguration.buildSettings.CODE_SIGN_IDENTITY = '"Apple Development"'; + xcBuildConfiguration.buildSettings.CODE_SIGN_IDENTITY = `"${profile.certificateCommonName}"`; } fs.writeFileSync(project.filepath, project.writeSync()); } diff --git a/packages/build-tools/src/steps/utils/ios/__tests__/configure.test.ts b/packages/build-tools/src/steps/utils/ios/__tests__/configure.test.ts index df10f1586b..72c9876e53 100644 --- a/packages/build-tools/src/steps/utils/ios/__tests__/configure.test.ts +++ b/packages/build-tools/src/steps/utils/ios/__tests__/configure.test.ts @@ -88,7 +88,7 @@ describe(configureCredentialsAsync, () => { '/app/ios/testapp.xcodeproj/project.pbxproj', 'utf-8' ) as string; - expect(pbxproj).toContain('CODE_SIGN_IDENTITY = "Apple Development"'); + expect(pbxproj).toContain('CODE_SIGN_IDENTITY = "Apple Development: Test User"'); expect(pbxproj).not.toContain('"iPhone Distribution"'); }); it('configures credentials for multi target project', async () => { diff --git a/packages/build-tools/src/steps/utils/ios/configure.ts b/packages/build-tools/src/steps/utils/ios/configure.ts index 23b1063ef0..da79a0ea5e 100644 --- a/packages/build-tools/src/steps/utils/ios/configure.ts +++ b/packages/build-tools/src/steps/utils/ios/configure.ts @@ -6,7 +6,7 @@ import uniq from 'lodash/uniq'; import path from 'path'; import { Credentials } from './credentials/manager'; -import { DistributionType } from './credentials/provisioningProfile'; +import { DistributionType, ProvisioningProfileData } from './credentials/provisioningProfile'; export async function configureCredentialsAsync( logger: bunyan, @@ -34,22 +34,26 @@ export async function configureCredentialsAsync( } if (credentials.distributionType === DistributionType.DEVELOPMENT) { - overrideCodeSignIdentityForDevelopment(workingDir, targetNames, buildConfiguration); + overrideCodeSignIdentityForDevelopment( + workingDir, + credentials.targetProvisioningProfiles, + buildConfiguration + ); } } function overrideCodeSignIdentityForDevelopment( projectRoot: string, - targetNames: string[], + targetProvisioningProfiles: Record, buildConfiguration: string ): void { const project = IOSConfig.XcodeUtils.getPbxproj(projectRoot); - for (const targetName of targetNames) { + for (const [targetName, profile] of Object.entries(targetProvisioningProfiles)) { const xcBuildConfiguration = IOSConfig.Target.getXCBuildConfigurationFromPbxproj(project, { targetName, buildConfiguration, }); - xcBuildConfiguration.buildSettings.CODE_SIGN_IDENTITY = '"Apple Development"'; + xcBuildConfiguration.buildSettings.CODE_SIGN_IDENTITY = `"${profile.certificateCommonName}"`; } fs.writeFileSync(project.filepath, project.writeSync()); } diff --git a/packages/eas-cli/src/credentials/ios/IosCredentialsProvider.ts b/packages/eas-cli/src/credentials/ios/IosCredentialsProvider.ts index b46648d690..43bd7cc8d8 100644 --- a/packages/eas-cli/src/credentials/ios/IosCredentialsProvider.ts +++ b/packages/eas-cli/src/credentials/ios/IosCredentialsProvider.ts @@ -183,7 +183,7 @@ export default class IosCredentialsProvider { } } else if (isAdHoc || isDevelopment) { throw new Error( - `You can't use an ${isAdHoc ? 'adhoc' : 'development'} provisioning profile${ + `You can't use ${isAdHoc ? 'an adhoc' : 'a development'} provisioning profile${ targetName ? ` (target '${targetName}')` : '' } for app store distribution.` ); From 40519d080f4191714d7a82b561c193b9f8884f2f Mon Sep 17 00:00:00 2001 From: Jake Date: Thu, 12 Mar 2026 12:52:39 -0400 Subject: [PATCH 4/6] [build-tools] Add CHANGELOG entry for development provisioning profile fix Co-Authored-By: Claude Opus 4.6 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 99c0335c3f..0fd0f7637c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ This is the log of notable changes to EAS CLI and related packages. ### ๐Ÿ› Bug fixes +- Detect iOS Development provisioning profiles and set correct code signing identity instead of treating them as Ad Hoc. ([#3496](https://github.com/expo/eas-cli/pull/3496) by [@qwertey6](https://github.com/qwertey6)) - [eas-cli] Fix workflow:logs for builds using built-in EAS build steps. ([#3523](https://github.com/expo/eas-cli/pull/3523) by [@douglowder](https://github.com/douglowder)) - [build-tools][worker] Read Expo app config with `expo config` CLI invocation before falling back to `@expo/config` ([#3536](https://github.com/expo/eas-cli/pull/3536) by [@kitten](https://github.com/kitten)) - Fix `hasIgnoredIosProjectAsync()` always returning `false` for ignored iOS projects. ([#3562](https://github.com/expo/eas-cli/pull/3562) by [@sjchmiela](https://github.com/sjchmiela)) @@ -53,7 +54,11 @@ This is the log of notable changes to EAS CLI and related packages. ### ๐Ÿ› Bug fixes +<<<<<<< HEAD - Check all certificates in provisioning profile during verification instead of only the first one. ([#3484](https://github.com/expo/eas-cli/pull/3484) by [@qwertey6](https://github.com/qwertey6)) +======= +- Detect iOS Development provisioning profiles and set correct code signing identity instead of treating them as Ad Hoc. ([#3496](https://github.com/expo/eas-cli/pull/3496) by [@qwertey6](https://github.com/qwertey6)) +>>>>>>> cf7b3fe3 ([build-tools] Add CHANGELOG entry for development provisioning profile fix) - Provide an override for the new --environment flag requirement in the update command. ([#3442](https://github.com/expo/eas-cli/pull/3442) by [@douglowder](https://github.com/douglowder)) - Add missing `--include=dev` for `npm install` commands ([#3459](https://github.com/expo/eas-cli/pull/3459) by [@kitten](https://github.com/kitten)) - Add missing `--production false` for `yarn install` commands for Yarn Classic ([#3459](https://github.com/expo/eas-cli/pull/3459) by [@kitten](https://github.com/kitten)) From 55acccab2051ef7a4d6dc265a9a6ff1f9e23d059 Mon Sep 17 00:00:00 2001 From: Jake Date: Tue, 24 Mar 2026 15:20:51 -0400 Subject: [PATCH 5/6] [build-tools] Use upstream codeSignIdentity parameter instead of workaround Now that @expo/config-plugins@55.0.7 supports the optional codeSignIdentity parameter in setProvisioningProfileForPbxproj, pass profile.certificateCommonName directly for development profiles and remove the overrideCodeSignIdentityForDevelopment workaround that was reading/writing the pbxproj a second time. Co-Authored-By: Claude Opus 4.6 --- packages/build-tools/src/ios/configure.ts | 29 +++---------------- .../src/steps/utils/ios/configure.ts | 29 +++---------------- 2 files changed, 8 insertions(+), 50 deletions(-) diff --git a/packages/build-tools/src/ios/configure.ts b/packages/build-tools/src/ios/configure.ts index 807f661fd7..827034362a 100644 --- a/packages/build-tools/src/ios/configure.ts +++ b/packages/build-tools/src/ios/configure.ts @@ -6,7 +6,7 @@ import uniq from 'lodash/uniq'; import path from 'path'; import { Credentials } from './credentials/manager'; -import { DistributionType, ProvisioningProfileData } from './credentials/provisioningProfile'; +import { DistributionType } from './credentials/provisioningProfile'; import { BuildContext } from '../context'; async function configureXcodeProject( @@ -57,33 +57,12 @@ async function configureCredentialsAsync( profileName: profile.name, appleTeamId: profile.teamId, buildConfiguration, + ...(credentials.distributionType === DistributionType.DEVELOPMENT && { + codeSignIdentity: profile.certificateCommonName, + }), } ); } - - if (credentials.distributionType === DistributionType.DEVELOPMENT) { - overrideCodeSignIdentityForDevelopment( - ctx.getReactNativeProjectDirectory(), - credentials.targetProvisioningProfiles, - buildConfiguration - ); - } -} - -function overrideCodeSignIdentityForDevelopment( - projectRoot: string, - targetProvisioningProfiles: Record, - buildConfiguration: string -): void { - const project = IOSConfig.XcodeUtils.getPbxproj(projectRoot); - for (const [targetName, profile] of Object.entries(targetProvisioningProfiles)) { - const xcBuildConfiguration = IOSConfig.Target.getXCBuildConfigurationFromPbxproj(project, { - targetName, - buildConfiguration, - }); - xcBuildConfiguration.buildSettings.CODE_SIGN_IDENTITY = `"${profile.certificateCommonName}"`; - } - fs.writeFileSync(project.filepath, project.writeSync()); } async function updateVersionsAsync( diff --git a/packages/build-tools/src/steps/utils/ios/configure.ts b/packages/build-tools/src/steps/utils/ios/configure.ts index da79a0ea5e..e37e66170a 100644 --- a/packages/build-tools/src/steps/utils/ios/configure.ts +++ b/packages/build-tools/src/steps/utils/ios/configure.ts @@ -6,7 +6,7 @@ import uniq from 'lodash/uniq'; import path from 'path'; import { Credentials } from './credentials/manager'; -import { DistributionType, ProvisioningProfileData } from './credentials/provisioningProfile'; +import { DistributionType } from './credentials/provisioningProfile'; export async function configureCredentialsAsync( logger: bunyan, @@ -30,32 +30,11 @@ export async function configureCredentialsAsync( profileName: profile.name, appleTeamId: profile.teamId, buildConfiguration, + ...(credentials.distributionType === DistributionType.DEVELOPMENT && { + codeSignIdentity: profile.certificateCommonName, + }), }); } - - if (credentials.distributionType === DistributionType.DEVELOPMENT) { - overrideCodeSignIdentityForDevelopment( - workingDir, - credentials.targetProvisioningProfiles, - buildConfiguration - ); - } -} - -function overrideCodeSignIdentityForDevelopment( - projectRoot: string, - targetProvisioningProfiles: Record, - buildConfiguration: string -): void { - const project = IOSConfig.XcodeUtils.getPbxproj(projectRoot); - for (const [targetName, profile] of Object.entries(targetProvisioningProfiles)) { - const xcBuildConfiguration = IOSConfig.Target.getXCBuildConfigurationFromPbxproj(project, { - targetName, - buildConfiguration, - }); - xcBuildConfiguration.buildSettings.CODE_SIGN_IDENTITY = `"${profile.certificateCommonName}"`; - } - fs.writeFileSync(project.filepath, project.writeSync()); } export async function updateVersionsAsync( From 02adc3b237e938c467cd14842f002c0f72bd5d92 Mon Sep 17 00:00:00 2001 From: Quinlan Jung Date: Thu, 2 Apr 2026 13:08:20 -0700 Subject: [PATCH 6/6] fix changelog Temporary Commit at 4/2/2026, 1:09:37 PM --- CHANGELOG.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0fd0f7637c..8ff581cd38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ This is the log of notable changes to EAS CLI and related packages. ### ๐Ÿ› Bug fixes +- Detect iOS Development provisioning profiles and set correct code signing identity instead of treating them as Ad Hoc. ([#3496](https://github.com/expo/eas-cli/pull/3496) by [@qwertey6](https://github.com/qwertey6)) + ### ๐Ÿงน Chores ## [18.5.0](https://github.com/expo/eas-cli/releases/tag/v18.5.0) - 2026-04-02 @@ -21,7 +23,6 @@ This is the log of notable changes to EAS CLI and related packages. ### ๐Ÿ› Bug fixes -- Detect iOS Development provisioning profiles and set correct code signing identity instead of treating them as Ad Hoc. ([#3496](https://github.com/expo/eas-cli/pull/3496) by [@qwertey6](https://github.com/qwertey6)) - [eas-cli] Fix workflow:logs for builds using built-in EAS build steps. ([#3523](https://github.com/expo/eas-cli/pull/3523) by [@douglowder](https://github.com/douglowder)) - [build-tools][worker] Read Expo app config with `expo config` CLI invocation before falling back to `@expo/config` ([#3536](https://github.com/expo/eas-cli/pull/3536) by [@kitten](https://github.com/kitten)) - Fix `hasIgnoredIosProjectAsync()` always returning `false` for ignored iOS projects. ([#3562](https://github.com/expo/eas-cli/pull/3562) by [@sjchmiela](https://github.com/sjchmiela)) @@ -54,11 +55,7 @@ This is the log of notable changes to EAS CLI and related packages. ### ๐Ÿ› Bug fixes -<<<<<<< HEAD - Check all certificates in provisioning profile during verification instead of only the first one. ([#3484](https://github.com/expo/eas-cli/pull/3484) by [@qwertey6](https://github.com/qwertey6)) -======= -- Detect iOS Development provisioning profiles and set correct code signing identity instead of treating them as Ad Hoc. ([#3496](https://github.com/expo/eas-cli/pull/3496) by [@qwertey6](https://github.com/qwertey6)) ->>>>>>> cf7b3fe3 ([build-tools] Add CHANGELOG entry for development provisioning profile fix) - Provide an override for the new --environment flag requirement in the update command. ([#3442](https://github.com/expo/eas-cli/pull/3442) by [@douglowder](https://github.com/douglowder)) - Add missing `--include=dev` for `npm install` commands ([#3459](https://github.com/expo/eas-cli/pull/3459) by [@kitten](https://github.com/kitten)) - Add missing `--production false` for `yarn install` commands for Yarn Classic ([#3459](https://github.com/expo/eas-cli/pull/3459) by [@kitten](https://github.com/kitten))