From 7120f362bb1a4d362c5417aa0b7892c0e1b2b30f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 22 Apr 2026 21:06:20 +0000 Subject: [PATCH 1/6] Plan agent failure caution callout placement Agent-Logs-Url: https://github.com/github/gh-aw/sessions/95de0e3e-54a7-4ea7-8086-c13bcdbbdf65 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .github/workflows/smoke-project.lock.yml | 4 ++-- .github/workflows/test-project-url-default.lock.yml | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/smoke-project.lock.yml b/.github/workflows/smoke-project.lock.yml index 228c765f09b..3bd1d6c005e 100644 --- a/.github/workflows/smoke-project.lock.yml +++ b/.github/workflows/smoke-project.lock.yml @@ -1130,7 +1130,7 @@ jobs: permissions: contents: write discussions: write - issues: write + issues: read pull-requests: write concurrency: group: "gh-aw-conclusion-smoke-project" @@ -1499,7 +1499,7 @@ jobs: permissions: contents: write discussions: write - issues: write + issues: read pull-requests: write timeout-minutes: 15 env: diff --git a/.github/workflows/test-project-url-default.lock.yml b/.github/workflows/test-project-url-default.lock.yml index 98b8937c414..c4b7f8d3f78 100644 --- a/.github/workflows/test-project-url-default.lock.yml +++ b/.github/workflows/test-project-url-default.lock.yml @@ -892,6 +892,7 @@ jobs: runs-on: ubuntu-slim permissions: contents: read + issues: read concurrency: group: "gh-aw-conclusion-test-project-url-default" cancel-in-progress: false @@ -1197,6 +1198,7 @@ jobs: runs-on: ubuntu-slim permissions: contents: read + issues: read timeout-minutes: 15 env: GH_AW_CALLER_WORKFLOW_ID: "${{ github.repository }}/test-project-url-default" From 571ec3b3d48a98fd6f37124594d3a86055e5c118 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 22 Apr 2026 21:11:32 +0000 Subject: [PATCH 2/6] Move detection caution alert to top of agent failure bodies Agent-Logs-Url: https://github.com/github/gh-aw/sessions/95de0e3e-54a7-4ea7-8086-c13bcdbbdf65 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/handle_agent_failure.cjs | 13 ++++++++++--- actions/setup/js/messages.test.cjs | 10 ++++------ actions/setup/js/messages_footer.cjs | 12 ------------ 3 files changed, 14 insertions(+), 21 deletions(-) diff --git a/actions/setup/js/handle_agent_failure.cjs b/actions/setup/js/handle_agent_failure.cjs index a8740a56db0..8d1a1d80d15 100644 --- a/actions/setup/js/handle_agent_failure.cjs +++ b/actions/setup/js/handle_agent_failure.cjs @@ -3,7 +3,7 @@ const { getErrorMessage } = require("./error_helpers.cjs"); const { sanitizeContent } = require("./sanitize_content.cjs"); -const { getFooterAgentFailureIssueMessage, getFooterAgentFailureCommentMessage, generateXMLMarker } = require("./messages.cjs"); +const { getDetectionCautionAlert, getFooterAgentFailureIssueMessage, getFooterAgentFailureCommentMessage, generateXMLMarker } = require("./messages.cjs"); const { renderTemplate, renderTemplateFromFile } = require("./messages_core.cjs"); const { getCurrentBranch } = require("./get_current_branch.cjs"); const { createExpirationLine, generateFooterWithExpiration } = require("./ephemerals.cjs"); @@ -1374,8 +1374,12 @@ async function main() { }; const footer = getFooterAgentFailureCommentMessage(ctx); + // Prepend detection caution alert (when present) so it appears first in the comment body + const detectionCaution = getDetectionCautionAlert(workflowName, runUrl); + const fullCommentBodyRaw = detectionCaution ? `${detectionCaution}\n\n${commentBody}\n\n${footer}` : `${commentBody}\n\n${footer}`; + // Combine comment body with footer - const fullCommentBody = sanitizeContent(commentBody + "\n\n" + footer, { maxLength: 65000 }); + const fullCommentBody = sanitizeContent(fullCommentBodyRaw, { maxLength: 65000 }); await github.rest.issues.createComment({ owner, @@ -1539,8 +1543,11 @@ async function main() { suffix: `\n\n${generateXMLMarker(workflowName, runUrl)}`, }); + // Prepend detection caution alert (when present) so it appears first in the issue body + const detectionCaution = getDetectionCautionAlert(workflowName, runUrl); + // Combine issue body with footer - const bodyLines = [issueBodyContent, "", footerWithExpires]; + const bodyLines = detectionCaution ? [detectionCaution, "", issueBodyContent, "", footerWithExpires] : [issueBodyContent, "", footerWithExpires]; const issueBody = bodyLines.join("\n"); const newIssue = await github.rest.issues.create({ diff --git a/actions/setup/js/messages.test.cjs b/actions/setup/js/messages.test.cjs index d2a877af152..b077507a2a8 100644 --- a/actions/setup/js/messages.test.cjs +++ b/actions/setup/js/messages.test.cjs @@ -921,7 +921,7 @@ describe("messages.cjs", () => { expect(result).toContain("> Generated by [Test Workflow]"); }); - it("should include caution alert in getFooterAgentFailureIssueMessage when detection is warning", async () => { + it("should not include caution alert in getFooterAgentFailureIssueMessage when detection is warning", async () => { process.env.GH_AW_DETECTION_CONCLUSION = "warning"; process.env.GH_AW_DETECTION_REASON = "threat_detected"; @@ -932,12 +932,11 @@ describe("messages.cjs", () => { runUrl: "https://github.com/test/repo/actions/runs/123", }); - expect(result).toContain("> [!CAUTION]"); - expect(result).toContain("Security scanning requires review"); + expect(result).not.toContain("> [!CAUTION]"); expect(result).toContain("> Generated from [Test Workflow]"); }); - it("should include caution alert in getFooterAgentFailureCommentMessage when detection is warning", async () => { + it("should not include caution alert in getFooterAgentFailureCommentMessage when detection is warning", async () => { process.env.GH_AW_DETECTION_CONCLUSION = "warning"; process.env.GH_AW_DETECTION_REASON = "parse_error"; @@ -948,8 +947,7 @@ describe("messages.cjs", () => { runUrl: "https://github.com/test/repo/actions/runs/123", }); - expect(result).toContain("> [!CAUTION]"); - expect(result).toContain("could not be parsed"); + expect(result).not.toContain("> [!CAUTION]"); expect(result).toContain("> Generated from [Test Workflow]"); }); }); diff --git a/actions/setup/js/messages_footer.cjs b/actions/setup/js/messages_footer.cjs index 41952d4ffdb..01c6e9883b8 100644 --- a/actions/setup/js/messages_footer.cjs +++ b/actions/setup/js/messages_footer.cjs @@ -250,12 +250,6 @@ function getFooterAgentFailureIssueMessage(ctx) { footer = renderTemplate(defaultFooter, templateContext); } - // Prepend detection caution alert if detection job found a potential issue - const detectionCaution = getDetectionCautionAlert(ctx.workflowName, ctx.runUrl); - if (detectionCaution) { - footer = detectionCaution + "\n\n" + footer; - } - return footer; } @@ -297,12 +291,6 @@ function getFooterAgentFailureCommentMessage(ctx) { footer = renderTemplate(defaultFooter, templateContext); } - // Prepend detection caution alert if detection job found a potential issue - const detectionCaution = getDetectionCautionAlert(ctx.workflowName, ctx.runUrl); - if (detectionCaution) { - footer = detectionCaution + "\n\n" + footer; - } - return footer; } From b2e49b6285cbdba6a1226a0ce63128a092901d4d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 22 Apr 2026 21:15:06 +0000 Subject: [PATCH 3/6] Revert unrelated workflow lock permission changes Agent-Logs-Url: https://github.com/github/gh-aw/sessions/95de0e3e-54a7-4ea7-8086-c13bcdbbdf65 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .github/workflows/smoke-project.lock.yml | 4 ++-- .github/workflows/test-project-url-default.lock.yml | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/smoke-project.lock.yml b/.github/workflows/smoke-project.lock.yml index 3bd1d6c005e..228c765f09b 100644 --- a/.github/workflows/smoke-project.lock.yml +++ b/.github/workflows/smoke-project.lock.yml @@ -1130,7 +1130,7 @@ jobs: permissions: contents: write discussions: write - issues: read + issues: write pull-requests: write concurrency: group: "gh-aw-conclusion-smoke-project" @@ -1499,7 +1499,7 @@ jobs: permissions: contents: write discussions: write - issues: read + issues: write pull-requests: write timeout-minutes: 15 env: diff --git a/.github/workflows/test-project-url-default.lock.yml b/.github/workflows/test-project-url-default.lock.yml index c4b7f8d3f78..98b8937c414 100644 --- a/.github/workflows/test-project-url-default.lock.yml +++ b/.github/workflows/test-project-url-default.lock.yml @@ -892,7 +892,6 @@ jobs: runs-on: ubuntu-slim permissions: contents: read - issues: read concurrency: group: "gh-aw-conclusion-test-project-url-default" cancel-in-progress: false @@ -1198,7 +1197,6 @@ jobs: runs-on: ubuntu-slim permissions: contents: read - issues: read timeout-minutes: 15 env: GH_AW_CALLER_WORKFLOW_ID: "${{ github.repository }}/test-project-url-default" From ded046653ac0e6445c4add41e09c845cb53d00a4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 22 Apr 2026 23:08:32 +0000 Subject: [PATCH 4/6] Plan addressing PR review comments Agent-Logs-Url: https://github.com/github/gh-aw/sessions/0207e738-267e-431c-9a99-636c5c6ccf17 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .github/workflows/smoke-project.lock.yml | 4 ++-- .github/workflows/test-project-url-default.lock.yml | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/smoke-project.lock.yml b/.github/workflows/smoke-project.lock.yml index 228c765f09b..3bd1d6c005e 100644 --- a/.github/workflows/smoke-project.lock.yml +++ b/.github/workflows/smoke-project.lock.yml @@ -1130,7 +1130,7 @@ jobs: permissions: contents: write discussions: write - issues: write + issues: read pull-requests: write concurrency: group: "gh-aw-conclusion-smoke-project" @@ -1499,7 +1499,7 @@ jobs: permissions: contents: write discussions: write - issues: write + issues: read pull-requests: write timeout-minutes: 15 env: diff --git a/.github/workflows/test-project-url-default.lock.yml b/.github/workflows/test-project-url-default.lock.yml index 98b8937c414..c4b7f8d3f78 100644 --- a/.github/workflows/test-project-url-default.lock.yml +++ b/.github/workflows/test-project-url-default.lock.yml @@ -892,6 +892,7 @@ jobs: runs-on: ubuntu-slim permissions: contents: read + issues: read concurrency: group: "gh-aw-conclusion-test-project-url-default" cancel-in-progress: false @@ -1197,6 +1198,7 @@ jobs: runs-on: ubuntu-slim permissions: contents: read + issues: read timeout-minutes: 15 env: GH_AW_CALLER_WORKFLOW_ID: "${{ github.repository }}/test-project-url-default" From b0cdfd29e772129e222d84020c0bc52db5582c31 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 22 Apr 2026 23:10:52 +0000 Subject: [PATCH 5/6] Add coverage for caution placement in handle_agent_failure main flow Agent-Logs-Url: https://github.com/github/gh-aw/sessions/0207e738-267e-431c-9a99-636c5c6ccf17 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .../setup/js/handle_agent_failure.test.cjs | 125 +++++++++++++++++- 1 file changed, 124 insertions(+), 1 deletion(-) diff --git a/actions/setup/js/handle_agent_failure.test.cjs b/actions/setup/js/handle_agent_failure.test.cjs index 157fce25f22..95335765756 100644 --- a/actions/setup/js/handle_agent_failure.test.cjs +++ b/actions/setup/js/handle_agent_failure.test.cjs @@ -6,6 +6,7 @@ import { createRequire } from "module"; const require = createRequire(import.meta.url); describe("handle_agent_failure", () => { + let main; let buildCodePushFailureContext; let buildPushRepoMemoryFailureContext; let getActionFailureIssueExpiresHours; @@ -25,7 +26,7 @@ describe("handle_agent_failure", () => { // Reset module registry so each test gets a fresh require vi.resetModules(); - ({ buildCodePushFailureContext, buildPushRepoMemoryFailureContext, getActionFailureIssueExpiresHours } = require("./handle_agent_failure.cjs")); + ({ main, buildCodePushFailureContext, buildPushRepoMemoryFailureContext, getActionFailureIssueExpiresHours } = require("./handle_agent_failure.cjs")); }); afterEach(() => { @@ -54,6 +55,128 @@ describe("handle_agent_failure", () => { }); }); + describe("detection caution placement in main()", () => { + const fs = require("fs"); + const path = require("path"); + const os = require("os"); + + /** @type {string} */ + let tmpDir; + /** @type {string} */ + let promptsDir; + + beforeEach(() => { + tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "aw-handle-agent-failure-")); + promptsDir = path.join(tmpDir, "gh-aw", "prompts"); + fs.mkdirSync(promptsDir, { recursive: true }); + + // Minimal templates used by main() + fs.writeFileSync(path.join(promptsDir, "agent_failure_comment.md"), "COMMENT TEMPLATE CONTENT"); + fs.writeFileSync(path.join(promptsDir, "agent_failure_issue.md"), "ISSUE TEMPLATE CONTENT"); + + process.env.RUNNER_TEMP = tmpDir; + process.env.GH_AW_WORKFLOW_NAME = "Test Workflow"; + process.env.GH_AW_WORKFLOW_ID = "test-workflow"; + process.env.GH_AW_RUN_URL = "https://github.com/owner/repo/actions/runs/123456"; + process.env.GH_AW_AGENT_CONCLUSION = "failure"; + process.env.GH_AW_DETECTION_CONCLUSION = "warning"; + process.env.GH_AW_DETECTION_REASON = "threat_detected"; + }); + + afterEach(() => { + delete process.env.RUNNER_TEMP; + delete process.env.GH_AW_WORKFLOW_NAME; + delete process.env.GH_AW_WORKFLOW_ID; + delete process.env.GH_AW_RUN_URL; + delete process.env.GH_AW_AGENT_CONCLUSION; + delete process.env.GH_AW_DETECTION_CONCLUSION; + delete process.env.GH_AW_DETECTION_REASON; + + if (tmpDir && fs.existsSync(tmpDir)) { + fs.rmSync(tmpDir, { recursive: true, force: true }); + } + }); + + it("prepends caution callout to existing-issue comment body and includes it only once", async () => { + /** @type {string} */ + let capturedCommentBody = ""; + + global.github = { + rest: { + search: { + issuesAndPullRequests: vi.fn(async ({ q }) => { + if (q.includes("is:pr")) { + return { data: { total_count: 0, items: [] } }; + } + return { + data: { + total_count: 1, + items: [{ number: 42, html_url: "https://github.com/owner/repo/issues/42" }], + }, + }; + }), + }, + issues: { + createComment: vi.fn(async ({ body }) => { + capturedCommentBody = body; + return { data: { id: 1001 } }; + }), + }, + pulls: { + get: vi.fn(), + }, + }, + graphql: vi.fn(), + }; + + await main(); + + expect(capturedCommentBody).toBeTruthy(); + expect(capturedCommentBody.startsWith("> [!CAUTION]")).toBe(true); + expect(capturedCommentBody.indexOf("> [!CAUTION]")).toBeLessThan(capturedCommentBody.indexOf("COMMENT TEMPLATE CONTENT")); + expect((capturedCommentBody.match(/> \[!CAUTION\]/g) || []).length).toBe(1); + expect(capturedCommentBody).toContain("> Generated from [Test Workflow]"); + }); + + it("prepends caution callout to new issue body and includes it only once", async () => { + /** @type {string} */ + let capturedIssueBody = ""; + + global.github = { + rest: { + search: { + issuesAndPullRequests: vi.fn(async ({ q }) => { + if (q.includes("is:pr")) { + return { data: { total_count: 0, items: [] } }; + } + return { data: { total_count: 0, items: [] } }; + }), + }, + issues: { + create: vi.fn(async ({ body }) => { + capturedIssueBody = body; + return { + data: { number: 101, html_url: "https://github.com/owner/repo/issues/101", node_id: "I_123" }, + }; + }), + }, + pulls: { + get: vi.fn(), + }, + }, + graphql: vi.fn(), + }; + + await main(); + + expect(capturedIssueBody).toBeTruthy(); + expect(capturedIssueBody.startsWith("> [!CAUTION]")).toBe(true); + expect(capturedIssueBody.indexOf("> [!CAUTION]")).toBeLessThan(capturedIssueBody.indexOf("ISSUE TEMPLATE CONTENT")); + expect((capturedIssueBody.match(/> \[!CAUTION\]/g) || []).length).toBe(1); + expect(capturedIssueBody).toContain("> Generated from [Test Workflow]"); + }); + }); + describe("buildCodePushFailureContext", () => { it("returns empty string when no errors", () => { expect(buildCodePushFailureContext("")).toBe(""); From bea4c5dfb59c9435126a9912bfc88e89a821c0fa Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 22 Apr 2026 23:14:15 +0000 Subject: [PATCH 6/6] Revert unrelated workflow lock file permission diffs Agent-Logs-Url: https://github.com/github/gh-aw/sessions/0207e738-267e-431c-9a99-636c5c6ccf17 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .github/workflows/smoke-project.lock.yml | 4 ++-- .github/workflows/test-project-url-default.lock.yml | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/smoke-project.lock.yml b/.github/workflows/smoke-project.lock.yml index 3bd1d6c005e..228c765f09b 100644 --- a/.github/workflows/smoke-project.lock.yml +++ b/.github/workflows/smoke-project.lock.yml @@ -1130,7 +1130,7 @@ jobs: permissions: contents: write discussions: write - issues: read + issues: write pull-requests: write concurrency: group: "gh-aw-conclusion-smoke-project" @@ -1499,7 +1499,7 @@ jobs: permissions: contents: write discussions: write - issues: read + issues: write pull-requests: write timeout-minutes: 15 env: diff --git a/.github/workflows/test-project-url-default.lock.yml b/.github/workflows/test-project-url-default.lock.yml index c4b7f8d3f78..98b8937c414 100644 --- a/.github/workflows/test-project-url-default.lock.yml +++ b/.github/workflows/test-project-url-default.lock.yml @@ -892,7 +892,6 @@ jobs: runs-on: ubuntu-slim permissions: contents: read - issues: read concurrency: group: "gh-aw-conclusion-test-project-url-default" cancel-in-progress: false @@ -1198,7 +1197,6 @@ jobs: runs-on: ubuntu-slim permissions: contents: read - issues: read timeout-minutes: 15 env: GH_AW_CALLER_WORKFLOW_ID: "${{ github.repository }}/test-project-url-default"