From 04970b15d36b1dcfab082db37dab179b3d53e4a4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Mar 2026 16:52:15 +0000 Subject: [PATCH 1/4] Initial plan From b5e1902e0a3ab8781bd2f0910a26e63d673e3233 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Mar 2026 17:03:16 +0000 Subject: [PATCH 2/4] Initial plan Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com> --- .github/aw/actions-lock.json | 5 +++++ .github/workflows/super-linter.lock.yml | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/aw/actions-lock.json b/.github/aw/actions-lock.json index 2e4c785c642..58a139cba5f 100644 --- a/.github/aw/actions-lock.json +++ b/.github/aw/actions-lock.json @@ -35,6 +35,11 @@ "version": "v3.0.0-beta.2", "sha": "bf559f85448f9380bcfa2899dbdc01eb5b37be3a" }, + "actions/download-artifact@v8": { + "repo": "actions/download-artifact", + "version": "v8", + "sha": "3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c" + }, "actions/download-artifact@v8.0.0": { "repo": "actions/download-artifact", "version": "v8.0.0", diff --git a/.github/workflows/super-linter.lock.yml b/.github/workflows/super-linter.lock.yml index a01b744c4be..c74c1b78cc2 100644 --- a/.github/workflows/super-linter.lock.yml +++ b/.github/workflows/super-linter.lock.yml @@ -299,7 +299,7 @@ jobs: - name: Create gh-aw temp directory run: bash /opt/gh-aw/actions/create_gh_aw_tmp_dir.sh - name: Download super-linter log - uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 with: name: super-linter-log path: /tmp/gh-aw/ From 1729ba9b62293f2ad718a92f311ed125beb5391f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Mar 2026 17:14:37 +0000 Subject: [PATCH 3/4] Fix safe_outputs failures: skip PR review comments outside PR context, register custom safe job types Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com> --- .github/workflows/smoke-copilot-arm.lock.yml | 1 + .github/workflows/smoke-copilot.lock.yml | 1 + actions/setup/js/create_pr_review_comment.cjs | 1 + .../js/create_pr_review_comment.test.cjs | 2 ++ .../setup/js/reply_to_pr_review_comment.cjs | 1 + .../js/reply_to_pr_review_comment.test.cjs | 1 + pkg/workflow/data/action_pins.json | 5 ++++ pkg/workflow/notify_comment.go | 25 +++++++++++++++++-- pkg/workflow/notify_comment_test.go | 19 +++++++++++--- 9 files changed, 51 insertions(+), 5 deletions(-) diff --git a/.github/workflows/smoke-copilot-arm.lock.yml b/.github/workflows/smoke-copilot-arm.lock.yml index a1125f07420..5277d8236d2 100644 --- a/.github/workflows/smoke-copilot-arm.lock.yml +++ b/.github/workflows/smoke-copilot-arm.lock.yml @@ -2181,6 +2181,7 @@ jobs: GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }} GH_AW_DETECTION_CONCLUSION: ${{ needs.agent.outputs.detection_conclusion }} GH_AW_SAFE_OUTPUT_MESSAGES: "{\"footer\":\"\\u003e 📰 *BREAKING: Report filed by [{workflow_name}]({run_url})*{history_link}\",\"appendOnlyComments\":true,\"runStarted\":\"📰 BREAKING: [{workflow_name}]({run_url}) is now investigating this {event_type}. Sources say the story is developing...\",\"runSuccess\":\"📰 VERDICT: [{workflow_name}]({run_url}) has concluded. All systems operational. This is a developing story. 🎤\",\"runFailure\":\"📰 DEVELOPING STORY: [{workflow_name}]({run_url}) reports {status}. Our correspondents are investigating the incident...\"}" + GH_AW_SAFE_OUTPUT_JOBS: "{\"send_slack_message\":\"\"}" with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | diff --git a/.github/workflows/smoke-copilot.lock.yml b/.github/workflows/smoke-copilot.lock.yml index 88511905675..44d25d17220 100644 --- a/.github/workflows/smoke-copilot.lock.yml +++ b/.github/workflows/smoke-copilot.lock.yml @@ -2296,6 +2296,7 @@ jobs: GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }} GH_AW_DETECTION_CONCLUSION: ${{ needs.agent.outputs.detection_conclusion }} GH_AW_SAFE_OUTPUT_MESSAGES: "{\"footer\":\"\\u003e 📰 *BREAKING: Report filed by [{workflow_name}]({run_url})*{history_link}\",\"appendOnlyComments\":true,\"runStarted\":\"📰 BREAKING: [{workflow_name}]({run_url}) is now investigating this {event_type}. Sources say the story is developing...\",\"runSuccess\":\"📰 VERDICT: [{workflow_name}]({run_url}) has concluded. All systems operational. This is a developing story. 🎤\",\"runFailure\":\"📰 DEVELOPING STORY: [{workflow_name}]({run_url}) reports {status}. Our correspondents are investigating the incident...\"}" + GH_AW_SAFE_OUTPUT_JOBS: "{\"send_slack_message\":\"\"}" with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | diff --git a/actions/setup/js/create_pr_review_comment.cjs b/actions/setup/js/create_pr_review_comment.cjs index 902286028f5..401a058b4c2 100644 --- a/actions/setup/js/create_pr_review_comment.cjs +++ b/actions/setup/js/create_pr_review_comment.cjs @@ -118,6 +118,7 @@ async function main(config = {}) { return { success: false, error: "Not in pull request context", + skipped: true, }; } diff --git a/actions/setup/js/create_pr_review_comment.test.cjs b/actions/setup/js/create_pr_review_comment.test.cjs index 02ea89436ec..65b543fe55b 100644 --- a/actions/setup/js/create_pr_review_comment.test.cjs +++ b/actions/setup/js/create_pr_review_comment.test.cjs @@ -234,6 +234,7 @@ describe("create_pr_review_comment.cjs", () => { expect(result.success).toBe(false); expect(result.error).toContain("Not in pull request context"); + expect(result.skipped).toBe(true); expect(buffer.getBufferedCount()).toBe(0); }); @@ -409,6 +410,7 @@ describe("create_pr_review_comment.cjs", () => { expect(result.success).toBe(false); expect(result.error).toContain("Not in pull request context"); + expect(result.skipped).toBe(true); expect(buffer.getBufferedCount()).toBe(0); }); diff --git a/actions/setup/js/reply_to_pr_review_comment.cjs b/actions/setup/js/reply_to_pr_review_comment.cjs index beeda671549..ef668e34f3c 100644 --- a/actions/setup/js/reply_to_pr_review_comment.cjs +++ b/actions/setup/js/reply_to_pr_review_comment.cjs @@ -120,6 +120,7 @@ async function main(config = {}) { return { success: false, error: "Cannot reply to review comments outside of a pull request context", + skipped: true, }; } targetPRNumber = triggeringPRNumber; diff --git a/actions/setup/js/reply_to_pr_review_comment.test.cjs b/actions/setup/js/reply_to_pr_review_comment.test.cjs index 6a346fc6cea..41d48c3d6f2 100644 --- a/actions/setup/js/reply_to_pr_review_comment.test.cjs +++ b/actions/setup/js/reply_to_pr_review_comment.test.cjs @@ -130,6 +130,7 @@ describe("reply_to_pr_review_comment", () => { expect(result.success).toBe(false); expect(result.error).toContain("pull request context"); + expect(result.skipped).toBe(true); }); it("should work when triggered from issue_comment on a PR", async () => { diff --git a/pkg/workflow/data/action_pins.json b/pkg/workflow/data/action_pins.json index 2e4c785c642..58a139cba5f 100644 --- a/pkg/workflow/data/action_pins.json +++ b/pkg/workflow/data/action_pins.json @@ -35,6 +35,11 @@ "version": "v3.0.0-beta.2", "sha": "bf559f85448f9380bcfa2899dbdc01eb5b37be3a" }, + "actions/download-artifact@v8": { + "repo": "actions/download-artifact", + "version": "v8", + "sha": "3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c" + }, "actions/download-artifact@v8.0.0": { "repo": "actions/download-artifact", "version": "v8.0.0", diff --git a/pkg/workflow/notify_comment.go b/pkg/workflow/notify_comment.go index 40492f176ba..652faf2751d 100644 --- a/pkg/workflow/notify_comment.go +++ b/pkg/workflow/notify_comment.go @@ -431,8 +431,23 @@ func (c *Compiler) buildConclusionJob(data *WorkflowData, mainJobName string, sa return job, nil } +// systemSafeOutputJobNames contains job names that are built-in system jobs and should not be +// treated as custom safe output job types in the GH_AW_SAFE_OUTPUT_JOBS mapping. +// The safe output handler manager uses this mapping to determine which message types are +// handled by custom job steps (and therefore should be silently skipped rather than flagged +// as "no handler loaded"). +var systemSafeOutputJobNames = map[string]bool{ + "safe_outputs": true, // consolidated safe outputs job + "upload_assets": true, // upload assets job +} + // buildSafeOutputJobsEnvVars creates environment variables for safe output job URLs -// Returns both a JSON mapping and the actual environment variable declarations +// Returns both a JSON mapping and the actual environment variable declarations. +// The mapping includes: +// - Built-in jobs with known URL outputs (e.g., create_issue → issue_url) +// - Custom safe-output jobs (from safe-outputs.jobs) with an empty URL key, so the handler +// manager knows those message types are handled by a dedicated job step and should be +// skipped gracefully rather than reported as "No handler loaded". func buildSafeOutputJobsEnvVars(jobNames []string) (string, []string) { // Map job names to their expected URL output keys jobOutputMapping := make(map[string]string) @@ -462,7 +477,13 @@ func buildSafeOutputJobsEnvVars(jobNames []string) (string, []string) { case "push_to_pull_request_branch": urlKey = "commit_url" default: - // Skip jobs that don't have URL outputs + if systemSafeOutputJobNames[jobName] { + // Skip known system jobs — they are not custom safe output types + continue + } + // Custom safe-output job: include in the mapping with an empty URL key so the + // handler manager can silently skip messages of this type. + jobOutputMapping[jobName] = "" continue } diff --git a/pkg/workflow/notify_comment_test.go b/pkg/workflow/notify_comment_test.go index aac7f055906..4b60d81a9bb 100644 --- a/pkg/workflow/notify_comment_test.go +++ b/pkg/workflow/notify_comment_test.go @@ -608,14 +608,27 @@ func TestBuildSafeOutputJobsEnvVars(t *testing.T) { checkJSONKeys: []string{"push_to_pull_request_branch"}, }, { - name: "skips jobs without URL outputs", - jobNames: []string{"create_issue", "detection", "some_custom_job"}, + name: "includes custom jobs and skips system jobs", + jobNames: []string{"create_issue", "safe_outputs", "some_custom_job"}, expectJSON: true, expectEnvVars: 1, checkEnvVars: []string{ "GH_AW_OUTPUT_CREATE_ISSUE_ISSUE_URL: ${{ needs.create_issue.outputs.issue_url }}", }, - checkJSONKeys: []string{"create_issue"}, + checkJSONKeys: []string{"create_issue", "some_custom_job"}, + }, + { + name: "custom-only jobs produce JSON without URL env vars", + jobNames: []string{"safe_outputs", "send_slack_message"}, + expectJSON: true, + expectEnvVars: 0, + checkJSONKeys: []string{"send_slack_message"}, + }, + { + name: "system jobs are excluded from JSON", + jobNames: []string{"safe_outputs", "upload_assets"}, + expectJSON: false, + expectEnvVars: 0, }, { name: "handles empty job list", From 20ed6c0371f81f27c94681474b2048adf94eed4e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Mar 2026 18:07:42 +0000 Subject: [PATCH 4/4] Fix TestGetActionPinsSorting: update expected pin count from 38 to 39 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- pkg/workflow/action_pins_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/workflow/action_pins_test.go b/pkg/workflow/action_pins_test.go index 415a53d1400..a14b3fd1885 100644 --- a/pkg/workflow/action_pins_test.go +++ b/pkg/workflow/action_pins_test.go @@ -297,9 +297,9 @@ func TestApplyActionPinToStep(t *testing.T) { func TestGetActionPinsSorting(t *testing.T) { pins := getActionPins() - // Verify we got all the pins (38 as of March 2026) - if len(pins) != 38 { - t.Errorf("getActionPins() returned %d pins, expected 38", len(pins)) + // Verify we got all the pins (39 as of March 2026) + if len(pins) != 39 { + t.Errorf("getActionPins() returned %d pins, expected 39", len(pins)) } // Verify they are sorted by version (descending) then by repository name (ascending)