Минимальная безопасная схема — два Job: Claude Code GitHub Actions читает задачу, меняет код и передаёт фиксированный Commit SHA, а отдельный Job на удалённом Mac выполняет Xcode-сборку и тесты. Не направляйте внешний Pull Request на узел с общей подписью: для публикации нужны отдельный Runner, минимальные права и ручное подтверждение. Такая граница согласуется с официальными правилами использования Claude Code Action, политикой безопасности Actions и маршрутизацией по меткам.

Кому предназначена эта инструкция

Она нужна разработчикам, которые хотят автоматически обрабатывать Issue или Pull Request и затем проверять iOS- или macOS-проект в Xcode. Она также пригодится DevOps-инженерам, обслуживающим GitHub self-hosted runner на Mac, и ответственным за границы доступа агента к исходному коду, сети, Keychain и сертификатам.

Последнее обновление: 7 сентября 2026 года. Сведения сверены с документацией Claude Code Action, GitHub Actions self-hosted runners и Apple Xcode.

Сначала разделите изменение кода и проверку Apple-инструментами

Claude Code Action, Claude Code CLI, GitHub Actions Runner и Xcode — разные компоненты. Ошибка в архитектуре часто возникает именно из-за их смешения.

Claude Code Action может получить контекст Issue или Pull Request, выполнить агентную работу в рабочем каталоге и подготовить изменение. Runner лишь принимает Job и запускает команды. Xcode отвечает за сборку, тестирование и формирование результатов. Удалённый Mac не должен автоматически получать все полномочия первого Job только потому, что проект предназначен для Apple-платформы.

В рабочем процессе лучше создать такие границы:

Job Где выполняется Основная задача Чего не должно быть
Agent Job Обычный доверенный Runner Прочитать задачу, изменить код, создать патч или ветку Доступа к сертификатам и производственной подписи
Validation Job Помеченный удалённый Mac Получить конкретный Commit SHA, запустить Xcode и тесты Автоматического изменения кода агентом
Release Job Отдельный защищённый Mac Runner Архивировать и подписать после одобрения Запуска из внешнего PR

В рабочем процессе идентификаторы используйте как шаблоны: <ORG>, <REPO>, <BRANCH>, <COMMIT_SHA>, <RUNNER_LABEL>, <SCHEME>, <WORKSPACE_PATH>. Не вставляйте в публичный YAML реальные токены, Team ID или имена сертификатов.

Точка входа: Issue, Pull Request или ручной запуск

Для Issue и Pull Request событием должен быть только тот тип, который действительно нужен репозиторию. Если агент получает возможность менять workflow-файлы, это отдельный риск: изменение YAML может расширить права последующего Job.

Перед включением Action проверьте:

  • какие события запускают Agent Job;
  • может ли внешний автор изменить workflow;
  • разрешена ли запись в ветку или только создание отдельной ветки;
  • какие разрешения указаны в permissions;
  • передаётся ли результат как Pull Request, комментарий или артефакт;
  • какие файлы разрешены для изменения.

Официальная документация Claude Code Action описывает варианты запуска и аутентификации, а руководство по безопасному использованию GitHub Actions отдельно предупреждает о рисках недоверенного кода, секретов и изменяемых workflow.

Почему общий Runner не должен выполнять всё подряд

Обычный анализ Markdown, JavaScript или серверного кода не требует macOS. Если такой Job каждый раз занимает Mac, вы усложняете очередь, очистку и аудит. На Mac следует отправлять только шаги, где нужны Xcode, Simulator, Apple SDK или специфичный системный инструмент.

Маршрутизация должна быть явной:

jobs:
  validate-apple:
    needs: agent
    runs-on: [self-hosted, macOS, <RUNNER_LABEL>]
    steps:
      - name: Checkout exact commit
        uses: actions/checkout@v4
        with:
          ref: ${{ needs.agent.outputs.commit_sha }}
      - name: Build and test
        run: ./ci/validate-apple.sh

Версию используемого Action и конкретные параметры сверяйте с актуальными официальными примерами перед публикацией. Сам факт, что Runner отображается как online, не доказывает готовность Xcode или проекта.

Проведите проверку Xcode по фиксированному Commit SHA

После изменения кода Agent Job должен передать не «последнюю ветку», а точный Commit SHA. Иначе между завершением Claude Code и стартом Mac Job может попасть другой коммит, исправление от другого участника или изменение workflow.

Минимальная последовательность такая:

  1. Claude Code получает Issue или Pull Request.
  2. Agent Job создаёт изменение в отдельной ветке.
  3. Job фиксирует итоговый <COMMIT_SHA>.
  4. Validation Job выполняет checkout именно этого SHA.
  5. Скрипт проверяет проект, Scheme и зависимости.
  6. xcodebuild возвращает статус.
  7. Логи и результат тестов отправляются в проверку Pull Request.
  8. При ошибке процесс останавливается; агент не получает право бесконечно менять узел.

Apple описывает параметры командной строки Xcode в официальном справочнике xcodebuild. На практике проверка должна включать не только сам вызов команды, но и подготовку окружения:

set -euo pipefail

test -n "${COMMIT_SHA:-}"
git rev-parse HEAD
xcodebuild -version
xcodebuild -list -workspace "<WORKSPACE_PATH>"

xcodebuild \
  -workspace "<WORKSPACE_PATH>" \
  -scheme "<SCHEME>" \
  -destination 'platform=iOS Simulator,name=<SIMULATOR_NAME>' \
  test \
  -resultBundlePath "<RESULT_BUNDLE_PATH>"

Здесь <SIMULATOR_NAME> не следует считать гарантированно установленным. Сначала получите список доступных устройств, затем выберите только то, что соответствует проекту. Если Scheme не shared, зависимости не разрешаются или нужный SDK отсутствует, это ошибка подготовки проекта, а не повод чистить весь узел.

Важно. Не считайте успешным результатом строку «Runner connected». Приём Job, доступная версия Xcode, успешная компиляция и завершённые тесты — четыре разных свидетельства.

Какие доказательства возвратить в Pull Request

Для каждого запуска сохраняйте:

  • проверенный Commit SHA;
  • вывод xcodebuild -version;
  • выбранные workspace, Scheme и destination;
  • код завершения команды;
  • путь к .xcresult;
  • краткую структурированную причину сбоя;
  • идентификатор Runner и рабочий каталог;
  • отметку об очистке после задания.

Если сборка завершилась ошибкой, возвращайте сокращённый лог и ссылку на полный артефакт. Не разрешайте Claude Code произвольно удалять DerivedData, менять настройки Xcode или редактировать Runner. Повторная попытка должна иметь ограниченную причину и новый аудит.

Разведите командную сборку и Simulator-проверки

У Apple-проекта есть несколько режимов, и требования к удалённому Mac различаются.

Режим Что требуется от узла Приёмочное свидетельство Остановка
Командная сборка macOS, нужный Xcode, SDK, зависимости Успешный xcodebuild для фиксированного SHA Отсутствует SDK, Scheme или зависимость
Тесты в Simulator Доступный runtime и устройство .xcresult, код завершения, список тестов Simulator не запускается или тесты не стартуют
Графическая UI-проверка Рабочая пользовательская сессия и видимый Simulator Лог сессии, результат теста, состояние устройства Сессия закрыта, экран недоступен, задача зависла
Архив и подпись Изолированный Runner и защищённая среда Архив, подпись, журнал одобрения Нет ручного разрешения или найден внешний код

Документация Apple по автоматизации тестов помогает отделить командное выполнение от требований тестовой сессии. Удалённое подключение по SSH подходит для многих CLI-задач, но не является доказательством того, что графический сеанс, Simulator или UI-тест доступны после переподключения.

Можно ли использовать GitHub self-hosted runner на удалённом Mac

Да, удалённый Mac может быть self-hosted runner, если вы самостоятельно принимаете ответственность за операционную систему, обновления, рабочий каталог, сеть и очистку. GitHub прямо описывает self-hosted Runner как машину, которой управляет владелец репозитория или организации; её состояние не становится безопасным автоматически после регистрации.

Назначьте отдельную метку, например <RUNNER_LABEL>, и направляйте на неё только нужные Job. Документация GitHub по меткам Runner показывает механизм выбора узла. Доступ репозиториев ограничивайте через Runner Group, а не только через строку runs-on; соответствующие настройки описаны в документации по группам доступа.

Нужны также следующие условия:

  • отдельный пользователь для Runner;
  • рабочий каталог на каждый запуск или строгая очистка;
  • запрет соседним репозиториям читать остаточные файлы;
  • контроль исходящих сетевых соединений;
  • журнал запуска, источника и SHA;
  • запрет хранения производственных секретов в Agent Job.

Если проект не требует Simulator, выбирайте SSH-команду и headless-проверку. Если нужен UI-сеанс, заранее проверяйте, кто входит в систему, как запускается Simulator и что происходит при разрыве VNC или SSH.

Защитите подпись, архив и публикацию отдельным контуром

Claude Code должен менять исходный код, а не одновременно владеть сертификатами, профилями и токенами публикации. Для обычной проверки используйте неподписанную сборку, тестовую подпись или заранее определённый безопасный режим.

Внешний Pull Request нельзя передавать на Runner, где доступны:

  • сертификаты разработчика или распространения;
  • пароли Keychain;
  • профили подготовки;
  • токены публикации;
  • секреты других репозиториев;
  • скрипты, которые могут менять сам Runner.

Рекомендации Claude Code Action по безопасности следует сопоставить с документацией Apple по подписанному коду и архиву. Из этих источников не следует, что любой внешний PR безопасен на узле с подписью. Безопасность определяется вашей границей доверия, правами Job и способом хранения ключей.

Как избежать доступа Claude Code Action к сертификатам

Используйте отдельные Job и секреты. Agent Job не должен видеть переменные окружения, относящиеся к подписи. Validation Job получает только те входы, которые нужны тесту. Release Job запускается после одобрения защищённой среды.

Рекомендуемая логика:

  1. Внешний PR — только Agent Job и безопасная проверка без производительной подписи.
  2. Внутренняя ветка — Xcode-тесты на отдельном Mac Runner.
  3. Защищённая ветка — архивирование после ручного подтверждения.
  4. Публикация — отдельная среда, отдельный пользователь и отдельная запись аудита.

Не маскируйте секреты как обычные параметры скрипта. Не передавайте агенту полный вывод Keychain. Не устанавливайте профиль подписи в общий каталог, если после задания его можно прочитать следующему репозиторию.

Опыт эксплуатации. Кэш ускоряет повторные сборки, но одновременно может сохранить исходники, зависимости и промежуточные данные. Для общего Mac Runner выгода от кэша должна быть доказана журналом очистки, а не предполагаться.

Организуйте общие Mac Runner для нескольких репозиториев

Один удалённый Mac для нескольких проектов удобен, пока все репозитории имеют одинаковый уровень доверия. После смешения внутренних и внешних источников появляются остаточные файлы, общие кэши, процессы и случайно сохранённые учётные данные.

Разделите репозитории по группам:

  • доверенные внутренние проекты;
  • проекты с внешними Pull Request;
  • проекты, которым нужна только сборка;
  • проекты с тестовой или производственной подписью.

Для разных уровней используйте разные Runner Group, метки, учётные записи и рабочие каталоги. Общие сведения GitHub о self-hosted Runner не заменяют вашу процедуру изоляции: зарегистрированный Runner остаётся вашей машиной, а не одноразовым контейнером.

После каждого задания фиксируйте:

  • источник запуска;
  • репозиторий и Commit SHA;
  • рабочий каталог;
  • список установленных временных файлов;
  • результат очистки;
  • активные процессы;
  • состояние Simulator;
  • наличие временных Keychain или профилей.

Постоянный Runner или изоляция на каждый Job

Постоянный Runner проще поддерживать и быстрее возвращается в очередь. Но его состояние накапливается. Одноразовая изоляция снижает остаточный риск, однако на macOS её нельзя бездумно копировать из Linux-контейнеров: Xcode, Simulator, пользовательская сессия и системные компоненты требуют отдельной подготовки.

Выбирайте постоянный узел только при наличии регулярной очистки и мониторинга. Для недоверенного кода используйте отдельный узел, а не попытку «дочистить» общий после выполнения.

Проверьте перезапуск и восстановление цепочки

Восстановление после перезагрузки — часть приёмки, а не аварийная мелочь. Нужно проверить не только запуск процесса Runner, но и судьбу незавершённого Job.

Сценарий проверки:

  1. Запустите реальный Agent Job из тестового Issue.
  2. Передайте его Commit SHA в Validation Job.
  3. Выполните Xcode-сборку и тесты.
  4. Проверьте возврат .xcresult и структурированного лога.
  5. Перезапустите удалённый Mac в согласованный момент.
  6. Убедитесь, что Runner снова регистрируется и принимает новые задания.
  7. Проверьте, что прерванный Job не объявлен успешным.
  8. Повторно поставьте задачу в очередь только с новым идентификатором запуска.
  9. Сверьте очистку старого рабочего каталога.
  10. Зафиксируйте результат в эксплуатационном журнале.

Для этого используйте инструкции GitHub по обслуживанию self-hosted Runner. Восстановление процесса Runner не означает восстановление пользовательской графической сессии или Simulator. Эти состояния проверяйте отдельно.

Условия допуска к эксплуатации

Используйте такой условный выбор:

  • Если Agent Job не видит сертификаты, фиксирует SHA, а Mac Job возвращает реальный результат Xcode — допускайте разработческое испытание.
  • Если тесты работают, но после перезапуска теряется сессия или остаётся рабочий каталог — оставляйте только ограниченное командное использование.
  • Если внешний PR может попасть на Runner с производственной подписью — останавливайте внедрение и разделяйте узлы.
  • Если публикация запускается без ручного подтверждения — переводите Release Job в защищённую среду.
  • Если неизвестно, какой SHA был проверен, — не принимайте результат, даже если сборка завершилась успешно.
  • Если лог не содержит результата тестов или код возврата — считайте проверку неполной.

Для постоянной работы вам понадобится Mac, который можно изолировать, перезапустить и администрировать без ограничений. Если текущий Linux-Runner не имеет Xcode, Simulator и Apple SDK, его нельзя превратить в полноценный узел Apple-проверки только добавлением метки. Временный Mac mini на рабочем столе тоже создаёт расходы на покупку, электричество, доступ извне, резервирование и обслуживание.

Для пробного контура разумнее взять удалённый Mac в аренду: вы сможете проверить реальный проект, SSH-доступ, Xcode, возврат логов и восстановление Runner до принятия решения о длительном сроке. В вариантах аренды Mac mini выбирайте срок после успешной приёмки, а не до неё. Если вам важны постоянный CI-узел и полный административный доступ, ознакомьтесь также с условиями удалённого Mac для разработчиков.

Такой подход не отменяет самостоятельный Mac Runner. Он позволяет сначала проверить архитектуру на настоящем macOS-узле, не смешивая агентную работу, Apple-проверку и производственную подпись. После успешного тестового запуска вы уже сможете решить, нужен ли вам краткосрочный контур для разработки, общий узел команды или отдельный Mac для защищённого выпуска.