Нотариальное заверение приложения macOS можно подключить к удалённому Mac CI: сначала подготовьте подписанный для Developer ID релизный артефакт, затем отправьте его через notarytool, разберите результат и, если этого требует формат поставки, прикрепите билет. Подход подходит для распространения вне Mac App Store; статус Accepted сам по себе ещё не подтверждает, что пользователи получили проверенный и запускаемый пакет.
Этот материал для независимых разработчиков, которые переводят ручное заверение в повторяемую процедуру, инженеров сборки, отвечающих за Archive и экспорт, и DevOps-инженеров, управляющих сертификатами, секретами и журналами CI.
План на эту неделю: проведите через удалённый Mac одну изолированную пробную публикацию и сохраните связь между исходным коммитом, подписанным файлом, результатом заверения и окончательным пакетом. Не включайте автоматическую публикацию, пока каждый переход не проверен отдельно.
Граница процесса и точки контроля
Нотариальное заверение — не проверка приложения в рамках App Review и не процедура загрузки приложения в Mac App Store. Здесь рассматривается именно распространяемая вне магазина сборка, подписанная для Developer ID. Apple описывает заверение, Developer ID-подпись и распространение через магазин как разные процессы; руководство Apple по заверению macOS-программ задаёт границы этого потока.
Полный результат релиза состоит не из одного ответа сервиса. Нужны подписанный исходный артефакт, запись о его отправке, итог обработки, билет, когда он необходим, и проверенный конечный файл, который действительно будет передан пользователю. Эти части отвечают на разные вопросы: подпись подтверждает происхождение и целостность кода; ответ заверения сообщает о результате проверки отправки; билет позволяет системе проверить заверенный объект; финальная проверка подтверждает, что выбранный формат доставки не потерял нужные свойства.
Практически важная граница проходит между «сервис принял отправку» и «релиз принят командой». Даже успешный ответ не доказывает, что в дистрибутив попал именно проверенный файл, что после обработки не изменились вложенные компоненты и что установщик или приложение запускаются в предполагаемом сценарии. Поэтому публикационный job должен проверять не только сетевой ответ, но и финальный артефакт.
Для распределения обязанностей удобно зафиксировать контрольные точки:
| Этап | Что должно остаться в CI | Что этим подтверждается |
|---|---|---|
| Подготовка | Идентификатор коммита, имя и контрольная сумма файла, результат проверки подписи | Какой именно объект отправляется |
| Отправка | Идентификатор отправки и журнал операции | Какой запрос относится к этой сборке |
| Обработка | Статус и журнал заверения, включая предупреждения | Как сервис обработал отправленный объект |
| Билет | Результат операции stapler, если она применима, и её проверка |
Что билет обработан для нужного объекта |
| Приёмка | Сведения о конечном пакете и результат установки или запуска | Что именно получает пользователь |
Здесь важна не сложность системы логирования, а возможность сопоставить строки журнала с конкретным выпуском. Например, общий статус CI «успешно» недостаточен, если он не показывает, к какому файлу относится submission ID или какой пакет был передан на публикацию.
Подготовка подписи и выпускаемого артефакта
До настройки API-секретов удалённый Mac должен получить воспроизводимый подписанный пакет. Для Developer ID Apple указывает требования к подписи распространяемого программного обеспечения, включая Hardened Runtime и метку времени; подробности следует сверять с официальной документацией Apple по подписи кода для распространения на Mac. Не подставляйте в сборку выдуманные имена сертификатов или значения параметров: используйте настройки проекта и фактические данные команды.
Сначала определите, какой файл будет входом для заверения. Archive, экспортированное приложение и конечный архив или образ диска — не взаимозаменяемые понятия. Если CI отправляет один файл, а после заверения собирает из него другой пакет, проверка отправки не переносится автоматически на новый объект. В манифесте релиза фиксируйте идентификатор исходного коммита, путь и контрольную сумму каждого значимого файла, а также результат проверки подписи.
Проверьте вложенный код, а не только верхний уровень .app: вспомогательные приложения, расширения, фреймворки и другие компоненты могут иметь собственные требования к подписи. Если выпуск включает установщик, отдельно установите, какой именно объект подписывается, какой отправляется на заверение и что получает конечный пользователь. Материал Apple о подготовке программного обеспечения Mac к распространению помогает соотнести упаковку с выбранным способом доставки.
Как перенести нотариальное заверение macOS-приложения в удалённый CI? Сначала стабилизируйте сборку и экспорт на Mac, затем добавьте отдельную задачу отправки именно того артефакта, который предназначен для распространения. После этого присоедините проверку результата и только в конце — публикацию.
Чтобы начать без смешения этапов, задайте для CI явные входы и выходы:
- вход: проверенный исходный коммит и необходимые подписывающие ресурсы;
- промежуточные результаты: Archive и экспортированный объект, если проект использует оба шага;
- вход
notarytool: конкретный форматированный файл, предусмотренный рабочим процессом; - выход: идентификатор отправки, статус, журнал обработки и файл для последующей проверки;
- финальный результат: дистрибутив с зафиксированным именем и контрольной суммой.
Проверка подписи должна происходить до отправки. Если она не проходит, остановите job до обращения к сервису заверения и сохраните командный вывод. Это сокращает число неоднозначных отказов: ошибка на этапе проверки локального файла не должна маскироваться под проблему сервиса, сети или арендуемого узла.
Подключение notarytool и управление секретами
В начале убедитесь, что выбранная версия Xcode или Command Line Tools на удалённом Mac предоставляет notarytool. Apple переводит скриптуемые рабочие процессы на этот инструмент; с 1 ноября 2023 года загрузки на заверение через altool или Xcode 13 и более ранние версии больше не принимаются — см. примечание Apple о переходе на актуальный инструмент. Текущие варианты аутентификации и параметры команд проверяйте по актуальной документации Apple по настройке рабочего процесса заверения.
Профиль в Keychain и хранилище секретов CI решают разные задачи. Keychain profile позволяет инструменту использовать сохранённые данные аутентификации; CI-секреты отвечают за контролируемую выдачу этих данных задаче. Если профиль создаётся во время job, не включайте исходные значения учётных данных в команду, файл репозитория или диагностический вывод. Секрет должен поступать через предусмотренный механизм защищённого внедрения, а доступ к нему следует выдавать только задаче, которой действительно нужно отправлять релиз.
Не переносите учётные данные в аргументы, которые могут попасть в журнал команды, трассировку shell или отчёт об ошибке. Проверьте маскирование секретов на тестовом запуске: факт наличия секретного хранилища ещё не подтверждает, что конкретный job не раскрывает значение.
В условном примере ниже показана только форма вызова. Имена файлов и профиля — заполнители, а способ создания профиля и параметры доступа следует брать из текущего руководства Apple. Значения учётных данных в команду не включаются.
xcrun notarytool submit "<путь-к-файлу-для-отправки>" \
--keychain-profile "<имя-профиля>" \
--wait
Для первого пробного цикла удобно дождаться результата в рамках задачи, чтобы подтвердить всю последовательность. В постоянном конвейере можно разделить отправку и ожидание на разные этапы, если CI сохраняет идентификатор отправки и умеет надёжно продолжить проверку после перезапуска. Документация Apple по Notary API описывает программный интерфейс для автоматизации; выбирайте API или команды notarytool исходя из требований к управлению задачами, а не только ради сокращения числа строк в скрипте.
Как хранить и выдавать данные для заверения в удалённом CI? Храните секрет в управляемом хранилище CI, подавайте его только соответствующей задаче и не помещайте в репозиторий, открытые переменные или сохраняемые диагностические файлы. Если CI использует Keychain profile, отдельно проверьте создание профиля, срок жизни временных данных и очистку после job.
Разделите полномочия насколько это позволяет устройство выпуска: сборка не должна получать секреты заверения, если она только компилирует код; задача отправки не должна иметь права менять исходный код; публикационный этап должен принимать только артефакт, прошедший проверки. Это не усложнение ради формальности, а способ локализовать ошибку: по журналу будет понятно, на каком переходе возник сбой и какие данные могли быть затронуты.
Результат отправки, журнал и диагностика
Сохраняйте идентификатор отправки рядом с идентификатором сборки. Если job завершился до получения конечного статуса, CI должен продолжить опрос именно этой отправки, а не создать новую без необходимости. В рабочем процессе Apple предусмотрены получение статуса и подробностей обработки; актуальные команды, параметры и формат журналов следует сверять с описанием пользовательского рабочего процесса заверения.
Условная команда для получения журнала выглядит так:
xcrun notarytool log "<идентификатор-отправки>" \
--keychain-profile "<имя-профиля>"
Здесь идентификатор и имя профиля — заполнители. Не публикуйте в открытом логе содержимое секретов или данные, не нужные для диагностики. Сохраняйте сам журнал обработки как артефакт CI с ограниченным доступом, вместе с именем отправленного файла и результатом локальной проверки подписи.
После ответа сервиса классифицируйте проблему по доказательствам, а не по первому предположению:
- ошибки подписи или структуры кода — перепроверьте идентификатор команды, целостность пакета, вложенные компоненты и настройки подписывания;
- сообщения о разрешениях или entitlements — сопоставьте фактические права приложения с тем, что предусмотрено проектом, и проверяйте конкретный компонент;
- неподходящий или неверно подготовленный формат — сравните отправленный объект с поддерживаемыми Apple форматами и способом упаковки;
- отказ или задержка взаимодействия с сервисом — сохраните ответ инструмента, код завершения и идентификатор отправки, затем отдельно исследуйте доступность и повторную попытку.
Одна строка ошибки не доказывает неисправность удалённого Mac или сети. Сначала проверьте, завершилась ли локальная подготовка и создан ли объект отправки; затем изучите ответ сервиса и журнал; только после этого проверяйте внешнее соединение и состояние CI. Руководство Apple по устранению распространённых проблем заверения полезно именно для сопоставления конкретного диагностического сообщения с причиной, а не для вывода по одному общему статусу.
Что проверять после успешной отправки через notarytool? Убедитесь, что получен итоговый статус, сохранён идентификатор отправки и просмотрены предупреждения или журнал обработки. Затем установите, требуется ли для выбранного дистрибутива установка билета, и проверьте уже конечный пакет, а не только ответ сервиса.
Не превращайте Accepted в единственный критерий публикации. Успешное принятие отправки означает, что соответствующий объект обработан в рамках процесса, но не заменяет проверку подписи, билета и файла, который попадёт в канал распространения. Предупреждение тоже нельзя автоматически приравнивать к отказу: оцените его влияние по документации и конкретному сценарию поставки.
Установка билета и проверка конечной поставки
После успешного заверения определите операцию с билетом по формату. Требование не следует механически применять ко всем объектам одинаково: для приложения, архива, образа диска или установщика шаги могут различаться. Используйте актуальную документацию Apple о заверении и упаковке, чтобы решить, нужно ли запускать stapler именно для выбранного объекта и поддерживает ли операция этот формат.
Если для артефакта уместна установка билета, условная последовательность может выглядеть так:
xcrun stapler staple "<путь-к-проверяемому-объекту>"
xcrun stapler validate "<путь-к-проверяемому-объекту>"
Эти команды не означают, что один и тот же путь подходит для любого способа доставки. Сначала проверьте соответствие формата текущим требованиям Apple; далее выполняйте операцию над объектом, предусмотренным вашим потоком публикации. Не переименовывайте или не перепаковывайте файл после проверки без повторной приёмки конечного результата.
Как подтвердить, что билет прикреплён? Выполните предусмотренную для данного формата проверку stapler и сохраните её вывод вместе с идентификатором отправки. Затем проверьте подпись и протестируйте именно тот архив, образ или установщик, который предназначен для скачивания; успешная проверка билета не подтверждает сама по себе, что весь сценарий установки и запуска прошёл.
На этапе приёмки разнесите проверки по смыслу:
- ответ заверения подтверждает обработку отправки;
- проверка билета подтверждает его доступность для проверяемого объекта;
- проверка подписи подтверждает состояние подписанного кода;
- установка или запуск проверяют практическую пригодность доставляемого пакета.
Проверяйте файл после всех преобразований, которые выполняются перед раздачей: создание архива, подготовку образа, копирование в хранилище или формирование установщика. Если производственный pipeline меняет конечный объект после заверения, повторно установите, сохраняются ли нужные свойства, и включите проверку именно получаемого пользователем файла.
Публикационная приёмка и выбор режима выпуска
Для первой приёмки используйте отдельную публикационную задачу, не связанную с автоматической раздачей пользователям. Пройдите полный маршрут: исходный коммит, сборка и экспорт, проверка подписи, отправка, чтение результата, обработка билета при необходимости и тест конечного дистрибутива. В журналах должны сопоставляться коммит, имя и контрольная сумма артефакта, идентификатор отправки и опубликованный файл.
При повторном запуске не перезаписывайте доказательства предыдущей попытки. Сохраняйте результат каждой отправки отдельно, чтобы отличить повтор после временной ошибки от новой сборки с изменённым кодом. Определите, кто отвечает за ротацию данных аутентификации, кто решает, допустим ли повтор, и кто восстанавливает процесс после частично завершившегося выпуска. Эти обязанности особенно важны, если публикация продолжается после завершения исходной сессии CI.
Выбирайте режим по состоянию доказательств:
- Если подпись проверена, результат обработки понятен, билет применён в соответствии с форматом, а тест конечного пакета пройден, то можно рассматривать автоматический выпуск.
- Если заверение прошло, но команда ещё не проверила установку или запуск конечного файла, то оставьте ручное подтверждение перед публикацией.
- Если невозможно связать отправку с конкретным исходником или релизным файлом, то приостановите выпуск и восстановите трассируемость.
- Если секрет попал в журнал или репозиторий, то остановите публикационный маршрут, отзовите или замените затронутые данные и проверьте журналы доступа до возобновления.
- Если формат конечного дистрибутива изменился после успешной отправки, то повторите проверку всей цепочки для фактического файла поставки.
Такой контрольный запуск выявляет не только ошибки Apple-инструментов. Он показывает, может ли удалённый Mac получить подписывающие ресурсы, создать ожидаемый пакет, передать его на заверение и сохранить проверяемые результаты без раскрытия секретов. Для общего понимания того, как устроен удалённый Mac на базе Mac mini, полезно заранее сопоставить требования конкретного CI с форматом удалённого доступа. Порядок подключения и организационные вопросы можно сверить в справочном центре NodeMini.
Если сейчас релиз строится на Linux-узле или рабочей станции без доступной macOS-среды, у такого решения есть реальные ограничения: невозможно локально выполнить весь Xcode-процесс на целевой платформе, подписание и тестирование приходится переносить на отдельный этап, а разнесённые по системам артефакты усложняют диагностику и контроль секретов. Mac, купленный для редких публикаций, в свою очередь, может простаивать между выпусками; постоянный узел оправдан прежде всего при устойчивой нагрузке и необходимости физического доступа к оборудованию.
Поэтому решение зависит от частоты релизов и требований к контролю. Если у команды уже есть подходящий Mac и стабильная эксплуатационная процедура, сначала проверьте на нём описанную цепочку. Если же для пробной публикации не хватает доступной macOS-среды, сравните локальный вариант с удалённым Mac и проверьте реальную задачу на подходящем арендном окружении NodeMini: результатом должен быть проверенный артефакт, а не только статус успешного CI job.