Cross-Repository CI Relay: как PyTorch решает проблему слепых зон в экосистеме
Когда разработчик Intel XPU открывает pull request в pytorch/pytorch, он не может узнать, сломал ли его изменения downstream-бэкенд. До июня 2026 года maintainers аппаратных проектов (Intel, AMD, Apple, Qualcomm) полагались на ручной polling, ad-hoc скрипты или вообще не тестировали интеграцию с основным репозиторием PyTorch. Результат: сломанные бэкенды обнаруживались через недели, когда пользователи уже страдали от regression.
Cross-Repository CI Relay (CRCR) закрывает эту дыру с помощью полностью автоматизированного pipeline, который связывает upstream-события PyTorch с downstream CI и возвращает статусы обратно в единую панель мониторинга. Это не просто webhook-обёртка — это распределённая система с 5-ступенчатой моделью безопасности, 4-уровневой матрицей доступа и реальной наблюдаемостью для инфраструктурных команд.
Проблема: почему обычный CI не работает для экосистемы
PyTorch сидит в центре огромной экосистемы. Аппаратные бэкенды (Intel XPU, AMD ROCm, Apple MPS, Qualcomm AI Engine) поддерживают собственные репозитории с кастомными операторами и ядрами. Проекты вроде vLLM, SGLang и Hugging Face Transformers зависят от PyTorch как фундаментальной библиотеки. Даже внутри самого PyTorch некоторые бэкенды частично in-tree (CPU-архитектурно-специфичный код), а другие полагаются на CI, работающий вне основного test suite.
PyTorch имеет зрелый upstream CI с merge-blocking checks, label-driven workflows и rerunnable PR checks, но он запускается только на pytorch/pytorch. Downstream-репозитории до CRCR не имели стандартного способа узнать, когда тестировать, как получить результаты обратно, и где смотреть агрегированную картину. Каждый бэкенд изобретал свой велосипед: кто-то использовал GitHub Actions с repository_dispatch, кто-то писал custom Lambda-функции, кто-то просто полагался на ручные триггеры через Slack-уведомления.
Результат: когда maintainer PyTorch менял внутренний API, он не знал, какие downstream-проекты сломаются, до тех пор пока пользователи не начинали жаловаться. Когда downstream-бэкенд ломался, maintainer PyTorch узнавал об этом из issue через несколько дней. Отсутствовала централизованная видимость состояния экосистемы.
Решение: как работает Cross-Repository CI Relay
CRCR — это fully automated pipeline, который связывает upstream-события PyTorch с downstream CI и маршрутизирует статусы обратно в PyTorch CI HUD. Вот как это работает:
PR в PyTorch триггерит relay через webhook. Relay dispatches ко всем зарегистрированным downstream-репозиториям. Эти репозитории запускают workflows в своём CI и сообщают статус обратно через authenticated callback. Результаты появляются на PyTorch HUD в течение секунд.
Система использует tiered allowlist для поддержки инкрементального onboarding и дифференцированного доступа. Downstream-репозитории проходят через 4 уровня по мере зрелости:
Уровень L1 (Notification tier) — репозиторий получает dispatches, но не отправляет результаты обратно. Это начальный уровень для проектов, которые только начинают интеграцию и хотят понять, как часто их нужно тестировать.
Уровень L2 (Full pipeline) — полный цикл: dispatch + HUD reporting. Репозиторий получает триггеры и отправляет статусы обратно. Это рабочий уровень для большинства бэкендов.
Уровень L3 (Merge gating) — результаты могут использоваться для блокировки upstream-merge, когда критические downstream-бэкенды сломаны. Это высший уровень доверия, который требует стабильной истории и валидации.
Уровень L4 (Reserved) — зарезервирован для будущих расширений, связанных с автоматическим rollback и продвинутой аналитикой.
Архитектура: от webhook до HUD
Система построена на пяти компонентах, каждый из которых решает конкретную задачу:
Webhook Lambda (Python 3.12, AWS Lambda) получает GitHub webhooks и fan-out dispatches ко всем зарегистрированным репозиториям. Callback Lambda (Python 3.12, AWS Lambda) верифицирует OIDC-токены, применяет state machine и форвардит данные в HUD. Redis (Amazon ElastiCache с TLS) хранит state machine, allowlist cache и rate limiting. HUD API (Next.js на Vercel) принимает данные relay и пишет в DynamoDB. DynamoDB (таблица torchci-oot-workflow-job) — первичное хранилище для downstream CI-записей. ClickHouse (таблица default.oot_workflow_job) — аналитические запросы для HUD frontend. Replicator (AWS Lambda через DynamoDB Streams) — real-time репликация из DynamoDB в ClickHouse. Callback Action — composite GitHub Action для OIDC minting и payload delivery для downstream-репозиториев.
Система проходит пять стадий: webhook приём, dispatch fan-out, downstream execution, callback verification, HUD ingestion. Каждая стадия логируется в CloudWatch для отладки и аудита.
Модель безопасности: 5 уровней валидации
Принятие CI-результатов из внешних репозиториев в инфраструктуру PyTorch требует тщательного security design. Relay применяет пять стадий валидации до того, как любые данные достигнут HUD.
Стадия 1: OIDC Identity Verification. Callback action генерирует GitHub OIDC-токен с audience pytorch-cross-repo-ci-relay. Callback Lambda верифицирует этот токен против публичного JWKS endpoint GitHub, используя RS256. Claim repository в токене криптографически привязан к вызывающему репозиторию — workflow в org/repo-a не может создать токен, утверждающий, что он от org/repo-b. Это основа trust model: relay никогда не доверяет self-reported identity.
Стадия 2: Allowlist Authorization. После верификации идентичности relay проверяет, что репозиторий находится в allowlist. Allowlist хранится в Redis с TTL для снижения нагрузки на DynamoDB. Если репозиторий не в allowlist, callback отклоняется с HTTP 403.
Стадия 3: Rate Limiting. Каждый репозиторий имеет лимит на количество callback'ов в единицу времени. Это защищает от accidentally или maliciously flood, когда сломанный workflow начинает спамить status updates. Rate limiter реализован через Redis sliding window.
Стадия 4: State Machine Validation. Callback должен соответствовать ожидаемой последовательности состояний: DISPATCHED → IN_PROGRESS → COMPLETED. Relay отслеживает state machine для каждого dispatch и отклоняет callbacks, которые нарушают последовательность (например, COMPLETED без IN_PROGRESS). Это защищает от race conditions и duplicate callbacks.
Стадия 5: Data Separation. Downstream CI-данные хранятся в отдельной таблице DynamoDB (torchci-oot-workflow-job) и отдельной таблице ClickHouse (default.oot_workflow_job). Это изолирует downstream-данные от upstream CI-данных и предотвращает accidental cross-contamination в запросах и дашбордах.
Известные ограничения и что они значат
CRCR аутентифицирует identity, но не correctness. Каждый downstream-репозиторий отвечает за точность своих callbacks. Компрометированный maintainer allowlisted репозитория может подделывать conclusion values в будущих callbacks — например, сообщая success для failing CI run. Impact ограничен отображением некорректных данных на HUD; это не может повлиять на build-инфраструктуру PyTorch, внедрить код в upstream или повлиять на merge decisions (если репозиторий не на будущем gating tier).
Митигации: поле verified_repo всегда идентифицирует реального вызывающего (OIDC-guaranteed). Misbehaviour наблюдаем в HUD-данных и CloudWatch logs. Оффендящий репозиторий может быть удалён из allowlist, немедленно отзывая доступ. Cross-validating reported conclusions против GitHub Check Run API — это future work, который добавит дополнительный уровень проверки.
Метрики CI: queue time и execution time
Relay вычисляет две timing-метрики из state machine timestamps. Queue time — время между DISPATCHED (webhook отправляет repository_dispatch) и IN_PROGRESS (downstream job starts). Это измеряет GitHub Actions queue delays. Execution time — время между IN_PROGRESS и COMPLETED. Это измеряет фактическую длительность CI execution.
Эти метрики форвардятся в HUD в trusted.ci_metrics блоке и отображаются на дашборде, давая инфраструктурным командам видимость как platform-level queuing, так и per-backend test performance. Если queue time для AMD ROCm внезапно вырастает с 2 минут до 15 минут, инфраструктурная команда может investigate GitHub Actions capacity issues или scheduler problems.
HUD Dashboard: единая панель для всей экосистемы
Результаты CRCR отображаются на PyTorch CI HUD по адресу hud.pytorch.org/crcr. Summary страница (/crcr) показывает агрегированные pass rates, количество jobs и среднее время выполнения для всех бэкендов за последние 14 дней. Backend dashboard (/crcr/{org}/{repo}) показывает per-PR matrix view с индивидуальными результатами jobs, количеством тестов и временем выполнения для конкретного бэкенда.
Дашборд использует ту же ClickHouse-backed query инфраструктуру, что и остальной PyTorch CI HUD, обеспечивая консистентную производительность и знакомый UX для maintainers. Это означает, что maintainer PyTorch может открыть один дашборд и увидеть состояние как in-tree CI, так и всех downstream-бэкендов в реальном времени.
Что нужно сделать downstream-репозиториям
Integration burden на downstream-репозитории минимальна. Репозиторию нужно: быть добавленным в allowlist (одна строка в YAML), добавить workflow file, который слушает repository_dispatch events, использовать composite callback action для отчётов in_progress и completed.
Минимальный downstream workflow включает repository_dispatch trigger для pull_request events, permissions с id-token: write для OIDC token minting, и два шага callback — один для статуса in_progress в начале работы, другой для статуса completed с результатом в конце. Это всё, что нужно для получения dispatches и отправки результатов обратно.
Что дальше
В планах команды: stale job cleanup — scheduled job для обнаружения и маркировки in_progress записей, которые никогда не получили completion callback. Upstream merge gating — использование L3/L4 tier результатов для опциональной блокировки upstream merges, когда критические downstream-бэкенды сломаны. Push event support — расширение dispatch beyond pull request events для покрытия post-merge CI на main branch.
CRCR был спроектирован и реализован как коллаборация между PyTorch Foundation infrastructure team и Linux Foundation. Ревьюеры и инфраструктурные инженеры, которые помогли сформировать систему, включают @malfet, @albanD, @atalman, @jathu, @zxiiro, @fffrog, @KarhouTam и @can-gaa-hou.
Часто задаваемые вопросы
Как CRCR отличается от обычного GitHub Actions workflow?
CRCR решает проблему координации между репозиториями. Обычный GitHub Actions workflow работает только в рамках одного репозитория. CRCR автоматически триггерит downstream workflows при изменениях в upstream, верифицирует идентичность через OIDC, и агрегирует результаты в единой панели мониторинга. Это не замена GitHub Actions, а оркестрационный слой поверх него.
Что произойдёт, если downstream-репозиторий сломается?
Если downstream-репозиторий ломается, его CI сообщает failure через callback. Это отображается на HUD как красный индикатор. Если репозиторий на уровне L3 (merge gating), это может заблокировать upstream merge до тех пор, пока проблема не будет решена. На уровнях L1/L2 это просто видимость — maintainers PyTorch видят, что downstream сломан, но могут продолжить merge, если это не критично.
Как обеспечивается безопасность OIDC-токенов?
GitHub OIDC-токены генерируются автоматически для каждого workflow run и имеют короткий срок жизни (обычно 5-10 минут). Audience claim гарантирует, что токен может быть использован только для конкретного сервиса (pytorch-cross-repo-ci-relay). Repository claim криптографически привязан к вызывающему репозиторию и не может быть подделан. Callback Lambda верифицирует подпись токена против публичного JWKS endpoint GitHub, используя RS256. Это стандартная industry practice для secure service-to-service authentication.
Какие бэкенды уже интегрированы?
На момент запуска интегрированы Intel XPU, AMD ROCm, Apple MPS и Qualcomm AI Engine. Проекты экосистемы (vLLM, SGLang, Hugging Face Transformers) находятся в процессе onboarding. Allowlist публична и находится в pytorch/pytorch/.github/allowlist.yml, так что любой downstream-репозиторий может запросить добавление через PR.
Как CRCR обрабатывает flaky tests?
CRCR не обрабатывает flaky tests напрямую — это ответственность downstream-репозиториев. Однако метрики queue time и execution time помогают выявить infrastructure issues, которые могут вызывать flaky behavior. Если execution time для конкретного бэкенда значительно варьируется между runs, это сигнал для инфраструктурной команды investigate resource contention или network issues.
Итог
Cross-Repository CI Relay закрывает критический пробел в инфраструктуре PyTorch: отсутствие автоматизированного тестирования downstream-бэкендов при изменениях в upstream. Система использует стандартные industry practices (OIDC, state machines, rate limiting) для обеспечения безопасности и наблюдаемости. Для maintainers downstream-репозиториев это означает меньше ручного polling и лучшую видимость. Для maintainers PyTorch это означает уверенность в том, что изменения не сломают экосистему незаметно. Если вы поддерживаете out-of-tree PyTorch бэкенд, интеграция занимает менее часа и даёт немедленную ценность через автоматические триггеры и централизованный мониторинг.