Skip to content

Commit 005b8e1

Browse files
[CP-beta]Test codesigning xcframeworks in artifacts (flutter#143015)
**This pull request is opened against a release branch.<br> To request a cherry pick of a commit, please fill in the form below.** (Questions with an asterisk are required.)<br> **To fill in the form, you can edit this PR description and type your answers after the 'My Answer' keywords. <br> A flutter domain expert will evaluate this cherry pick request shortly after ALL questions are answered.** * Issue Link: What is the link to the issue this cherry-pick is addressing?<br> <pre> <b>My Answer:</b> flutter#140934 </pre> * Changelog Description: Explain this cherry pick in one line that is accessible to most Flutter developers See https://github.com/flutter/flutter/wiki/Hotfix-Documentation-Best-Practices for examples (Bug fix, feature, docs update, ...)<br> <pre> <b>My Answer:</b> This cherry pick enables code signing test to run on release branches. </pre> * Impacted Users: Approximately who will hit this issue (ex. all Flutter devs, Windows developers, all end-customers, apps using X framework feature)?<br> <pre> <b>My Answer:</b> Release engineers who run code signing tests on releases. </pre> * impact_description: What is the impact (ex. visual jank on Samsung phones, app crash, cannot ship an iOS app)? Does it impact development (ex. flutter doctor crashes when Android Studio is installed), or the shipping production app (the app crashes on launch)<br> <pre> <b>My Answer:</b> Enabling codesigning Test would test the release artifact, and make sure both binaries and bundles are code signed. </pre> * Workaround: Is there a workaround for this issue?<br> <pre> <b>My Answer:</b> We can verify manually, but enabling an automated Code signing test would be better. </pre> * Risk: What is the risk level of this cherry-pick?<br> <pre> <b>My Answer:</b> </pre> * Test Coverage: Are you confident that your fix is well-tested by automated tests?<br> <pre> <b>My Answer:</b> </pre> * Validation Steps: What are the steps to validate that this fix works?<br> <pre> <b>My Answer:</b> code sign test should run on post submit of release branches and pass </pre>
1 parent b7e7d46 commit 005b8e1

File tree

2 files changed

+153
-40
lines changed

2 files changed

+153
-40
lines changed

dev/bots/test.dart

Lines changed: 78 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1676,7 +1676,7 @@ const List<String> expectedEntitlements = <String>[
16761676
///
16771677
/// This list should be kept in sync with the actual contents of Flutter's
16781678
/// cache.
1679-
Future<List<String>> binariesWithEntitlements(String flutterRoot) async {
1679+
List<String> binariesWithEntitlements(String flutterRoot) {
16801680
return <String> [
16811681
'artifacts/engine/android-arm-profile/darwin-x64/gen_snapshot',
16821682
'artifacts/engine/android-arm-release/darwin-x64/gen_snapshot',
@@ -1717,7 +1717,7 @@ Future<List<String>> binariesWithEntitlements(String flutterRoot) async {
17171717
///
17181718
/// This list should be kept in sync with the actual contents of Flutter's
17191719
/// cache.
1720-
Future<List<String>> binariesWithoutEntitlements(String flutterRoot) async {
1720+
List<String> binariesWithoutEntitlements(String flutterRoot) {
17211721
return <String>[
17221722
'artifacts/engine/darwin-x64-profile/FlutterMacOS.framework/Versions/A/FlutterMacOS',
17231723
'artifacts/engine/darwin-x64-release/FlutterMacOS.framework/Versions/A/FlutterMacOS',
@@ -1743,6 +1743,22 @@ Future<List<String>> binariesWithoutEntitlements(String flutterRoot) async {
17431743
.map((String relativePath) => path.join(flutterRoot, 'bin', 'cache', relativePath)).toList();
17441744
}
17451745

1746+
/// xcframeworks that are expected to be codesigned.
1747+
///
1748+
/// This list should be kept in sync with the actual contents of Flutter's
1749+
/// cache.
1750+
List<String> signedXcframeworks(String flutterRoot) {
1751+
return <String>[
1752+
'artifacts/engine/ios-profile/Flutter.xcframework',
1753+
'artifacts/engine/ios-profile/extension_safe/Flutter.xcframework',
1754+
'artifacts/engine/ios-release/Flutter.xcframework',
1755+
'artifacts/engine/ios-release/extension_safe/Flutter.xcframework',
1756+
'artifacts/engine/ios/Flutter.xcframework',
1757+
'artifacts/engine/ios/extension_safe/Flutter.xcframework',
1758+
]
1759+
.map((String relativePath) => path.join(flutterRoot, 'bin', 'cache', relativePath)).toList();
1760+
}
1761+
17461762
/// Verify the existence of all expected binaries in cache.
17471763
///
17481764
/// This function ignores code signatures and entitlements, and is intended to
@@ -1757,21 +1773,19 @@ Future<void> verifyExist(
17571773
final Set<String> foundFiles = <String>{};
17581774
final String cacheDirectory = path.join(flutterRoot, 'bin', 'cache');
17591775

1760-
1761-
17621776
for (final String binaryPath
17631777
in await findBinaryPaths(cacheDirectory, processManager: processManager)) {
1764-
if ((await binariesWithEntitlements(flutterRoot)).contains(binaryPath)) {
1778+
if (binariesWithEntitlements(flutterRoot).contains(binaryPath)) {
17651779
foundFiles.add(binaryPath);
1766-
} else if ((await binariesWithoutEntitlements(flutterRoot)).contains(binaryPath)) {
1780+
} else if (binariesWithoutEntitlements(flutterRoot).contains(binaryPath)) {
17671781
foundFiles.add(binaryPath);
17681782
} else {
17691783
throw Exception(
17701784
'Found unexpected binary in cache: $binaryPath');
17711785
}
17721786
}
17731787

1774-
final List<String> allExpectedFiles = await binariesWithEntitlements(flutterRoot) + await binariesWithoutEntitlements(flutterRoot);
1788+
final List<String> allExpectedFiles = binariesWithEntitlements(flutterRoot) + binariesWithoutEntitlements(flutterRoot);
17751789
if (foundFiles.length < allExpectedFiles.length) {
17761790
final List<String> unfoundFiles = allExpectedFiles
17771791
.where(
@@ -1795,71 +1809,76 @@ Future<void> verifySignatures(
17951809
String flutterRoot,
17961810
{@visibleForTesting ProcessManager processManager = const LocalProcessManager()}
17971811
) async {
1798-
final List<String> unsignedBinaries = <String>[];
1812+
final List<String> unsignedFiles = <String>[];
17991813
final List<String> wrongEntitlementBinaries = <String>[];
1800-
final List<String> unexpectedBinaries = <String>[];
1814+
final List<String> unexpectedFiles = <String>[];
18011815
final String cacheDirectory = path.join(flutterRoot, 'bin', 'cache');
18021816

1803-
for (final String binaryPath
1804-
in await findBinaryPaths(cacheDirectory, processManager: processManager)) {
1817+
final List<String> binariesAndXcframeworks =
1818+
(await findBinaryPaths(cacheDirectory, processManager: processManager)) + (await findXcframeworksPaths(cacheDirectory, processManager: processManager));
1819+
1820+
for (final String pathToCheck in binariesAndXcframeworks) {
18051821
bool verifySignature = false;
18061822
bool verifyEntitlements = false;
1807-
if ((await binariesWithEntitlements(flutterRoot)).contains(binaryPath)) {
1823+
if (binariesWithEntitlements(flutterRoot).contains(pathToCheck)) {
18081824
verifySignature = true;
18091825
verifyEntitlements = true;
18101826
}
1811-
if ((await binariesWithoutEntitlements(flutterRoot)).contains(binaryPath)) {
1827+
if (binariesWithoutEntitlements(flutterRoot).contains(pathToCheck)) {
1828+
verifySignature = true;
1829+
}
1830+
if (signedXcframeworks(flutterRoot).contains(pathToCheck)) {
18121831
verifySignature = true;
18131832
}
18141833
if (!verifySignature && !verifyEntitlements) {
1815-
unexpectedBinaries.add(binaryPath);
1816-
print('Unexpected binary $binaryPath found in cache!');
1834+
unexpectedFiles.add(pathToCheck);
1835+
print('Unexpected binary or xcframework $pathToCheck found in cache!');
18171836
continue;
18181837
}
1819-
print('Verifying the code signature of $binaryPath');
1838+
print('Verifying the code signature of $pathToCheck');
18201839
final io.ProcessResult codeSignResult = await processManager.run(
18211840
<String>[
18221841
'codesign',
18231842
'-vvv',
1824-
binaryPath,
1843+
pathToCheck,
18251844
],
18261845
);
18271846
if (codeSignResult.exitCode != 0) {
1828-
unsignedBinaries.add(binaryPath);
1847+
unsignedFiles.add(pathToCheck);
18291848
print(
1830-
'File "$binaryPath" does not appear to be codesigned.\n'
1849+
'File "$pathToCheck" does not appear to be codesigned.\n'
18311850
'The `codesign` command failed with exit code ${codeSignResult.exitCode}:\n'
18321851
'${codeSignResult.stderr}\n',
18331852
);
18341853
continue;
18351854
}
18361855
if (verifyEntitlements) {
1837-
print('Verifying entitlements of $binaryPath');
1838-
if (!(await hasExpectedEntitlements(binaryPath, flutterRoot, processManager: processManager))) {
1839-
wrongEntitlementBinaries.add(binaryPath);
1856+
print('Verifying entitlements of $pathToCheck');
1857+
if (!(await hasExpectedEntitlements(pathToCheck, flutterRoot, processManager: processManager))) {
1858+
wrongEntitlementBinaries.add(pathToCheck);
18401859
}
18411860
}
18421861
}
18431862

18441863
// First print all deviations from expectations
1845-
if (unsignedBinaries.isNotEmpty) {
1846-
print('Found ${unsignedBinaries.length} unsigned binaries:');
1847-
unsignedBinaries.forEach(print);
1864+
if (unsignedFiles.isNotEmpty) {
1865+
print('Found ${unsignedFiles.length} unsigned files:');
1866+
unsignedFiles.forEach(print);
18481867
}
18491868

18501869
if (wrongEntitlementBinaries.isNotEmpty) {
1851-
print('Found ${wrongEntitlementBinaries.length} binaries with unexpected entitlements:');
1870+
print('Found ${wrongEntitlementBinaries.length} files with unexpected entitlements:');
18521871
wrongEntitlementBinaries.forEach(print);
18531872
}
18541873

1855-
if (unexpectedBinaries.isNotEmpty) {
1856-
print('Found ${unexpectedBinaries.length} unexpected binaries in the cache:');
1857-
unexpectedBinaries.forEach(print);
1874+
if (unexpectedFiles.isNotEmpty) {
1875+
print('Found ${unexpectedFiles.length} unexpected files in the cache:');
1876+
unexpectedFiles.forEach(print);
18581877
}
18591878

18601879
// Finally, exit on any invalid state
1861-
if (unsignedBinaries.isNotEmpty) {
1862-
throw Exception('Test failed because unsigned binaries detected.');
1880+
if (unsignedFiles.isNotEmpty) {
1881+
throw Exception('Test failed because unsigned files detected.');
18631882
}
18641883

18651884
if (wrongEntitlementBinaries.isNotEmpty) {
@@ -1869,10 +1888,10 @@ Future<void> verifySignatures(
18691888
);
18701889
}
18711890

1872-
if (unexpectedBinaries.isNotEmpty) {
1873-
throw Exception('Test failed because unexpected binaries found in the cache.');
1891+
if (unexpectedFiles.isNotEmpty) {
1892+
throw Exception('Test failed because unexpected files found in the cache.');
18741893
}
1875-
print('Verified that binaries are codesigned and have expected entitlements.');
1894+
print('Verified that files are codesigned and have expected entitlements.');
18761895
}
18771896

18781897
/// Find every binary file in the given [rootDirectory].
@@ -1903,6 +1922,30 @@ Future<List<String>> findBinaryPaths(
19031922
return allBinaryPaths;
19041923
}
19051924

1925+
/// Find every xcframework in the given [rootDirectory].
1926+
Future<List<String>> findXcframeworksPaths(
1927+
String rootDirectory,
1928+
{@visibleForTesting ProcessManager processManager = const LocalProcessManager()
1929+
}) async {
1930+
final io.ProcessResult result = await processManager.run(
1931+
<String>[
1932+
'find',
1933+
rootDirectory,
1934+
'-type',
1935+
'd',
1936+
'-name',
1937+
'*xcframework',
1938+
],
1939+
);
1940+
final List<String> allXcframeworkPaths = LineSplitter.split(result.stdout as String)
1941+
.where((String s) => s.isNotEmpty)
1942+
.toList();
1943+
for (final String path in allXcframeworkPaths) {
1944+
print('Found: $path\n');
1945+
}
1946+
return allXcframeworkPaths;
1947+
}
1948+
19061949
/// Check mime-type of file at [filePath] to determine if it is binary.
19071950
Future<bool> isBinary(
19081951
String filePath,
@@ -1947,7 +1990,7 @@ Future<bool> hasExpectedEntitlements(
19471990
final String output = entitlementResult.stdout as String;
19481991
for (final String entitlement in expectedEntitlements) {
19491992
final bool entitlementExpected =
1950-
(await binariesWithEntitlements(flutterRoot)).contains(binaryPath);
1993+
binariesWithEntitlements(flutterRoot).contains(binaryPath);
19511994
if (output.contains(entitlement) != entitlementExpected) {
19521995
print(
19531996
'File "$binaryPath" ${entitlementExpected ? 'does not have expected' : 'has unexpected'} '

dev/bots/test/codesign_test.dart

Lines changed: 75 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@ import './common.dart';
1111

1212
void main() async {
1313
const String flutterRoot = '/a/b/c';
14-
final List<String> allExpectedFiles = await binariesWithEntitlements(flutterRoot) + await binariesWithoutEntitlements(flutterRoot);
14+
final List<String> allExpectedFiles = binariesWithEntitlements(flutterRoot) + binariesWithoutEntitlements(flutterRoot);
1515
final String allFilesStdout = allExpectedFiles.join('\n');
16-
final List<String> withEntitlements = await binariesWithEntitlements(flutterRoot);
16+
final List<String> allExpectedXcframeworks = signedXcframeworks(flutterRoot);
17+
final String allXcframeworksStdout = allExpectedXcframeworks.join('\n');
18+
final List<String> withEntitlements = binariesWithEntitlements(flutterRoot);
1719

1820
group('verifyExist', () {
1921
test('Not all files found', () async {
@@ -74,8 +76,8 @@ void main() async {
7476
});
7577
});
7678

77-
group('findBinaryPaths', () {
78-
test('All files found', () async {
79+
group('find paths', () {
80+
test('All binary files found', () async {
7981
final List<FakeCommand> commandList = <FakeCommand>[];
8082
final FakeCommand findCmd = FakeCommand(
8183
command: const <String>[
@@ -117,7 +119,26 @@ void main() async {
117119
final ProcessManager processManager = FakeProcessManager.list(commandList);
118120
final List<String> foundFiles = await findBinaryPaths('$flutterRoot/bin/cache', processManager: processManager);
119121
expect(foundFiles, <String>[]);
120-
});
122+
});
123+
124+
test('All xcframeworks files found', () async {
125+
final List<FakeCommand> commandList = <FakeCommand>[
126+
FakeCommand(
127+
command: const <String>[
128+
'find',
129+
'$flutterRoot/bin/cache',
130+
'-type',
131+
'd',
132+
'-name',
133+
'*xcframework',
134+
],
135+
stdout: allXcframeworksStdout,
136+
)
137+
];
138+
final ProcessManager processManager = FakeProcessManager.list(commandList);
139+
final List<String> foundFiles = await findXcframeworksPaths('$flutterRoot/bin/cache', processManager: processManager);
140+
expect(foundFiles, allExpectedXcframeworks);
141+
});
121142

122143
group('isBinary', () {
123144
test('isTrue', () async {
@@ -223,6 +244,19 @@ void main() async {
223244
)
224245
);
225246
}
247+
commandList.add(
248+
FakeCommand(
249+
command: const <String>[
250+
'find',
251+
'$flutterRoot/bin/cache',
252+
'-type',
253+
'd',
254+
'-name',
255+
'*xcframework',
256+
],
257+
stdout: allXcframeworksStdout,
258+
),
259+
);
226260
for (final String expectedFile in allExpectedFiles) {
227261
commandList.add(
228262
FakeCommand(
@@ -248,6 +282,18 @@ void main() async {
248282
);
249283
}
250284
}
285+
286+
for (final String expectedXcframework in allExpectedXcframeworks) {
287+
commandList.add(
288+
FakeCommand(
289+
command: <String>[
290+
'codesign',
291+
'-vvv',
292+
expectedXcframework,
293+
],
294+
)
295+
);
296+
}
251297
final ProcessManager processManager = FakeProcessManager.list(commandList);
252298
await expectLater(verifySignatures(flutterRoot, processManager: processManager), completes);
253299
});
@@ -276,6 +322,19 @@ void main() async {
276322
)
277323
);
278324
}
325+
commandList.add(
326+
FakeCommand(
327+
command: const <String>[
328+
'find',
329+
'$flutterRoot/bin/cache',
330+
'-type',
331+
'd',
332+
'-name',
333+
'*xcframework',
334+
],
335+
stdout: allXcframeworksStdout,
336+
),
337+
);
279338
for (final String expectedFile in allExpectedFiles) {
280339
commandList.add(
281340
FakeCommand(
@@ -300,6 +359,17 @@ void main() async {
300359
);
301360
}
302361
}
362+
for (final String expectedXcframework in allExpectedXcframeworks) {
363+
commandList.add(
364+
FakeCommand(
365+
command: <String>[
366+
'codesign',
367+
'-vvv',
368+
expectedXcframework,
369+
],
370+
)
371+
);
372+
}
303373
final ProcessManager processManager = FakeProcessManager.list(commandList);
304374

305375
expect(

0 commit comments

Comments
 (0)