mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Test codesigning xcframeworks in artifacts (#142666)
On the beta branch: ``` Verifying the code signature of /Users/m/Projects/flutter/bin/cache/artifacts/engine/ios-profile/extension_safe/Flutter.xcframework Verifying the code signature of /Users/m/Projects/flutter/bin/cache/artifacts/engine/ios-profile/Flutter.xcframework Verifying the code signature of /Users/m/Projects/flutter/bin/cache/artifacts/engine/ios/extension_safe/Flutter.xcframework Verifying the code signature of /Users/m/Projects/flutter/bin/cache/artifacts/engine/ios/Flutter.xcframework Verifying the code signature of /Users/m/Projects/flutter/bin/cache/artifacts/engine/ios-release/extension_safe/Flutter.xcframework Verifying the code signature of /Users/m/Projects/flutter/bin/cache/artifacts/engine/ios-release/Flutter.xcframework ``` Fixes https://github.com/flutter/flutter/issues/140934
This commit is contained in:
parent
d242d1368f
commit
899f423464
@ -1688,7 +1688,7 @@ const List<String> expectedEntitlements = <String>[
|
||||
///
|
||||
/// This list should be kept in sync with the actual contents of Flutter's
|
||||
/// cache.
|
||||
Future<List<String>> binariesWithEntitlements(String flutterRoot) async {
|
||||
List<String> binariesWithEntitlements(String flutterRoot) {
|
||||
return <String> [
|
||||
'artifacts/engine/android-arm-profile/darwin-x64/gen_snapshot',
|
||||
'artifacts/engine/android-arm-release/darwin-x64/gen_snapshot',
|
||||
@ -1729,7 +1729,7 @@ Future<List<String>> binariesWithEntitlements(String flutterRoot) async {
|
||||
///
|
||||
/// This list should be kept in sync with the actual contents of Flutter's
|
||||
/// cache.
|
||||
Future<List<String>> binariesWithoutEntitlements(String flutterRoot) async {
|
||||
List<String> binariesWithoutEntitlements(String flutterRoot) {
|
||||
return <String>[
|
||||
'artifacts/engine/darwin-x64-profile/FlutterMacOS.framework/Versions/A/FlutterMacOS',
|
||||
'artifacts/engine/darwin-x64-release/FlutterMacOS.framework/Versions/A/FlutterMacOS',
|
||||
@ -1755,6 +1755,22 @@ Future<List<String>> binariesWithoutEntitlements(String flutterRoot) async {
|
||||
.map((String relativePath) => path.join(flutterRoot, 'bin', 'cache', relativePath)).toList();
|
||||
}
|
||||
|
||||
/// xcframeworks that are expected to be codesigned.
|
||||
///
|
||||
/// This list should be kept in sync with the actual contents of Flutter's
|
||||
/// cache.
|
||||
List<String> signedXcframeworks(String flutterRoot) {
|
||||
return <String>[
|
||||
'artifacts/engine/ios-profile/Flutter.xcframework',
|
||||
'artifacts/engine/ios-profile/extension_safe/Flutter.xcframework',
|
||||
'artifacts/engine/ios-release/Flutter.xcframework',
|
||||
'artifacts/engine/ios-release/extension_safe/Flutter.xcframework',
|
||||
'artifacts/engine/ios/Flutter.xcframework',
|
||||
'artifacts/engine/ios/extension_safe/Flutter.xcframework',
|
||||
]
|
||||
.map((String relativePath) => path.join(flutterRoot, 'bin', 'cache', relativePath)).toList();
|
||||
}
|
||||
|
||||
/// Verify the existence of all expected binaries in cache.
|
||||
///
|
||||
/// This function ignores code signatures and entitlements, and is intended to
|
||||
@ -1769,13 +1785,11 @@ Future<void> verifyExist(
|
||||
final Set<String> foundFiles = <String>{};
|
||||
final String cacheDirectory = path.join(flutterRoot, 'bin', 'cache');
|
||||
|
||||
|
||||
|
||||
for (final String binaryPath
|
||||
in await findBinaryPaths(cacheDirectory, processManager: processManager)) {
|
||||
if ((await binariesWithEntitlements(flutterRoot)).contains(binaryPath)) {
|
||||
if (binariesWithEntitlements(flutterRoot).contains(binaryPath)) {
|
||||
foundFiles.add(binaryPath);
|
||||
} else if ((await binariesWithoutEntitlements(flutterRoot)).contains(binaryPath)) {
|
||||
} else if (binariesWithoutEntitlements(flutterRoot).contains(binaryPath)) {
|
||||
foundFiles.add(binaryPath);
|
||||
} else {
|
||||
throw Exception(
|
||||
@ -1783,7 +1797,7 @@ Future<void> verifyExist(
|
||||
}
|
||||
}
|
||||
|
||||
final List<String> allExpectedFiles = await binariesWithEntitlements(flutterRoot) + await binariesWithoutEntitlements(flutterRoot);
|
||||
final List<String> allExpectedFiles = binariesWithEntitlements(flutterRoot) + binariesWithoutEntitlements(flutterRoot);
|
||||
if (foundFiles.length < allExpectedFiles.length) {
|
||||
final List<String> unfoundFiles = allExpectedFiles
|
||||
.where(
|
||||
@ -1807,71 +1821,76 @@ Future<void> verifySignatures(
|
||||
String flutterRoot,
|
||||
{@visibleForTesting ProcessManager processManager = const LocalProcessManager()}
|
||||
) async {
|
||||
final List<String> unsignedBinaries = <String>[];
|
||||
final List<String> unsignedFiles = <String>[];
|
||||
final List<String> wrongEntitlementBinaries = <String>[];
|
||||
final List<String> unexpectedBinaries = <String>[];
|
||||
final List<String> unexpectedFiles = <String>[];
|
||||
final String cacheDirectory = path.join(flutterRoot, 'bin', 'cache');
|
||||
|
||||
for (final String binaryPath
|
||||
in await findBinaryPaths(cacheDirectory, processManager: processManager)) {
|
||||
final List<String> binariesAndXcframeworks =
|
||||
(await findBinaryPaths(cacheDirectory, processManager: processManager)) + (await findXcframeworksPaths(cacheDirectory, processManager: processManager));
|
||||
|
||||
for (final String pathToCheck in binariesAndXcframeworks) {
|
||||
bool verifySignature = false;
|
||||
bool verifyEntitlements = false;
|
||||
if ((await binariesWithEntitlements(flutterRoot)).contains(binaryPath)) {
|
||||
if (binariesWithEntitlements(flutterRoot).contains(pathToCheck)) {
|
||||
verifySignature = true;
|
||||
verifyEntitlements = true;
|
||||
}
|
||||
if ((await binariesWithoutEntitlements(flutterRoot)).contains(binaryPath)) {
|
||||
if (binariesWithoutEntitlements(flutterRoot).contains(pathToCheck)) {
|
||||
verifySignature = true;
|
||||
}
|
||||
if (signedXcframeworks(flutterRoot).contains(pathToCheck)) {
|
||||
verifySignature = true;
|
||||
}
|
||||
if (!verifySignature && !verifyEntitlements) {
|
||||
unexpectedBinaries.add(binaryPath);
|
||||
print('Unexpected binary $binaryPath found in cache!');
|
||||
unexpectedFiles.add(pathToCheck);
|
||||
print('Unexpected binary or xcframework $pathToCheck found in cache!');
|
||||
continue;
|
||||
}
|
||||
print('Verifying the code signature of $binaryPath');
|
||||
print('Verifying the code signature of $pathToCheck');
|
||||
final io.ProcessResult codeSignResult = await processManager.run(
|
||||
<String>[
|
||||
'codesign',
|
||||
'-vvv',
|
||||
binaryPath,
|
||||
pathToCheck,
|
||||
],
|
||||
);
|
||||
if (codeSignResult.exitCode != 0) {
|
||||
unsignedBinaries.add(binaryPath);
|
||||
unsignedFiles.add(pathToCheck);
|
||||
print(
|
||||
'File "$binaryPath" does not appear to be codesigned.\n'
|
||||
'File "$pathToCheck" does not appear to be codesigned.\n'
|
||||
'The `codesign` command failed with exit code ${codeSignResult.exitCode}:\n'
|
||||
'${codeSignResult.stderr}\n',
|
||||
);
|
||||
continue;
|
||||
}
|
||||
if (verifyEntitlements) {
|
||||
print('Verifying entitlements of $binaryPath');
|
||||
if (!(await hasExpectedEntitlements(binaryPath, flutterRoot, processManager: processManager))) {
|
||||
wrongEntitlementBinaries.add(binaryPath);
|
||||
print('Verifying entitlements of $pathToCheck');
|
||||
if (!(await hasExpectedEntitlements(pathToCheck, flutterRoot, processManager: processManager))) {
|
||||
wrongEntitlementBinaries.add(pathToCheck);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// First print all deviations from expectations
|
||||
if (unsignedBinaries.isNotEmpty) {
|
||||
print('Found ${unsignedBinaries.length} unsigned binaries:');
|
||||
unsignedBinaries.forEach(print);
|
||||
if (unsignedFiles.isNotEmpty) {
|
||||
print('Found ${unsignedFiles.length} unsigned files:');
|
||||
unsignedFiles.forEach(print);
|
||||
}
|
||||
|
||||
if (wrongEntitlementBinaries.isNotEmpty) {
|
||||
print('Found ${wrongEntitlementBinaries.length} binaries with unexpected entitlements:');
|
||||
print('Found ${wrongEntitlementBinaries.length} files with unexpected entitlements:');
|
||||
wrongEntitlementBinaries.forEach(print);
|
||||
}
|
||||
|
||||
if (unexpectedBinaries.isNotEmpty) {
|
||||
print('Found ${unexpectedBinaries.length} unexpected binaries in the cache:');
|
||||
unexpectedBinaries.forEach(print);
|
||||
if (unexpectedFiles.isNotEmpty) {
|
||||
print('Found ${unexpectedFiles.length} unexpected files in the cache:');
|
||||
unexpectedFiles.forEach(print);
|
||||
}
|
||||
|
||||
// Finally, exit on any invalid state
|
||||
if (unsignedBinaries.isNotEmpty) {
|
||||
throw Exception('Test failed because unsigned binaries detected.');
|
||||
if (unsignedFiles.isNotEmpty) {
|
||||
throw Exception('Test failed because unsigned files detected.');
|
||||
}
|
||||
|
||||
if (wrongEntitlementBinaries.isNotEmpty) {
|
||||
@ -1881,10 +1900,10 @@ Future<void> verifySignatures(
|
||||
);
|
||||
}
|
||||
|
||||
if (unexpectedBinaries.isNotEmpty) {
|
||||
throw Exception('Test failed because unexpected binaries found in the cache.');
|
||||
if (unexpectedFiles.isNotEmpty) {
|
||||
throw Exception('Test failed because unexpected files found in the cache.');
|
||||
}
|
||||
print('Verified that binaries are codesigned and have expected entitlements.');
|
||||
print('Verified that files are codesigned and have expected entitlements.');
|
||||
}
|
||||
|
||||
/// Find every binary file in the given [rootDirectory].
|
||||
@ -1915,6 +1934,30 @@ Future<List<String>> findBinaryPaths(
|
||||
return allBinaryPaths;
|
||||
}
|
||||
|
||||
/// Find every xcframework in the given [rootDirectory].
|
||||
Future<List<String>> findXcframeworksPaths(
|
||||
String rootDirectory,
|
||||
{@visibleForTesting ProcessManager processManager = const LocalProcessManager()
|
||||
}) async {
|
||||
final io.ProcessResult result = await processManager.run(
|
||||
<String>[
|
||||
'find',
|
||||
rootDirectory,
|
||||
'-type',
|
||||
'd',
|
||||
'-name',
|
||||
'*xcframework',
|
||||
],
|
||||
);
|
||||
final List<String> allXcframeworkPaths = LineSplitter.split(result.stdout as String)
|
||||
.where((String s) => s.isNotEmpty)
|
||||
.toList();
|
||||
for (final String path in allXcframeworkPaths) {
|
||||
print('Found: $path\n');
|
||||
}
|
||||
return allXcframeworkPaths;
|
||||
}
|
||||
|
||||
/// Check mime-type of file at [filePath] to determine if it is binary.
|
||||
Future<bool> isBinary(
|
||||
String filePath,
|
||||
@ -1959,7 +2002,7 @@ Future<bool> hasExpectedEntitlements(
|
||||
final String output = entitlementResult.stdout as String;
|
||||
for (final String entitlement in expectedEntitlements) {
|
||||
final bool entitlementExpected =
|
||||
(await binariesWithEntitlements(flutterRoot)).contains(binaryPath);
|
||||
binariesWithEntitlements(flutterRoot).contains(binaryPath);
|
||||
if (output.contains(entitlement) != entitlementExpected) {
|
||||
print(
|
||||
'File "$binaryPath" ${entitlementExpected ? 'does not have expected' : 'has unexpected'} '
|
||||
|
||||
@ -11,9 +11,11 @@ import './common.dart';
|
||||
|
||||
void main() async {
|
||||
const String flutterRoot = '/a/b/c';
|
||||
final List<String> allExpectedFiles = await binariesWithEntitlements(flutterRoot) + await binariesWithoutEntitlements(flutterRoot);
|
||||
final List<String> allExpectedFiles = binariesWithEntitlements(flutterRoot) + binariesWithoutEntitlements(flutterRoot);
|
||||
final String allFilesStdout = allExpectedFiles.join('\n');
|
||||
final List<String> withEntitlements = await binariesWithEntitlements(flutterRoot);
|
||||
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 {
|
||||
@ -74,8 +76,8 @@ void main() async {
|
||||
});
|
||||
});
|
||||
|
||||
group('findBinaryPaths', () {
|
||||
test('All files found', () async {
|
||||
group('find paths', () {
|
||||
test('All binary files found', () async {
|
||||
final List<FakeCommand> commandList = <FakeCommand>[];
|
||||
final FakeCommand findCmd = FakeCommand(
|
||||
command: const <String>[
|
||||
@ -117,7 +119,26 @@ void main() async {
|
||||
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 {
|
||||
@ -223,6 +244,19 @@ void main() async {
|
||||
)
|
||||
);
|
||||
}
|
||||
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(
|
||||
@ -248,6 +282,18 @@ void main() async {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
});
|
||||
@ -276,6 +322,19 @@ void main() async {
|
||||
)
|
||||
);
|
||||
}
|
||||
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(
|
||||
@ -300,6 +359,17 @@ void main() async {
|
||||
);
|
||||
}
|
||||
}
|
||||
for (final String expectedXcframework in allExpectedXcframeworks) {
|
||||
commandList.add(
|
||||
FakeCommand(
|
||||
command: <String>[
|
||||
'codesign',
|
||||
'-vvv',
|
||||
expectedXcframework,
|
||||
],
|
||||
)
|
||||
);
|
||||
}
|
||||
final ProcessManager processManager = FakeProcessManager.list(commandList);
|
||||
|
||||
expect(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user