web-dev-qa-db-fra.com

macOS: Notariser dans le script?

Parce que la signature de codes et l'archivage par Xcode prennent du temps, sont ennuyeux et problématiques, j'ai toujours signé, archivé et expédié mon application macOS signée Developer ID en utilisant les outils de ligne de commande xcodebuild, codesign , etc. via mon propre script. La notarisation semble être une douleur majeure. Est-il possible d'ajouter la notarisation à mon script?

14
Jerry Krinock

Oui. Malheureusement, le réponse officielle laisse quelques extrémités lâches, par exemple ceci friandise importante de Quinn "l'Eskimo" . Voici comment faire:

Configurations uniques

Obtenez un mot de passe spécifique à l'application

Décidez d'un nom pour votre "application" de notarisation des applications. J'utilise le nom de mon script d'expédition de produit, _SSYShipProduct.pl_ car c'est "l'application" qui utilisera ce mot de passe. Nous désignerons le nom que vous composez comme votre-nom-notarié .

Accédez à https://appleid.Apple.com/account/manage , faites défiler jusqu'à Sécurité > Mot de passe spécifique à l'application et générez un mot de passe spécifique à l'application pour une application nommée votre-nom-notarié . Copiez le mot de passe qu'il vous donne. Nous appellerons cela mot de passe spécifique à l'application .

Ajoutez le mot de passe spécifique à l'application à votre trousseau macOS

Exécutez cette commande pour ajouter le mot de passe que vous venez de créer à votre trousseau:

_security add-generic-password -a "your-Apple-ID-email" -w "app-specific-password" -s "your-notarizing-name"_

Le paramètre _-s_ est le nom que cet élément aura dans votre trousseau. Je pense que vous pourriez en fait utiliser un nom différent, mais dans mon esprit, il est logique d'utiliser _your-notarizing-name_ ici aussi.

Vous pouvez vérifier que cela a fonctionné en recherchant dans l'application Keychain Access . Cependant, sachez que les nouveaux éléments ne sont pas répertoriés dans Keychain Access tant que vous ne l'avez pas quitté et relancé.

Peut-être, obtenez le fournisseur itc pertinent

Si votre Apple ID est associé à plus d'une Apple équipe Developer Connection (comme si vous travaillez sous contrat), vous aurez besoin du itc_provider de l'équipe pour laquelle cette application doit être notariée.

Pour trouver le itc_provider de votre équipe, exécutez cette commande:

_/Applications/Xcode.app/Contents/Applications/Application\ Loader.app/Contents/itms/bin/iTMSTransporter -m provider -u "your-Apple-ID-email" -p "app-specific-password"_

Faites défiler jusqu'à la fin de la sortie imprimée par cette commande et regardez la table Liste des fournisseurs . Copiez le nom court de l'équipe souhaitée. Nous appellerons cela "développeur-équipe-fournisseur-itc".

Pour chaque envoi (Scriptable!)

Si vous signez des composants de votre application à l'aide de l'outil de ligne de commande _/usr/bin/codesign_, chaque appel de codesign doit avoir le nouveau paramètre d'argument suivant, qui indique à codesign de signer avec le soi-disant runtime renforcé :

_ `--options runtime`
_

Inversement, si votre application est signée dans Xcode, vous devez définir le paramètre de build Runtime renforcé , disponible dans Xcode 10 ou version ultérieure, sur Oui dans tous les exécutables cibles des composants.

En dehors de cela, votre script devrait créer une version de votre application dans la configuration de la version et la signer, comme lors des jours de pré-notarisation.

Télécharger sur Apple Service notarial

Votre script doit ensuite archiver votre application dans un .Zip ou .dmg. Notez qu'il s'agit d'un fichier intermédiaire qui ne sera téléchargé que vers le service notaire Apple, non expédié.

Ensuite, votre script doit composer une valeur d'ID de bundle principal , qui sera l'identifiant de bundle de votre application avec _.Zip_ ou _.dmg_ ajouté. Exemple: votre-valeur-pbid = _com.mycompany.YourApp.Zip_.

Dans ce qui suit, votre script utilisera altool, qui est le nom d'Apple pour Application Loader Tool .

Votre script doit ensuite exécuter cette commande pour obtenir votre .Zip ou .dmg notarié:

_/usr/bin/xcrun altool --notarize-app --primary-bundle-id "your-pbid-value" --username "your-Apple-id-email" --password "@keychain:your-notarizing-name" -itc_provider "developer-team-itc-provider" --file /path/to/YourApp.Zip/or/YourApp.dmg --output-format "xml"_

(Notez que, dans la commande ci-dessus, bizarrement, tous les noms d'argument sont précédés de deux tirets, sauf que _-itc_provider_ est précédé d'un seul tiret. De plus, si le langage de script que vous utilisez interpole _@_ caractères dans les chaînes , codez-le pour empêcher l'interpolation de _@keychain_).

Au bout d'une minute environ, xcrun se fermera et s'imprimera pour sortir du XML qui, si votre soumission a été acceptée (note: non approuvé pour l'instant), ressemblera à cet exemple:

_<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.Apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>notarization-upload</key>
    <dict>
        <key>RequestUUID</key>
        <string>2ab59b26-19ec-4a30-84cf-6d2cb8d3c97e</string>
    </dict>
    <key>os-version</key>
    <string>10.15.0</string>
    <key>success-message</key>
    <string>No errors uploading 'path/to/YourApp.Zip'.</string>
    <key>tool-path</key>
    <string>/Applications/Xcode.app/Contents/Applications/Application Loader.app/Contents/Frameworks/ITunesSoftwareService.framework</string>
    <key>tool-version</key>
    <string>1.1.1138</string>
</dict>
</plist>
_



Tout ce dont vous avez vraiment besoin, c'est de cette valeur RequestUUID. Cependant, comme j'expédie souvent quatre applications, et parce que cela gâche ma journée lorsque mon script d'expédition échoue sans fournir d'informations d'erreur utiles, et parce que (voir ci-dessous) vous allez faire un autre appel qui renvoie également du XML intéressant, j'ai investi un certain temps ajouter à mon script un sous-programme qui prend deux paramètres, XML et un chemin de clé, et renvoie la valeur du XML à un chemin de clé donné. Dans le cas ci-dessus, j'appelle ce sous-programme pour obtenir le RequestUUID, puis à nouveau pour obtenir le _success-message_.

(Mon script est en Perl. Bien qu'il existe dans CPAN un module nommé XML :: Simple qui peut effectuer cette analyse en une ou deux lignes, il est marqué par le responsable comme n'étant pas pour donc pour éviter d'avoir à installer et à utiliser un analyseur XML réel , j'ai plutôt choisi d'utiliser PlistBuddy comme suggéré dans le commentaire de @khuttun. Cela a été un peu douloureux aussi parce que, malheureusement, altool n'a pas d'option pour écrire sa sortie dans un fichier, et PlistBuddy n'est pas documenté pour accepter stdin. Donc mon sous-programme écrit la stdout à partir de altool dans un fichier temporaire, puis passe le chemin de ce fichier temporaire à PlistBuddy. C'est dégoûtant, mais ça marche.)

Supprimer le package Zip non agrafé

À ce stade, je recommande que votre script supprime le fichier _.Zip_ ou _.dmg_ qu'il a téléchargé. Raison: ce fichier a été archivé à partir d'un produit qui n'a pas encore votre ticket de notarisation agrafé . À la fin de votre script, vous allez créer un nouveau _.Zip_ ou _.dmg_ à partir d'une application modifiée qui a le ticket. La suppression du fichier vous empêche immédiatement d'expédier par erreur une application non agrafée.

Attendez en boucle la réponse d'Apple

Votre script peut alors commencer à harceler le serveur d'Apple pour vos résultats finaux, en exécutant cette commande en boucle avec un peu de sommeil:

`/ usr/bin/xcrun altool --notarization-info --username" your-Apple-id-email "--password" @keychain: your-notarizing-name "--output-format" xml "

Si votre script exécute cette commande immédiatement, il sera renvoyé dans stdout du xml qui ressemblera à cet exemple:

_<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.Apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>notarization-info</key>
    <dict>
        <key>Date</key>
        <date>2019-08-07T01:17:37Z</date>
        <key>RequestUUID</key>
        <string>4ba71353-9d99-4b52-b579-37f384717130</string>
        <key>Status</key>
        <string>in progress</string>
    </dict>
    <key>os-version</key>
    <string>10.15.0</string>
    <key>success-message</key>
    <string>No errors getting notarization info.</string>
    <key>tool-path</key>
    <string>/Applications/Xcode.app/Contents/Applications/Application Loader.app/Contents/Frameworks/ITunesSoftwareService.framework</string>
    <key>tool-version</key>
    <string>1.1.1138</string>
</dict>
</plist>
_


Le chemin d'accès clé principal est _notarization-info:Status_, dont la valeur _in progress_ signifie que Apple travaille toujours sur votre soumission. Après quelques minutes en général (Apple dit que "devrait être moins d'une heure", mais j'ai connu des heures allant jusqu'à trois heures et demie les après-midi de vacances aux États-Unis de 2019-juil-04), altool va revenir à votre script un xml différent dans stdout, quelque chose comme ceci:

_<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.Apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>notarization-info</key>
    <dict>
        <key>Date</key>
        <date>2019-08-06T23:28:25Z</date>
        <key>LogFileURL</key>
        <string>https://osxapps-ssl.iTunes.Apple.com/iTunes-assets/Enigma113/v4/f6/09/be/f609bee3-b031-323a-0987-d1f620a78758/developer_log.json?accessKey=1565410613_1722173034418364591_TvycjBAzd6FRTYGKZEFU6EwDfsws8Wa1MV%2FYnTiJ1zyOZamc%2FoeO5RMeIzZN669ZQJgO2Q4W48ipKNFO%2BQGuq%2FITXN8MQAetbNe90w9ogzqXbrzTHg%2FgYK89yvEFmiiRxhaVlZqLI93NBpY0hwBqXv2bvvlg%2FRCc%2BVaCNRJ%2BrnE%3D</string>
        <key>RequestUUID</key>
        <string>07fc3745-b0ff-4d1a-9b15-37f384717130</string>
        <key>Status</key>
        <string>success</string>
        <key>Status Code</key>
        <integer>0</integer>
        <key>Status Message</key>
        <string>Package Approved</string>
    </dict>
    <key>os-version</key>
    <string>10.15.0</string>
    <key>success-message</key>
    <string>No errors getting notarization info.</string>
    <key>tool-path</key>
    <string>/Applications/Xcode.app/Contents/Applications/Application Loader.app/Contents/Frameworks/ITunesSoftwareService.framework</string>
    <key>tool-version</key>
    <string>1.1.1138</string>
</dict>
</plist>
_


Après une rétro-ingénierie, vous voyez que, dans chaque itération de boucle, votre script doit analyser le XML et sortir de la boucle chaque fois que la valeur de Status est autre que _in progress_, ou si vous préférez, lorsque LogFileURL est défini. Ou si vous préférez les déclencheurs d'e-mails, votre script peut rechercher un e-mail de Apple avec une ligne d'objet Vous pouvez maintenant distribuer votre logiciel Mac. .

MISE À JOUR 2019-11-02

Après avoir eu des problèmes avec cette étape dans mes deux dernières expéditions, et encore aujourd'hui, j'ai maintenant confirmé un bug dans le service notarial d'Apple. Le bogue est que la commande _altool --notarization-info_ échouera pendant 1 à 5 heures, renvoyant des codes de sortie différents de zéro et dans stdout un code d'erreur 1519 "Impossible de trouver le RequestUUID", comme dans l'exemple suivant stdout:

_<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.Apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>os-version</key>
    <string>10.15.1</string>
    <key>product-errors</key>
    <array>
        <dict>
            <key>code</key>
            <integer>1519</integer>
            <key>message</key>
            <string>Could not find the RequestUUID.</string>
            <key>userInfo</key>
            <dict>
                <key>NSLocalizedDescription</key>
                <string>Could not find the RequestUUID.</string>
                <key>NSLocalizedFailureReason</key>
                <string>Apple Services operation failed.</string>
                <key>NSLocalizedRecoverySuggestion</key>
                <string>Could not find the RequestUUID.</string>
            </dict>
        </dict>
    </array>
    <key>tool-path</key>
    <string>/Applications/Xcode.app/Contents/SharedFrameworks/ContentDeliveryServices.framework/Versions/A/Frameworks/AppStoreService.framework</string>
    <key>tool-version</key>
    <string>4.00.1181</string>
</dict>
</plist>
_


Il s'agit d'un bogue car, bien sûr, mon script a soumis l'UUID de demande qu'il vient de recevoir de Apple Service notarial, Apple devrait être en mesure de le trouver et, en outre, lorsque j'ai continué à envoyer la commande manuellement, après environ 2 heures, soudainement, la commande a renvoyé Success et a continué de revenir Success avec les commandes suivantes, et j'ai reçu l'e-mail Success d'Apple. Ce retard s'est produit aujourd'hui avec 7 bonnes UUID de demande différentes, la plus longue étant de 5 heures. Il se peut, à ce moment, qu'il y ait un délai de 1 à 5 heures entre Apple le service notaire créant et vous envoyant un UUID de demande, et qu'il apparaisse dans la base de données que Apple le service notaire utilise pour répondre à _notarization-info_ requêtes, vous obtenez donc cette fausse erreur. Très triste.

Comme je n'ai aucun contrôle sur le moment où [Apple affecte des personnes pour corriger les bogues, j'ai modifié cette étape de mon script pour analyser la réponse de Apple et mourir uniquement si la commande renvoie un état de sortie différent de zéro et le code de la première (index = 0) _product-errors_ tableau n'est pas 1519. Si vous utilisez PlistBuddy pour analyser XML tel que je suis, le le chemin d'accès clé pour ce code doit être _product-errors:0:code_. La boucle de mon script s'imprime chaque fois que l'erreur 1519 est reçue, donc je peux voir ce qui se passe, et bien sûr, j'ai modifié sa condition while pour ne pas quitter si le code d'erreur est 1519.

Après avoir corrigé mon script, j'avais plusieurs applications à expédier. Apple Le service notarial a bien traité la première: aucune erreur 1519 et succès après environ deux minutes. Le suivant, cependant, avait besoin de cette nouvelle fonctionnalité de mon script. À l'heure 09:54 (HH: mm), mon script a reçu l'UUID de demande d'Apple. 20 secondes plus tard, il a envoyé la première requête _altool --notarization-info_. La réponse a été une fausse erreur 1519. Les requêtes suivantes ont également renvoyé de fausses erreurs 1519, pendant près de 3 heures, jusqu'à 12 h 44. Puis, à 12 h 45, tout à coup, il a reçu une réponse _in progress_. Après 5 autres réponses _in progress_, à 12 h 47, enfin, Succès .

Une dernière chose avant de quitter cette rubrique: une heure après que cette demande a réussi sans erreur 1519, une demande antérieure d'il y a une heure a soudainement commencé à renvoyer _in progress_ puis quelques minutes plus tard, Succès . Conclusion: les UUID de demande qui sont déviés dans le bourbier de l'erreur 1519 ne sont pas mis en file d'attente FIFO avec des UUID de demande ultérieurs qui pourraient, par hasard, éviter le détour de l'erreur 1519. Ainsi, une meilleure solution de contournement pourrait être d'abandonner un UUID de demande après avoir reçu une réponse supplémentaire à l'Erreur 1519 et de recommencer en téléchargeant l'application sur Apple Notary Service et en obtenant un autre UUID de demande qui, vous l'espérez, fonctionnera mieux. Bien sûr, vous recevrez de nombreux e-mails au cours des prochaines heures, car tous les UUID de demande que vous avez abandonnés réussissent finalement.

En tout cas, maintenant, passons à l'étape suivante du script…

Vérifiez le fichier journal d'Apple

Votre script doit analyser la valeur de LogFileURL pour pouvoir consulter le journal, car même si la notarisation réussit, le fichier journal créé par Apple peut contenir des avertissements. Pour obtenir le fichier journal, votre script doit, bien sûr,

_curl <LogFileURL-Value>
_

Le fichier journal est apparemment JSON. Les avertissements ou les erreurs sont présentés sous forme de tableau, qui correspond à la valeur de la clé issues. Votre script doit donc analyser cette sortie curl avec un analyseur JSON et si la valeur de la clé issues est un null JSON ou un tableau vide, continuez la livraison.

Agrafez le ticket à votre application

Cette étape est assez simple…

_xcrun stapler staple /path/to/YourApp.app
_

L'exécution de cette commande ajoutera au package de votre application un nouveau fichier: _YourApp.app/Contents/CodeResources_. Il s'agit apparemment de votre ticket de notarisation . Notez que ce fichier est en plus du fichier _YourApp.app/Contents/_CodeSignature/CodeResources_ qui est toujours là et contient la signature de code, la même que dans les jours de pré-notarisation.

Vérifiez l'agrafage des tickets

Mais il existe un meilleur moyen de vérifier que votre application dispose désormais d'un bon ticket. Votre script doit maintenant exécuter (ou réexécuter) une vérification Gatekeeper:

_spctl -a -v /path/to/YourApp.app
_

Le résultat, dans stderr, devrait être,

_/path/to/YourApp.app: accepted
source=Notarized Developer ID
_

qui est le même résultat que la pré-notarisation, à l'exception de l'insertion de notarié . Des scripts astucieux analyseront ce stderr et abandonneront l'expédition si les mots ci-dessus ne sont pas détectés.

Zip et expédier

Maintenant que le ticket a été ajouté, votre script peut à nouveau compresser ou dmg votre .app, mais cette fois, expédiez-le.

22
Jerry Krinock

Voici un script de notarisation et d'agrafage réutilisable et sous licence libre pour les versions automatisées:

https://github.com/rednoah/notarize-app/blob/master/notarize-app

Il fonctionnera et attendra et ne sortira qu'une fois que tout sera fait:

  1. Courir altool --notarize-app
  2. Courir altool --notarization-info périodiquement jusqu'à la fin de la notarisation
  3. Courir stapler staple
3
rednoah

Voici un exemple de notariseur automatique que j'ai écrit pour RawTherapee. Tout d'abord, nous notarions l'application:

https://github.com/Beep6581/RawTherapee/blob/6fa533c40b34dec527f1176d47cc6c683422a73f/tools/osx/macosx_bundle.sh#L225-L25

Ensuite, nous notarions le dmg:

https://github.com/Beep6581/RawTherapee/blob/6fa533c40b34dec527f1176d47cc6c683422a73f/tools/osx/macosx_bundle.sh#L283-L307

Les informations d'identification du notaire sont transmises via la directive de commande cmake

-DNOTARY="--username [email protected] --password abcd-efgh-ijkl-mnop"
0
Richard Barber