From 4951fda500442a1b09abd3410b0a5dc0f13e0f5b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 11 Jun 2026 20:49:01 +0000 Subject: [PATCH 1/3] Customize agent failure issue for missing COPILOT_GITHUB_TOKEN to suggest permissions.copilot-requests:write Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/handle_agent_failure.cjs | 39 ++++++++++++++----- .../setup/js/handle_agent_failure.test.cjs | 27 ++++++++++++- 2 files changed, 55 insertions(+), 11 deletions(-) diff --git a/actions/setup/js/handle_agent_failure.cjs b/actions/setup/js/handle_agent_failure.cjs index 47e503873c9..21230ab6ada 100644 --- a/actions/setup/js/handle_agent_failure.cjs +++ b/actions/setup/js/handle_agent_failure.cjs @@ -1869,6 +1869,32 @@ function buildAssignCopilotFailureContext(hasAssignCopilotFailures, assignCopilo return "\n" + renderTemplateFromFile(templatePath, { issues: issueList }); } +/** + * Build the secret verification failure context for the agent failure issue/comment. + * For the Copilot engine, adds a suggestion to use `permissions.copilot-requests: write` + * to enable Copilot inference through the org without a personal access token. + * @param {string} secretVerificationResult - The secret verification result ("failed" or other) + * @param {string} engineId - The lowercase engine ID (e.g. "copilot") + * @returns {string} Formatted context string, or empty string if verification did not fail + */ +function buildSecretVerificationContext(secretVerificationResult, engineId) { + if (secretVerificationResult !== "failed") { + return ""; + } + + let context = + buildWarningAlertLine("Secret Verification Failed", "The workflow's secret validation step failed. Please check that the required secrets are configured in your repository settings.") + + "\nFor more information on configuring tokens, see: https://github.github.com/gh-aw/reference/engines/\n"; + + if (engineId === "copilot") { + context += + "\n**Alternative**: If your organization has a Copilot subscription, you can avoid the need for a personal access token by adding `permissions: copilot-requests: write` to your workflow frontmatter. This enables Copilot inference through the org using the built-in GitHub Actions token.\n" + + "\nSee: https://github.github.com/gh-aw/reference/engines/#github-copilot-default\n"; + } + + return context; +} + /** * Check whether agent-stdio.log contains a terminal_reason: "completed" result entry, * indicating the agent finished its task successfully despite a non-zero job exit code. @@ -2870,11 +2896,7 @@ async function main() { workflow_source: workflowSource, workflow_source_url: workflowSourceURL, secret_verification_failed: String(secretVerificationResult === "failed"), - secret_verification_context: - secretVerificationResult === "failed" - ? buildWarningAlertLine("Secret Verification Failed", "The workflow's secret validation step failed. Please check that the required secrets are configured in your repository settings.") + - "\nFor more information on configuring tokens, see: https://github.github.com/gh-aw/reference/engines/\n" - : "", + secret_verification_context: buildSecretVerificationContext(secretVerificationResult, engineId), credential_auth_error_context: credentialAuthErrorContext, assignment_errors_context: assignmentErrorsContext, assign_copilot_failure_context: assignCopilotFailureContext, @@ -3099,11 +3121,7 @@ async function main() { branch: currentBranch, pull_request_info: pullRequest ? ` \n**Pull Request:** [#${pullRequest.number}](${pullRequest.html_url})` : "", secret_verification_failed: String(secretVerificationResult === "failed"), - secret_verification_context: - secretVerificationResult === "failed" - ? buildWarningAlertLine("Secret Verification Failed", "The workflow's secret validation step failed. Please check that the required secrets are configured in your repository settings.") + - "\nFor more information on configuring tokens, see: https://github.github.com/gh-aw/reference/engines/\n" - : "", + secret_verification_context: buildSecretVerificationContext(secretVerificationResult, engineId), credential_auth_error_context: credentialAuthErrorContext, assignment_errors_context: assignmentErrorsContext, assign_copilot_failure_context: assignCopilotFailureContext, @@ -3240,6 +3258,7 @@ module.exports = { hasAgentTerminalReasonCompleted, detectAndHandleFailureCascade, findRecentFailureIssues, + buildSecretVerificationContext, CASCADE_WINDOW_MINUTES, CASCADE_WINDOW_MS, CASCADE_THRESHOLD, diff --git a/actions/setup/js/handle_agent_failure.test.cjs b/actions/setup/js/handle_agent_failure.test.cjs index baca25fdfa6..62fe9a48330 100644 --- a/actions/setup/js/handle_agent_failure.test.cjs +++ b/actions/setup/js/handle_agent_failure.test.cjs @@ -11,6 +11,7 @@ describe("handle_agent_failure", () => { let buildPushRepoMemoryFailureContext; let buildReportIncompleteContext; let buildFailureIssueTitle; + let buildSecretVerificationContext; let getActionFailureIssueExpiresHours; const ENGINE_RATE_LIMIT_TEMPLATE = "> [!WARNING]\n> **Engine Rate Limited (HTTP 429)**\n> OTLP telemetry\n> {engine_label}\n"; @@ -29,7 +30,7 @@ describe("handle_agent_failure", () => { // Reset module registry so each test gets a fresh require vi.resetModules(); - ({ main, buildCodePushFailureContext, buildPushRepoMemoryFailureContext, buildReportIncompleteContext, buildFailureIssueTitle, getActionFailureIssueExpiresHours } = require("./handle_agent_failure.cjs")); + ({ main, buildCodePushFailureContext, buildPushRepoMemoryFailureContext, buildReportIncompleteContext, buildFailureIssueTitle, buildSecretVerificationContext, getActionFailureIssueExpiresHours } = require("./handle_agent_failure.cjs")); }); afterEach(() => { @@ -1299,6 +1300,30 @@ describe("handle_agent_failure", () => { }); }); + describe("buildSecretVerificationContext", () => { + it("returns empty string when verification did not fail", () => { + expect(buildSecretVerificationContext("", "copilot")).toBe(""); + expect(buildSecretVerificationContext("success", "copilot")).toBe(""); + expect(buildSecretVerificationContext("", "")).toBe(""); + }); + + it("returns generic warning for non-copilot engines when verification failed", () => { + const result = buildSecretVerificationContext("failed", "claude"); + expect(result).toContain("Secret Verification Failed"); + expect(result).toContain("required secrets are configured"); + expect(result).toContain("https://github.github.com/gh-aw/reference/engines/"); + expect(result).not.toContain("copilot-requests"); + }); + + it("returns copilot-specific message with permissions.copilot-requests:write suggestion when verification failed", () => { + const result = buildSecretVerificationContext("failed", "copilot"); + expect(result).toContain("Secret Verification Failed"); + expect(result).toContain("required secrets are configured"); + expect(result).toContain("copilot-requests: write"); + expect(result).toContain("permissions"); + }); + }); + describe("buildCodePushFailureContext", () => { it("returns empty string when no errors", () => { expect(buildCodePushFailureContext("")).toBe(""); From 1dd58de2edd206d38bad4c258192aaacc476fe0c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 11 Jun 2026 21:01:24 +0000 Subject: [PATCH 2/3] Use fenced YAML code block for copilot-requests permission snippet Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/handle_agent_failure.cjs | 3 ++- actions/setup/js/handle_agent_failure.test.cjs | 3 +-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/actions/setup/js/handle_agent_failure.cjs b/actions/setup/js/handle_agent_failure.cjs index 21230ab6ada..99c4918f37c 100644 --- a/actions/setup/js/handle_agent_failure.cjs +++ b/actions/setup/js/handle_agent_failure.cjs @@ -1888,7 +1888,8 @@ function buildSecretVerificationContext(secretVerificationResult, engineId) { if (engineId === "copilot") { context += - "\n**Alternative**: If your organization has a Copilot subscription, you can avoid the need for a personal access token by adding `permissions: copilot-requests: write` to your workflow frontmatter. This enables Copilot inference through the org using the built-in GitHub Actions token.\n" + + "\n**Alternative**: If your organization has a Copilot subscription, you can avoid the need for a personal access token by adding the following to your workflow frontmatter. This enables Copilot inference through the org using the built-in GitHub Actions token.\n" + + "\n```yaml\npermissions:\n copilot-requests: write\n```\n" + "\nSee: https://github.github.com/gh-aw/reference/engines/#github-copilot-default\n"; } diff --git a/actions/setup/js/handle_agent_failure.test.cjs b/actions/setup/js/handle_agent_failure.test.cjs index 62fe9a48330..0e1528c7ac6 100644 --- a/actions/setup/js/handle_agent_failure.test.cjs +++ b/actions/setup/js/handle_agent_failure.test.cjs @@ -1319,8 +1319,7 @@ describe("handle_agent_failure", () => { const result = buildSecretVerificationContext("failed", "copilot"); expect(result).toContain("Secret Verification Failed"); expect(result).toContain("required secrets are configured"); - expect(result).toContain("copilot-requests: write"); - expect(result).toContain("permissions"); + expect(result).toContain("```yaml\npermissions:\n copilot-requests: write\n```"); }); }); From 33bfd58f11fbeb55bcd51d84f4e80ce9228ead94 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 11 Jun 2026 23:15:26 +0000 Subject: [PATCH 3/3] Address PR review feedback on copilot secret guidance Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/handle_agent_failure.cjs | 6 +++--- actions/setup/js/handle_agent_failure.test.cjs | 5 ++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/actions/setup/js/handle_agent_failure.cjs b/actions/setup/js/handle_agent_failure.cjs index 6c66e696a86..e9eb3dd0375 100644 --- a/actions/setup/js/handle_agent_failure.cjs +++ b/actions/setup/js/handle_agent_failure.cjs @@ -1874,7 +1874,7 @@ function buildAssignCopilotFailureContext(hasAssignCopilotFailures, assignCopilo * For the Copilot engine, adds a suggestion to use `permissions.copilot-requests: write` * to enable Copilot inference through the org without a personal access token. * @param {string} secretVerificationResult - The secret verification result ("failed" or other) - * @param {string} engineId - The lowercase engine ID (e.g. "copilot") + * @param {string} engineId - The engine ID (e.g. "copilot") * @returns {string} Formatted context string, or empty string if verification did not fail */ function buildSecretVerificationContext(secretVerificationResult, engineId) { @@ -1886,9 +1886,9 @@ function buildSecretVerificationContext(secretVerificationResult, engineId) { buildWarningAlertLine("Secret Verification Failed", "The workflow's secret validation step failed. Please check that the required secrets are configured in your repository settings.") + "\nFor more information on configuring tokens, see: https://github.github.com/gh-aw/reference/engines/\n"; - if (engineId === "copilot") { + if ((engineId || "").toLowerCase() === "copilot") { context += - "\n**Alternative**: If your organization has a Copilot subscription, you can avoid the need for a personal access token by adding the following to your workflow frontmatter. This enables Copilot inference through the org using the built-in GitHub Actions token.\n" + + "\n**Alternative**: If your organization has a Copilot subscription, you can avoid the need for a personal access token by adding a top-level `permissions` block to your workflow file. This enables Copilot inference through the org using the built-in GitHub Actions token.\n" + "\n```yaml\npermissions:\n copilot-requests: write\n```\n" + "\nSee: https://github.github.com/gh-aw/reference/engines/#github-copilot-default\n"; } diff --git a/actions/setup/js/handle_agent_failure.test.cjs b/actions/setup/js/handle_agent_failure.test.cjs index c0c55222172..3d6b990df88 100644 --- a/actions/setup/js/handle_agent_failure.test.cjs +++ b/actions/setup/js/handle_agent_failure.test.cjs @@ -1315,11 +1315,14 @@ describe("handle_agent_failure", () => { expect(result).not.toContain("copilot-requests"); }); - it("returns copilot-specific message with permissions.copilot-requests:write suggestion when verification failed", () => { + it("returns copilot-specific message with copilot-requests: write permissions suggestion when verification failed", () => { const result = buildSecretVerificationContext("failed", "copilot"); + const mixedCaseResult = buildSecretVerificationContext("failed", "Copilot"); expect(result).toContain("Secret Verification Failed"); expect(result).toContain("required secrets are configured"); expect(result).toContain("```yaml\npermissions:\n copilot-requests: write\n```"); + expect(result).toContain("https://github.github.com/gh-aw/reference/engines/#github-copilot-default"); + expect(mixedCaseResult).toContain("copilot-requests: write"); }); });