From 7e6240513f9c0bf9ff646c5e14452330e693d3d7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 19 Jun 2026 22:29:26 +0000 Subject: [PATCH 1/3] Initial plan From 86661b72265e1e1d1abc14de144715f2a65d49fd Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 19 Jun 2026 22:46:12 +0000 Subject: [PATCH 2/3] fix(contribution-check): use context files for pre-fetched data Steps run in the agent job but the prompt is built in the activation job, so ${{ steps.*.outputs.* }} expressions always evaluate to empty strings. Follow the doc-maintainer pattern: write fetched data to /tmp/gh-aw/contribution-check-context/ and update the prompt to read those files. Remove stale GH_AW_EXPR env vars from activation job. Closes #5289 --- .github/workflows/contribution-check.lock.yml | 17 ++--- .github/workflows/contribution-check.md | 68 +++++++------------ .../ci/contribution-check-workflow.test.ts | 13 ++-- 3 files changed, 38 insertions(+), 60 deletions(-) diff --git a/.github/workflows/contribution-check.lock.yml b/.github/workflows/contribution-check.lock.yml index 6aa8c5b44..060447351 100644 --- a/.github/workflows/contribution-check.lock.yml +++ b/.github/workflows/contribution-check.lock.yml @@ -339,9 +339,6 @@ jobs: GH_AW_ENGINE_ID: "copilot" GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number || inputs.item_number }} GH_AW_GITHUB_REPOSITORY: ${{ github.repository }} - GH_AW_STEPS_CONTRIBUTING_OUTPUTS_CONTENT: ${{ steps.contributing.outputs.CONTENT }} - GH_AW_EXPR_BAA3A6C6: ${{ steps.pr-diff.outputs.PR_FILES }} - GH_AW_EXPR_F5E0997D: ${{ steps.pr-meta.outputs.PR_META }} with: script: | const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); @@ -355,8 +352,6 @@ jobs: GH_AW_EXPR_1A3A194A: ${{ github.event.discussion.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'discussion' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} GH_AW_EXPR_463A214A: ${{ github.event.pull_request.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'pull_request' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} GH_AW_EXPR_802A9F6A: ${{ github.event.issue.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'issue' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} - GH_AW_EXPR_BAA3A6C6: ${{ steps.pr-diff.outputs.PR_FILES }} - GH_AW_EXPR_F5E0997D: ${{ steps.pr-meta.outputs.PR_META }} GH_AW_EXPR_FF1D34CE: ${{ github.event.comment.id || fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').comment_id }} GH_AW_GITHUB_ACTOR: ${{ github.actor }} GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number || inputs.item_number }} @@ -364,7 +359,6 @@ jobs: GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} GH_AW_MCP_CLI_SERVERS_LIST: '- `safeoutputs` — run `safeoutputs --help` to see available tools' - GH_AW_STEPS_CONTRIBUTING_OUTPUTS_CONTENT: ${{ steps.contributing.outputs.CONTENT }} with: script: | const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); @@ -379,16 +373,13 @@ jobs: GH_AW_EXPR_1A3A194A: process.env.GH_AW_EXPR_1A3A194A, GH_AW_EXPR_463A214A: process.env.GH_AW_EXPR_463A214A, GH_AW_EXPR_802A9F6A: process.env.GH_AW_EXPR_802A9F6A, - GH_AW_EXPR_BAA3A6C6: process.env.GH_AW_EXPR_BAA3A6C6, - GH_AW_EXPR_F5E0997D: process.env.GH_AW_EXPR_F5E0997D, GH_AW_EXPR_FF1D34CE: process.env.GH_AW_EXPR_FF1D34CE, GH_AW_GITHUB_ACTOR: process.env.GH_AW_GITHUB_ACTOR, GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: process.env.GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER, GH_AW_GITHUB_REPOSITORY: process.env.GH_AW_GITHUB_REPOSITORY, GH_AW_GITHUB_RUN_ID: process.env.GH_AW_GITHUB_RUN_ID, GH_AW_GITHUB_WORKSPACE: process.env.GH_AW_GITHUB_WORKSPACE, - GH_AW_MCP_CLI_SERVERS_LIST: process.env.GH_AW_MCP_CLI_SERVERS_LIST, - GH_AW_STEPS_CONTRIBUTING_OUTPUTS_CONTENT: process.env.GH_AW_STEPS_CONTRIBUTING_OUTPUTS_CONTENT + GH_AW_MCP_CLI_SERVERS_LIST: process.env.GH_AW_MCP_CLI_SERVERS_LIST } }); - name: Validate prompt placeholders @@ -491,7 +482,7 @@ jobs: GH_TOKEN: ${{ github.token }} id: contributing name: Fetch CONTRIBUTING.md - run: "DELIM=\"GHAW_CONTRIBUTING_$(date +%s)\"\n{\n echo \"CONTENT<<${DELIM}\"\n gh api \"repos/${GH_REPO}/contents/CONTRIBUTING.md\" --jq '.content' 2>/dev/null | tr -d '\\n' | base64 -d 2>/dev/null || echo \"(CONTRIBUTING.md not found)\"\n echo \"${DELIM}\"\n} >> \"$GITHUB_OUTPUT\"\n" + run: "CONTEXT_DIR=/tmp/gh-aw/contribution-check-context\nmkdir -p \"$CONTEXT_DIR\"\ngh api \"repos/${GH_REPO}/contents/CONTRIBUTING.md\" --jq '.content' 2>/dev/null \\\n | tr -d '\\n' | base64 -d 2>/dev/null \\\n > \"$CONTEXT_DIR/contributing.md\" \\\n || echo \"(CONTRIBUTING.md not found)\" > \"$CONTEXT_DIR/contributing.md\"\n" - env: GH_REPO: ${{ github.repository }} GH_TOKEN: ${{ github.token }} @@ -499,7 +490,7 @@ jobs: id: pr-diff if: github.event.pull_request.number || github.event.inputs.item_number name: Fetch PR changed files - run: "DELIM=\"GHAW_PR_FILES_$(date +%s)\"\nDIFF_LIMIT=50000\nDIFF_TMP=\"$(mktemp)\"\n{\n echo \"PR_FILES<<${DELIM}\"\n gh api \"repos/${GH_REPO}/pulls/${PR_NUMBER}/files\" \\\n --paginate --jq '.[] | \"### \" + .filename + \" (+\" + (.additions|tostring) + \"/-\" + (.deletions|tostring) + \")\\n\" + (.patch // \"\") + \"\\n\"' \\\n > \"$DIFF_TMP\" || true\n DIFF_SIZE=\"$(wc -c < \"$DIFF_TMP\" | tr -d ' ')\"\n head -c \"$DIFF_LIMIT\" \"$DIFF_TMP\" || true\n if [ \"$DIFF_SIZE\" -gt \"$DIFF_LIMIT\" ]; then\n echo -e \"\\n[DIFF TRUNCATED at ${DIFF_LIMIT} bytes]\"\n fi\n echo \"\"\n echo \"${DELIM}\"\n} >> \"$GITHUB_OUTPUT\"\nrm -f \"$DIFF_TMP\"\n" + run: "CONTEXT_DIR=/tmp/gh-aw/contribution-check-context\nmkdir -p \"$CONTEXT_DIR\"\nDIFF_LIMIT=50000\nDIFF_TMP=\"$(mktemp)\"\ngh api \"repos/${GH_REPO}/pulls/${PR_NUMBER}/files\" \\\n --paginate --jq '.[] | \"### \" + .filename + \" (+\" + (.additions|tostring) + \"/-\" + (.deletions|tostring) + \")\\n\" + (.patch // \"\") + \"\\n\"' \\\n > \"$DIFF_TMP\" || true\nDIFF_SIZE=\"$(wc -c < \"$DIFF_TMP\" | tr -d ' ')\"\nhead -c \"$DIFF_LIMIT\" \"$DIFF_TMP\" > \"$CONTEXT_DIR/pr-files.md\" || true\nif [ \"$DIFF_SIZE\" -gt \"$DIFF_LIMIT\" ]; then\n echo -e \"\\n[DIFF TRUNCATED at ${DIFF_LIMIT} bytes]\" >> \"$CONTEXT_DIR/pr-files.md\"\nfi\nrm -f \"$DIFF_TMP\"\n" - env: GH_REPO: ${{ github.repository }} GH_TOKEN: ${{ github.token }} @@ -507,7 +498,7 @@ jobs: id: pr-meta if: github.event.pull_request.number || github.event.inputs.item_number name: Fetch PR metadata - run: "DELIM=\"GHAW_PR_META_$(date +%s)\"\nPR_INFO=$(gh pr view \"$PR_NUMBER\" --repo \"$GH_REPO\" \\\n --json title,author,baseRefName,headRefName,body \\\n --jq '\"**Title:** \" + .title + \"\\n**Author:** \" + .author.login + \"\\n**Base→Head:** \" + .baseRefName + \"→\" + .headRefName + \"\\n**Description:**\\n\" + (.body // \"\")')\n{\n echo \"PR_META<<${DELIM}\"\n printf '%s\\n' \"$PR_INFO\"\n echo \"${DELIM}\"\n} >> \"$GITHUB_OUTPUT\"\n" + run: "CONTEXT_DIR=/tmp/gh-aw/contribution-check-context\nmkdir -p \"$CONTEXT_DIR\"\ngh pr view \"$PR_NUMBER\" --repo \"$GH_REPO\" \\\n --json title,author,baseRefName,headRefName,body \\\n --jq '\"**Title:** \" + .title + \"\\n**Author:** \" + .author.login + \"\\n**Base\\u2192Head:** \" + .baseRefName + \"\\u2192\" + .headRefName + \"\\n**Description:**\\n\" + (.body // \"\")' \\\n > \"$CONTEXT_DIR/pr-meta.md\"\n" - name: Configure Git credentials env: diff --git a/.github/workflows/contribution-check.md b/.github/workflows/contribution-check.md index ea93ea798..4f8165a42 100644 --- a/.github/workflows/contribution-check.md +++ b/.github/workflows/contribution-check.md @@ -41,12 +41,12 @@ steps: - name: Fetch CONTRIBUTING.md id: contributing run: | - DELIM="GHAW_CONTRIBUTING_$(date +%s)" - { - echo "CONTENT<<${DELIM}" - gh api "repos/${GH_REPO}/contents/CONTRIBUTING.md" --jq '.content' 2>/dev/null | tr -d '\n' | base64 -d 2>/dev/null || echo "(CONTRIBUTING.md not found)" - echo "${DELIM}" - } >> "$GITHUB_OUTPUT" + CONTEXT_DIR=/tmp/gh-aw/contribution-check-context + mkdir -p "$CONTEXT_DIR" + gh api "repos/${GH_REPO}/contents/CONTRIBUTING.md" --jq '.content' 2>/dev/null \ + | tr -d '\n' | base64 -d 2>/dev/null \ + > "$CONTEXT_DIR/contributing.md" \ + || echo "(CONTRIBUTING.md not found)" > "$CONTEXT_DIR/contributing.md" env: GH_TOKEN: ${{ github.token }} GH_REPO: ${{ github.repository }} @@ -54,22 +54,18 @@ steps: id: pr-diff if: github.event.pull_request.number || github.event.inputs.item_number run: | - DELIM="GHAW_PR_FILES_$(date +%s)" + CONTEXT_DIR=/tmp/gh-aw/contribution-check-context + mkdir -p "$CONTEXT_DIR" DIFF_LIMIT=50000 DIFF_TMP="$(mktemp)" - { - echo "PR_FILES<<${DELIM}" - gh api "repos/${GH_REPO}/pulls/${PR_NUMBER}/files" \ - --paginate --jq '.[] | "### " + .filename + " (+" + (.additions|tostring) + "/-" + (.deletions|tostring) + ")\n" + (.patch // "") + "\n"' \ - > "$DIFF_TMP" || true - DIFF_SIZE="$(wc -c < "$DIFF_TMP" | tr -d ' ')" - head -c "$DIFF_LIMIT" "$DIFF_TMP" || true - if [ "$DIFF_SIZE" -gt "$DIFF_LIMIT" ]; then - echo -e "\n[DIFF TRUNCATED at ${DIFF_LIMIT} bytes]" - fi - echo "" - echo "${DELIM}" - } >> "$GITHUB_OUTPUT" + gh api "repos/${GH_REPO}/pulls/${PR_NUMBER}/files" \ + --paginate --jq '.[] | "### " + .filename + " (+" + (.additions|tostring) + "/-" + (.deletions|tostring) + ")\n" + (.patch // "") + "\n"' \ + > "$DIFF_TMP" || true + DIFF_SIZE="$(wc -c < "$DIFF_TMP" | tr -d ' ')" + head -c "$DIFF_LIMIT" "$DIFF_TMP" > "$CONTEXT_DIR/pr-files.md" || true + if [ "$DIFF_SIZE" -gt "$DIFF_LIMIT" ]; then + echo -e "\n[DIFF TRUNCATED at ${DIFF_LIMIT} bytes]" >> "$CONTEXT_DIR/pr-files.md" + fi rm -f "$DIFF_TMP" env: GH_TOKEN: ${{ github.token }} @@ -80,15 +76,12 @@ steps: id: pr-meta if: github.event.pull_request.number || github.event.inputs.item_number run: | - DELIM="GHAW_PR_META_$(date +%s)" - PR_INFO=$(gh pr view "$PR_NUMBER" --repo "$GH_REPO" \ + CONTEXT_DIR=/tmp/gh-aw/contribution-check-context + mkdir -p "$CONTEXT_DIR" + gh pr view "$PR_NUMBER" --repo "$GH_REPO" \ --json title,author,baseRefName,headRefName,body \ - --jq '"**Title:** " + .title + "\n**Author:** " + .author.login + "\n**Base→Head:** " + .baseRefName + "→" + .headRefName + "\n**Description:**\n" + (.body // "")') - { - echo "PR_META<<${DELIM}" - printf '%s\n' "$PR_INFO" - echo "${DELIM}" - } >> "$GITHUB_OUTPUT" + --jq '"**Title:** " + .title + "\n**Author:** " + .author.login + "\n**Base→Head:** " + .baseRefName + "→" + .headRefName + "\n**Description:**\n" + (.body // "")' \ + > "$CONTEXT_DIR/pr-meta.md" env: GH_TOKEN: ${{ github.token }} PR_NUMBER: ${{ github.event.pull_request.number || github.event.inputs.item_number }} @@ -104,21 +97,12 @@ You are a contribution guidelines reviewer for the `gh-aw-firewall` (AWF) reposi Review PR #${{ github.event.pull_request.number }} in repository ${{ github.repository }}. -**Use ONLY the pre-fetched data below.** Do NOT call `gh pr diff`, `gh pr view`, `gh api`, `git diff`, `git log`, or `git show`. Do not read files from the checkout. +Read the following pre-fetched context files before proceeding: +- `/tmp/gh-aw/contribution-check-context/pr-meta.md` — PR metadata (title, author, base/head branch, description) +- `/tmp/gh-aw/contribution-check-context/pr-files.md` — Changed files with diffs +- `/tmp/gh-aw/contribution-check-context/contributing.md` — CONTRIBUTING.md content -## Pre-Fetched PR Metadata - -${{ steps.pr-meta.outputs.PR_META }} - -## Pre-Fetched Changed Files - -``` -${{ steps.pr-diff.outputs.PR_FILES }} -``` - -## CONTRIBUTING.md (Pre-Fetched) - -${{ steps.contributing.outputs.CONTENT }} +**Use ONLY the pre-fetched data in these context files.** Do NOT call `gh pr diff`, `gh pr view`, `gh api`, `git diff`, `git log`, or `git show`. Do not read other files from the checkout. ## Review Checklist diff --git a/scripts/ci/contribution-check-workflow.test.ts b/scripts/ci/contribution-check-workflow.test.ts index 9f8c85a50..52f633465 100644 --- a/scripts/ci/contribution-check-workflow.test.ts +++ b/scripts/ci/contribution-check-workflow.test.ts @@ -13,17 +13,20 @@ describe('contribution-check workflow', () => { expect(source).toContain('Fetch PR metadata'); expect(source).toContain('Fetch CONTRIBUTING.md'); expect(source).toContain('GH_TOKEN: ${{ github.token }}'); - expect(source).toContain('${{ steps.pr-diff.outputs.PR_FILES }}'); - expect(source).toContain('${{ steps.pr-meta.outputs.PR_META }}'); - expect(source).toContain('${{ steps.contributing.outputs.CONTENT }}'); + + // Steps write to context files (not $GITHUB_OUTPUT), so data persists for the agent + expect(source).toContain('/tmp/gh-aw/contribution-check-context/contributing.md'); + expect(source).toContain('/tmp/gh-aw/contribution-check-context/pr-files.md'); + expect(source).toContain('/tmp/gh-aw/contribution-check-context/pr-meta.md'); }); it('instructs agent to use pre-fetched data and not re-fetch via proxy', () => { const source = fs.readFileSync(sourcePath, 'utf-8'); - expect(source).toContain('Use ONLY the pre-fetched data below'); + // Agent reads from context files written by the pre-fetch steps + expect(source).toContain('Read the following pre-fetched context files before proceeding'); expect(source).toContain("Do NOT call `gh pr diff`"); - expect(source).toContain('Do not read files from the checkout'); + expect(source).toContain('Use ONLY the pre-fetched data in these context files'); }); it('has conservative turn limit and appropriate model', () => { From b79f2ba284b77b1145eff6e325408bafb1cfaec1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 19 Jun 2026 23:59:23 +0000 Subject: [PATCH 3/3] fix(workflows): address contribution-check review feedback --- .github/workflows/contribution-check.lock.yml | 3 +-- .github/workflows/contribution-check.md | 3 ++- scripts/ci/contribution-check-workflow.test.ts | 2 ++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/contribution-check.lock.yml b/.github/workflows/contribution-check.lock.yml index 060447351..de7a1e619 100644 --- a/.github/workflows/contribution-check.lock.yml +++ b/.github/workflows/contribution-check.lock.yml @@ -482,7 +482,7 @@ jobs: GH_TOKEN: ${{ github.token }} id: contributing name: Fetch CONTRIBUTING.md - run: "CONTEXT_DIR=/tmp/gh-aw/contribution-check-context\nmkdir -p \"$CONTEXT_DIR\"\ngh api \"repos/${GH_REPO}/contents/CONTRIBUTING.md\" --jq '.content' 2>/dev/null \\\n | tr -d '\\n' | base64 -d 2>/dev/null \\\n > \"$CONTEXT_DIR/contributing.md\" \\\n || echo \"(CONTRIBUTING.md not found)\" > \"$CONTEXT_DIR/contributing.md\"\n" + run: "set -o pipefail\nCONTEXT_DIR=/tmp/gh-aw/contribution-check-context\nmkdir -p \"$CONTEXT_DIR\"\ngh api \"repos/${GH_REPO}/contents/CONTRIBUTING.md\" --jq '.content' 2>/dev/null \\\n | tr -d '\\n' | base64 -d 2>/dev/null \\\n > \"$CONTEXT_DIR/contributing.md\" \\\n || echo \"(CONTRIBUTING.md not found)\" > \"$CONTEXT_DIR/contributing.md\"\n" - env: GH_REPO: ${{ github.repository }} GH_TOKEN: ${{ github.token }} @@ -1392,4 +1392,3 @@ jobs: /tmp/gh-aw/safe-output-items.jsonl /tmp/gh-aw/temporary-id-map.json if-no-files-found: ignore - diff --git a/.github/workflows/contribution-check.md b/.github/workflows/contribution-check.md index 4f8165a42..189d79c43 100644 --- a/.github/workflows/contribution-check.md +++ b/.github/workflows/contribution-check.md @@ -41,6 +41,7 @@ steps: - name: Fetch CONTRIBUTING.md id: contributing run: | + set -o pipefail CONTEXT_DIR=/tmp/gh-aw/contribution-check-context mkdir -p "$CONTEXT_DIR" gh api "repos/${GH_REPO}/contents/CONTRIBUTING.md" --jq '.content' 2>/dev/null \ @@ -95,7 +96,7 @@ You are a contribution guidelines reviewer for the `gh-aw-firewall` (AWF) reposi ## Your Task -Review PR #${{ github.event.pull_request.number }} in repository ${{ github.repository }}. +Review PR #${{ github.event.pull_request.number || github.event.inputs.item_number }} in repository ${{ github.repository }}. Read the following pre-fetched context files before proceeding: - `/tmp/gh-aw/contribution-check-context/pr-meta.md` — PR metadata (title, author, base/head branch, description) diff --git a/scripts/ci/contribution-check-workflow.test.ts b/scripts/ci/contribution-check-workflow.test.ts index 52f633465..d416086ff 100644 --- a/scripts/ci/contribution-check-workflow.test.ts +++ b/scripts/ci/contribution-check-workflow.test.ts @@ -13,6 +13,7 @@ describe('contribution-check workflow', () => { expect(source).toContain('Fetch PR metadata'); expect(source).toContain('Fetch CONTRIBUTING.md'); expect(source).toContain('GH_TOKEN: ${{ github.token }}'); + expect(source).toContain('set -o pipefail'); // Steps write to context files (not $GITHUB_OUTPUT), so data persists for the agent expect(source).toContain('/tmp/gh-aw/contribution-check-context/contributing.md'); @@ -27,6 +28,7 @@ describe('contribution-check workflow', () => { expect(source).toContain('Read the following pre-fetched context files before proceeding'); expect(source).toContain("Do NOT call `gh pr diff`"); expect(source).toContain('Use ONLY the pre-fetched data in these context files'); + expect(source).toContain('Review PR #${{ github.event.pull_request.number || github.event.inputs.item_number }}'); }); it('has conservative turn limit and appropriate model', () => {