Commit 5f8dd50
[CRCR] Initial implementation of L2 (#7967)
## Author
- @KarhouTam
- @can-gaa-hou
- @fffrog
## Summary
- This PR implements the L2 levels of the cross-repository CI relay
described in pytorch/rfcs#90.
- For the previous L1 implementation, please refer to
#7847.
- Please refer to
pytorch/rfcs#90 (comment) for the
overall implementation.
- Please refer to pytorch/rfcs#96 for the design
of HUD side.
- Please refer to #8069 for
the implementation of HUD side.
Higher-level behaviors for `L3` and `L4` are intentionally left for
follow-up work.
## Architecture
The relay is split into two AWS Lambda functions:
- `webhook` lambda function (Updated)
- [x] receives GitHub webhook PR and push events from the upstream repo
- [x] validates webhook signatures and authenticates with AWS Secret
Manager
- [x] reads the downstream whitelist from the URL and stores it in Redis
- [x] for `opened`/`reopened`/`synchronized`/`closed` actions, forwards
repository_dispatch events to downstream repos
- `callback` lambda function (Added)
- [x] receives downstream callback payload through a public lambda
function URL
- [x] validates callback payload with OIDC
- [x] reads the downstream whitelist from the URL and stores it in Redis
- [x] extracts CI result information from the payload and uploads to
PyTorch HUD
- [x] records `queue time` and `execute time` for evolution to `L3` repo
## Changes
```md
..github/
├── workflows/
│ └── _lambda-do-release-runners.yml # Updates the Lambda release workflow to include cross-repo-ci-relay packaging/release
│
└── actions/
└── cross-repo-ci-relay-callback/
└── action.yml # Composite action used by downstream workflows to report status back to the relay/result endpoint
aws/lambda/cross_repo_ci_relay/
├── tests/ # Unit tests for allowlist/config/webhook/result/redis behavior
├── README.md # Project overview, local development, callback flow, and result-side validation steps
├── Makefile # Top-level local developer entrypoint for test / deploy / clean
├── local_server.py # FastAPI wrapper for local end-to-end testing of both webhook and result endpoints
├── requirements.txt # Python dependencies required by the relay Lambdas
│
├── utils/
│ ├── allowlist.py # Loads, parses, and queries the downstream allowlist by rollout level
│ ├── config.py # Shared runtime config loading and cached get_config() helper
│ ├── gh_helper.py # GitHub App, repository_dispatch, and GitHub file access helpers
│ ├── hud.py # HUD write helpers for downstream result reporting
│ ├── jwt_helper.py # Helpers for minting/verifying relay callback tokens
│ ├── redis_helper.py # Redis helpers for allowlist cache, OOT state, and timing data
│ └── misc.py # Shared TypedDict definitions and HTTPException
│
├── webhook/
│ ├── Makefile # Build/package/deploy commands for the webhook Lambda
│ ├── lambda_function.py # Webhook Lambda entrypoint: verifies GitHub webhook requests and routes events
│ └── event_handler.py # Handles PR/push events, resolves allowlist targets, and dispatches to downstream repos
│
└── callback/
├── Makefile # Build/package/deploy commands for the result Lambda
├── lambda_function.py # Result Lambda entrypoint: verifies callback token and GitHub OIDC token
└── callback_handler.py # Validates callback payloads, checks L2+ eligibility, stores state, and writes to HUD
```
## Usage
See
[README.md](https://github.com/KarhouTam/test-infra/blob/crcr-L2/aws/lambda/cross_repo_ci_relay/README.md)
for more details.
## Verification
We performed the following scenario verification on our AWS Lambda
instance:
- [x] Test with Upstream PR create/reopen/synchronize and push events
triggering webhook, then redispatching to the Downstream CI (different
organization) workflow.
- [x] Test with Downstream workflow send callback payload through the
added action to the result lambda, then extract CI result information
and send to PyTorch HUD.
## Terraform configuration
- pytorch/ci-infra#446
## Unit Tests
- [x] Unit Tests (Mock)
## Security
- **Callback payload carries full upstream webhook data back to HUD** —
`action.yml` builds the callback body by mutating
`github.event.client_payload` (which contains the entire original
webhook payload: PR metadata, commits, author info) and adding
`status`/`conclusion`/`workflow_name`/`workflow_url` on top. This full
blob is forwarded verbatim by `hud.py` to HUD with no relay-side
filtering. HUD receives both relay-trusted `verified_repo` and an
unvalidated body — if HUD trusts self-reported fields inside the body
over `verified_repo`, a manipulated dispatch payload could tamper with
HUD records.
- **Lambda callback URL is public and hardcoded** — The endpoint is
hardcoded in `action.yml and exposed in a public action, making it
trivially discoverable. OIDC verification blocks unauthorized HUD
writes, but the endpoint has no rate limiting; request flooding can
cause Lambda concurrency exhaustion or Redis connection saturation.
- **Only OIDC is used for verification** — The callback lambda relies
solely on GitHub OIDC token verification for authentication, without
additional application-level secrets or signatures. If an attacker
compromises a downstream repo's GitHub Actions permissions, they could
forge authenticated requests to the callback endpoint. Besides, OIDC has
its own limitations (e.g., token expiration, potential
misconfigurations) that could lead to unauthorized access if not
carefully managed.
## HUD Interaction
- **Design Principle: Transparent Relay & Decoupling**
The Relay Server acts as a **lightweight data passthrough layer**. It
does not define or parse specific CI data formats; instead, it offloads
data interpretation and validation to the HUD. This ensures complete
decoupling between the relay infrastructure and business-specific data.
- **Security & Risk Mitigation**
The relay uses **OIDC authentication** to guarantee the authenticity of
the data source (**Verified Repo**). Its core responsibility is to
ensure the data originates from the claimed repository, while security
filtering and content compliance are enforced at the HUD level.
---------
Co-authored-by: can-gaa-hou <jiahaochen535@gmail.com>
Co-authored-by: fffrog <ljw1101.vip@gmail.com>1 parent a966a81 commit 5f8dd50
30 files changed
Lines changed: 2209 additions & 243 deletions
File tree
- .github
- actions/cross-repo-ci-relay-callback
- workflows
- aws/lambda/cross_repo_ci_relay
- callback
- tests
- utils
- webhook
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
93 | 93 | | |
94 | 94 | | |
95 | 95 | | |
96 | | - | |
| 96 | + | |
| 97 | + | |
97 | 98 | | |
98 | 99 | | |
99 | 100 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
2 | | - | |
3 | | - | |
4 | | - | |
| 1 | + | |
| 2 | + | |
| 3 | + | |
5 | 4 | | |
6 | | - | |
7 | | - | |
8 | | - | |
9 | | - | |
10 | | - | |
11 | | - | |
12 | | - | |
13 | | - | |
| 5 | + | |
14 | 6 | | |
15 | 7 | | |
16 | 8 | | |
17 | 9 | | |
18 | | - | |
19 | | - | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
20 | 18 | | |
21 | | - | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
0 commit comments