diff --git a/actions/setup/js/assign_to_agent.cjs b/actions/setup/js/assign_to_agent.cjs index 5697e233bfa..01a9df4f70a 100644 --- a/actions/setup/js/assign_to_agent.cjs +++ b/actions/setup/js/assign_to_agent.cjs @@ -10,6 +10,7 @@ const { loadTemporaryIdMap, resolveRepoIssueTarget } = require("./temporary_id.c const { sleep } = require("./error_recovery.cjs"); const { parseAllowedRepos, validateRepo, resolveTargetRepoConfig, resolveAndValidateRepo } = require("./repo_helpers.cjs"); const { resolvePullRequestRepo } = require("./pr_helpers.cjs"); +const { sanitizeContent } = require("./sanitize_content.cjs"); async function main() { const result = loadAgentOutput(); @@ -612,7 +613,7 @@ async function main() { owner: r.owner, repo: r.repo, issue_number: failedNumber, - body: `⚠️ **Assignment failed**: Failed to assign ${r.agent} coding agent to this ${failedType}.\n\nError: ${r.error}`, + body: sanitizeContent(`⚠️ **Assignment failed**: Failed to assign ${r.agent} coding agent to this ${failedType}.\n\nError: ${r.error}`, { maxLength: 65000 }), }); core.info(`Posted failure comment on ${failedType} #${failedNumber} in ${r.owner}/${r.repo}`); } catch (commentError) { diff --git a/actions/setup/js/assign_to_agent.test.cjs b/actions/setup/js/assign_to_agent.test.cjs index 775820d50aa..c2824a30350 100644 --- a/actions/setup/js/assign_to_agent.test.cjs +++ b/actions/setup/js/assign_to_agent.test.cjs @@ -1059,6 +1059,29 @@ describe("assign_to_agent", () => { ); }); + it("should sanitize dangerous content in failure comment body", async () => { + setAgentOutput({ + items: [{ type: "assign_to_agent", issue_number: 11, agent: "copilot" }], + errors: [], + }); + + // Simulate an error whose message contains an @mention and an HTML comment — + // both are potentially dangerous if posted unsanitized. + const dangerousError = new Error("@admin triggered error"); + mockGithub.graphql.mockRejectedValue(dangerousError); + + await eval(`(async () => { ${assignToAgentScript}; await main(); })()`); + + expect(mockGithub.rest.issues.createComment).toHaveBeenCalledTimes(1); + const [callArg] = mockGithub.rest.issues.createComment.mock.calls[0]; + // The body must be a string (sanitizeContent never returns undefined) + expect(typeof callArg.body).toBe("string"); + // The raw @mention should be neutralized (wrapped in backticks, not bare) + expect(callArg.body).not.toMatch(/(?"); + }); + it("should not post failure comment when ignore-if-error skips the assignment", async () => { process.env.GH_AW_AGENT_IGNORE_IF_ERROR = "true"; setAgentOutput({