Skip to content

fix: make sure queries are not made ahead of the anchor block #1652

fix: make sure queries are not made ahead of the anchor block

fix: make sure queries are not made ahead of the anchor block #1652

Workflow file for this run

name: ClaudeBox
on:
issue_comment:
types: [created]
pull_request:
types: [labeled]
workflow_dispatch:
inputs:
prompt:
description: 'Prompt / instructions for Claude'
required: true
type: string
link:
description: 'Context link (e.g., PR URL, issue URL, external reference)'
required: false
type: string
jobs:
claudebox:
if: >-
github.event_name == 'workflow_dispatch' ||
startsWith(github.event.comment.body, '/claudebox')
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Check write access
if: github.event_name == 'issue_comment'
run: |
ASSOCIATION="${{ github.event.comment.author_association }}"
echo "Author association: $ASSOCIATION"
if [[ "$ASSOCIATION" != "OWNER" && "$ASSOCIATION" != "MEMBER" && "$ASSOCIATION" != "COLLABORATOR" ]]; then
echo "ERROR: User does not have write access (association: $ASSOCIATION)"
exit 1
fi
echo "Access granted."
- name: Add reaction
if: github.event_name == 'issue_comment'
env:
GH_TOKEN: ${{ secrets.AZTEC_BOT_GITHUB_TOKEN }}
run: |
gh api \
repos/${{ github.repository }}/issues/comments/${{ github.event.comment.id }}/reactions \
-f content='eyes' || true
- name: Setup SSH tunnel to ClaudeBox
env:
BUILD_INSTANCE_SSH_KEY: ${{ secrets.BUILD_INSTANCE_SSH_KEY }}
run: |
set -eu
mkdir -p ~/.ssh
echo "${BUILD_INSTANCE_SSH_KEY}" | base64 --decode > ~/.ssh/build_instance_key
chmod 600 ~/.ssh/build_instance_key
# SSH tunnel: CI runner :4001 → bastion :3000 → (reverse tunnel) → claude-box :3001
ssh -f -N -L 4001:localhost:3000 \
-o StrictHostKeyChecking=no \
-o ServerAliveInterval=30 \
-o ServerAliveCountMax=3 \
-o ConnectTimeout=15 \
-i ~/.ssh/build_instance_key \
ubuntu@ci.aztec-labs.com
# Wait for tunnel
for i in $(seq 1 15); do
if curl -s -o /dev/null --max-time 2 http://localhost:4001/ 2>/dev/null; then
echo "SSH tunnel ready"
exit 0
fi
sleep 1
done
echo "ERROR: SSH tunnel failed to connect"
exit 1
- name: Parse command
id: parse
env:
COMMENT_BODY: ${{ github.event.comment.body || '' }}
INPUT_PROMPT: ${{ inputs.prompt || '' }}
INPUT_LINK: ${{ inputs.link || '' }}
run: |
if [ -n "$INPUT_PROMPT" ]; then
PROMPT="$INPUT_PROMPT"
LINK="$INPUT_LINK"
else
PROMPT=$(printf '%s' "$COMMENT_BODY" | sed 's|^/claudebox[[:space:]]*||')
LINK=""
fi
echo "link=$LINK" >> "$GITHUB_OUTPUT"
{
echo "prompt<<PROMPT_EOF"
echo "$PROMPT"
echo "PROMPT_EOF"
} >> "$GITHUB_OUTPUT"
echo "Parsed: prompt=${PROMPT:0:120}"
- name: Post status comment
id: status_comment
if: github.event_name == 'issue_comment'
env:
GH_TOKEN: ${{ secrets.AZTEC_BOT_GITHUB_TOKEN }}
PROMPT_TEXT: ${{ steps.parse.outputs.prompt }}
run: |
ISSUE_NUM="${{ github.event.issue.number }}"
RUN_URL="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
SHORT_PROMPT=$(printf '%.120s' "$PROMPT_TEXT")
BODY="**ClaudeBox**: _${SHORT_PROMPT}_ ... [workflow run]($RUN_URL)"
COMMENT_ID=$(gh api \
repos/${{ github.repository }}/issues/$ISSUE_NUM/comments \
-f body="$BODY" \
--jq '.id')
echo "run_comment_id=$COMMENT_ID" >> "$GITHUB_OUTPUT"
echo "Posted status comment: $COMMENT_ID"
- name: Run ClaudeBox
timeout-minutes: 120
env:
CLAUDEBOX_URL: http://localhost:4001
CLAUDEBOX_API_SECRET: ${{ secrets.CLAUDEBOX_API_SECRET }}
CLAUDEBOX_PROMPT: ${{ steps.parse.outputs.prompt }}
CLAUDEBOX_LINK: ${{ steps.parse.outputs.link }}
COMMENT_ID: ${{ github.event.comment.id || '' }}
RUN_COMMENT_ID: ${{ steps.status_comment.outputs.run_comment_id || '' }}
REPO: ${{ github.repository }}
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
AUTHOR: ${{ github.event.comment.user.login || github.actor }}
run: |
AUTH="Authorization: Bearer ${CLAUDEBOX_API_SECRET}"
echo "Creating payload..."
PAYLOAD=$(jq -n \
--arg prompt "$CLAUDEBOX_PROMPT" \
--arg user "$AUTHOR" \
--arg comment_id "$COMMENT_ID" \
--arg run_comment_id "$RUN_COMMENT_ID" \
--arg repo "$REPO" \
--arg run_url "$RUN_URL" \
--arg link "$CLAUDEBOX_LINK" \
'{prompt: $prompt, user: $user, comment_id: $comment_id, run_comment_id: $run_comment_id, repo: $repo, run_url: $run_url, link: $link}')
echo "Sending payload..."
# Start session — returns 202 with log URL
RESPONSE=$(curl -sS -w "\n%{http_code}" \
-H "$AUTH" -H "Content-Type: application/json" \
-d "$PAYLOAD" "${CLAUDEBOX_URL}/run")
HTTP_CODE=$(echo "$RESPONSE" | tail -1)
BODY=$(echo "$RESPONSE" | head -n -1)
if [ "$HTTP_CODE" -ge 400 ] 2>/dev/null; then
echo "ClaudeBox returned HTTP $HTTP_CODE: $BODY"
exit 1
fi
LOG_URL=$(echo "$BODY" | jq -r '.log_url // empty')
SESSION_ID=$(basename "$LOG_URL")
echo "Session started: $LOG_URL"
echo "Session received, polling..."
# Poll until completed
while true; do
sleep 30
STATUS_BODY=$(curl -sS -H "$AUTH" "${CLAUDEBOX_URL}/session/${SESSION_ID}" 2>/dev/null || echo '{}')
STATUS=$(echo "$STATUS_BODY" | jq -r '.status // "unknown"')
echo "$(date -u +%H:%M:%S) status=$STATUS"
if [ "$STATUS" != "running" ]; then
EXIT_CODE=$(echo "$STATUS_BODY" | jq -r '.exit_code // 1')
echo "Session finished: status=$STATUS exit_code=$EXIT_CODE"
echo "Log: $LOG_URL"
exit "$EXIT_CODE"
fi
done
claude-review:
if: >-
github.event_name == 'pull_request' &&
github.event.action == 'labeled' &&
github.event.label.name == 'claude-review'
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Setup SSH tunnel to ClaudeBox
env:
BUILD_INSTANCE_SSH_KEY: ${{ secrets.BUILD_INSTANCE_SSH_KEY }}
run: |
set -eu
mkdir -p ~/.ssh
echo "${BUILD_INSTANCE_SSH_KEY}" | base64 --decode > ~/.ssh/build_instance_key
chmod 600 ~/.ssh/build_instance_key
ssh -f -N -L 4001:localhost:3000 \
-o StrictHostKeyChecking=no \
-o ServerAliveInterval=30 \
-o ServerAliveCountMax=3 \
-o ConnectTimeout=15 \
-i ~/.ssh/build_instance_key \
ubuntu@ci.aztec-labs.com
for i in $(seq 1 15); do
if curl -s -o /dev/null --max-time 2 http://localhost:4001/ 2>/dev/null; then
echo "SSH tunnel ready"
exit 0
fi
sleep 1
done
echo "ERROR: SSH tunnel failed to connect"
exit 1
- name: Post review status comment
id: status_comment
env:
GH_TOKEN: ${{ secrets.AZTEC_BOT_GITHUB_TOKEN }}
run: |
PR_NUM="${{ github.event.pull_request.number }}"
RUN_URL="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
BODY="**Claude Review**: Starting automated code review... [workflow run]($RUN_URL)"
COMMENT_ID=$(gh api \
repos/${{ github.repository }}/issues/$PR_NUM/comments \
-f body="$BODY" \
--jq '.id')
echo "run_comment_id=$COMMENT_ID" >> "$GITHUB_OUTPUT"
echo "Posted review status comment: $COMMENT_ID"
- name: Trigger ClaudeBox review
timeout-minutes: 120
env:
CLAUDEBOX_URL: http://localhost:4001
CLAUDEBOX_API_SECRET: ${{ secrets.CLAUDEBOX_API_SECRET }}
PR_NUMBER: ${{ github.event.pull_request.number }}
PR_TITLE: ${{ github.event.pull_request.title }}
PR_URL: ${{ github.event.pull_request.html_url }}
PR_AUTHOR: ${{ github.event.pull_request.user.login }}
HEAD_REF: ${{ github.event.pull_request.head.ref }}
RUN_COMMENT_ID: ${{ steps.status_comment.outputs.run_comment_id || '' }}
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
REPO: ${{ github.repository }}
run: |
AUTH="Authorization: Bearer ${CLAUDEBOX_API_SECRET}"
PROMPT="Review PR #${PR_NUMBER}: ${PR_TITLE}
${PR_URL}
Author: ${PR_AUTHOR}
Head branch: ${HEAD_REF}
Thoroughly review this PR. Read the diff, description, linked issues, and recent git history.
Focus on non-obvious bugs: edge cases, concurrency, security, correctness, compatibility.
If you find a direct fix, create a PR. When done, call manage_review_labels(pr_number=${PR_NUMBER})."
PAYLOAD=$(jq -n \
--arg prompt "$PROMPT" \
--arg user "review/${PR_AUTHOR}" \
--arg run_comment_id "$RUN_COMMENT_ID" \
--arg repo "$REPO" \
--arg run_url "$RUN_URL" \
--arg link "$PR_URL" \
--arg profile "review" \
'{prompt: $prompt, user: $user, run_comment_id: $run_comment_id, repo: $repo, run_url: $run_url, link: $link, profile: $profile}')
RESPONSE=$(curl -sS -w "\n%{http_code}" \
-H "$AUTH" -H "Content-Type: application/json" \
-d "$PAYLOAD" "${CLAUDEBOX_URL}/run")
HTTP_CODE=$(echo "$RESPONSE" | tail -1)
BODY=$(echo "$RESPONSE" | head -n -1)
if [ "$HTTP_CODE" -ge 400 ] 2>/dev/null; then
echo "ClaudeBox returned HTTP $HTTP_CODE: $BODY"
exit 1
fi
LOG_URL=$(echo "$BODY" | jq -r '.log_url // empty')
SESSION_ID=$(basename "$LOG_URL")
echo "Review session started: $LOG_URL"
# Poll until completed
while true; do
sleep 30
STATUS_BODY=$(curl -sS -H "$AUTH" "${CLAUDEBOX_URL}/session/${SESSION_ID}" 2>/dev/null || echo '{}')
STATUS=$(echo "$STATUS_BODY" | jq -r '.status // "unknown"')
echo "$(date -u +%H:%M:%S) status=$STATUS"
if [ "$STATUS" != "running" ]; then
EXIT_CODE=$(echo "$STATUS_BODY" | jq -r '.exit_code // 1')
echo "Review finished: status=$STATUS exit_code=$EXIT_CODE"
echo "Log: $LOG_URL"
# Don't fail the workflow on review errors — the review itself is informational
exit 0
fi
done