Let iOS auto-signing tool handle Googler scenario (#16010) * Let iOS auto-signing tool handle Googler scenario * Forgot to update tests
diff --git a/packages/flutter_tools/lib/src/ios/code_signing.dart b/packages/flutter_tools/lib/src/ios/code_signing.dart index 54f2289..2e1d5c2 100644 --- a/packages/flutter_tools/lib/src/ios/code_signing.dart +++ b/packages/flutter_tools/lib/src/ios/code_signing.dart
@@ -83,9 +83,15 @@ /// signing identities in the user's keychain prompting a choice if multiple /// are found. /// +/// Returns a set of build configuration settings that uses the selected +/// signing identities. +/// /// Will return null if none are found, if the user cancels or if the Xcode /// project has a development team set in the project's build settings. -Future<String> getCodeSigningIdentityDevelopmentTeam({BuildableIOSApp iosApp, bool usesTerminalUi: true}) async{ +Future<Map<String, String>> getCodeSigningIdentityDevelopmentTeam({ + BuildableIOSApp iosApp, + bool usesTerminalUi: true +}) async{ if (iosApp.buildSettings == null) return null; @@ -154,9 +160,19 @@ if (await opensslProcess.exitCode != 0) return null; - return _certificateOrganizationalUnitExtractionPattern + final Map<String, String> signingConfigs = <String, String> { + 'DEVELOPMENT_TEAM': _certificateOrganizationalUnitExtractionPattern .firstMatch(opensslOutput) - ?.group(1); + ?.group(1), + }; + + if (opensslOutput.contains('iPhone Developer: Google Development')) { + signingConfigs['PROVISIONING_PROFILE_SPECIFIER'] = 'Google Development'; + signingConfigs['CODE_SIGN_STYLE'] = 'Manual'; + printStatus("Manually selecting Google's mobile provisioning profile (see go/google-flutter-signing)."); + } + + return signingConfigs; } Future<String> _chooseSigningIdentity(List<String> validCodeSigningIdentities, bool usesTerminalUi) async {
diff --git a/packages/flutter_tools/lib/src/ios/mac.dart b/packages/flutter_tools/lib/src/ios/mac.dart index 7356716..ff3d9d1 100644 --- a/packages/flutter_tools/lib/src/ios/mac.dart +++ b/packages/flutter_tools/lib/src/ios/mac.dart
@@ -225,9 +225,9 @@ return new XcodeBuildResult(success: false); } - String developmentTeam; + Map<String, String> autoSigningConfigs; if (codesign && buildForDevice) - developmentTeam = await getCodeSigningIdentityDevelopmentTeam(iosApp: app, usesTerminalUi: usesTerminalUi); + autoSigningConfigs = await getCodeSigningIdentityDevelopmentTeam(iosApp: app, usesTerminalUi: usesTerminalUi); // Before the build, all service definitions must be updated and the dylibs // copied over to a location that is suitable for Xcodebuild to find them. @@ -287,8 +287,10 @@ buildCommands.add('-quiet'); } - if (developmentTeam != null) { - buildCommands.add('DEVELOPMENT_TEAM=$developmentTeam'); + if (autoSigningConfigs != null) { + for (MapEntry<String, String> signingConfig in autoSigningConfigs.entries) { + buildCommands.add('${signingConfig.key}=${signingConfig.value}'); + } buildCommands.add('-allowProvisioningUpdates'); buildCommands.add('-allowProvisioningDeviceRegistration'); }
diff --git a/packages/flutter_tools/test/ios/code_signing_test.dart b/packages/flutter_tools/test/ios/code_signing_test.dart index 5137b30..fcd5522 100644 --- a/packages/flutter_tools/test/ios/code_signing_test.dart +++ b/packages/flutter_tools/test/ios/code_signing_test.dart
@@ -38,8 +38,8 @@ testUsingContext('No auto-sign if Xcode project settings are not available', () async { app = new BuildableIOSApp(projectBundleId: 'test.app'); - final String developmentTeam = await getCodeSigningIdentityDevelopmentTeam(iosApp: app); - expect(developmentTeam, isNull); + final Map<String, String> signingConfigs = await getCodeSigningIdentityDevelopmentTeam(iosApp: app); + expect(signingConfigs, isNull); }); testUsingContext('No discovery if development team specified in Xcode project', () async { @@ -49,8 +49,8 @@ 'DEVELOPMENT_TEAM': 'abc', }, ); - final String developmentTeam = await getCodeSigningIdentityDevelopmentTeam(iosApp: app); - expect(developmentTeam, isNull); + final Map<String, String> signingConfigs = await getCodeSigningIdentityDevelopmentTeam(iosApp: app); + expect(signingConfigs, isNull); expect(testLogger.statusText, equals( 'Automatically signing iOS for device deployment using specified development team in Xcode project: abc\n' )); @@ -59,8 +59,8 @@ testUsingContext('No auto-sign if security or openssl not available', () async { when(mockProcessManager.runSync(<String>['which', 'security'])) .thenReturn(exitsFail); - final String developmentTeam = await getCodeSigningIdentityDevelopmentTeam(iosApp: app); - expect(developmentTeam, isNull); + final Map<String, String> signingConfigs = await getCodeSigningIdentityDevelopmentTeam(iosApp: app); + expect(signingConfigs, isNull); }, overrides: <Type, Generator>{ ProcessManager: () => mockProcessManager, @@ -75,12 +75,12 @@ argThat(contains('find-identity')), environment: any, workingDirectory: any) ).thenReturn(exitsHappy); - String developmentTeam; + Map<String, String> signingConfigs; try { - developmentTeam = await getCodeSigningIdentityDevelopmentTeam(iosApp: app); + signingConfigs = await getCodeSigningIdentityDevelopmentTeam(iosApp: app); fail('No identity should throw tool error'); } on ToolExit { - expect(developmentTeam, isNull); + expect(signingConfigs, isNull); expect(testLogger.errorText, contains('No valid code signing certificates were found')); } }, @@ -132,12 +132,71 @@ when(mockProcess.stderr).thenAnswer((Invocation invocation) => mockStdErr); when(mockProcess.exitCode).thenReturn(0); - final String developmentTeam = await getCodeSigningIdentityDevelopmentTeam(iosApp: app); + final Map<String, String> signingConfigs = await getCodeSigningIdentityDevelopmentTeam(iosApp: app); expect(testLogger.statusText, contains('iPhone Developer: Profile 1 (1111AAAA11)')); expect(testLogger.errorText, isEmpty); verify(mockStdIn.write('This is a mock certificate')); - expect(developmentTeam, '3333CCCC33'); + expect(signingConfigs, <String, String> {'DEVELOPMENT_TEAM': '3333CCCC33'}); + }, + overrides: <Type, Generator>{ + ProcessManager: () => mockProcessManager, + }); + + testUsingContext('Test Google cert also manually selects a provisioning profile', () async { + when(mockProcessManager.runSync(<String>['which', 'security'])) + .thenReturn(exitsHappy); + when(mockProcessManager.runSync(<String>['which', 'openssl'])) + .thenReturn(exitsHappy); + when(mockProcessManager.runSync( + argThat(contains('find-identity')), environment: any, workingDirectory: any, + )).thenReturn(new ProcessResult( + 1, // pid + 0, // exitCode + ''' +1) 86f7e437faa5a7fce15d1ddcb9eaeaea377667b8 "iPhone Developer: Google Development (1111AAAA11)" + 1 valid identities found''', + '' + )); + when(mockProcessManager.runSync( + <String>['security', 'find-certificate', '-c', '1111AAAA11', '-p'], + environment: any, + workingDirectory: any, + )).thenReturn(new ProcessResult( + 1, // pid + 0, // exitCode + 'This is a mock certificate', + '', + )); + + final MockProcess mockProcess = new MockProcess(); + final MockStdIn mockStdIn = new MockStdIn(); + final MockStream mockStdErr = new MockStream(); + + when(mockProcessManager.start( + argThat(contains('openssl')), environment: any, workingDirectory: any, + )).thenAnswer((Invocation invocation) => new Future<Process>.value(mockProcess)); + + when(mockProcess.stdin).thenReturn(mockStdIn); + when(mockProcess.stdout) + .thenAnswer((Invocation invocation) => new Stream<List<int>>.fromFuture( + new Future<List<int>>.value(utf8.encode( + 'subject= /CN=iPhone Developer: Google Development (1111AAAA11)/OU=3333CCCC33/O=My Team/C=US' + )) + )); + when(mockProcess.stderr).thenAnswer((Invocation invocation) => mockStdErr); + when(mockProcess.exitCode).thenReturn(0); + + final Map<String, String> signingConfigs = await getCodeSigningIdentityDevelopmentTeam(iosApp: app); + + expect(testLogger.statusText, contains('iPhone Developer: Google Development (1111AAAA11)')); + expect(testLogger.errorText, isEmpty); + verify(mockStdIn.write('This is a mock certificate')); + expect(signingConfigs, <String, String> { + 'DEVELOPMENT_TEAM': '3333CCCC33', + 'PROVISIONING_PROFILE_SPECIFIER': 'Google Development', + 'CODE_SIGN_STYLE': 'Manual', + }); }, overrides: <Type, Generator>{ ProcessManager: () => mockProcessManager, @@ -191,7 +250,7 @@ when(mockOpenSslProcess.stderr).thenAnswer((Invocation invocation) => mockOpenSslStdErr); when(mockOpenSslProcess.exitCode).thenAnswer((_) => new Future<int>.value(0)); - final String developmentTeam = await getCodeSigningIdentityDevelopmentTeam(iosApp: app); + final Map<String, String> signingConfigs = await getCodeSigningIdentityDevelopmentTeam(iosApp: app); expect( testLogger.statusText, @@ -203,7 +262,7 @@ ); expect(testLogger.errorText, isEmpty); verify(mockOpenSslStdIn.write('This is a mock certificate')); - expect(developmentTeam, '4444DDDD44'); + expect(signingConfigs, <String, String> {'DEVELOPMENT_TEAM':'4444DDDD44'}); verify(config.setValue('ios-signing-cert', 'iPhone Developer: Profile 3 (3333CCCC33)')); }, @@ -261,7 +320,7 @@ when(mockOpenSslProcess.stderr).thenAnswer((Invocation invocation) => mockOpenSslStdErr); when(mockOpenSslProcess.exitCode).thenAnswer((_) => new Future<int>.value(0)); - final String developmentTeam = await getCodeSigningIdentityDevelopmentTeam(iosApp: app, usesTerminalUi: false); + final Map<String, String> signingConfigs = await getCodeSigningIdentityDevelopmentTeam(iosApp: app, usesTerminalUi: false); expect( testLogger.statusText, @@ -269,7 +328,7 @@ ); expect(testLogger.errorText, isEmpty); verify(mockOpenSslStdIn.write('This is a mock certificate')); - expect(developmentTeam, '5555EEEE55'); + expect(signingConfigs, <String, String> {'DEVELOPMENT_TEAM':'5555EEEE55'}); }, overrides: <Type, Generator>{ ProcessManager: () => mockProcessManager, @@ -324,7 +383,7 @@ when(mockOpenSslProcess.exitCode).thenAnswer((_) => new Future<int>.value(0)); when<String>(mockConfig.getValue('ios-signing-cert')).thenReturn('iPhone Developer: Profile 3 (3333CCCC33)'); - final String developmentTeam = await getCodeSigningIdentityDevelopmentTeam(iosApp: app); + final Map<String, String> signingConfigs = await getCodeSigningIdentityDevelopmentTeam(iosApp: app); expect( testLogger.statusText, @@ -336,7 +395,7 @@ ); expect(testLogger.errorText, isEmpty); verify(mockOpenSslStdIn.write('This is a mock certificate')); - expect(developmentTeam, '4444DDDD44'); + expect(signingConfigs, <String, String> {'DEVELOPMENT_TEAM':'4444DDDD44'}); }, overrides: <Type, Generator>{ ProcessManager: () => mockProcessManager, @@ -393,7 +452,7 @@ when(mockOpenSslProcess.exitCode).thenAnswer((_) => new Future<int>.value(0)); when<String>(mockConfig.getValue('ios-signing-cert')).thenReturn('iPhone Developer: Invalid Profile'); - final String developmentTeam = await getCodeSigningIdentityDevelopmentTeam(iosApp: app); + final Map<String, String> signingConfigs = await getCodeSigningIdentityDevelopmentTeam(iosApp: app); expect( testLogger.errorText, @@ -403,7 +462,7 @@ testLogger.statusText, contains('Certificate choice "iPhone Developer: Profile 3 (3333CCCC33)"') ); - expect(developmentTeam, '4444DDDD44'); + expect(signingConfigs, <String, String> {'DEVELOPMENT_TEAM':'4444DDDD44'}); verify(config.setValue('ios-signing-cert', 'iPhone Developer: Profile 3 (3333CCCC33)')); }, overrides: <Type, Generator>{