blob: 49d9d226ebc939aaeb5db2204c07985187bbb374 [file] [log] [blame]
// Copyright 2019 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.
import 'package:codesign/verify.dart';
import 'package:file/file.dart';
import 'package:file/memory.dart';
import 'package:logging/logging.dart';
import 'package:test/test.dart';
import 'src/fake_process_manager.dart';
void main() {
const String binaryPath = '/path/to/binary';
late FakeProcessManager processManager;
late FileSystem fs;
late Logger logger;
late VerificationService service;
late List<LogRecord> logs;
setUp(() {
fs = MemoryFileSystem.test();
fs.file(binaryPath).createSync(recursive: true);
processManager = FakeProcessManager.empty();
logs = <LogRecord>[];
logger = Logger.detached('test');
logger.onRecord.listen((LogRecord record) => logs.add(record));
service = VerificationService(
binaryPath: binaryPath,
fs: fs,
logger: logger,
pm: processManager,
);
});
test('parses codesign output and can present', () async {
processManager.addCommands(const <FakeCommand>[
FakeCommand(
command: <String>['codesign', '--display', '-vv', binaryPath],
stderr: '''
Executable=$binaryPath
Identifier=mybinary
Format=Mach-O thin (x86_64)
CodeDirectory v=20500 size=38000 flags=0x10000(runtime) hashes=1177+7 location=embedded
Signature size=8979
Authority=Developer ID Application: Dev Shop ABC (ABCC0VV123)
Authority=Developer ID Certification Authority
Authority=Apple Root CA
Timestamp=Jan 9, 2023 at 9:39:07 AM
Info.plist=not bound
TeamIdentifier=ABCC0VV123
Runtime Version=13.1.0
Sealed Resources=none
Internal requirements count=1 size=164
''',
),
FakeCommand(
command: <String>[
'codesign',
'--verify',
'-v',
'-R=notarized',
'--check-notarization',
binaryPath,
],
stderr: '''
$binaryPath: valid on disk
$binaryPath: satisfies its Designated Requirement
$binaryPath: explicit requirement satisfied
''',
),
]);
final VerificationResult result = await service.run();
expect(processManager, hasNoRemainingExpectations);
expect(result, VerificationResult.codesignedAndNotarized);
expect(
service.present(),
'''
Authority: Developer ID Application: Dev Shop ABC (ABCC0VV123)
Time stamp: Jan 9, 2023 at 9:39:07 AM
Format: Mach-O thin (x86_64)
Signature size: 8979
Notarization: true
''',
);
});
test('detects codesigned but not notarized binary', () async {
processManager.addCommands(const <FakeCommand>[
FakeCommand(
command: <String>['codesign', '--display', '-vv', binaryPath],
stderr: '''
Executable=$binaryPath
Identifier=mybinary
Format=Mach-O thin (x86_64)
CodeDirectory v=20500 size=38000 flags=0x10000(runtime) hashes=1177+7 location=embedded
Signature size=8979
Authority=Developer ID Application: Dev Shop ABC (ABCC0VV123)
Authority=Developer ID Certification Authority
Authority=Apple Root CA
Timestamp=Jan 9, 2023 at 9:39:07 AM
Info.plist=not bound
TeamIdentifier=ABCC0VV123
Runtime Version=13.1.0
Sealed Resources=none
Internal requirements count=1 size=164
''',
),
FakeCommand(
command: <String>[
'codesign',
'--verify',
'-v',
'-R=notarized',
'--check-notarization',
binaryPath,
],
stderr: '''
$binaryPath: valid on disk
$binaryPath: satisfies its Designated Requirement
test-requirement: code failed to satisfy specified code requirement(s)
''',
exitCode: 3,
),
]);
final VerificationResult result = await service.run();
expect(processManager, hasNoRemainingExpectations);
expect(result, VerificationResult.codesignedOnly);
expect(
service.present(),
'''
Authority: Developer ID Application: Dev Shop ABC (ABCC0VV123)
Time stamp: Jan 9, 2023 at 9:39:07 AM
Format: Mach-O thin (x86_64)
Signature size: 8979
Notarization: false
''',
);
});
test('detects unsigned binary', () async {
processManager.addCommands(const <FakeCommand>[
FakeCommand(
command: <String>['codesign', '--display', '-vv', binaryPath],
stderr: '$binaryPath: code object is not signed at all',
exitCode: 1,
),
]);
final VerificationResult result = await service.run();
expect(processManager, hasNoRemainingExpectations);
expect(result, VerificationResult.unsigned);
expect(
logs.first,
isA<LogRecord>().having(
(LogRecord record) => record.message,
'message',
contains('File $binaryPath is not codesigned.'),
),
);
});
}