| ... | ... | @@ -27,8 +27,8 @@ CHECKS = [ |
| 27 | 27 | # Clover's Developer ID Application certificate, by its SHA-1 hash: its name is the account |
| 28 | 28 | # holder's legal name, which nothing here prints or stores. |
| 29 | 29 | IDENTITY = 'BA308AA3591299E053E8824CEF1651F686F8908E' |
| 30 | | # The notarytool keychain profile that notarizes it, once `xcrun notarytool store-credentials` makes it. |
| 31 | | NOTARY = 'snowbound' |
| 30 | # The App Store Connect API key that notarizes it: {"key": P8 PATH, "key_id": ID, "issuer": ID}. |
| 31 | NOTARY = Path('~/.config/snowbound/notary.json').expanduser() |
| 32 | 32 | # What hardened runtime needs for Record Audio and Record Video. |
| 33 | 33 | ENTITLEMENTS = { |
| 34 | 34 | 'com.apple.security.device.audio-input': True, |
| ... | ... | @@ -98,10 +98,14 @@ def zip_bundle(bundle, archive): |
| 98 | 98 | run(['ditto', '-c', '-k', '--norsrc', '--noextattr', '--noqtn', '--noacl', '--keepParent', bundle, archive]) |
| 99 | 99 | |
| 100 | 100 | |
| 101 | | def notarizes(): |
| 102 | | """Whether the NOTARY profile exists and signs in.""" |
| 103 | | return subprocess.run(['xcrun', 'notarytool', 'history', '--keychain-profile', NOTARY], |
| 104 | | capture_output=True).returncode == 0 |
| 101 | def notary(): |
| 102 | """notarytool's credential arguments from NOTARY, if they sign in.""" |
| 103 | if not NOTARY.exists(): |
| 104 | return None |
| 105 | key = json.loads(NOTARY.read_text()) |
| 106 | arguments = ['--key', str(Path(key['key']).expanduser()), '--key-id', key['key_id'], '--issuer', key['issuer']] |
| 107 | signs_in = subprocess.run(['xcrun', 'notarytool', 'history', *arguments], capture_output=True).returncode == 0 |
| 108 | return arguments if signs_in else None |
| 105 | 109 | |
| 106 | 110 | |
| 107 | 111 | def build_mac(platform, folder, developer_id, notarize): |
| ... | ... | @@ -117,7 +121,7 @@ def build_mac(platform, folder, developer_id, notarize): |
| 117 | 121 | '--sign', IDENTITY, bundle]) |
| 118 | 122 | if notarize: |
| 119 | 123 | zip_bundle(bundle, archive) |
| 120 | | run(['xcrun', 'notarytool', 'submit', archive, '--keychain-profile', NOTARY, '--wait']) |
| 124 | run(['xcrun', 'notarytool', 'submit', archive, *notarize, '--wait']) |
| 121 | 125 | run(['xcrun', 'stapler', 'staple', bundle]) |
| 122 | 126 | archive.unlink() |
| 123 | 127 | zip_bundle(bundle, archive) |
| ... | ... | @@ -143,9 +147,9 @@ def main(): |
| 143 | 147 | capture_output=True, text=True).stdout |
| 144 | 148 | if developer_id and IDENTITY not in identities: |
| 145 | 149 | sys.exit(f'The keychain has no signing identity {IDENTITY}; release with --ad-hoc, or add it.') |
| 146 | | notarize = developer_id and notarizes() |
| 150 | notarize = notary() if developer_id else None |
| 147 | 151 | if developer_id and not notarize: |
| 148 | | print(f'Not notarizing: no notarytool profile "{NOTARY}" that signs in (see tools/RELEASE.md).', |
| 152 | print(f'Not notarizing: no API key in {NOTARY} that signs in (see tools/RELEASE.md).', |
| 149 | 153 | file=sys.stderr) |
| 150 | 154 | |
| 151 | 155 | commit = jj('log', '--no-graph', '-r', 'main', '-T', 'commit_id').strip() |
| ... | ... | @@ -174,9 +178,9 @@ def main(): |
| 174 | 178 | built = {} |
| 175 | 179 | for platform in args.platforms: |
| 176 | 180 | if platform.startswith('macos'): |
| 177 | | folder = stage / platform |
| 178 | | folder.mkdir() |
| 179 | | built[platform] = build_mac(platform, folder, developer_id, notarize) |
| 181 | work = stage / platform |
| 182 | work.mkdir() |
| 183 | built[platform] = build_mac(platform, work, developer_id, notarize) |
| 180 | 184 | linux = [platform.removeprefix('linux-') for platform in args.platforms if platform.startswith('linux')] |
| 181 | 185 | if linux: |
| 182 | 186 | built |= build_linux(linux) |