[feat] support timestamp order in HSTU Match #197
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # 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" |