forked from alibaba/TorchEasyRec
-
Notifications
You must be signed in to change notification settings - Fork 0
268 lines (242 loc) · 10.8 KB
/
Copy pathcode_review.yml
File metadata and controls
268 lines (242 loc) · 10.8 KB
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
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
# AI Code Review Workflow (Claude Code / OpenAI Codex)
#
# Triggered by adding the "claude-review" or "codex-review" label to a PR.
# Uses stored OAuth credentials on self-hosted runner (no API keys needed).
#
# Usage:
# 1. Contributor opens PR
# 2. Collaborator adds "claude-review" or "codex-review" label when ready for review
# 3. Workflow triggers, removes the label, runs the review
# 4. Want to re-review after changes? Add the label again
#
# Review instructions live only in .claude/ (commands/review-pr.md + agents/*.md);
# the Codex job converts them at runtime via scripts/ci/gen_codex_review.py.
#
# ---- Runner One-Time Setup ----
# SSH into tzrec-codereview-runner as the runner user and run:
#
# # Install bun
# curl -fsSL https://bun.sh/install | bash
#
# # Install Claude Code
# curl -fsSL https://claude.ai/install.sh | sh
#
# # Clone claude-code-action at pinned version and install deps (for MCP inline comment server)
# git clone --branch v1 https://github.com/anthropics/claude-code-action.git /opt/claude-code-action
# cd /opt/claude-code-action && bun install
#
# # Configure MCP server for inline PR comments (~/.claude/mcp.json)
# mkdir -p ~/.claude && cat > ~/.claude/mcp.json << 'EOF'
# {
# "mcpServers": {
# "github_inline_comment": {
# "command": "bun",
# "args": ["run", "/opt/claude-code-action/src/mcp/github-inline-comment-server.ts"]
# }
# }
# }
# EOF
#
# # Login (stores OAuth credentials for headless use)
# claude /login
#
# # Verify headless mode works without API key
# unset ANTHROPIC_API_KEY && unset ANTHROPIC_BASE_URL
# claude -p "Say hello"
#
# If auth fails after a long period, re-run `claude /login` on the runner.
# Do NOT use --bare flag — it disables OAuth/keychain reads.
# ---- End Setup ----
#
# ---- Codex Runner One-Time Setup ----
# Shares bun + /opt/claude-code-action from the Claude setup above.
#
# # Install Codex CLI (keep current: subagents + mcp env_vars need a recent version)
# npm install -g @openai/codex
#
# # Login with ChatGPT account (device-code flow, no browser needed on runner)
# codex login --device-auth
# codex login status
#
# # REQUIRED: set the review model (the job copies top-level model* keys; no other
# # personal config loads)
# echo 'model = "gpt-5.5"' >> ~/.codex/config.toml
#
# # Verify headless mode
# echo "Say hello" | codex exec - --sandbox read-only
#
# If auth goes stale, re-run `codex login --device-auth` on the runner.
# If the runner lacks direct OpenAI egress, set HTTPS_PROXY for the runner service.
#
# Trust model: the collaborator-added label gates every run (review before labeling).
# Model commands run in a no-network sandbox; only the gh pr view/diff/comment
# allowlist (scripts/ci/codex_review.rules) runs outside it — as with the claude
# job's --allowedTools, a PR comment is the only exfil path for injected content.
# ---- End Codex Setup ----
name: Code Review
on:
pull_request_target:
types: [labeled]
# Group by label so a codex run does not cancel an in-flight claude run
concurrency:
group: codereview-${{ github.event.label.name }}-${{ github.event.pull_request.number }}
cancel-in-progress: true
jobs:
review:
if: github.event.label.name == 'claude-review'
runs-on: tzrec-codereview-runner
timeout-minutes: 30
permissions:
contents: read
pull-requests: write
steps:
- name: Remove label to allow re-triggering later
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh pr edit ${{ github.event.pull_request.number }} \
--repo ${{ github.repository }} \
--remove-label claude-review
# Checkout trusted agent files; cone mode also includes root-level files.
# github.sha = the workflow's own commit; the PR's base.sha is frozen and can lag
- name: Checkout trusted agent files
uses: actions/checkout@v4
with:
ref: ${{ github.sha }}
sparse-checkout: |
.claude
scripts/ci
path: trusted-claude
# Checkout PR code for review. Fork checkout is intentional here: trusted
# agent files come from github.sha above and the model runs sandboxed.
- name: Checkout PR code
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 1
path: pr-code
allow-unsafe-pr-checkout: true
- name: Use trusted agent files
run: bash trusted-claude/scripts/ci/use_trusted_agent_files.sh trusted-claude pr-code
- name: RunCodeReview
working-directory: pr-code
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REPO_OWNER: ${{ github.repository_owner }}
REPO_NAME: ${{ github.event.repository.name }}
PR_NUMBER: ${{ github.event.pull_request.number }}
# No ANTHROPIC_API_KEY — uses stored OAuth from `claude /login` on the runner
# MCP server inherits env vars (GITHUB_TOKEN, REPO_OWNER, REPO_NAME, PR_NUMBER)
run: |
set -euo pipefail
# Resolve full bun path (bun installed to ~/.bun/bin/ — not in Claude's subprocess PATH)
BUN_PATH="$(which bun 2>/dev/null || echo "$HOME/.bun/bin/bun")"
echo "bun path: $BUN_PATH ($("$BUN_PATH" --version))"
MCP_CONFIG="{\"mcpServers\":{\"github_inline_comment\":{\"command\":\"${BUN_PATH}\",\"args\":[\"run\",\"/opt/claude-code-action/src/mcp/github-inline-comment-server.ts\"]}}}"
claude -p \
--output-format stream-json \
--verbose \
--settings '{"disableRemoteControl": true}' \
--mcp-config "$MCP_CONFIG" \
--allowedTools "mcp__github_inline_comment__create_inline_comment,Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh pr comment:*),Read,Grep,Glob,Agent" \
-- "/review-pr REPO: ${{ github.repository }} PR_NUMBER: ${PR_NUMBER}"
codex-review:
if: github.event.label.name == 'codex-review'
runs-on: tzrec-codereview-runner
timeout-minutes: 30
permissions:
contents: read
pull-requests: write
steps:
- name: Remove label to allow re-triggering later
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh pr edit ${{ github.event.pull_request.number }} \
--repo ${{ github.repository }} \
--remove-label codex-review
# Trusted .claude/ + scripts at github.sha (the workflow's own commit, never the
# PR's frozen base.sha)
- name: Checkout trusted agent files
uses: actions/checkout@v4
with:
ref: ${{ github.sha }}
sparse-checkout: |
.claude
scripts/ci
path: trusted-claude
# Checkout PR code for review. Fork checkout is intentional here: trusted
# agent files come from github.sha above and the model runs sandboxed.
- name: Checkout PR code
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 1
path: pr-code
allow-unsafe-pr-checkout: true
# Same trusted-file setup as the claude job, plus generated codex agents as an overlay
- name: Use trusted agent files
run: |
python3 trusted-claude/scripts/ci/gen_codex_review.py \
--claude-dir trusted-claude/.claude \
--out-dir "${{ runner.temp }}/codex-gen" \
--repo ${{ github.repository }} \
--pr-number ${{ github.event.pull_request.number }} \
--prompt-out "${{ runner.temp }}/codex-prompt.md"
bash trusted-claude/scripts/ci/use_trusted_agent_files.sh \
trusted-claude pr-code "${{ runner.temp }}/codex-gen"
- name: RunCodexReview
working-directory: pr-code
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REPO_OWNER: ${{ github.repository_owner }}
REPO_NAME: ${{ github.event.repository.name }}
PR_NUMBER: ${{ github.event.pull_request.number }}
# No OPENAI_API_KEY — uses stored OAuth from `codex login` on the runner
run: |
set -euo pipefail
# Resolve full bun path (bun installed to ~/.bun/bin/ — not in subprocess PATH)
BUN_PATH="$(which bun 2>/dev/null || echo "$HOME/.bun/bin/bun")"
echo "bun path: $BUN_PATH ($("$BUN_PATH" --version))"
codex --version
# Per-run CODEX_HOME (stored auth + trusted rules + generated config only)
REAL_CODEX_HOME="${CODEX_HOME:-$HOME/.codex}"
export CODEX_HOME="${RUNNER_TEMP}/codex-home"
rm -rf "$CODEX_HOME" && mkdir -p "$CODEX_HOME/rules"
cp "$REAL_CODEX_HOME/auth.json" "$CODEX_HOME/auth.json"
cp "$GITHUB_WORKSPACE/trusted-claude/scripts/ci/codex_review.rules" \
"$CODEX_HOME/rules/default.rules"
# Copy the runner's top-level model* settings; subagent spawn needs explicit model=
awk '/^\[/{exit} /^model[a-z_]* *=/{print}' "$REAL_CODEX_HOME/config.toml" \
> "$CODEX_HOME/config.toml"
grep -q '^model *=' "$CODEX_HOME/config.toml" || {
echo "::error::set model = \"...\" in the runner's ~/.codex/config.toml"; exit 1; }
# The MCP server gets its token here (config file, not argv or codex env)
cat >> "$CODEX_HOME/config.toml" << EOF
[mcp_servers.github_inline_comment]
command = "${BUN_PATH}"
args = ["run", "/opt/claude-code-action/src/mcp/github-inline-comment-server.ts"]
default_tools_approval_mode = "approve"
[mcp_servers.github_inline_comment.env]
GITHUB_TOKEN = "${GITHUB_TOKEN}"
REPO_OWNER = "${REPO_OWNER}"
REPO_NAME = "${REPO_NAME}"
PR_NUMBER = "${PR_NUMBER}"
EOF
chmod 600 "$CODEX_HOME/config.toml"
# HOME shim hides the runner user's personal ~/.agents skills
export HOME="${RUNNER_TEMP}/codex-home-shim"
rm -rf "$HOME" && mkdir -p "$HOME"
# Store gh login in the shim HOME; codex runs token-free so model commands can't read it
echo "$GITHUB_TOKEN" | env -u GITHUB_TOKEN -u GH_TOKEN gh auth login --with-token
# No-network sandbox; only the gh pr view/diff/comment rules allowlist escapes it
env -u GITHUB_TOKEN -u GH_TOKEN codex exec \
--ephemeral \
--sandbox workspace-write \
--output-last-message "${RUNNER_TEMP}/codex-review-last.md" \
- < "${RUNNER_TEMP}/codex-prompt.md"
# Persist token refreshes back to the runner's stored auth
cmp -s "$CODEX_HOME/auth.json" "$REAL_CODEX_HOME/auth.json" || \
cp "$CODEX_HOME/auth.json" "$REAL_CODEX_HOME/auth.json"