| // Copyright 2014 The Flutter Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| @TestOn('mac-os') | |
| library; | |
| import '../../../packages/flutter_tools/test/src/fake_process_manager.dart'; | |
| import '../suite_runners/run_verify_binaries_codesigned_tests.dart'; | |
| import './common.dart'; | |
| void main() async { | |
| const flutterRoot = '/a/b/c'; | |
| final List<String> allExpectedFiles = | |
| binariesWithEntitlements(flutterRoot) + binariesWithoutEntitlements(flutterRoot); | |
| final String allFilesStdout = allExpectedFiles.join('\n'); | |
| final List<String> allExpectedXcframeworks = signedXcframeworks(flutterRoot); | |
| final String allXcframeworksStdout = allExpectedXcframeworks.join('\n'); | |
| final List<String> withEntitlements = binariesWithEntitlements(flutterRoot); | |
| group('verifyExist', () { | |
| test('Not all files found', () async { | |
| final ProcessManager processManager = FakeProcessManager.list(<FakeCommand>[ | |
| const FakeCommand( | |
| command: <String>['find', '/a/b/c/bin/cache', '-type', 'f'], | |
| stdout: '/a/b/c/bin/cache/artifacts/engine/android-arm-profile/darwin-x64/gen_snapshot', | |
| ), | |
| const FakeCommand( | |
| command: <String>[ | |
| 'file', | |
| '--mime-type', | |
| '-b', | |
| '/a/b/c/bin/cache/artifacts/engine/android-arm-profile/darwin-x64/gen_snapshot', | |
| ], | |
| stdout: 'application/x-mach-binary', | |
| ), | |
| ]); | |
| expect( | |
| () async => verifyExist(flutterRoot, processManager: processManager), | |
| throwsExceptionWith('Did not find all expected binaries!'), | |
| ); | |
| }); | |
| test('All files found', () async { | |
| final commandList = <FakeCommand>[]; | |
| final findCmd = FakeCommand( | |
| command: const <String>['find', '$flutterRoot/bin/cache', '-type', 'f'], | |
| stdout: allFilesStdout, | |
| ); | |
| commandList.add(findCmd); | |
| for (final expectedFile in allExpectedFiles) { | |
| commandList.add( | |
| FakeCommand( | |
| command: <String>['file', '--mime-type', '-b', expectedFile], | |
| stdout: 'application/x-mach-binary', | |
| ), | |
| ); | |
| } | |
| final ProcessManager processManager = FakeProcessManager.list(commandList); | |
| await expectLater(verifyExist('/a/b/c', processManager: processManager), completes); | |
| }); | |
| }); | |
| group('find paths', () { | |
| test('All binary files found', () async { | |
| final commandList = <FakeCommand>[]; | |
| final findCmd = FakeCommand( | |
| command: const <String>['find', '$flutterRoot/bin/cache', '-type', 'f'], | |
| stdout: allFilesStdout, | |
| ); | |
| commandList.add(findCmd); | |
| for (final expectedFile in allExpectedFiles) { | |
| commandList.add( | |
| FakeCommand( | |
| command: <String>['file', '--mime-type', '-b', expectedFile], | |
| stdout: 'application/x-mach-binary', | |
| ), | |
| ); | |
| } | |
| final ProcessManager processManager = FakeProcessManager.list(commandList); | |
| final List<String> foundFiles = await findBinaryPaths( | |
| '$flutterRoot/bin/cache', | |
| processManager: processManager, | |
| ); | |
| expect(foundFiles, allExpectedFiles); | |
| }); | |
| test('Empty file list', () async { | |
| final commandList = <FakeCommand>[]; | |
| const findCmd = FakeCommand( | |
| command: <String>['find', '$flutterRoot/bin/cache', '-type', 'f'], | |
| ); | |
| commandList.add(findCmd); | |
| final ProcessManager processManager = FakeProcessManager.list(commandList); | |
| final List<String> foundFiles = await findBinaryPaths( | |
| '$flutterRoot/bin/cache', | |
| processManager: processManager, | |
| ); | |
| expect(foundFiles, <String>[]); | |
| }); | |
| test('All xcframeworks files found', () async { | |
| final commandList = <FakeCommand>[ | |
| FakeCommand( | |
| command: const <String>[ | |
| 'find', | |
| '$flutterRoot/bin/cache', | |
| '-type', | |
| 'd', | |
| '-name', | |
| '*xcframework', | |
| ], | |
| stdout: allXcframeworksStdout, | |
| ), | |
| ]; | |
| final ProcessManager processManager = FakeProcessManager.list(commandList); | |
| final List<String> foundFiles = await findXcframeworksPaths( | |
| '$flutterRoot/bin/cache', | |
| processManager: processManager, | |
| ); | |
| expect(foundFiles, allExpectedXcframeworks); | |
| }); | |
| group('isBinary', () { | |
| test('isTrue', () async { | |
| final commandList = <FakeCommand>[]; | |
| const fileToCheck = '/a/b/c/one.zip'; | |
| const findCmd = FakeCommand( | |
| command: <String>['file', '--mime-type', '-b', fileToCheck], | |
| stdout: 'application/x-mach-binary', | |
| ); | |
| commandList.add(findCmd); | |
| final ProcessManager processManager = FakeProcessManager.list(commandList); | |
| final bool result = await isBinary(fileToCheck, processManager: processManager); | |
| expect(result, isTrue); | |
| }); | |
| test('isFalse', () async { | |
| final commandList = <FakeCommand>[]; | |
| const fileToCheck = '/a/b/c/one.zip'; | |
| const findCmd = FakeCommand( | |
| command: <String>['file', '--mime-type', '-b', fileToCheck], | |
| stdout: 'text/xml', | |
| ); | |
| commandList.add(findCmd); | |
| final ProcessManager processManager = FakeProcessManager.list(commandList); | |
| final bool result = await isBinary(fileToCheck, processManager: processManager); | |
| expect(result, isFalse); | |
| }); | |
| }); | |
| group('hasExpectedEntitlements', () { | |
| test('expected entitlements', () async { | |
| final commandList = <FakeCommand>[]; | |
| const fileToCheck = '/a/b/c/one.zip'; | |
| const codesignCmd = FakeCommand( | |
| command: <String>['codesign', '--display', '--entitlements', ':-', fileToCheck], | |
| ); | |
| commandList.add(codesignCmd); | |
| final ProcessManager processManager = FakeProcessManager.list(commandList); | |
| final bool result = await hasExpectedEntitlements( | |
| fileToCheck, | |
| flutterRoot, | |
| processManager: processManager, | |
| ); | |
| expect(result, isTrue); | |
| }); | |
| test('unexpected entitlements', () async { | |
| final commandList = <FakeCommand>[]; | |
| const fileToCheck = '/a/b/c/one.zip'; | |
| const codesignCmd = FakeCommand( | |
| command: <String>['codesign', '--display', '--entitlements', ':-', fileToCheck], | |
| exitCode: 1, | |
| ); | |
| commandList.add(codesignCmd); | |
| final ProcessManager processManager = FakeProcessManager.list(commandList); | |
| final bool result = await hasExpectedEntitlements( | |
| fileToCheck, | |
| flutterRoot, | |
| processManager: processManager, | |
| ); | |
| expect(result, isFalse); | |
| }); | |
| }); | |
| }); | |
| group('verifySignatures', () { | |
| test('succeeds if every binary is codesigned and has correct entitlements', () async { | |
| final commandList = <FakeCommand>[]; | |
| final findCmd = FakeCommand( | |
| command: const <String>['find', '$flutterRoot/bin/cache', '-type', 'f'], | |
| stdout: allFilesStdout, | |
| ); | |
| commandList.add(findCmd); | |
| for (final expectedFile in allExpectedFiles) { | |
| commandList.add( | |
| FakeCommand( | |
| command: <String>['file', '--mime-type', '-b', expectedFile], | |
| stdout: 'application/x-mach-binary', | |
| ), | |
| ); | |
| } | |
| commandList.add( | |
| FakeCommand( | |
| command: const <String>[ | |
| 'find', | |
| '$flutterRoot/bin/cache', | |
| '-type', | |
| 'd', | |
| '-name', | |
| '*xcframework', | |
| ], | |
| stdout: allXcframeworksStdout, | |
| ), | |
| ); | |
| for (final expectedFile in allExpectedFiles) { | |
| commandList.add(FakeCommand(command: <String>['codesign', '-vvv', expectedFile])); | |
| if (withEntitlements.contains(expectedFile)) { | |
| commandList.add( | |
| FakeCommand( | |
| command: <String>['codesign', '--display', '--entitlements', ':-', expectedFile], | |
| stdout: expectedEntitlements.join('\n'), | |
| ), | |
| ); | |
| } | |
| } | |
| for (final expectedXcframework in allExpectedXcframeworks) { | |
| commandList.add(FakeCommand(command: <String>['codesign', '-vvv', expectedXcframework])); | |
| } | |
| final ProcessManager processManager = FakeProcessManager.list(commandList); | |
| await expectLater(verifySignatures(flutterRoot, processManager: processManager), completes); | |
| }); | |
| test('fails if binaries do not have the right entitlements', () async { | |
| final commandList = <FakeCommand>[]; | |
| final findCmd = FakeCommand( | |
| command: const <String>['find', '$flutterRoot/bin/cache', '-type', 'f'], | |
| stdout: allFilesStdout, | |
| ); | |
| commandList.add(findCmd); | |
| for (final expectedFile in allExpectedFiles) { | |
| commandList.add( | |
| FakeCommand( | |
| command: <String>['file', '--mime-type', '-b', expectedFile], | |
| stdout: 'application/x-mach-binary', | |
| ), | |
| ); | |
| } | |
| commandList.add( | |
| FakeCommand( | |
| command: const <String>[ | |
| 'find', | |
| '$flutterRoot/bin/cache', | |
| '-type', | |
| 'd', | |
| '-name', | |
| '*xcframework', | |
| ], | |
| stdout: allXcframeworksStdout, | |
| ), | |
| ); | |
| for (final expectedFile in allExpectedFiles) { | |
| commandList.add(FakeCommand(command: <String>['codesign', '-vvv', expectedFile])); | |
| if (withEntitlements.contains(expectedFile)) { | |
| commandList.add( | |
| FakeCommand( | |
| command: <String>['codesign', '--display', '--entitlements', ':-', expectedFile], | |
| ), | |
| ); | |
| } | |
| } | |
| for (final expectedXcframework in allExpectedXcframeworks) { | |
| commandList.add(FakeCommand(command: <String>['codesign', '-vvv', expectedXcframework])); | |
| } | |
| final ProcessManager processManager = FakeProcessManager.list(commandList); | |
| expect( | |
| () async => verifySignatures(flutterRoot, processManager: processManager), | |
| throwsExceptionWith('Test failed because files found with the wrong entitlements'), | |
| ); | |
| }); | |
| }); | |
| group('verifyFatBinaries', () { | |
| test('succeeds if every binary is fat', () async { | |
| final commandList = <FakeCommand>[]; | |
| final List<String> fatBinaries = | |
| presignedBinariesWithEntitlements(flutterRoot) + | |
| presignedBinariesWithoutEntitlements(flutterRoot); | |
| for (final binaryPath in fatBinaries) { | |
| commandList.add( | |
| FakeCommand( | |
| command: <String>['file', binaryPath], | |
| stdout: 'Mach-O universal binary with 2 architectures: [x86_64:Mach-O 64-bit executable x86_64] [arm64:Mach-O 64-bit executable arm64]', | |
| ), | |
| ); | |
| } | |
| final ProcessManager processManager = FakeProcessManager.list(commandList); | |
| await expectLater(verifyFatBinaries(flutterRoot, processManager: processManager), completes); | |
| }); | |
| test('fails if a binary is not fat', () async { | |
| final commandList = <FakeCommand>[]; | |
| final List<String> fatBinaries = | |
| presignedBinariesWithEntitlements(flutterRoot) + | |
| presignedBinariesWithoutEntitlements(flutterRoot); | |
| if (fatBinaries.isNotEmpty) { | |
| commandList.add( | |
| FakeCommand( | |
| command: <String>['file', fatBinaries.first], | |
| stdout: 'Mach-O 64-bit executable x86_64', | |
| ), | |
| ); | |
| for (final String binaryPath in fatBinaries.skip(1)) { | |
| commandList.add( | |
| FakeCommand( | |
| command: <String>['file', binaryPath], | |
| stdout: 'Mach-O universal binary with 2 architectures: [x86_64:Mach-O 64-bit executable x86_64] [arm64:Mach-O 64-bit executable arm64]', | |
| ), | |
| ); | |
| } | |
| } | |
| final ProcessManager processManager = FakeProcessManager.list(commandList); | |
| expect( | |
| () async => verifyFatBinaries(flutterRoot, processManager: processManager), | |
| throwsExceptionWith('Failed fat binary verification for:'), | |
| ); | |
| }); | |
| }); | |
| } |