Skip to content

Commit afb2006

Browse files
Hotfix 8 - sign binaries and increase minimum Xcode version to 11 (flutter#50291)
1 parent 9f5ff23 commit afb2006

File tree

7 files changed

+144
-19
lines changed

7 files changed

+144
-19
lines changed

.cirrus.yml

+16
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ environment:
1919
# TODO(amirha): remove once we've migrated to newer Gradle
2020
CIRRUS_CHANGE_MESSAGE: ""
2121
CIRRUS_COMMIT_MESSAGE: ""
22+
FLUTTER_TESTS_PIN_HASH: 'f73542b1dcf6866948ca13d4f61c3557c7c3d4ad'
2223

2324
# LINUX SHARDS
2425
task:
@@ -283,6 +284,8 @@ task:
283284
script:
284285
- rm -rf bin/cache/pkg/tests
285286
- git clone https://github.com/flutter/tests.git bin/cache/pkg/tests
287+
# Hotfix only, this pins the flutter/tests repo
288+
- (cd bin/cache/pkg/tests ; git checkout "$FLUTTER_TESTS_PIN_HASH")
286289
- dart --enable-asserts dev/customer_testing/run_tests.dart --skip-on-fetch-failure --skip-template bin/cache/pkg/tests/registry/*.test
287290

288291
- name: firebase_test_lab_tests-linux # linux-only
@@ -425,6 +428,8 @@ task:
425428
script:
426429
- CMD /S /C "IF EXIST "bin\cache\pkg\tests\" RMDIR /S /Q bin\cache\pkg\tests"
427430
- git clone https://github.com/flutter/tests.git bin\cache\pkg\tests
431+
# Hotfix only, this pins the flutter/tests repo
432+
- CMD /S /C "CD bin\cache\pkg\tests & git checkout "%FLUTTER_TESTS_PIN_HASH%""
428433
- dart --enable-asserts dev\customer_testing\run_tests.dart --skip-on-fetch-failure --skip-template bin/cache/pkg/tests/registry/*.test
429434

430435
# MACOS SHARDS
@@ -548,6 +553,8 @@ task:
548553
- ulimit -S -n 2048 # https://github.com/flutter/flutter/issues/2976
549554
- rm -rf bin/cache/pkg/tests
550555
- git clone https://github.com/flutter/tests.git bin/cache/pkg/tests
556+
# Hotfix only, this pins the flutter/tests repo
557+
- (cd bin/cache/pkg/tests ; git checkout "$FLUTTER_TESTS_PIN_HASH")
551558
- dart --enable-asserts dev/customer_testing/run_tests.dart --skip-on-fetch-failure --skip-template bin/cache/pkg/tests/registry/*.test
552559

553560
- name: deploy_gallery-macos # linux- and macos- only
@@ -577,6 +584,15 @@ task:
577584
- ulimit -S -n 2048 # https://github.com/flutter/flutter/issues/2976
578585
- ./dev/bots/deploy_gallery.sh
579586

587+
- name: verify_binaries_codesigned-macos # macos-only
588+
# TODO(fujino): remove this `only_if` after https://github.com/flutter/flutter/issues/44372
589+
only_if: "$CIRRUS_BRANCH == 'dev' || $CIRRUS_BRANCH == 'beta' || $CIRRUS_BRANCH == 'stable' || $CIRRUS_BRANCH =~ '.*hotfix.*'"
590+
depends_on:
591+
- analyze-linux
592+
script:
593+
- ulimit -S -n 2048 # https://github.com/flutter/flutter/issues/2976
594+
- dart --enable-asserts ./dev/bots/codesign.dart
595+
580596
docker_builder:
581597
# Only build a new docker image when we tag a release (for dev, beta, or
582598
# stable). Note: tagging a commit and pushing to a release branch are

bin/internal/engine.version

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
a67792536ca236a971d0efbcfd7af4efb8f6c119
1+
e1e6ced81d029258d449bdec2ba3cddca9c2ca0c

dev/bots/codesign.dart

+105
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
// Copyright 2014 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'dart:io';
6+
import 'package:path/path.dart' as path;
7+
8+
String get repoRoot => path.normalize(path.join(path.dirname(Platform.script.toFilePath()), '..', '..'));
9+
String get cacheDirectory => path.normalize(path.join(repoRoot, 'bin', 'cache'));
10+
11+
/// Check mime-type of file at [filePath] to determine if it is binary
12+
bool isBinary(String filePath) {
13+
final ProcessResult result = Process.runSync(
14+
'file',
15+
<String>[
16+
'--mime-type',
17+
'-b', // is binary
18+
filePath,
19+
],
20+
);
21+
return (result.stdout as String).contains('application/x-mach-binary');
22+
}
23+
24+
/// Find every binary file in the given [rootDirectory]
25+
List<String> findBinaryPaths([String rootDirectory]) {
26+
rootDirectory ??= cacheDirectory;
27+
final ProcessResult result = Process.runSync(
28+
'find',
29+
<String>[
30+
rootDirectory,
31+
'-type',
32+
'f',
33+
'-perm',
34+
'+111', // is executable
35+
],
36+
);
37+
final List<String> allFiles = (result.stdout as String).split('\n').where((String s) => s.isNotEmpty).toList();
38+
return allFiles.where(isBinary).toList();
39+
}
40+
41+
/// Given the path to a stamp file, read the contents.
42+
///
43+
/// Will throw if the file doesn't exist.
44+
String readStamp(String filePath) {
45+
final File file = File(filePath);
46+
if (!file.existsSync()) {
47+
throw 'Error! Stamp file $filePath does not exist!';
48+
}
49+
return file.readAsStringSync().trim();
50+
}
51+
52+
/// Return whether or not the flutter cache is up to date.
53+
bool checkCacheIsCurrent() {
54+
try {
55+
final String dartSdkStamp = readStamp(path.join(cacheDirectory, 'engine-dart-sdk.stamp'));
56+
final String engineVersion = readStamp(path.join(repoRoot, 'bin', 'internal', 'engine.version'));
57+
return dartSdkStamp == engineVersion;
58+
} catch (e) {
59+
print(e);
60+
return false;
61+
}
62+
}
63+
64+
void main() {
65+
final List<String> failures = <String>[];
66+
67+
if (!Platform.isMacOS) {
68+
print('Error! Expected operating system "macos", actual operating system '
69+
'is: "${Platform.operatingSystem}"');
70+
exit(1);
71+
}
72+
73+
if (!checkCacheIsCurrent()) {
74+
print(
75+
'Warning! Your cache is either not present or not matching your flutter\n'
76+
'version. Run a `flutter` command to update your cache, and re-try this\n'
77+
'test.');
78+
exit(1);
79+
}
80+
81+
for (final String binaryPath in findBinaryPaths(cacheDirectory)) {
82+
print('Verifying the code signature of $binaryPath');
83+
final ProcessResult result = Process.runSync(
84+
'codesign',
85+
<String>[
86+
'-vvv',
87+
binaryPath,
88+
],
89+
);
90+
if (result.exitCode != 0) {
91+
failures.add(binaryPath);
92+
print('File "$binaryPath" does not appear to be codesigned.\n'
93+
'The `codesign` command failed with exit code ${result.exitCode}:\n'
94+
'${result.stderr}\n');
95+
}
96+
}
97+
98+
if (failures.isNotEmpty) {
99+
print('Found ${failures.length} unsigned binaries.');
100+
failures.forEach(print);
101+
exit(1);
102+
}
103+
104+
print('Verified that binaries are codesigned.');
105+
}

packages/flutter_tools/lib/src/macos/xcode.dart

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ import '../base/platform.dart';
1212
import '../base/process.dart';
1313
import '../ios/xcodeproj.dart';
1414

15-
const int kXcodeRequiredVersionMajor = 10;
16-
const int kXcodeRequiredVersionMinor = 2;
15+
const int kXcodeRequiredVersionMajor = 11;
16+
const int kXcodeRequiredVersionMinor = 0;
1717

1818
Xcode get xcode => context.get<Xcode>();
1919

packages/flutter_tools/test/general.shard/ios/xcodeproj_test.dart

+2-2
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,8 @@ void main() {
7979

8080
testUsingOsxContext('majorVersion returns major version', () {
8181
when(mockProcessManager.runSync(<String>[xcodebuild, '-version']))
82-
.thenReturn(ProcessResult(1, 0, 'Xcode 10.3.3\nBuild version 8E3004b', ''));
83-
expect(xcodeProjectInterpreter.majorVersion, 10);
82+
.thenReturn(ProcessResult(1, 0, 'Xcode 11.4.3\nBuild version 11N111s', ''));
83+
expect(xcodeProjectInterpreter.majorVersion, 11);
8484
});
8585

8686
testUsingOsxContext('majorVersion is null when version has unexpected format', () {

packages/flutter_tools/test/general.shard/macos/xcode_test.dart

+15-11
Original file line numberDiff line numberDiff line change
@@ -68,25 +68,27 @@ void main() {
6868

6969
testUsingContext('xcodeVersionSatisfactory is true when version meets minimum', () {
7070
when(mockXcodeProjectInterpreter.isInstalled).thenReturn(true);
71-
when(mockXcodeProjectInterpreter.majorVersion).thenReturn(10);
72-
when(mockXcodeProjectInterpreter.minorVersion).thenReturn(2);
71+
when(mockXcodeProjectInterpreter.majorVersion).thenReturn(11);
72+
when(mockXcodeProjectInterpreter.minorVersion).thenReturn(0);
73+
7374
expect(xcode.isVersionSatisfactory, isTrue);
7475
}, overrides: <Type, Generator>{
7576
XcodeProjectInterpreter: () => mockXcodeProjectInterpreter,
7677
});
7778

7879
testUsingContext('xcodeVersionSatisfactory is true when major version exceeds minimum', () {
7980
when(mockXcodeProjectInterpreter.isInstalled).thenReturn(true);
80-
when(mockXcodeProjectInterpreter.majorVersion).thenReturn(11);
81-
when(mockXcodeProjectInterpreter.minorVersion).thenReturn(2);
81+
when(mockXcodeProjectInterpreter.majorVersion).thenReturn(12);
82+
when(mockXcodeProjectInterpreter.minorVersion).thenReturn(0);
83+
8284
expect(xcode.isVersionSatisfactory, isTrue);
8385
}, overrides: <Type, Generator>{
8486
XcodeProjectInterpreter: () => mockXcodeProjectInterpreter,
8587
});
8688

8789
testUsingContext('xcodeVersionSatisfactory is true when minor version exceeds minimum', () {
8890
when(mockXcodeProjectInterpreter.isInstalled).thenReturn(true);
89-
when(mockXcodeProjectInterpreter.majorVersion).thenReturn(10);
91+
when(mockXcodeProjectInterpreter.majorVersion).thenReturn(11);
9092
when(mockXcodeProjectInterpreter.minorVersion).thenReturn(3);
9193
expect(xcode.isVersionSatisfactory, isTrue);
9294
}, overrides: <Type, Generator>{
@@ -123,8 +125,8 @@ void main() {
123125
.thenReturn(ProcessResult(1, 127, '', 'ERROR'));
124126

125127
when(mockXcodeProjectInterpreter.isInstalled).thenReturn(true);
126-
when(mockXcodeProjectInterpreter.majorVersion).thenReturn(10);
127-
when(mockXcodeProjectInterpreter.minorVersion).thenReturn(2);
128+
when(mockXcodeProjectInterpreter.majorVersion).thenReturn(11);
129+
when(mockXcodeProjectInterpreter.minorVersion).thenReturn(0);
128130

129131
expect(xcode.isInstalledAndMeetsVersionCheck, isFalse);
130132
}, overrides: <Type, Generator>{
@@ -141,8 +143,9 @@ void main() {
141143
.thenReturn(ProcessResult(1, 0, xcodePath, ''));
142144

143145
when(mockXcodeProjectInterpreter.isInstalled).thenReturn(true);
144-
when(mockXcodeProjectInterpreter.majorVersion).thenReturn(9);
145-
when(mockXcodeProjectInterpreter.minorVersion).thenReturn(0);
146+
when(mockXcodeProjectInterpreter.majorVersion).thenReturn(10);
147+
when(mockXcodeProjectInterpreter.minorVersion).thenReturn(2);
148+
146149
expect(xcode.isInstalledAndMeetsVersionCheck, isFalse);
147150
}, overrides: <Type, Generator>{
148151
XcodeProjectInterpreter: () => mockXcodeProjectInterpreter,
@@ -158,8 +161,9 @@ void main() {
158161
.thenReturn(ProcessResult(1, 0, xcodePath, ''));
159162

160163
when(mockXcodeProjectInterpreter.isInstalled).thenReturn(true);
161-
when(mockXcodeProjectInterpreter.majorVersion).thenReturn(10);
162-
when(mockXcodeProjectInterpreter.minorVersion).thenReturn(2);
164+
when(mockXcodeProjectInterpreter.majorVersion).thenReturn(11);
165+
when(mockXcodeProjectInterpreter.minorVersion).thenReturn(0);
166+
163167
expect(xcode.isInstalledAndMeetsVersionCheck, isTrue);
164168
}, overrides: <Type, Generator>{
165169
XcodeProjectInterpreter: () => mockXcodeProjectInterpreter,

packages/flutter_tools/test/src/context.dart

+3-3
Original file line numberDiff line numberDiff line change
@@ -349,13 +349,13 @@ class FakeXcodeProjectInterpreter implements XcodeProjectInterpreter {
349349
bool get isInstalled => true;
350350

351351
@override
352-
String get versionText => 'Xcode 10.2';
352+
String get versionText => 'Xcode 11.0';
353353

354354
@override
355-
int get majorVersion => 10;
355+
int get majorVersion => 11;
356356

357357
@override
358-
int get minorVersion => 2;
358+
int get minorVersion => 0;
359359

360360
@override
361361
Future<Map<String, String>> getBuildSettings(

0 commit comments

Comments
 (0)