name: e2e-bot # Comment "/e2e" (fixed suite) or "/e2e diff" (generate tests for the PR's diff) # on a pull request to run the e2e benchmark against the real provider and post a # report back. Gated to trusted authors: the job checks out PR-head code and runs # it with the provider API key, so only the repo owner, members, and collaborators # may trigger it. on: issue_comment: types: [created] permissions: contents: read pull-requests: write concurrency: group: e2e-bot-${{ github.event.issue.number }} cancel-in-progress: true jobs: e2e: if: >- github.event.issue.pull_request && contains(github.event.comment.body, '/e2e') && contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association) runs-on: ubuntu-latest # Running PR-head code with the provider secret is gated twice: the author_ # association check above, and this deployment environment. Configure the # `e2e-bot` environment with required reviewers in repo settings to force a # human approval per run (actions/untrusted-checkout-toctou). environment: e2e-bot steps: - name: Acknowledge uses: actions/github-script@v9 with: script: | await github.rest.reactions.createForIssueComment({ owner: context.repo.owner, repo: context.repo.repo, comment_id: context.payload.comment.id, content: 'eyes', }); # Default-branch checkout: this is where the harness (cmd/e2ebench), the # suite, and a run --metrics-capable agent live. - uses: actions/checkout@v7 with: fetch-depth: 0 - uses: actions/setup-go@v6 with: go-version-file: go.mod cache: true - uses: actions/setup-python@v6 with: python-version: '3.12' - name: Build harness + fallback agent from the default branch # Harness (e2ebench) and suite always come from main-v2 so a PR can't weaken # its own grader or tests. The agent is rebuilt from the PR head below; this # main-v2 build is only the fallback for heads that predate `run --metrics`. run: | go build -o "$RUNNER_TEMP/reasonix-base" ./cmd/reasonix go build -o "$RUNNER_TEMP/e2ebench" ./cmd/e2ebench cp -r benchmarks/e2e "$RUNNER_TEMP/suite" - name: Check out the PR head env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Pin to the head commit resolved now and check it out detached, not the # mutable PR ref: a force-push mid-run can't swap in different code after # the trusted-author gate passed. run: | SHA=$(gh pr view ${{ github.event.issue.number }} --json headRefOid -q .headRefOid) git fetch -q origin "$SHA" git checkout -q --detach "$SHA" - name: Build the agent from the PR head # The whole point of the bot is to drive the PR's code, not main-v2's. Fall # back to the main-v2 build only when the PR head can't yield a # run --metrics-capable binary (build break or predates the flag). id: agent run: | bin="$RUNNER_TEMP/reasonix-base" src="main-v2 fallback (PR head lacks run --metrics)" if go build -o "$RUNNER_TEMP/reasonix-pr" ./cmd/reasonix \ && "$RUNNER_TEMP/reasonix-pr" run -h 2>&1 | grep -q -- '-metrics'; then bin="$RUNNER_TEMP/reasonix-pr" src="PR head ($(git rev-parse --short HEAD))" fi echo "bin=$bin" >> "$GITHUB_OUTPUT" echo "src=$src" >> "$GITHUB_OUTPUT" echo "agent under test: $src" - name: Write provider config # User config covers suite tasks (they run in temp dirs); the repo-root copy # covers diff mode (the agent runs in the repo root, where project config wins). run: | mkdir -p ~/.config/reasonix cat > /tmp/reasonix-e2e.toml < report.md exit 0 fi if printf '%s' "$COMMENT_BODY" | grep -q '/e2e[[:space:]]\+diff'; then ATTEMPTS=$(printf '%s' "$COMMENT_BODY" | sed -nE 's@.*/e2e[[:space:]]+diff[[:space:]]+x([0-9]+).*@\1@p' | head -1) [ -z "$ATTEMPTS" ] && ATTEMPTS=1 [ "$ATTEMPTS" -gt 5 ] && ATTEMPTS=5 BASE_REF=$(gh pr view ${{ github.event.issue.number }} --json baseRefName -q .baseRefName) git fetch -q origin "$BASE_REF" BASE=$(git merge-base "origin/$BASE_REF" HEAD) "$RUNNER_TEMP/e2ebench" -mode diff -bin "${{ steps.agent.outputs.bin }}" -repo . -base "$BASE" -model e2e -attempts "$ATTEMPTS" -out report.md else "$RUNNER_TEMP/e2ebench" -bin "${{ steps.agent.outputs.bin }}" -suite "$RUNNER_TEMP/suite" -model e2e -out report.md -json report.json -budget 400000 fi - name: Post report env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} TRIGGER_USER: ${{ github.event.comment.user.login }} run: | printf '\n> agent: %s · triggered by @%s\n' "${{ steps.agent.outputs.src }}" "$TRIGGER_USER" >> report.md gh pr comment ${{ github.event.issue.number }} --body-file report.md - name: Report failure if: failure() env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: gh pr comment ${{ github.event.issue.number }} --body "🤖 e2e bot failed — see the [run log](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})."