Статус Archive меняется на ошибку подписи, а CI не может экспортировать IPA без диалога.
Быстрое решение: для Organizer и редких ручных публикаций выбирайте облачно управляемую подпись, для xcodebuild, fastlane и CI — контролируемую локальную Apple Distribution; небольшой команде нужна изолированная двухконтурная схема.

Эта статья для вас, если вы отправляете TestFlight через Xcode Organizer и хотите меньше обслуживать сертификаты. Она также предназначена для владельцев автоматизированного удалённого Mac и небольших команд, где необходимо разделить Apple аккаунты, Keychain, приватные ключи и права публикации.

Карта решений по роли выпуска

«Облачная подпись Xcode» и локальная подпись — не два равнозначных переключателя одного уровня. Облачное управление сертификатом, автоматическое управление подписью, локальная Apple Distribution, Provisioning Profile и учётные данные App Store Connect решают разные задачи.

Ваша задача Основной выбор Почему Резервный путь
Archive и отправка через Organizer вручную Облачная подпись Меньше импорта и ручной ротации сертификатов Локальная Apple Distribution для аварийного выпуска
xcodebuild и -exportArchive без пользователя Локальная Apple Distribution CI должен получить идентичность и приватный ключ без диалога Двухконтурная схема после проверки конкретного проекта
fastlane и регулярный выпуск Локальная подпись в отдельном Keychain Процессу нужны воспроизводимые профили и права доступа Облачный режим только после подтверждённого теста
Несколько разработчиков на одном Mac Разделённые пользователи и Keychain Снижается радиус утечки Запрет экспорта распределительной идентичности
Ручная публикация плюс CI Два контура Каждый процесс получает только необходимый доступ Единый локальный контур с более строгой изоляцией

Apple описывает облачно управляемые сертификаты отдельно от общего обзора сертификатов и подписывания. Поэтому начинать нужно не с вопроса «какой сертификат новее», а с точки входа в выпуск: Organizer, автоматический экспорт или служба CI. Сверьте текущие ограничения с документацией Apple о cloud-managed certificates и обзором типов сертификатов.

Ручной Organizer для независимого разработчика

Если вы один раз в день или неделю создаёте Archive, открываете Organizer, выбираете Distribute App и отправляете сборку в TestFlight, облачно управляемая подпись обычно требует меньше ручной работы. Это не отменяет проверку команды, Bundle ID и разрешений. Она лишь переносит часть управления сертификатом в поддерживаемый Apple процесс.

Преимущества для такого сценария:

  • не нужно вручную переносить каждую локальную идентичность между рабочими станциями;
  • проще восстановить ручной поток после замены удалённого Mac;
  • меньше вероятность, что вы забудете обновить профиль перед обычной публикацией;
  • публикация остаётся видимой в интерфейсе Organizer.

Ограничения тоже существенны:

  • режим автоматической подписи не доказывает, что экспорт из CI будет работать;
  • профиль, Bundle ID и Team должны соответствовать проекту;
  • право разработчика в Apple Developer Program не равно праву выполнять все операции в App Store Connect;
  • успешный Archive ещё не равен успешной загрузке в TestFlight.

Для ручного выпуска проверяйте две независимые зоны. В Xcode откройте Signing & Capabilities и убедитесь, что выбраны правильные Team и Bundle Identifier. Затем проверьте роль аккаунта и состояние приложения в описании процесса распространения приложения через Xcode.

Приёмка первой публикации

После первой реальной отправки не ограничивайтесь зелёным статусом в Organizer. Сохраните:

  • название Archive и время его создания;
  • журнал Distribute App;
  • идентификатор загруженной сборки;
  • статус обработки в App Store Connect;
  • результат установки TestFlight на тестовое устройство;
  • сведения о том, какой Apple аккаунт выполнил публикацию.

Это важнее абстрактного утверждения «облачная подпись включена». Вы получаете проверяемую цепочку: Archive — экспорт — загрузка — обработка — установка.

CLI и fastlane на удалённом Mac

Автоматизированный выпуск устроен строже. xcodebuild и fastlane не могут рассчитывать на окно авторизации, ручное подтверждение Keychain или случайно сохранённую сессию Xcode. Runner должен выполнить Archive, экспортировать IPA и завершить публикацию в предсказуемом окружении.

Типичный минимальный набор команд выглядит так:

xcodebuild \
  -workspace <WORKSPACE_PATH> \
  -scheme <SCHEME_NAME> \
  -configuration Release \
  -archivePath <ARCHIVE_PATH> \
  archive

xcodebuild \
  -exportArchive \
  -archivePath <ARCHIVE_PATH> \
  -exportOptionsPlist <EXPORT_OPTIONS_PATH> \
  -exportPath <EXPORT_PATH>

Значения в угловых скобках — только placeholders. Не помещайте в репозиторий реальный Team ID, Bundle ID, пароль Keychain, путь с именем пользователя или токен публикации.

Локальная Apple Distribution нужна автоматизированному процессу не из-за самого слова «локальная», а потому что экспорт должен найти согласованную пару:

  • сертификат распространения;
  • приватный ключ в доступном Keychain;
  • подходящий Provisioning Profile;
  • параметры экспорта;
  • разрешения процесса CI на чтение ключа.

Проверять наличие идентичности можно в отдельном сеансе удалённого Mac:

security find-identity -v -p codesigning <KEYCHAIN_PATH>

Путь также оставляйте условным. Команда должна показать ожидаемую подписывающую идентичность, но сама по себе ещё не подтверждает успешный экспорт. После сборки проверяйте IPA и журнал -exportArchive. Apple отдельно описывает параметры сборки в справочнике Build Settings, а правила создания distribution-signed code — в документации о подписанном коде для распространения.

Почему автоматическая подпись не решает всё

Включённая настройка Automatically manage signing может помочь Xcode подобрать профиль в интерактивном сценарии. Но fastlane запускает другой набор действий. Он может обращаться к экспорту, отдельному пользователю macOS, очищенному окружению или закрытому Keychain.

Поэтому проверяйте фактические артефакты:

codesign -dv --verbose=4 <APP_PATH>
unzip -l <IPA_PATH>
security find-identity -v -p codesigning <KEYCHAIN_PATH>

Ищите в выводе идентичность подписи, корректное приложение внутри IPA и ожидаемые файлы профиля. Если процесс останавливается на User interaction is not allowed, это сигнал проверить разблокировку Keychain и разрешение CI-службы. Не подменяйте проблему переключением режима без журнала: можно получить успешную локальную сборку и неисправный ночной выпуск.

Общий удалённый Mac для небольшой команды

В общей среде самый опасный вопрос звучит не как «облачная или локальная подпись», а как «кто может извлечь приватный ключ». Один macOS-сеанс, один вход Xcode и один общий Keychain превращают любой доступ к машине в потенциальный доступ к распределительной идентичности.

Разделите контуры:

  • Apple Developer Program — управление идентификаторами, сертификатами и профилями;
  • App Store Connect — загрузка, TestFlight и управление приложением;
  • macOS-пользователь — файловые права и доступ к сеансу;
  • Keychain — хранение сертификата и приватного ключа;
  • CI-служба — запуск автоматической сборки;
  • исходный код — отдельная область доступа.

Роли App Store Connect не следует считать взаимозаменяемыми. Проверьте, кто может выполнять публикацию, кто видит приложение, а кто только просматривает сведения, используя официальную таблицу ролей App Store Connect.

Практическая схема для команды:

  1. Создайте отдельного macOS-пользователя для CI.
  2. Используйте отдельный Keychain, а не личный ключ разработчика.
  3. Разрешите CI-службе только нужную операцию подписи.
  4. Не передавайте всем участникам пароль от Keychain.
  5. Разделите право изменения сертификатов и право загрузки сборки.
  6. Удаляйте доступ подрядчика после завершения работ.
  7. Перед отзывом сертификата проверьте, какие приложения и Runner его используют.

Apple также описывает перенос и совместное использование signing certificates в документации о синхронизации идентичностей. Любая передача сертификата с приватным ключом должна рассматриваться как передача секретного материала, а не как обычный файл проекта.

Несколько приложений и временные участники

Общий удалённый Mac часто обслуживает несколько Bundle ID. Это удобно, но увеличивает радиус ошибки. Если один участник получает широкий доступ к локальному Keychain, проблема уже не ограничивается его приложением.

Для нескольких приложений применяйте принцип минимального доступа:

  • отдельная идентичность для автоматического выпуска, если это оправдано процессом;
  • отдельные профили для разных Bundle ID;
  • отсутствие приватных ключей на Runner, который только собирает исходники;
  • отдельный пользователь для долгоживущих задач;
  • журналирование загрузок и изменений прав;
  • заранее сохранённый способ остановить публикацию.

Временный подрядчик или внешний разработчик не обязан получать доступ к distribution private key. Если ему нужен только результат сборки, выдайте исходный код и тестовый контур, а подпись оставьте владельцу проекта. Если автоматический Runner должен подписывать самостоятельно, используйте отдельную контролируемую идентичность с ограниченным сроком применения и понятной процедурой отзыва.

Контрольный список перед изменением подписи

  • [ ] Вы зафиксировали последний рабочий Archive и IPA.
  • [ ] В журнале указаны Team, Bundle ID и фактическая идентичность подписи.
  • [ ] Понятно, какие приложения используют текущий сертификат.
  • [ ] Приватный ключ сохранён в защищённом резервном контуре.
  • [ ] Есть отдельный план для Organizer и для CI.
  • [ ] Keychain доступен именно пользователю, запускающему сборку.
  • [ ] После перезапуска Mac известны условия восстановления.
  • [ ] Отзыв сертификата не выполняется до успешной проверки запасного пути.
  • [ ] Временные учётные записи и разрешения можно удалить без остановки проекта.
  • [ ] Реальный TestFlight-выпуск будет повторён после изменения.

Ответы для частых рабочих ситуаций

Автоматическая подпись и удалённый Mac

Импорт распределительного сертификата не всегда требуется для ручной отправки через Organizer. Но удалённая машина должна иметь согласованные Team, Bundle ID и профиль, а аккаунт — необходимые разрешения. Для CI проверяйте не только настройки Xcode, но и экспорт IPA из чистого сеанса. Если профиль получается автоматически, это ещё не означает, что приватный ключ доступен без взаимодействия пользователя.

fastlane без участия пользователя

Облачный режим нельзя объявлять совместимым со всеми задачами fastlane заранее. Сценарий зависит от того, как проект создаёт Archive, получает профиль, выполняет экспорт и передаёт сборку в App Store Connect. Проведите тест на отдельном Runner: очистите интерактивную сессию, запустите lane, сохраните лог и проверьте подпись IPA. При отказе настройте локальную Apple Distribution.

Защита приватного ключа в общей среде

Никогда не используйте общий логин и общий Keychain для всех разработчиков. Разделите пользователя CI, личные сеансы и административный доступ. Ограничьте чтение ключа процессом сборки, не храните пароль в репозитории и не показывайте секреты в логах. App Store Connect также разделяйте по ролям: право загрузки не должно автоматически означать право менять сертификаты.

Переход после ошибки облачной подписи

Сначала отделите ошибку аккаунта или профиля от ошибки самой подписи. Сохраните журнал, Archive и экспортные параметры. Затем проверьте локальный сертификат, приватный ключ и доступ CI к Keychain. Только после этого решайте, нужен ли локальный Apple Distribution. Отзыв прежней идентичности без рабочего резервного выпуска может остановить несколько приложений сразу.

Сравнение затрат обслуживания и риска

Ниже нет искусственных ценовых оценок: выбор определяется не только стоимостью удалённого Mac, но и временем восстановления, числом участников и последствиями утечки ключа.

Критерий Облачное управление Локальная Apple Distribution
Ручной Organizer Обычно удобнее Требует подготовленного Keychain
Ночной CI Нельзя предполагать совместимость Подходит после проверки доступа к ключу
Перенос на другой Mac Меньше ручного импорта в поддерживаемом сценарии Нужны сертификат, приватный ключ и профиль
Контроль приватного ключа Ограниченный видимостью Apple-процесса Полный контроль владельца среды
Ошибка восстановления Зависит от доступности облачного сценария Зависит от резервной копии и изоляции
Общая команда Не отменяет разделение ролей Требует строгой изоляции Keychain

Матрица выбора по операционному сценарию

Сценарий Что выбрать сначала Что проверить до выпуска Когда добавить второй контур
Один разработчик, редкий TestFlight Облачное управление Реальный Organizer upload и обработка сборки Если появляется CI или частый выпуск
Один разработчик, fastlane Локальная идентичность Headless export и восстановление Keychain Если ручной выпуск должен остаться независимым
Два и более разработчика Разделённые учётные записи Роли, пользователи macOS и журнал доступа При совмещении ручного и ночного выпуска
Временный подрядчик Без доступа к ключу Проверка результата владельцем Если подрядчику нужен ограниченный Runner
Несколько приложений Изолированные профили и права Радиус отзыва и список зависимых задач При общей CI-инфраструктуре

Приёмочная таблица удалённой среды

Проверка Ожидаемый результат Действие при отказе
Archive через Organizer Archive создаётся без лишних диалогов Проверить Team, Bundle ID и автоматическую подпись
Экспорт IPA -exportArchive завершается в headless-сеансе Проверить Keychain, сертификат и профиль
Подпись приложения codesign показывает ожидаемую идентичность Сопоставить сертификат и приватный ключ
Загрузка в App Store Connect Сборка появляется и проходит обработку Проверить роль и состояние приложения
Перезапуск Mac CI восстанавливает доступ по утверждённой процедуре Не считать среду готовой до исправления
Отзыв доступа Удалённый участник больше не может подписывать Немедленно пересмотреть Keychain и роли

Финальный выбор и план перехода

Выбирайте облачно управляемую подпись, если вы публикуете вручную через Organizer, не строите headless-процесс и хотите сократить обслуживание сертификатов. Выбирайте локальную Apple Distribution, если выпуск выполняют xcodebuild, fastlane или CI без человека. Выбирайте оба контура, если ручная публикация и автоматизация должны пережить отказ друг друга.

Перед изменением среды выполните один полный цикл: Archive, экспорт IPA, загрузка в TestFlight, проверка обработки и повтор после перезапуска удалённого Mac. Если текущий хост не поддерживает отдельного пользователя, устойчивый Keychain и восстановление после перезагрузки, проблема уже не в выборе типа подписи. В таком случае разумно оценить удалённый Mac с полным доступом для сборки или подобрать вариант аренды Mac mini с нужным уровнем доступа.

Локальная подпись даёт контроль, но требует резервного плана, дисциплины прав и безопасного хранения ключа. Облачное управление уменьшает ручные операции, но не превращает любой CLI-процесс в готовый CI. Если вам нужен временный или постоянно доступный Mac для проверки Archive и TestFlight, аренда MACCOME может быть практичнее текущей среды, где общий сеанс, непостоянный Keychain и восстановление после перезапуска мешают выпуску.