Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 23 additions & 3 deletions actions/setup/js/notify_comment_error.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const { sanitizeContent } = require("./sanitize_content.cjs");
const { ERR_VALIDATION } = require("./error_codes.cjs");
const { parseBoolTemplatable } = require("./templatable.cjs");
const { resolveTopLevelDiscussionCommentId } = require("./github_api_helpers.cjs");
const { assembleMarkdownBodyParts } = require("./markdown_body_helpers.cjs");

/**
* Collect generated asset URLs from safe output jobs
Expand Down Expand Up @@ -258,6 +259,25 @@ async function main() {
});
}

// Build the generated footer (attribution + XML marker). Appended after sanitization
// so that the XML traceability marker is not stripped by sanitizeContent.
const workflowSource = process.env.GH_AW_WORKFLOW_SOURCE ?? "";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/codebase-design] GH_AW_WORKFLOW_SOURCE and GH_AW_WORKFLOW_SOURCE_URL are re-read from process.env here, but workflowName and runUrl were already read at lines 114–115 from the same source. Consider reading all workflow env vars together near the top of main() for consistency and to make the full set of dependencies obvious at a glance.

@copilot please address this.

const workflowSourceURL = process.env.GH_AW_WORKFLOW_SOURCE_URL ?? "";
const triggeringIssueNumber = context.payload?.issue?.number;
const triggeringPRNumber = context.payload?.pull_request?.number;
const triggeringDiscussionNumber = context.payload?.discussion?.number;
const markdownParts = assembleMarkdownBodyParts({
includeFooter: true,
workflowName,
runUrl,
workflowSource,
workflowSourceURL,
triggeringIssueNumber,
triggeringPRNumber,
triggeringDiscussionNumber,
});
const footer = markdownParts.footer;

// Add "needs-review" label when detection produced a warning
if (detectionConclusion === "warning") {
await tryAddNeedsReviewLabel(commentRepo);
Expand Down Expand Up @@ -309,7 +329,7 @@ async function main() {
}
}`;

const sanitizedMessage = sanitizeContent(message);
const sanitizedMessage = sanitizeContent(message) + "\n\n" + footer;
const variables = replyToId ? { dId: discussionId, body: sanitizedMessage, replyToId } : { dId: discussionId, body: sanitizedMessage };
const result = await github.graphql(mutation, variables);
const created = result?.addDiscussionComment?.comment;
Expand All @@ -326,7 +346,7 @@ async function main() {
return;
}

const sanitizedMessage = sanitizeContent(message);
const sanitizedMessage = sanitizeContent(message) + "\n\n" + footer;
const response = await github.request("POST /repos/{owner}/{repo}/issues/{issue_number}/comments", {
owner: repoOwner,
repo: repoName,
Expand Down Expand Up @@ -364,7 +384,7 @@ async function main() {
// Check if this is a discussion comment (GraphQL node ID format)
const isDiscussionComment = commentId.startsWith("DC_");

const sanitizedMessage = sanitizeContent(message);
const sanitizedMessage = sanitizeContent(message) + "\n\n" + footer;

try {
if (isDiscussionComment) {
Expand Down
26 changes: 24 additions & 2 deletions actions/setup/js/notify_comment_error.test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@
(process.env.GH_AW_WORKFLOW_NAME = "test-workflow"),
(process.env.GH_AW_AGENT_CONCLUSION = "failure"),
(process.env.GH_AW_DETECTION_CONCLUSION = "warning"),
await eval(`(async () => { ${notifyCommentScript}; await main(); })()`),

Check failure on line 238 in actions/setup/js/notify_comment_error.test.cjs

View workflow job for this annotation

GitHub Actions / impacted-js-tests

notify_comment_error.test.cjs > notify_comment_error.cjs > when updating an issue/PR comment > should show failure message with detection warning when agent fails

Error: Failed to read file /home/runner/work/_temp/gh-aw/prompts/threat_detection_caution.md: ENOENT: no such file or directory, open '/home/runner/work/_temp/gh-aw/prompts/threat_detection_caution.md' ❯ renderTemplateFromFile messages_core.cjs:146:11 ❯ getDetectionWarningMessage messages_run_status.cjs:164:10 ❯ main notify_comment_error.test.cjs:238:21 ❯ eval notify_comment_error.test.cjs:238:21 ❯ eval notify_comment_error.test.cjs:238:21 ❯ notify_comment_error.test.cjs:238:21 Caused by: Caused by: Error: ENOENT: no such file or directory, open '/home/runner/work/_temp/gh-aw/prompts/threat_detection_caution.md' ❯ renderTemplateFromFile messages_core.cjs:144:19 ❯ getDetectionWarningMessage messages_run_status.cjs:164:10 ❯ main notify_comment_error.test.cjs:238:21 ❯ eval notify_comment_error.test.cjs:238:21 ❯ eval notify_comment_error.test.cjs:238:21 ❯ notify_comment_error.test.cjs:238:21 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Serialized Error: { errno: -2, code: 'ENOENT', syscall: 'open', path: '/home/runner/work/_temp/gh-aw/prompts/threat_detection_caution.md' }
expect(mockGithub.request).toHaveBeenCalledWith("PATCH /repos/{owner}/{repo}/issues/comments/{comment_id}", expect.objectContaining({ body: expect.stringContaining("failed. Please review the logs") })));
}),
it("should show cancelled message with detection warning when agent is cancelled", async () => {
Expand All @@ -244,7 +244,7 @@
(process.env.GH_AW_WORKFLOW_NAME = "test-workflow"),
(process.env.GH_AW_AGENT_CONCLUSION = "cancelled"),
(process.env.GH_AW_DETECTION_CONCLUSION = "warning"),
await eval(`(async () => { ${notifyCommentScript}; await main(); })()`),

Check failure on line 247 in actions/setup/js/notify_comment_error.test.cjs

View workflow job for this annotation

GitHub Actions / impacted-js-tests

notify_comment_error.test.cjs > notify_comment_error.cjs > when updating an issue/PR comment > should show cancelled message with detection warning when agent is cancelled

Error: Failed to read file /home/runner/work/_temp/gh-aw/prompts/threat_detection_caution.md: ENOENT: no such file or directory, open '/home/runner/work/_temp/gh-aw/prompts/threat_detection_caution.md' ❯ renderTemplateFromFile messages_core.cjs:146:11 ❯ getDetectionWarningMessage messages_run_status.cjs:164:10 ❯ main notify_comment_error.test.cjs:247:21 ❯ eval notify_comment_error.test.cjs:247:21 ❯ eval notify_comment_error.test.cjs:247:21 ❯ notify_comment_error.test.cjs:247:21 Caused by: Caused by: Error: ENOENT: no such file or directory, open '/home/runner/work/_temp/gh-aw/prompts/threat_detection_caution.md' ❯ renderTemplateFromFile messages_core.cjs:144:19 ❯ getDetectionWarningMessage messages_run_status.cjs:164:10 ❯ main notify_comment_error.test.cjs:247:21 ❯ eval notify_comment_error.test.cjs:247:21 ❯ eval notify_comment_error.test.cjs:247:21 ❯ notify_comment_error.test.cjs:247:21 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Serialized Error: { errno: -2, code: 'ENOENT', syscall: 'open', path: '/home/runner/work/_temp/gh-aw/prompts/threat_detection_caution.md' }
expect(mockGithub.request).toHaveBeenCalledWith("PATCH /repos/{owner}/{repo}/issues/comments/{comment_id}", expect.objectContaining({ body: expect.stringContaining("was cancelled. Please review the logs") })));
}),
it("should show timed out message with detection warning when agent times out", async () => {
Expand All @@ -253,7 +253,7 @@
(process.env.GH_AW_WORKFLOW_NAME = "test-workflow"),
(process.env.GH_AW_AGENT_CONCLUSION = "timed_out"),
(process.env.GH_AW_DETECTION_CONCLUSION = "warning"),
await eval(`(async () => { ${notifyCommentScript}; await main(); })()`),

Check failure on line 256 in actions/setup/js/notify_comment_error.test.cjs

View workflow job for this annotation

GitHub Actions / impacted-js-tests

notify_comment_error.test.cjs > notify_comment_error.cjs > when updating an issue/PR comment > should show timed out message with detection warning when agent times out

Error: Failed to read file /home/runner/work/_temp/gh-aw/prompts/threat_detection_caution.md: ENOENT: no such file or directory, open '/home/runner/work/_temp/gh-aw/prompts/threat_detection_caution.md' ❯ renderTemplateFromFile messages_core.cjs:146:11 ❯ getDetectionWarningMessage messages_run_status.cjs:164:10 ❯ main notify_comment_error.test.cjs:256:21 ❯ eval notify_comment_error.test.cjs:256:21 ❯ eval notify_comment_error.test.cjs:256:21 ❯ notify_comment_error.test.cjs:256:21 Caused by: Caused by: Error: ENOENT: no such file or directory, open '/home/runner/work/_temp/gh-aw/prompts/threat_detection_caution.md' ❯ renderTemplateFromFile messages_core.cjs:144:19 ❯ getDetectionWarningMessage messages_run_status.cjs:164:10 ❯ main notify_comment_error.test.cjs:256:21 ❯ eval notify_comment_error.test.cjs:256:21 ❯ eval notify_comment_error.test.cjs:256:21 ❯ notify_comment_error.test.cjs:256:21 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Serialized Error: { errno: -2, code: 'ENOENT', syscall: 'open', path: '/home/runner/work/_temp/gh-aw/prompts/threat_detection_caution.md' }
expect(mockGithub.request).toHaveBeenCalledWith("PATCH /repos/{owner}/{repo}/issues/comments/{comment_id}", expect.objectContaining({ body: expect.stringContaining("timed out. Please review the logs") })));
}),
it("should show assignment failure message with detection warning when agent succeeds but assign-to-agent fails", async () => {
Expand All @@ -263,7 +263,7 @@
(process.env.GH_AW_AGENT_CONCLUSION = "success"),
(process.env.GH_AW_ASSIGNMENT_ERROR_COUNT = "2"),
(process.env.GH_AW_DETECTION_CONCLUSION = "warning"),
await eval(`(async () => { ${notifyCommentScript}; await main(); })()`),

Check failure on line 266 in actions/setup/js/notify_comment_error.test.cjs

View workflow job for this annotation

GitHub Actions / impacted-js-tests

notify_comment_error.test.cjs > notify_comment_error.cjs > when updating an issue/PR comment > should show assignment failure message with detection warning when agent succeeds but assign-to-agent fails

Error: Failed to read file /home/runner/work/_temp/gh-aw/prompts/threat_detection_caution.md: ENOENT: no such file or directory, open '/home/runner/work/_temp/gh-aw/prompts/threat_detection_caution.md' ❯ renderTemplateFromFile messages_core.cjs:146:11 ❯ getDetectionWarningMessage messages_run_status.cjs:164:10 ❯ main notify_comment_error.test.cjs:266:21 ❯ eval notify_comment_error.test.cjs:266:21 ❯ eval notify_comment_error.test.cjs:266:21 ❯ notify_comment_error.test.cjs:266:21 Caused by: Caused by: Error: ENOENT: no such file or directory, open '/home/runner/work/_temp/gh-aw/prompts/threat_detection_caution.md' ❯ renderTemplateFromFile messages_core.cjs:144:19 ❯ getDetectionWarningMessage messages_run_status.cjs:164:10 ❯ main notify_comment_error.test.cjs:266:21 ❯ eval notify_comment_error.test.cjs:266:21 ❯ eval notify_comment_error.test.cjs:266:21 ❯ notify_comment_error.test.cjs:266:21 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Serialized Error: { errno: -2, code: 'ENOENT', syscall: 'open', path: '/home/runner/work/_temp/gh-aw/prompts/threat_detection_caution.md' }
expect(mockGithub.request).toHaveBeenCalledWith("PATCH /repos/{owner}/{repo}/issues/comments/{comment_id}", expect.objectContaining({ body: expect.stringContaining("failed to assign the coding agent") })));
}));
}),
Expand Down Expand Up @@ -331,7 +331,7 @@
(process.env.GH_AW_SAFE_OUTPUT_JOBS = JSON.stringify({ create_issue: "issue_url" })),
await eval(`(async () => { ${notifyCommentScript}; await main(); })()`));
const callArgs = mockGithub.request.mock.calls[0][1];
expect(callArgs.body).toMatch(/completed successfully!$/);
expect(callArgs.body).toContain("completed successfully!");
}),
it("should handle empty safe output jobs gracefully", async () => {
((process.env.GH_AW_COMMENT_ID = "123456"),
Expand All @@ -340,7 +340,7 @@
(process.env.GH_AW_AGENT_CONCLUSION = "success"),
await eval(`(async () => { ${notifyCommentScript}; await main(); })()`));
const callArgs = mockGithub.request.mock.calls[0][1];
expect(callArgs.body).toMatch(/completed successfully!$/);
expect(callArgs.body).toContain("completed successfully!");
}));
}),
describe("when safe_outputs job fails", () => {
Expand All @@ -361,7 +361,7 @@
(process.env.GH_AW_AGENT_CONCLUSION = "success"),
(process.env.GH_AW_SAFE_OUTPUTS_RESULT = "failure"),
(process.env.GH_AW_DETECTION_CONCLUSION = "warning"),
await eval(`(async () => { ${notifyCommentScript}; await main(); })()`),

Check failure on line 364 in actions/setup/js/notify_comment_error.test.cjs

View workflow job for this annotation

GitHub Actions / impacted-js-tests

notify_comment_error.test.cjs > notify_comment_error.cjs > when safe_outputs job fails > should show failure message when agent succeeds, safe_outputs fails, and detection warns

Error: Failed to read file /home/runner/work/_temp/gh-aw/prompts/threat_detection_caution.md: ENOENT: no such file or directory, open '/home/runner/work/_temp/gh-aw/prompts/threat_detection_caution.md' ❯ renderTemplateFromFile messages_core.cjs:146:11 ❯ getDetectionWarningMessage messages_run_status.cjs:164:10 ❯ main notify_comment_error.test.cjs:364:21 ❯ eval notify_comment_error.test.cjs:364:21 ❯ eval notify_comment_error.test.cjs:364:21 ❯ notify_comment_error.test.cjs:364:21 Caused by: Caused by: Error: ENOENT: no such file or directory, open '/home/runner/work/_temp/gh-aw/prompts/threat_detection_caution.md' ❯ renderTemplateFromFile messages_core.cjs:144:19 ❯ getDetectionWarningMessage messages_run_status.cjs:164:10 ❯ main notify_comment_error.test.cjs:364:21 ❯ eval notify_comment_error.test.cjs:364:21 ❯ eval notify_comment_error.test.cjs:364:21 ❯ notify_comment_error.test.cjs:364:21 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Serialized Error: { errno: -2, code: 'ENOENT', syscall: 'open', path: '/home/runner/work/_temp/gh-aw/prompts/threat_detection_caution.md' }
expect(mockGithub.request).toHaveBeenCalledWith("PATCH /repos/{owner}/{repo}/issues/comments/{comment_id}", expect.objectContaining({ body: expect.stringContaining("failed to deliver outputs. Please review the logs") })));
}),
it("should show success message when agent succeeds and safe_outputs succeeds", async () => {
Expand All @@ -373,5 +373,27 @@
await eval(`(async () => { ${notifyCommentScript}; await main(); })()`),
expect(mockGithub.request).toHaveBeenCalledWith("PATCH /repos/{owner}/{repo}/issues/comments/{comment_id}", expect.objectContaining({ body: expect.stringContaining("completed successfully!") })));
}));
}),
describe("footer in status comment", () => {
(it("should include the generated footer in the updated comment body", async () => {
((process.env.GH_AW_COMMENT_ID = "123456"),
(process.env.GH_AW_RUN_URL = "https://github.com/owner/repo/actions/runs/123"),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/tdd] The two new footer tests share identical env setup and differ only in GH_AW_AGENT_CONCLUSION. Extracting the shared setup into a beforeEach (or a helper) would make it clear which variables are the test-specific inputs vs. shared context, and reduce copy-paste risk when new env vars are added to the footer path.

@copilot please address this.

(process.env.GH_AW_WORKFLOW_NAME = "test-workflow"),
(process.env.GH_AW_AGENT_CONCLUSION = "success"),
await eval(`(async () => { ${notifyCommentScript}; await main(); })()`));
const callArgs = mockGithub.request.mock.calls[0][1];
expect(callArgs.body).toMatch(/Generated by \[test-workflow\]/);
expect(callArgs.body).toMatch(/gh-aw-agentic-workflow/);
}),
it("should include the generated footer even when agent fails", async () => {
((process.env.GH_AW_COMMENT_ID = "123456"),
(process.env.GH_AW_RUN_URL = "https://github.com/owner/repo/actions/runs/123"),
(process.env.GH_AW_WORKFLOW_NAME = "test-workflow"),
(process.env.GH_AW_AGENT_CONCLUSION = "failure"),
await eval(`(async () => { ${notifyCommentScript}; await main(); })()`));
const callArgs = mockGithub.request.mock.calls[0][1];
expect(callArgs.body).toMatch(/Generated by \[test-workflow\]/);
expect(callArgs.body).toMatch(/gh-aw-agentic-workflow/);
}));
}));
}));
Loading