signMacosPayload function
Implementation
Future<void> signMacosPayload(MacosSignConfig config) async {
if (!config.isAppBundle) {
return signMacosExecutable(
inputPath: config.inputPath,
entitlementsPath: config.entitlementsPath,
skipNotarize: config.skipNotarize,
environment: config.environment,
);
}
final env = config.environment ?? currentShipworldEnvironment;
final identity = await _installSigningIdentity(env);
try {
final nested = <String>[];
await for (final entity in Directory(
config.inputPath,
).list(recursive: true, followLinks: false)) {
final isNested = switch (entity) {
File() => await _isMachO(entity),
// Nested bundles seal their own resources, so signing the bundle
// covers everything inside it.
Directory() => _bundleExtensions.contains(p.extension(entity.path)),
_ => false,
};
if (isNested) {
nested.add(entity.path);
}
}
// Deepest first, so an inner bundle is sealed before the one containing it.
nested.sort((left, right) => right.length.compareTo(left.length));
for (final path in nested) {
await runChecked('codesign', [
'--force',
'--options',
'runtime',
'--sign',
identity,
path,
]);
}
await runChecked('codesign', [
'--force',
'--options',
'runtime',
'--entitlements',
config.entitlementsPath,
'--sign',
identity,
config.inputPath,
]);
if (identity != '-' &&
(env['APPLE_NOTARY_KEY_P8_BASE64']?.isNotEmpty ?? false) &&
!config.skipNotarize) {
// The notary service takes an archive, and stapling writes the ticket
// into the bundle so Gatekeeper accepts it without network access.
final zipPath = '${config.inputPath}.notarize.zip';
await runChecked('ditto', [
'-c',
'-k',
'--keepParent',
config.inputPath,
zipPath,
]);
try {
await _notarize(
archivePath: zipPath,
env: env,
skipNotarize: config.skipNotarize,
);
await runChecked('xcrun', ['stapler', 'staple', config.inputPath]);
} finally {
await _deleteIfExists(zipPath);
}
} else {
await _notarize(
archivePath: config.inputPath,
env: env,
skipNotarize: config.skipNotarize,
);
}
} finally {
await _disposeSigningIdentity();
}
await runChecked('codesign', [
'--verify',
'--deep',
'--strict',
config.inputPath,
]);
}