// 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 '../test.dart'; import './common.dart'; void main() async { const String 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 List<FakeCommand> commandList = <FakeCommand>[]; final FakeCommand findCmd = FakeCommand( command: const <String>[ 'find', '$flutterRoot/bin/cache', '-type', 'f',], stdout: allFilesStdout, ); commandList.add(findCmd); for (final String 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 List<FakeCommand> commandList = <FakeCommand>[]; final FakeCommand findCmd = FakeCommand( command: const <String>[ 'find', '$flutterRoot/bin/cache', '-type', 'f',], stdout: allFilesStdout, ); commandList.add(findCmd); for (final String 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 List<FakeCommand> commandList = <FakeCommand>[]; const FakeCommand 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 List<FakeCommand> 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 List<FakeCommand> commandList = <FakeCommand>[]; const String fileToCheck = '/a/b/c/one.zip'; const FakeCommand 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 List<FakeCommand> commandList = <FakeCommand>[]; const String fileToCheck = '/a/b/c/one.zip'; const FakeCommand 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 List<FakeCommand> commandList = <FakeCommand>[]; const String fileToCheck = '/a/b/c/one.zip'; const FakeCommand 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 List<FakeCommand> commandList = <FakeCommand>[]; const String fileToCheck = '/a/b/c/one.zip'; const FakeCommand 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 List<FakeCommand> commandList = <FakeCommand>[]; final FakeCommand findCmd = FakeCommand( command: const <String>[ 'find', '$flutterRoot/bin/cache', '-type', 'f',], stdout: allFilesStdout, ); commandList.add(findCmd); for (final String 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 String 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 String 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 List<FakeCommand> commandList = <FakeCommand>[]; final FakeCommand findCmd = FakeCommand( command: const <String>[ 'find', '$flutterRoot/bin/cache', '-type', 'f',], stdout: allFilesStdout, ); commandList.add(findCmd); for (final String 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 String 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 String 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'), ); }); }); }