Корпоративный пул Mac CI: параллельный codesign, Keychain и provisioning profile

Когда несколько CI job на одном и том же Mac выполняют codesign, сбои выглядят как гонки за Keychain, дубли provisioning profile с одинаковым UUID или два пайплайна, которые пишут в один префикс DerivedData. Корпоративные пулы сочетают долгоживущие self-hosted runner с всплесками PR-очередей, поэтому вопрос дизайна простой: можно ли подписывать параллельно, не деля изменяемое доверенное состояние между несвязанными запусками. Ниже — границы ответственности keychain, раскладка профилей, корни рабочей области, поэтапный rollout и короткий сравнительный FAQ. Параллельные runner и гонки за диском и кэшем логично читать вместе с материалом 2026: несколько самохостинговых Mac runner и параллельный CI — как настроить GitHub Actions Cache и локальный постоянный диск? Гонки блокировок, заполненный диск и очистка артефактов: FAQ корпоративного пула, а права учёток, метки и совместная работа нескольких процессов runner — в заметке 2026 OpenClaw: пошаговое развёртывание и интеграция с автоматизацией — офлайн‑устойчивость кроссплатформенных агентов, права выполнения и совместная работа нескольких runner в GitHub Actions.

1. Режимы отказов, против которых вы на самом деле проектируете

Типичные поломки: повторный импорт в login keychain одной и той же пары, два файла профиля с одним UUID и разными entitlements, скрипты, которые молча предполагают один HOME, или job, удаляющий временные каталоги подписи, пока соседний архив ещё читает сертификат. В автоматизации особенно болезненны интерактивные запросы: они замирают до таймаута оркестратора и забивают очередь. Форма исправления: разнести секреты и изменяемые деревья по идентификатору job, по политике отключать UI-запросы в безнадзорных потоках и явно удалять артефакты подписи, чтобы ключи не переживали арендатора и не перетекали между веткой PR и релизной линией.

Правило большого пальца: если два job теоретически могут открыть один файл keychain или один и тот же путь профиля, под нагрузкой они это сделают — даже если на ноутбуке разработчика всё «случайно» серийное.

2. Стратегии Keychain: общий login против отдельного файла на job

Общий login keychain живёт ровно до тех пор, пока параллелизм не упирается в глобальные блокировки подписи и смешение учётных записей. Отдельный keychain на каждый запуск (путь от RUN_ID, разблокировка только на время job, удаление в finally) держит личности разъединёнными и даёт аудиторам простую историю: секрет на диске существовал только в рамках этого пайплайна. Компромисс — один keychain на сервисную учётку на статическом железе плюс низкий параллелизм на учётку и календарная ротация сертификатов вместо «на каждый коммит». Документируйте, делят ли GUI и SSH один и тот же keychain: смешанная отладка на продовых runner быстро возвращает гонки. Там, где бюджет позволяет, разводите интерактивные человеческие хосты и безнадзорные CI-хосты.

3. Provisioning profile: файловая раскладка и коллизии

Профили — это файлы с ключом UUID; дубликаты с разными capabilities дают плавающие ошибки codesign. Предпочтительнее локальная установка в workspace и явные specifier в настройках проекта вместо бесшумного заполнения ~/Library/MobileDevice/Provisioning Profiles. Если глобальная папка неизбежна, копируйте профили в подкаталог на job и не перетирайте чужие UUID. Владельцев профилей привязывайте к bundle id и capability, чтобы линия поддержки знала, кого дергать при истечении.

4. Изоляция рабочей области шире, чем только подпись

Изолируйте также DerivedData, кэши SwiftPM и CocoaPods, а также промежуточные каталоги нотаризации — например единый корень вида /Volumes/builds/<job>. Направьте туда же TMPDIR. При повторном использовании runner делайте пост-job очистку workspace и job keychain; тёплые кэши держите на томах с ключом по версии Xcode, чтобы entitlements не «перетекали» между ветками с разной конфигурацией.

5. FAQ: сравнение шаблонов одним взглядом

В: Один Apple ID и один keychain на много репозиториев? Возможно, но связность высокая; подавайте секреты файлами и импортируйте в keychain уровня job, чтобы радиус поражения совпадал с границей запуска.

В: Эфемерные VM против статических mini? VM дают чистый сброс; статические узлы остаются тёплыми для инкрементальных сборок — сочетайте их со скриптами очистки и не переиспользуйте keychain между уровнями комплаенса.

В: Match и расшифровка? Только рабочая область job и одноразовый keychain — не общий login keychain с долгоживущими ключами.

В: Разделить App Store и enterprise-подпись? Разные учётки или хосты, когда политики расходятся, чтобы export-профили не пересекали архивы.

В: Нотаризация и stapling при параллели? Сериализуйте нотариальные креденшлы по команде или изолируйте API-ключи так же, как ключи подписи; токены загрузки — полноценные секреты с той же гигиеной на job.

6. Шаги внедрения, которые переживают ревью ИБ

  1. Инвентаризация сертификатов и профилей: keychain, пути Library, Fastlane.
  2. Канареечный запуск отдельных keychain на job; по часам влияние обычно мало по сравнению с компиляцией.
  3. Перенос профилей в workspace; CI падает на дубликат UUID до merge.
  4. Уникальные OBJROOT/SYMROOT/DSTROOT на job в шаблонах оркестратора.
  5. Документ отзыва: какая личность на каком пуле и как безопасно дренировать хосты.

7. Чеклист оператора перед повышением параллелизма

  • Создаёт и удаляет ли каждый job свой файл keychain по детерминированному пути?
  • Профили закреплены по версии и ставятся без перетирания параллельных UUID?
  • HOME или как минимум переменные подписи ограничены job, а не дефолтом машины?
  • Скрипты очистки убирают приватные ключи с диска даже при обрыве job посередине?
  • Протестированы ли два одновременных archive на том же классе runner, а не только последовательные сборки?

Почему «настоящий» Mac mini по-прежнему выигрывает у пулов с тяжёлым подписанием

Стек подписи Apple рассчитан на поддерживаемое Mac-железо и прошивку — то, что узлы Mac mini дают без обходных путей, — плюс сильная производительность CPU на ватт для связки «скомпилировал — подписал — упаковал». Gatekeeper, SIP и штатное шифрование диска упрощают разговор с ИБ по сравнению с разрозненными PC-фермами, а низкое энергопотребление Apple Silicon в простое делает тёплые пулы экономически терпимыми.

Стандартизируйте узлы класса Mac mini M4 с правилами изоляции выше, масштабируйтесь вширь раньше, чем перегрузите одну интерактивную сессию логина, и сверяйте регионы с политикой данных на главной странице Macstripe. Если вы хотите прогнать описанную схему на самом отзывчивом железе без длинного цикла закупки, Mac mini M4 сейчас самый прагматичный вход: возьмите выделенный облачный Mac, зафиксируйте per-job keychain и workspace — и параллельный codesign перестанет быть лотереей.