From 72a976c4c2ffc45a300d612d4096989ebe4db717 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 16 Jul 2026 13:22:31 +0000
Subject: [PATCH 01/14] Initial plan


From e136e17307fa33e8f2b551d6745ed2b79734d697 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 16 Jul 2026 13:41:48 +0000
Subject: [PATCH 02/14] Fix safe-outputs handler step token precedence

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
 pkg/workflow/compiler_safe_outputs_steps.go   | 16 ++++-------
 ...safe_outputs_handler_manager_token_test.go | 28 +++++++++++++++----
 2 files changed, 27 insertions(+), 17 deletions(-)

diff --git a/pkg/workflow/compiler_safe_outputs_steps.go b/pkg/workflow/compiler_safe_outputs_steps.go
index f714c56d3a4..d90e2ca3bd2 100644
--- a/pkg/workflow/compiler_safe_outputs_steps.go
+++ b/pkg/workflow/compiler_safe_outputs_steps.go
@@ -272,24 +272,18 @@ func (c *Compiler) buildHandlerManagerStep(data *WorkflowData) ([]string, error)
 	}
 
 	// With section for github-token
-	// Use the standard safe outputs token for all operations.
-	// If project operations are configured, prefer the project token for the github-script client.
-	// Rationale: update_project/create_project_status_update call the Projects v2 GraphQL API, which
-	// cannot be accessed with the default GITHUB_TOKEN. GH_AW_PROJECT_GITHUB_TOKEN is the required
-	// token for Projects v2 operations.
+	// Use the standard safe-outputs token for the shared github-script client.
+	// Project operations use GH_AW_PROJECT_GITHUB_TOKEN from env with dedicated handler logic.
 	steps = append(steps, "        with:\n")
 	// Token precedence for the handler manager step:
-	//   1. Project token (if project operations are configured) - already set above
-	//   2. Safe-outputs level token (so.GitHubToken)
-	//   3. Magic secret fallback via getEffectiveSafeOutputGitHubToken()
+	//   1. Safe-outputs level token (so.GitHubToken)
+	//   2. Magic secret fallback via getEffectiveSafeOutputGitHubToken()
 	//
 	// Note: We do NOT fall back to per-output tokens (add-comment, create-issue, etc.)
 	// because those are specific to their operations. The handler manager needs a
 	// general-purpose token for the github-script client.
 	configToken := ""
-	if projectToken != "" {
-		configToken = projectToken
-	} else if data.SafeOutputs != nil && data.SafeOutputs.GitHubToken != "" {
+	if data.SafeOutputs != nil && data.SafeOutputs.GitHubToken != "" {
 		configToken = data.SafeOutputs.GitHubToken
 	}
 	c.addSafeOutputGitHubTokenForConfig(&steps, data, configToken)
diff --git a/pkg/workflow/safe_outputs_handler_manager_token_test.go b/pkg/workflow/safe_outputs_handler_manager_token_test.go
index c001ab7b4ab..8bfab091981 100644
--- a/pkg/workflow/safe_outputs_handler_manager_token_test.go
+++ b/pkg/workflow/safe_outputs_handler_manager_token_test.go
@@ -194,7 +194,23 @@ func TestHandlerManagerProjectGitHubTokenEnvVar(t *testing.T) {
 				},
 			},
 			expectedEnvVarValue: "GH_AW_PROJECT_GITHUB_TOKEN: ${{ secrets.PROJECTS_PAT }}",
-			expectedWithToken:   "github-token: ${{ secrets.PROJECTS_PAT }}",
+			expectedWithToken:   "github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}",
+			shouldHaveToken:     true,
+		},
+		{
+			name: "update-project with custom github-token and safe-outputs github-token",
+			frontmatter: map[string]any{
+				"name": "Test Workflow",
+				"safe-outputs": map[string]any{
+					"github-token": "${{ secrets.SAFE_OUTPUTS_TOKEN }}",
+					"update-project": map[string]any{
+						"github-token": "${{ secrets.PROJECTS_PAT }}",
+						"project":      "https://github.com/orgs/myorg/projects/1",
+					},
+				},
+			},
+			expectedEnvVarValue: "GH_AW_PROJECT_GITHUB_TOKEN: ${{ secrets.PROJECTS_PAT }}",
+			expectedWithToken:   "github-token: ${{ secrets.SAFE_OUTPUTS_TOKEN }}",
 			shouldHaveToken:     true,
 		},
 		{
@@ -208,7 +224,7 @@ func TestHandlerManagerProjectGitHubTokenEnvVar(t *testing.T) {
 				},
 			},
 			expectedEnvVarValue: "GH_AW_PROJECT_GITHUB_TOKEN: ${{ secrets.GH_AW_PROJECT_GITHUB_TOKEN }}",
-			expectedWithToken:   "github-token: ${{ secrets.GH_AW_PROJECT_GITHUB_TOKEN }}",
+			expectedWithToken:   "github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}",
 			shouldHaveToken:     true,
 		},
 		{
@@ -238,7 +254,7 @@ func TestHandlerManagerProjectGitHubTokenEnvVar(t *testing.T) {
 				},
 			},
 			expectedEnvVarValue: "GH_AW_PROJECT_GITHUB_TOKEN: ${{ secrets.STATUS_PAT }}",
-			expectedWithToken:   "github-token: ${{ secrets.STATUS_PAT }}",
+			expectedWithToken:   "github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}",
 			shouldHaveToken:     true,
 		},
 		{
@@ -252,7 +268,7 @@ func TestHandlerManagerProjectGitHubTokenEnvVar(t *testing.T) {
 				},
 			},
 			expectedEnvVarValue: "GH_AW_PROJECT_GITHUB_TOKEN: ${{ secrets.CREATE_PAT }}",
-			expectedWithToken:   "github-token: ${{ secrets.CREATE_PAT }}",
+			expectedWithToken:   "github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}",
 			shouldHaveToken:     true,
 		},
 		{
@@ -274,7 +290,7 @@ func TestHandlerManagerProjectGitHubTokenEnvVar(t *testing.T) {
 				},
 			},
 			expectedEnvVarValue: "GH_AW_PROJECT_GITHUB_TOKEN: ${{ secrets.UPDATE_PAT }}",
-			expectedWithToken:   "github-token: ${{ secrets.UPDATE_PAT }}",
+			expectedWithToken:   "github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}",
 			shouldHaveToken:     true,
 		},
 		{
@@ -312,7 +328,7 @@ func TestHandlerManagerProjectGitHubTokenEnvVar(t *testing.T) {
 					"Expected environment variable %q to be set in handler manager step",
 					tt.expectedEnvVarValue)
 
-				// Check that the github-script token matches the effective project token
+				// Check that the github-script token uses safe-outputs token precedence.
 				assert.Contains(t, yamlStr, tt.expectedWithToken,
 					"Expected github-script token %q to be set in handler manager step",
 					tt.expectedWithToken)

From 9ae4b9383b950f9ce2d5d22c8a583c6e0cdd0bfd Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 16 Jul 2026 13:48:25 +0000
Subject: [PATCH 03/14] chore: outline plan for safe-output token pollution
 tests

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
 .github/workflows/smoke-project.lock.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/smoke-project.lock.yml b/.github/workflows/smoke-project.lock.yml
index dd2c2acb155..3dcba967766 100644
--- a/.github/workflows/smoke-project.lock.yml
+++ b/.github/workflows/smoke-project.lock.yml
@@ -2195,7 +2195,7 @@ jobs:
           GH_AW_PROJECT_URL: "https://github.com/orgs/github/projects/24068"
           GH_AW_PROJECT_GITHUB_TOKEN: ${{ secrets.GH_AW_PROJECT_GITHUB_TOKEN }}
         with:
-          github-token: ${{ secrets.GH_AW_PROJECT_GITHUB_TOKEN }}
+          github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
           script: |
             const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
             setupGlobals(core, github, context, exec, io, getOctokit);

From 65dfd4e210e09221a1b13f16c47dd31d4f7fdf46 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 16 Jul 2026 14:00:55 +0000
Subject: [PATCH 04/14] test: cover handler-manager token isolation across safe
 outputs

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
 ...safe_outputs_handler_manager_token_test.go | 48 +++++++++++++++++++
 1 file changed, 48 insertions(+)

diff --git a/pkg/workflow/safe_outputs_handler_manager_token_test.go b/pkg/workflow/safe_outputs_handler_manager_token_test.go
index 8bfab091981..0eaa986d23a 100644
--- a/pkg/workflow/safe_outputs_handler_manager_token_test.go
+++ b/pkg/workflow/safe_outputs_handler_manager_token_test.go
@@ -3,6 +3,7 @@
 package workflow
 
 import (
+	"sort"
 	"strings"
 	"testing"
 
@@ -340,3 +341,50 @@ func TestHandlerManagerProjectGitHubTokenEnvVar(t *testing.T) {
 		})
 	}
 }
+
+// TestHandlerManagerGitHubTokenIsolationAcrossSafeOutputHandlers verifies that the shared
+// github-script client token remains sourced from safe-outputs.github-token regardless of which
+// safe-output handler is configured alongside project-specific token settings.
+func TestHandlerManagerGitHubTokenIsolationAcrossSafeOutputHandlers(t *testing.T) {
+	handlerNames := make([]string, 0, len(handlerRegistry))
+	for handlerName := range handlerRegistry {
+		handlerNames = append(handlerNames, handlerName)
+	}
+	sort.Strings(handlerNames)
+
+	for _, handlerName := range handlerNames {
+		t.Run(handlerName, func(t *testing.T) {
+			safeOutputs := map[string]any{
+				"github-token": "${{ secrets.SAFE_OUTPUTS_TOKEN }}",
+				"update-project": map[string]any{
+					"github-token": "${{ secrets.PROJECTS_PAT }}",
+					"project":      "https://github.com/orgs/myorg/projects/1",
+				},
+			}
+
+			safeOutputKey := strings.ReplaceAll(handlerName, "_", "-")
+			if safeOutputKey != "update-project" {
+				safeOutputs[safeOutputKey] = map[string]any{}
+			}
+
+			frontmatter := map[string]any{
+				"name":         "Test Workflow",
+				"safe-outputs": safeOutputs,
+			}
+
+			compiler := NewCompiler()
+			workflowData := &WorkflowData{
+				Name:        "test-workflow",
+				SafeOutputs: compiler.extractSafeOutputsConfig(frontmatter),
+			}
+
+			steps, err := compiler.buildHandlerManagerStep(workflowData)
+			require.NoError(t, err)
+
+			yamlStr := strings.Join(steps, "")
+			assert.Contains(t, yamlStr, "github-token: ${{ secrets.SAFE_OUTPUTS_TOKEN }}")
+			assert.NotContains(t, yamlStr, "github-token: ${{ secrets.PROJECTS_PAT }}")
+			assert.Contains(t, yamlStr, "GH_AW_PROJECT_GITHUB_TOKEN: ${{ secrets.PROJECTS_PAT }}")
+		})
+	}
+}

From ea7118ff8c321f5dee259febc60302f2493cb1ba Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 16 Jul 2026 15:18:30 +0000
Subject: [PATCH 05/14] fix: preserve project handler token isolation at
 runtime

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
 actions/setup/js/handler_auth.cjs             |  2 +-
 .../setup/js/safe_output_handler_manager.cjs  | 25 ++++-
 .../js/safe_output_handler_manager.test.cjs   | 91 +++++++++++++++++++
 ...safe_outputs_handler_manager_token_test.go |  7 +-
 4 files changed, 121 insertions(+), 4 deletions(-)

diff --git a/actions/setup/js/handler_auth.cjs b/actions/setup/js/handler_auth.cjs
index a6cfacdfa3b..f5135dc3b4e 100644
--- a/actions/setup/js/handler_auth.cjs
+++ b/actions/setup/js/handler_auth.cjs
@@ -14,7 +14,7 @@
  *   2. global github          — step-level token set in the github-script with.github-token
  *
  * The step-level token itself follows (as set by the Go compiler):
- *   project token > global safe-outputs.github-token > magic secrets
+ *   global safe-outputs.github-token > magic secrets
  */
 
 /**
diff --git a/actions/setup/js/safe_output_handler_manager.cjs b/actions/setup/js/safe_output_handler_manager.cjs
index 2520014ae46..3e4c82ef9f8 100644
--- a/actions/setup/js/safe_output_handler_manager.cjs
+++ b/actions/setup/js/safe_output_handler_manager.cjs
@@ -101,6 +101,9 @@ const STANDALONE_STEP_TYPES = new Set(["upload_asset", "noop"]);
  */
 const CODE_PUSH_TYPES = new Set(["push_to_pull_request_branch", "create_pull_request"]);
 
+/** @type {Set<string>} Project-safe-output handlers that should default to GH_AW_PROJECT_GITHUB_TOKEN when no per-handler github-token is configured. */
+const PROJECT_HANDLER_TYPES = new Set(["create_project", "create_project_status_update", "update_project"]);
+
 // Threat-detection warn-mode requirement IDs from safe-outputs specification:
 // - WTD2: Convertible outputs must be mapped to a reviewable type.
 // - WTD3: Non-reviewable outputs must be aborted.
@@ -306,6 +309,10 @@ async function loadHandlers(config, prReviewBufferRegistry, resolvedAllowedMenti
           // Call the factory function with config to get the message handler
           const handlerConfig = { ...(config[type] || {}) };
 
+          if (PROJECT_HANDLER_TYPES.has(type) && !handlerConfig["github-token"] && process.env.GH_AW_PROJECT_GITHUB_TOKEN) {
+            handlerConfig["github-token"] = process.env.GH_AW_PROJECT_GITHUB_TOKEN;
+          }
+
           // Pass top-level mentions policy through so handlers can preserve
           // the same allowed mention aliases used during collection.
           if (handlerConfig.mentions == null && config.mentions != null) {
@@ -320,7 +327,8 @@ async function loadHandlers(config, prReviewBufferRegistry, resolvedAllowedMenti
             handlerConfig._prReviewBufferRegistry = prReviewBufferRegistry;
           }
 
-          const messageHandler = await handlerModule.main(handlerConfig);
+          const handlerGithubClient = handlerConfig["github-token"] && typeof global.getOctokit === "function" ? global.getOctokit(handlerConfig["github-token"]) : null;
+          const messageHandler = await handlerModule.main(handlerConfig, handlerGithubClient);
 
           if (typeof messageHandler !== "function") {
             // This is a fatal error - the handler is misconfigured
@@ -330,7 +338,20 @@ async function loadHandlers(config, prReviewBufferRegistry, resolvedAllowedMenti
             throw error;
           }
 
-          messageHandlers.set(type, messageHandler);
+          const wrappedMessageHandler =
+            PROJECT_HANDLER_TYPES.has(type) && handlerGithubClient
+              ? async (...args) => {
+                  const previousGithub = global.github;
+                  global.github = handlerGithubClient;
+                  try {
+                    return await messageHandler(...args);
+                  } finally {
+                    global.github = previousGithub;
+                  }
+                }
+              : messageHandler;
+
+          messageHandlers.set(type, wrappedMessageHandler);
           core.info(`✓ Loaded and initialized handler for: ${type}`);
         } else {
           core.warning(`Handler module ${type} does not export a main function`);
diff --git a/actions/setup/js/safe_output_handler_manager.test.cjs b/actions/setup/js/safe_output_handler_manager.test.cjs
index a5c5260fe45..5dced16d632 100644
--- a/actions/setup/js/safe_output_handler_manager.test.cjs
+++ b/actions/setup/js/safe_output_handler_manager.test.cjs
@@ -291,6 +291,97 @@ describe("Safe Output Handler Manager", () => {
         createIssueMainSpy.mockRestore();
       }
     });
+
+    it("injects GH_AW_PROJECT_GITHUB_TOKEN for project handlers when github-token is missing", async () => {
+      process.env.GH_AW_PROJECT_GITHUB_TOKEN = "projects-token";
+      global.getOctokit = vi.fn().mockReturnValue({ client: "project-client" });
+
+      const updateProjectModule = require("./update_project.cjs");
+      const updateProjectMainSpy = vi.spyOn(updateProjectModule, "main").mockImplementation(async () => async () => ({ success: true }));
+
+      try {
+        const handlers = await loadHandlers({
+          update_project: { project: "https://github.com/orgs/myorg/projects/1" },
+        });
+
+        expect(handlers.has("update_project")).toBe(true);
+        expect(global.getOctokit).toHaveBeenCalledWith("projects-token");
+        expect(updateProjectMainSpy).toHaveBeenCalledWith(
+          expect.objectContaining({
+            project: "https://github.com/orgs/myorg/projects/1",
+            "github-token": "projects-token",
+          }),
+          expect.objectContaining({ client: "project-client" })
+        );
+      } finally {
+        updateProjectMainSpy.mockRestore();
+        delete process.env.GH_AW_PROJECT_GITHUB_TOKEN;
+        delete global.getOctokit;
+      }
+    });
+
+    it("preserves explicit project handler github-token over GH_AW_PROJECT_GITHUB_TOKEN fallback", async () => {
+      process.env.GH_AW_PROJECT_GITHUB_TOKEN = "fallback-project-token";
+      global.getOctokit = vi.fn().mockReturnValue({ client: "project-client" });
+
+      const updateProjectModule = require("./update_project.cjs");
+      const updateProjectMainSpy = vi.spyOn(updateProjectModule, "main").mockImplementation(async () => async () => ({ success: true }));
+
+      try {
+        await loadHandlers({
+          update_project: {
+            project: "https://github.com/orgs/myorg/projects/1",
+            "github-token": "explicit-project-token",
+          },
+        });
+
+        expect(global.getOctokit).toHaveBeenCalledWith("explicit-project-token");
+        expect(updateProjectMainSpy).toHaveBeenCalledWith(
+          expect.objectContaining({
+            "github-token": "explicit-project-token",
+          }),
+          expect.objectContaining({ client: "project-client" })
+        );
+      } finally {
+        updateProjectMainSpy.mockRestore();
+        delete process.env.GH_AW_PROJECT_GITHUB_TOKEN;
+        delete global.getOctokit;
+      }
+    });
+
+    it("wraps project handlers so global.github is set to the project client during execution", async () => {
+      process.env.GH_AW_PROJECT_GITHUB_TOKEN = "projects-token";
+      const projectClient = { client: "project-client" };
+      global.getOctokit = vi.fn().mockReturnValue(projectClient);
+
+      const previousGithub = { client: "shared-client" };
+      global.github = previousGithub;
+      let seenGithub = null;
+
+      const updateProjectModule = require("./update_project.cjs");
+      const updateProjectMainSpy = vi.spyOn(updateProjectModule, "main").mockImplementation(async () => async () => {
+        seenGithub = global.github;
+        return { success: true };
+      });
+
+      try {
+        const handlers = await loadHandlers({
+          update_project: { project: "https://github.com/orgs/myorg/projects/1" },
+        });
+        const handler = handlers.get("update_project");
+        expect(typeof handler).toBe("function");
+
+        await handler({ type: "update_project" });
+
+        expect(seenGithub).toBe(projectClient);
+        expect(global.github).toBe(previousGithub);
+      } finally {
+        updateProjectMainSpy.mockRestore();
+        delete process.env.GH_AW_PROJECT_GITHUB_TOKEN;
+        delete global.getOctokit;
+        global.github = previousGithub;
+      }
+    });
   });
 
   describe("loadHandlers - path traversal sanitization", () => {
diff --git a/pkg/workflow/safe_outputs_handler_manager_token_test.go b/pkg/workflow/safe_outputs_handler_manager_token_test.go
index 0eaa986d23a..c65c4f9cab2 100644
--- a/pkg/workflow/safe_outputs_handler_manager_token_test.go
+++ b/pkg/workflow/safe_outputs_handler_manager_token_test.go
@@ -382,9 +382,14 @@ func TestHandlerManagerGitHubTokenIsolationAcrossSafeOutputHandlers(t *testing.T
 			require.NoError(t, err)
 
 			yamlStr := strings.Join(steps, "")
+			if !strings.Contains(yamlStr, handlerName) {
+				t.Skipf("handler %q not materialized from minimal config; skipping isolation assertions", handlerName)
+			}
 			assert.Contains(t, yamlStr, "github-token: ${{ secrets.SAFE_OUTPUTS_TOKEN }}")
 			assert.NotContains(t, yamlStr, "github-token: ${{ secrets.PROJECTS_PAT }}")
-			assert.Contains(t, yamlStr, "GH_AW_PROJECT_GITHUB_TOKEN: ${{ secrets.PROJECTS_PAT }}")
+			if handlerName == "update_project" {
+				assert.Contains(t, yamlStr, "GH_AW_PROJECT_GITHUB_TOKEN: ${{ secrets.PROJECTS_PAT }}")
+			}
 		})
 	}
 }

From bb6e74cf226b301dc694df19c129812449a4a5b5 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 16 Jul 2026 15:24:00 +0000
Subject: [PATCH 06/14] test: clarify project token handler assertions and
 mocks

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
 actions/setup/js/safe_output_handler_manager.cjs      | 5 ++++-
 actions/setup/js/safe_output_handler_manager.test.cjs | 1 +
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/actions/setup/js/safe_output_handler_manager.cjs b/actions/setup/js/safe_output_handler_manager.cjs
index 3e4c82ef9f8..a252dd4c0ce 100644
--- a/actions/setup/js/safe_output_handler_manager.cjs
+++ b/actions/setup/js/safe_output_handler_manager.cjs
@@ -327,7 +327,10 @@ async function loadHandlers(config, prReviewBufferRegistry, resolvedAllowedMenti
             handlerConfig._prReviewBufferRegistry = prReviewBufferRegistry;
           }
 
-          const handlerGithubClient = handlerConfig["github-token"] && typeof global.getOctokit === "function" ? global.getOctokit(handlerConfig["github-token"]) : null;
+          let handlerGithubClient = null;
+          if (handlerConfig["github-token"] && typeof global.getOctokit === "function") {
+            handlerGithubClient = global.getOctokit(handlerConfig["github-token"]);
+          }
           const messageHandler = await handlerModule.main(handlerConfig, handlerGithubClient);
 
           if (typeof messageHandler !== "function") {
diff --git a/actions/setup/js/safe_output_handler_manager.test.cjs b/actions/setup/js/safe_output_handler_manager.test.cjs
index 5dced16d632..b7c5e4a2ab4 100644
--- a/actions/setup/js/safe_output_handler_manager.test.cjs
+++ b/actions/setup/js/safe_output_handler_manager.test.cjs
@@ -360,6 +360,7 @@ describe("Safe Output Handler Manager", () => {
 
       const updateProjectModule = require("./update_project.cjs");
       const updateProjectMainSpy = vi.spyOn(updateProjectModule, "main").mockImplementation(async () => async () => {
+        // outer function: handler factory at loadHandlers() time; inner function: message handler at processMessages() time
         seenGithub = global.github;
         return { success: true };
       });

From 8866a063b53f07f4ac05f9556371e6028244ae62 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 16 Jul 2026 15:29:27 +0000
Subject: [PATCH 07/14] fix: restore global github state in project handler
 wrapper

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
 .../setup/js/safe_output_handler_manager.cjs  |  7 ++++-
 .../js/safe_output_handler_manager.test.cjs   | 27 +++++++++++++++++++
 2 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/actions/setup/js/safe_output_handler_manager.cjs b/actions/setup/js/safe_output_handler_manager.cjs
index a252dd4c0ce..89820f1e272 100644
--- a/actions/setup/js/safe_output_handler_manager.cjs
+++ b/actions/setup/js/safe_output_handler_manager.cjs
@@ -344,12 +344,17 @@ async function loadHandlers(config, prReviewBufferRegistry, resolvedAllowedMenti
           const wrappedMessageHandler =
             PROJECT_HANDLER_TYPES.has(type) && handlerGithubClient
               ? async (...args) => {
+                  const hadGithub = Object.prototype.hasOwnProperty.call(global, "github");
                   const previousGithub = global.github;
                   global.github = handlerGithubClient;
                   try {
                     return await messageHandler(...args);
                   } finally {
-                    global.github = previousGithub;
+                    if (hadGithub) {
+                      global.github = previousGithub;
+                    } else {
+                      delete global.github;
+                    }
                   }
                 }
               : messageHandler;
diff --git a/actions/setup/js/safe_output_handler_manager.test.cjs b/actions/setup/js/safe_output_handler_manager.test.cjs
index b7c5e4a2ab4..d5df7b3e165 100644
--- a/actions/setup/js/safe_output_handler_manager.test.cjs
+++ b/actions/setup/js/safe_output_handler_manager.test.cjs
@@ -383,6 +383,33 @@ describe("Safe Output Handler Manager", () => {
         global.github = previousGithub;
       }
     });
+
+    it("restores global.github to absent state after wrapped project handler execution", async () => {
+      process.env.GH_AW_PROJECT_GITHUB_TOKEN = "projects-token";
+      const projectClient = { client: "project-client" };
+      global.getOctokit = vi.fn().mockReturnValue(projectClient);
+      delete global.github;
+
+      const updateProjectModule = require("./update_project.cjs");
+      const updateProjectMainSpy = vi.spyOn(updateProjectModule, "main").mockImplementation(async () => async () => ({ success: true }));
+
+      try {
+        const handlers = await loadHandlers({
+          update_project: { project: "https://github.com/orgs/myorg/projects/1" },
+        });
+        const handler = handlers.get("update_project");
+        expect(typeof handler).toBe("function");
+
+        await handler({ type: "update_project" });
+
+        expect("github" in global).toBe(false);
+      } finally {
+        updateProjectMainSpy.mockRestore();
+        delete process.env.GH_AW_PROJECT_GITHUB_TOKEN;
+        delete global.getOctokit;
+        delete global.github;
+      }
+    });
   });
 
   describe("loadHandlers - path traversal sanitization", () => {

From 5af8ac4264818ab54e525111974b2488e407e6ff Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 16 Jul 2026 15:36:00 +0000
Subject: [PATCH 08/14] refactor: extract project github client rebinding
 helper

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
 .../setup/js/safe_output_handler_manager.cjs  | 49 ++++++++++++-------
 ...safe_outputs_handler_manager_token_test.go |  3 +-
 2 files changed, 32 insertions(+), 20 deletions(-)

diff --git a/actions/setup/js/safe_output_handler_manager.cjs b/actions/setup/js/safe_output_handler_manager.cjs
index 89820f1e272..c8b57613331 100644
--- a/actions/setup/js/safe_output_handler_manager.cjs
+++ b/actions/setup/js/safe_output_handler_manager.cjs
@@ -286,6 +286,35 @@ function loadConfig() {
 /** @type {Set<string>} Handler types that participate in the PR review buffer */
 const PR_REVIEW_HANDLER_TYPES = new Set(["create_pull_request_review_comment", "submit_pull_request_review"]);
 
+/**
+ * Wrap a handler so project-safe-output execution can temporarily bind global.github
+ * to the handler-specific authenticated client.
+ *
+ * @param {string} type - Safe-output handler type
+ * @param {Function} messageHandler - Loaded handler function
+ * @param {Object|null} handlerGithubClient - Optional per-handler GitHub client
+ * @returns {Function} Wrapped handler function
+ */
+function wrapWithClientRebinding(type, messageHandler, handlerGithubClient) {
+  if (!PROJECT_HANDLER_TYPES.has(type) || !handlerGithubClient) {
+    return messageHandler;
+  }
+  return async (...args) => {
+    const hadGithub = Object.prototype.hasOwnProperty.call(global, "github");
+    const previousGithub = global.github;
+    global.github = handlerGithubClient;
+    try {
+      return await messageHandler(...args);
+    } finally {
+      if (hadGithub) {
+        global.github = previousGithub;
+      } else {
+        delete global.github;
+      }
+    }
+  };
+}
+
 /**
  * Load and initialize handlers for enabled safe output types
  * Calls each handler's factory function (main) to get message processors
@@ -341,25 +370,7 @@ async function loadHandlers(config, prReviewBufferRegistry, resolvedAllowedMenti
             throw error;
           }
 
-          const wrappedMessageHandler =
-            PROJECT_HANDLER_TYPES.has(type) && handlerGithubClient
-              ? async (...args) => {
-                  const hadGithub = Object.prototype.hasOwnProperty.call(global, "github");
-                  const previousGithub = global.github;
-                  global.github = handlerGithubClient;
-                  try {
-                    return await messageHandler(...args);
-                  } finally {
-                    if (hadGithub) {
-                      global.github = previousGithub;
-                    } else {
-                      delete global.github;
-                    }
-                  }
-                }
-              : messageHandler;
-
-          messageHandlers.set(type, wrappedMessageHandler);
+          messageHandlers.set(type, wrapWithClientRebinding(type, messageHandler, handlerGithubClient));
           core.info(`✓ Loaded and initialized handler for: ${type}`);
         } else {
           core.warning(`Handler module ${type} does not export a main function`);
diff --git a/pkg/workflow/safe_outputs_handler_manager_token_test.go b/pkg/workflow/safe_outputs_handler_manager_token_test.go
index c65c4f9cab2..76a3a05a0e7 100644
--- a/pkg/workflow/safe_outputs_handler_manager_token_test.go
+++ b/pkg/workflow/safe_outputs_handler_manager_token_test.go
@@ -382,7 +382,8 @@ func TestHandlerManagerGitHubTokenIsolationAcrossSafeOutputHandlers(t *testing.T
 			require.NoError(t, err)
 
 			yamlStr := strings.Join(steps, "")
-			if !strings.Contains(yamlStr, handlerName) {
+			handlerConfigKey := "\\\"" + handlerName + "\\\":"
+			if !strings.Contains(yamlStr, handlerConfigKey) {
 				t.Skipf("handler %q not materialized from minimal config; skipping isolation assertions", handlerName)
 			}
 			assert.Contains(t, yamlStr, "github-token: ${{ secrets.SAFE_OUTPUTS_TOKEN }}")

From 60abf429468c12c6483838c262c7113e36939f29 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 16 Jul 2026 15:41:18 +0000
Subject: [PATCH 09/14] refactor: centralize project handler github-token
 config key

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
 actions/setup/js/safe_output_handler_manager.cjs | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/actions/setup/js/safe_output_handler_manager.cjs b/actions/setup/js/safe_output_handler_manager.cjs
index c8b57613331..f40d0efed55 100644
--- a/actions/setup/js/safe_output_handler_manager.cjs
+++ b/actions/setup/js/safe_output_handler_manager.cjs
@@ -29,6 +29,7 @@ const { checkRateLimitHeadroom } = require("./rate_limit_helpers.cjs");
 const { redactSensitiveConfig } = require("./safe_outputs_config_redact.cjs");
 const nodePath = require("path");
 const fs = require("fs");
+const GITHUB_TOKEN_CONFIG_KEY = "github-token";
 
 /**
  * Handler map configuration
@@ -338,8 +339,8 @@ async function loadHandlers(config, prReviewBufferRegistry, resolvedAllowedMenti
           // Call the factory function with config to get the message handler
           const handlerConfig = { ...(config[type] || {}) };
 
-          if (PROJECT_HANDLER_TYPES.has(type) && !handlerConfig["github-token"] && process.env.GH_AW_PROJECT_GITHUB_TOKEN) {
-            handlerConfig["github-token"] = process.env.GH_AW_PROJECT_GITHUB_TOKEN;
+          if (PROJECT_HANDLER_TYPES.has(type) && !handlerConfig[GITHUB_TOKEN_CONFIG_KEY] && process.env.GH_AW_PROJECT_GITHUB_TOKEN) {
+            handlerConfig[GITHUB_TOKEN_CONFIG_KEY] = process.env.GH_AW_PROJECT_GITHUB_TOKEN;
           }
 
           // Pass top-level mentions policy through so handlers can preserve
@@ -357,8 +358,8 @@ async function loadHandlers(config, prReviewBufferRegistry, resolvedAllowedMenti
           }
 
           let handlerGithubClient = null;
-          if (handlerConfig["github-token"] && typeof global.getOctokit === "function") {
-            handlerGithubClient = global.getOctokit(handlerConfig["github-token"]);
+          if (handlerConfig[GITHUB_TOKEN_CONFIG_KEY] && typeof global.getOctokit === "function") {
+            handlerGithubClient = global.getOctokit(handlerConfig[GITHUB_TOKEN_CONFIG_KEY]);
           }
           const messageHandler = await handlerModule.main(handlerConfig, handlerGithubClient);
 

From 0b13b43029ff4ef9042f191c9c424a76e65d0e82 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 16 Jul 2026 16:06:07 +0000
Subject: [PATCH 10/14] test: tighten safe-output handler token isolation
 coverage

Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>
---
 ...safe_outputs_handler_manager_token_test.go | 143 +++++++++++++++---
 1 file changed, 118 insertions(+), 25 deletions(-)

diff --git a/pkg/workflow/safe_outputs_handler_manager_token_test.go b/pkg/workflow/safe_outputs_handler_manager_token_test.go
index 76a3a05a0e7..a4cae47f012 100644
--- a/pkg/workflow/safe_outputs_handler_manager_token_test.go
+++ b/pkg/workflow/safe_outputs_handler_manager_token_test.go
@@ -3,6 +3,8 @@
 package workflow
 
 import (
+	"encoding/json"
+	"reflect"
 	"sort"
 	"strings"
 	"testing"
@@ -346,6 +348,15 @@ func TestHandlerManagerProjectGitHubTokenEnvVar(t *testing.T) {
 // github-script client token remains sourced from safe-outputs.github-token regardless of which
 // safe-output handler is configured alongside project-specific token settings.
 func TestHandlerManagerGitHubTokenIsolationAcrossSafeOutputHandlers(t *testing.T) {
+	const safeOutputsToken = "${{ secrets.SAFE_OUTPUTS_TOKEN }}"
+	const handlerToken = "${{ secrets.HANDLER_TOKEN }}"
+
+	projectHandlers := map[string]bool{
+		"update_project":               true,
+		"create_project_status_update": true,
+		"create_project":               true,
+	}
+
 	handlerNames := make([]string, 0, len(handlerRegistry))
 	for handlerName := range handlerRegistry {
 		handlerNames = append(handlerNames, handlerName)
@@ -354,43 +365,125 @@ func TestHandlerManagerGitHubTokenIsolationAcrossSafeOutputHandlers(t *testing.T
 
 	for _, handlerName := range handlerNames {
 		t.Run(handlerName, func(t *testing.T) {
-			safeOutputs := map[string]any{
-				"github-token": "${{ secrets.SAFE_OUTPUTS_TOKEN }}",
-				"update-project": map[string]any{
-					"github-token": "${{ secrets.PROJECTS_PAT }}",
-					"project":      "https://github.com/orgs/myorg/projects/1",
-				},
-			}
-
-			safeOutputKey := strings.ReplaceAll(handlerName, "_", "-")
-			if safeOutputKey != "update-project" {
-				safeOutputs[safeOutputKey] = map[string]any{}
-			}
-
-			frontmatter := map[string]any{
-				"name":         "Test Workflow",
-				"safe-outputs": safeOutputs,
+			safeOutputs := &SafeOutputsConfig{
+				GitHubToken: safeOutputsToken,
 			}
+			enableHandlerForIsolationTest(t, safeOutputs, handlerName, handlerToken)
 
 			compiler := NewCompiler()
 			workflowData := &WorkflowData{
 				Name:        "test-workflow",
-				SafeOutputs: compiler.extractSafeOutputsConfig(frontmatter),
+				SafeOutputs: safeOutputs,
 			}
 
 			steps, err := compiler.buildHandlerManagerStep(workflowData)
 			require.NoError(t, err)
 
 			yamlStr := strings.Join(steps, "")
-			handlerConfigKey := "\\\"" + handlerName + "\\\":"
-			if !strings.Contains(yamlStr, handlerConfigKey) {
-				t.Skipf("handler %q not materialized from minimal config; skipping isolation assertions", handlerName)
-			}
-			assert.Contains(t, yamlStr, "github-token: ${{ secrets.SAFE_OUTPUTS_TOKEN }}")
-			assert.NotContains(t, yamlStr, "github-token: ${{ secrets.PROJECTS_PAT }}")
-			if handlerName == "update_project" {
-				assert.Contains(t, yamlStr, "GH_AW_PROJECT_GITHUB_TOKEN: ${{ secrets.PROJECTS_PAT }}")
+			handlerConfig := extractHandlerManagerConfigFromYAML(t, yamlStr)
+			_, ok := handlerConfig[handlerName]
+			assert.True(t, ok, "expected handler %q to be present in GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG", handlerName)
+
+			assert.Contains(t, yamlStr, "github-token: "+safeOutputsToken)
+			assert.NotContains(t, yamlStr, "github-token: "+handlerToken)
+			if projectHandlers[handlerName] {
+				assert.Contains(t, yamlStr, "GH_AW_PROJECT_GITHUB_TOKEN: "+handlerToken)
+			} else {
+				assert.NotContains(t, yamlStr, "GH_AW_PROJECT_GITHUB_TOKEN:")
 			}
 		})
 	}
 }
+
+func enableHandlerForIsolationTest(t *testing.T, safeOutputs *SafeOutputsConfig, handlerName, token string) {
+	t.Helper()
+
+	switch handlerName {
+	case "dispatch_repository":
+		safeOutputs.DispatchRepository = &DispatchRepositoryConfig{
+			Tools: map[string]*DispatchRepositoryToolConfig{
+				"default": {
+					Workflow:    "safe-outputs-dispatch",
+					EventType:   "safe-outputs-dispatch",
+					Repository:  "github/gh-aw",
+					Max:         strPtr("1"),
+					GitHubToken: token,
+				},
+			},
+		}
+		return
+	case "create_report_incomplete_issue":
+		safeOutputs.ReportIncomplete = &ReportIncompleteConfig{
+			BaseSafeOutputConfig: BaseSafeOutputConfig{
+				Max:         strPtr("1"),
+				GitHubToken: token,
+			},
+		}
+		return
+	}
+
+	configValue := reflect.ValueOf(safeOutputs).Elem()
+	configType := configValue.Type()
+
+	for i := range configType.NumField() {
+		field := configType.Field(i)
+		yamlTag := strings.Split(field.Tag.Get("yaml"), ",")[0]
+		if yamlTag == "" || yamlTag == "-" {
+			continue
+		}
+		if strings.ReplaceAll(yamlTag, "-", "_") != handlerName {
+			continue
+		}
+
+		require.Equal(t, reflect.Pointer, field.Type.Kind(), "handler field %s must be a pointer type", field.Name)
+		handlerValue := reflect.New(field.Type.Elem())
+		initializeHandlerConfigForIsolationTest(handlerValue.Elem(), token)
+		configValue.Field(i).Set(handlerValue)
+		return
+	}
+
+	require.Failf(t, "missing handler field", "no SafeOutputsConfig field found for handler %q", handlerName)
+}
+
+func initializeHandlerConfigForIsolationTest(handlerStruct reflect.Value, token string) {
+	baseField := handlerStruct.FieldByName("BaseSafeOutputConfig")
+	if baseField.IsValid() {
+		if maxField := baseField.FieldByName("Max"); maxField.IsValid() && maxField.CanSet() {
+			maxField.Set(reflect.ValueOf(strPtr("1")))
+		}
+		if tokenField := baseField.FieldByName("GitHubToken"); tokenField.IsValid() && tokenField.CanSet() {
+			tokenField.SetString(token)
+		}
+	}
+	if tokenField := handlerStruct.FieldByName("GitHubToken"); tokenField.IsValid() && tokenField.CanSet() && tokenField.Kind() == reflect.String {
+		tokenField.SetString(token)
+	}
+
+	// project URL is required for update-project and create-project-status-update
+	if projectField := handlerStruct.FieldByName("Project"); projectField.IsValid() && projectField.CanSet() && projectField.Kind() == reflect.String {
+		projectField.SetString("https://github.com/orgs/myorg/projects/1")
+	}
+}
+
+func extractHandlerManagerConfigFromYAML(t *testing.T, yamlStr string) map[string]map[string]any {
+	t.Helper()
+
+	const prefix = "GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "
+	for line := range strings.SplitSeq(yamlStr, "\n") {
+		trimmed := strings.TrimSpace(line)
+		if !strings.HasPrefix(trimmed, prefix) {
+			continue
+		}
+
+		configJSON := strings.TrimPrefix(trimmed, prefix)
+		configJSON = strings.Trim(configJSON, "\"")
+		configJSON = strings.ReplaceAll(configJSON, "\\\"", "\"")
+
+		var config map[string]map[string]any
+		require.NoError(t, json.Unmarshal([]byte(configJSON), &config), "handler config JSON should be valid")
+		return config
+	}
+
+	require.Fail(t, "missing GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG in compiled YAML")
+	return nil
+}

From 454e9c1d7fd7024cd331bfb5ef1b87287e4f42c5 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 16 Jul 2026 16:10:30 +0000
Subject: [PATCH 11/14] test: avoid vacuous handler iteration assertions

Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>
---
 pkg/workflow/safe_outputs_handler_manager_token_test.go | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/pkg/workflow/safe_outputs_handler_manager_token_test.go b/pkg/workflow/safe_outputs_handler_manager_token_test.go
index a4cae47f012..5348d83e1d2 100644
--- a/pkg/workflow/safe_outputs_handler_manager_token_test.go
+++ b/pkg/workflow/safe_outputs_handler_manager_token_test.go
@@ -425,7 +425,8 @@ func enableHandlerForIsolationTest(t *testing.T, safeOutputs *SafeOutputsConfig,
 	configValue := reflect.ValueOf(safeOutputs).Elem()
 	configType := configValue.Type()
 
-	for i := range configType.NumField() {
+	//nolint:intrange // explicit bounds loop keeps compatibility with reviewers/tools that don't accept range-over-int
+	for i := 0; i < configType.NumField(); i++ {
 		field := configType.Field(i)
 		yamlTag := strings.Split(field.Tag.Get("yaml"), ",")[0]
 		if yamlTag == "" || yamlTag == "-" {

From a653044a727fdfe2f5fea2a6597100c0614c40c6 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 16 Jul 2026 16:20:52 +0000
Subject: [PATCH 12/14] chore: start CI failure triage

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
 .github/workflows/agentic-auto-upgrade.yml   | 2 +-
 .github/workflows/avenger.lock.yml           | 5 ++---
 .github/workflows/hourly-ci-cleaner.lock.yml | 5 ++---
 .github/workflows/release.lock.yml           | 6 +++---
 .github/workflows/skillet.lock.yml           | 5 ++---
 5 files changed, 10 insertions(+), 13 deletions(-)

diff --git a/.github/workflows/agentic-auto-upgrade.yml b/.github/workflows/agentic-auto-upgrade.yml
index 7035101ee35..e169cea32b6 100644
--- a/.github/workflows/agentic-auto-upgrade.yml
+++ b/.github/workflows/agentic-auto-upgrade.yml
@@ -34,7 +34,7 @@ name: Agentic Auto-Upgrade
 
 on:
   schedule:
-    - cron: "21 3 * * 5"  # Weekly (auto-upgrade)
+    - cron: "11 4 * * 6"  # Weekly (auto-upgrade)
   workflow_dispatch:
 
 permissions:
diff --git a/.github/workflows/avenger.lock.yml b/.github/workflows/avenger.lock.yml
index c1462431878..759bba75c28 100644
--- a/.github/workflows/avenger.lock.yml
+++ b/.github/workflows/avenger.lock.yml
@@ -1,5 +1,5 @@
 # gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"6807590fb97b42c0858f3b0e068f5f2b823e6d3a5a873b1a1652f5658361eb44","body_hash":"e5fd04fe008ba327d939d9aee395ffb802836e30fd1f3772ca36984bdd1478f4","strict":true,"agent_id":"claude","agent_model":"claude-haiku-4.5","engine_versions":{"claude":"2.1.210"}}
-# gh-aw-manifest: {"version":1,"secrets":["ANTHROPIC_API_KEY","COPILOT_GITHUB_TOKEN","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GH_AW_OTEL_GRAFANA_AUTHORIZATION","GH_AW_OTEL_GRAFANA_ENDPOINT","GH_AW_OTEL_SENTRY_AUTHORIZATION","GH_AW_OTEL_SENTRY_ENDPOINT","GITHUB_TOKEN"],"actions":[{"repo":"actions/cache/restore","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/cache/save","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-go","sha":"b7ad1dad31e06c5925ef5d2fc7ad053ef454303e","version":"v7.0.0"},{"repo":"actions/setup-node","sha":"820762786026740c76f36085b0efc47a31fe5020","version":"v7.0.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.35","digest":"sha256:2202f63e8650b2b8b0d38033b44a05387b2b71ad3e690c4d23a34786f5462aed","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.35@sha256:2202f63e8650b2b8b0d38033b44a05387b2b71ad3e690c4d23a34786f5462aed"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.35","digest":"sha256:755b79d0dfda82bd6b43a208d68666721e504110c5d342a4eeb199802644ff04","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.35@sha256:755b79d0dfda82bd6b43a208d68666721e504110c5d342a4eeb199802644ff04"},{"image":"ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.35","digest":"sha256:fe83cd274636efa9de3f456e2b078fae137328b9bb6ee4986ae510acaef0cec5","pinned_image":"ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.35@sha256:fe83cd274636efa9de3f456e2b078fae137328b9bb6ee4986ae510acaef0cec5"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.35","digest":"sha256:f69282ec7b1326ba53891c399cf5b10475c0d3ccf4e1519b33d234a5427b57d3","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.35@sha256:f69282ec7b1326ba53891c399cf5b10475c0d3ccf4e1519b33d234a5427b57d3"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.4.1","digest":"sha256:ad2a979c2cd8b50098e84938ca9c9c1580eb8e91526f101a90adfba7859b2c32","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.4.1@sha256:ad2a979c2cd8b50098e84938ca9c9c1580eb8e91526f101a90adfba7859b2c32"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b","pinned_image":"ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b"},{"image":"ghcr.io/github/github-mcp-server:v1.6.0","digest":"sha256:2b0c48b070f61e9d3969269ead600f62d00fb237b60ac849ef3d166ee7de9ad3","pinned_image":"ghcr.io/github/github-mcp-server:v1.6.0@sha256:2b0c48b070f61e9d3969269ead600f62d00fb237b60ac849ef3d166ee7de9ad3"}]}
+# gh-aw-manifest: {"version":1,"secrets":["ANTHROPIC_API_KEY","COPILOT_GITHUB_TOKEN","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GH_AW_OTEL_GRAFANA_AUTHORIZATION","GH_AW_OTEL_GRAFANA_ENDPOINT","GH_AW_OTEL_SENTRY_AUTHORIZATION","GH_AW_OTEL_SENTRY_ENDPOINT","GITHUB_TOKEN"],"actions":[{"repo":"actions/cache/restore","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/cache/save","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"v7.0.0"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-go","sha":"b7ad1dad31e06c5925ef5d2fc7ad053ef454303e","version":"v7.0.0"},{"repo":"actions/setup-node","sha":"820762786026740c76f36085b0efc47a31fe5020","version":"v7.0.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.35","digest":"sha256:2202f63e8650b2b8b0d38033b44a05387b2b71ad3e690c4d23a34786f5462aed","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.35@sha256:2202f63e8650b2b8b0d38033b44a05387b2b71ad3e690c4d23a34786f5462aed"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.35","digest":"sha256:755b79d0dfda82bd6b43a208d68666721e504110c5d342a4eeb199802644ff04","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.35@sha256:755b79d0dfda82bd6b43a208d68666721e504110c5d342a4eeb199802644ff04"},{"image":"ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.35","digest":"sha256:fe83cd274636efa9de3f456e2b078fae137328b9bb6ee4986ae510acaef0cec5","pinned_image":"ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.35@sha256:fe83cd274636efa9de3f456e2b078fae137328b9bb6ee4986ae510acaef0cec5"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.35","digest":"sha256:f69282ec7b1326ba53891c399cf5b10475c0d3ccf4e1519b33d234a5427b57d3","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.35@sha256:f69282ec7b1326ba53891c399cf5b10475c0d3ccf4e1519b33d234a5427b57d3"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.4.1","digest":"sha256:ad2a979c2cd8b50098e84938ca9c9c1580eb8e91526f101a90adfba7859b2c32","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.4.1@sha256:ad2a979c2cd8b50098e84938ca9c9c1580eb8e91526f101a90adfba7859b2c32"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b","pinned_image":"ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b"},{"image":"ghcr.io/github/github-mcp-server:v1.6.0","digest":"sha256:2b0c48b070f61e9d3969269ead600f62d00fb237b60ac849ef3d166ee7de9ad3","pinned_image":"ghcr.io/github/github-mcp-server:v1.6.0@sha256:2b0c48b070f61e9d3969269ead600f62d00fb237b60ac849ef3d166ee7de9ad3"}]}
 # This file was automatically generated by gh-aw. DO NOT EDIT. To debug this workflow, load the skill at https://github.com/github/gh-aw/blob/main/debug.md
 #
 #    ___                   _   _
@@ -44,7 +44,6 @@
 # Custom actions used:
 #   - actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
 #   - actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
-#   - actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # 9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
 #   - actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
 #   - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
 #   - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
@@ -1146,7 +1145,7 @@ jobs:
           GH_HOST="${GH_HOST#http://}"
           echo "GH_HOST=${GH_HOST}" >> "$GITHUB_ENV"
       - name: Checkout repository
-        uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # 9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
+        uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
         with:
           persist-credentials: false
       - name: Check last CI workflow run status on main branch
diff --git a/.github/workflows/hourly-ci-cleaner.lock.yml b/.github/workflows/hourly-ci-cleaner.lock.yml
index ca0f005228e..430262a8018 100644
--- a/.github/workflows/hourly-ci-cleaner.lock.yml
+++ b/.github/workflows/hourly-ci-cleaner.lock.yml
@@ -1,5 +1,5 @@
 # gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"8b86cc12904088cf1b7630e0faa28299f64081df184a028b6293cb4f8bfdd07d","body_hash":"8eb6f8fd1e8e3d63cfd268226d09333129d49634435ae9a3c88debb099521ed5","strict":true,"agent_id":"claude","engine_versions":{"claude":"2.1.210"}}
-# gh-aw-manifest: {"version":1,"secrets":["ANTHROPIC_API_KEY","COPILOT_GITHUB_TOKEN","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GH_AW_OTEL_GRAFANA_AUTHORIZATION","GH_AW_OTEL_GRAFANA_ENDPOINT","GH_AW_OTEL_SENTRY_AUTHORIZATION","GH_AW_OTEL_SENTRY_ENDPOINT","GITHUB_TOKEN"],"actions":[{"repo":"actions/cache/restore","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/cache/save","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-go","sha":"b7ad1dad31e06c5925ef5d2fc7ad053ef454303e","version":"v7.0.0"},{"repo":"actions/setup-node","sha":"820762786026740c76f36085b0efc47a31fe5020","version":"v7.0.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.35","digest":"sha256:2202f63e8650b2b8b0d38033b44a05387b2b71ad3e690c4d23a34786f5462aed","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.35@sha256:2202f63e8650b2b8b0d38033b44a05387b2b71ad3e690c4d23a34786f5462aed"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.35","digest":"sha256:755b79d0dfda82bd6b43a208d68666721e504110c5d342a4eeb199802644ff04","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.35@sha256:755b79d0dfda82bd6b43a208d68666721e504110c5d342a4eeb199802644ff04"},{"image":"ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.35","digest":"sha256:fe83cd274636efa9de3f456e2b078fae137328b9bb6ee4986ae510acaef0cec5","pinned_image":"ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.35@sha256:fe83cd274636efa9de3f456e2b078fae137328b9bb6ee4986ae510acaef0cec5"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.35","digest":"sha256:f69282ec7b1326ba53891c399cf5b10475c0d3ccf4e1519b33d234a5427b57d3","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.35@sha256:f69282ec7b1326ba53891c399cf5b10475c0d3ccf4e1519b33d234a5427b57d3"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.4.1","digest":"sha256:ad2a979c2cd8b50098e84938ca9c9c1580eb8e91526f101a90adfba7859b2c32","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.4.1@sha256:ad2a979c2cd8b50098e84938ca9c9c1580eb8e91526f101a90adfba7859b2c32"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b","pinned_image":"ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b"},{"image":"ghcr.io/github/github-mcp-server:v1.6.0","digest":"sha256:2b0c48b070f61e9d3969269ead600f62d00fb237b60ac849ef3d166ee7de9ad3","pinned_image":"ghcr.io/github/github-mcp-server:v1.6.0@sha256:2b0c48b070f61e9d3969269ead600f62d00fb237b60ac849ef3d166ee7de9ad3"}]}
+# gh-aw-manifest: {"version":1,"secrets":["ANTHROPIC_API_KEY","COPILOT_GITHUB_TOKEN","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GH_AW_OTEL_GRAFANA_AUTHORIZATION","GH_AW_OTEL_GRAFANA_ENDPOINT","GH_AW_OTEL_SENTRY_AUTHORIZATION","GH_AW_OTEL_SENTRY_ENDPOINT","GITHUB_TOKEN"],"actions":[{"repo":"actions/cache/restore","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/cache/save","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"v7.0.0"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-go","sha":"b7ad1dad31e06c5925ef5d2fc7ad053ef454303e","version":"v7.0.0"},{"repo":"actions/setup-node","sha":"820762786026740c76f36085b0efc47a31fe5020","version":"v7.0.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.35","digest":"sha256:2202f63e8650b2b8b0d38033b44a05387b2b71ad3e690c4d23a34786f5462aed","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.35@sha256:2202f63e8650b2b8b0d38033b44a05387b2b71ad3e690c4d23a34786f5462aed"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.35","digest":"sha256:755b79d0dfda82bd6b43a208d68666721e504110c5d342a4eeb199802644ff04","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.35@sha256:755b79d0dfda82bd6b43a208d68666721e504110c5d342a4eeb199802644ff04"},{"image":"ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.35","digest":"sha256:fe83cd274636efa9de3f456e2b078fae137328b9bb6ee4986ae510acaef0cec5","pinned_image":"ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.35@sha256:fe83cd274636efa9de3f456e2b078fae137328b9bb6ee4986ae510acaef0cec5"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.35","digest":"sha256:f69282ec7b1326ba53891c399cf5b10475c0d3ccf4e1519b33d234a5427b57d3","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.35@sha256:f69282ec7b1326ba53891c399cf5b10475c0d3ccf4e1519b33d234a5427b57d3"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.4.1","digest":"sha256:ad2a979c2cd8b50098e84938ca9c9c1580eb8e91526f101a90adfba7859b2c32","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.4.1@sha256:ad2a979c2cd8b50098e84938ca9c9c1580eb8e91526f101a90adfba7859b2c32"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b","pinned_image":"ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b"},{"image":"ghcr.io/github/github-mcp-server:v1.6.0","digest":"sha256:2b0c48b070f61e9d3969269ead600f62d00fb237b60ac849ef3d166ee7de9ad3","pinned_image":"ghcr.io/github/github-mcp-server:v1.6.0@sha256:2b0c48b070f61e9d3969269ead600f62d00fb237b60ac849ef3d166ee7de9ad3"}]}
 # This file was automatically generated by gh-aw. DO NOT EDIT. To debug this workflow, load the skill at https://github.com/github/gh-aw/blob/main/debug.md
 #
 #    ___                   _   _
@@ -45,7 +45,6 @@
 # Custom actions used:
 #   - actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
 #   - actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
-#   - actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # 9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
 #   - actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
 #   - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
 #   - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
@@ -1153,7 +1152,7 @@ jobs:
           GH_HOST="${GH_HOST#http://}"
           echo "GH_HOST=${GH_HOST}" >> "$GITHUB_ENV"
       - name: Checkout repository
-        uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # 9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
+        uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
         with:
           persist-credentials: false
       - name: Check last CI workflow run status on main branch
diff --git a/.github/workflows/release.lock.yml b/.github/workflows/release.lock.yml
index 5ffc07c471f..c3e4b45dede 100644
--- a/.github/workflows/release.lock.yml
+++ b/.github/workflows/release.lock.yml
@@ -1,5 +1,5 @@
 # gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"2b85ad1e6c3e13e577935d3841133c8c2d72ba5ad9c46e4116d3d60d49ee875b","body_hash":"646353d7bb4e5523bc85349c2cce38188190095a303f83cc95961ff145a47043","strict":true,"agent_id":"copilot","engine_versions":{"copilot":"1.0.70"}}
-# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GH_AW_OTEL_GRAFANA_AUTHORIZATION","GH_AW_OTEL_GRAFANA_ENDPOINT","GH_AW_OTEL_SENTRY_AUTHORIZATION","GH_AW_OTEL_SENTRY_ENDPOINT","GITHUB_TOKEN"],"actions":[{"repo":"actions/cache/restore","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/cache/save","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"v7.0.0"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-go","sha":"b7ad1dad31e06c5925ef5d2fc7ad053ef454303e","version":"b7ad1dad31e06c5925ef5d2fc7ad053ef454303e"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"anchore/sbom-action","sha":"e22c389904149dbc22b58101806040fa8d37a610","version":"v0.24.0"},{"repo":"docker/build-push-action","sha":"53b7df96c91f9c12dcc8a07bcb9ccacbed38856a","version":"v7.3.0"},{"repo":"docker/login-action","sha":"af1e73f918a031802d376d3c8bbc3fe56130a9b0","version":"v4.4.0"},{"repo":"docker/metadata-action","sha":"dc802804100637a589fabce1cb79ff13a1411302","version":"v6.2.0"},{"repo":"docker/setup-buildx-action","sha":"bb05f3f5519dd87d3ba754cc423b652a5edd6d2c","version":"v4.2.0"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.35","digest":"sha256:2202f63e8650b2b8b0d38033b44a05387b2b71ad3e690c4d23a34786f5462aed","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.35@sha256:2202f63e8650b2b8b0d38033b44a05387b2b71ad3e690c4d23a34786f5462aed"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.35","digest":"sha256:755b79d0dfda82bd6b43a208d68666721e504110c5d342a4eeb199802644ff04","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.35@sha256:755b79d0dfda82bd6b43a208d68666721e504110c5d342a4eeb199802644ff04"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.35","digest":"sha256:f69282ec7b1326ba53891c399cf5b10475c0d3ccf4e1519b33d234a5427b57d3","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.35@sha256:f69282ec7b1326ba53891c399cf5b10475c0d3ccf4e1519b33d234a5427b57d3"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.4.1","digest":"sha256:ad2a979c2cd8b50098e84938ca9c9c1580eb8e91526f101a90adfba7859b2c32","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.4.1@sha256:ad2a979c2cd8b50098e84938ca9c9c1580eb8e91526f101a90adfba7859b2c32"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b","pinned_image":"ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b"},{"image":"ghcr.io/github/github-mcp-server:v1.6.0","digest":"sha256:2b0c48b070f61e9d3969269ead600f62d00fb237b60ac849ef3d166ee7de9ad3","pinned_image":"ghcr.io/github/github-mcp-server:v1.6.0@sha256:2b0c48b070f61e9d3969269ead600f62d00fb237b60ac849ef3d166ee7de9ad3"}]}
+# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GH_AW_OTEL_GRAFANA_AUTHORIZATION","GH_AW_OTEL_GRAFANA_ENDPOINT","GH_AW_OTEL_SENTRY_AUTHORIZATION","GH_AW_OTEL_SENTRY_ENDPOINT","GITHUB_TOKEN"],"actions":[{"repo":"actions/cache/restore","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/cache/save","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"v7.0.0"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-go","sha":"b7ad1dad31e06c5925ef5d2fc7ad053ef454303e","version":"v7.0.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"anchore/sbom-action","sha":"e22c389904149dbc22b58101806040fa8d37a610","version":"v0.24.0"},{"repo":"docker/build-push-action","sha":"53b7df96c91f9c12dcc8a07bcb9ccacbed38856a","version":"v7.3.0"},{"repo":"docker/login-action","sha":"af1e73f918a031802d376d3c8bbc3fe56130a9b0","version":"v4.4.0"},{"repo":"docker/metadata-action","sha":"dc802804100637a589fabce1cb79ff13a1411302","version":"v6.2.0"},{"repo":"docker/setup-buildx-action","sha":"bb05f3f5519dd87d3ba754cc423b652a5edd6d2c","version":"v4.2.0"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.35","digest":"sha256:2202f63e8650b2b8b0d38033b44a05387b2b71ad3e690c4d23a34786f5462aed","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.35@sha256:2202f63e8650b2b8b0d38033b44a05387b2b71ad3e690c4d23a34786f5462aed"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.35","digest":"sha256:755b79d0dfda82bd6b43a208d68666721e504110c5d342a4eeb199802644ff04","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.35@sha256:755b79d0dfda82bd6b43a208d68666721e504110c5d342a4eeb199802644ff04"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.35","digest":"sha256:f69282ec7b1326ba53891c399cf5b10475c0d3ccf4e1519b33d234a5427b57d3","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.35@sha256:f69282ec7b1326ba53891c399cf5b10475c0d3ccf4e1519b33d234a5427b57d3"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.4.1","digest":"sha256:ad2a979c2cd8b50098e84938ca9c9c1580eb8e91526f101a90adfba7859b2c32","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.4.1@sha256:ad2a979c2cd8b50098e84938ca9c9c1580eb8e91526f101a90adfba7859b2c32"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b","pinned_image":"ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b"},{"image":"ghcr.io/github/github-mcp-server:v1.6.0","digest":"sha256:2b0c48b070f61e9d3969269ead600f62d00fb237b60ac849ef3d166ee7de9ad3","pinned_image":"ghcr.io/github/github-mcp-server:v1.6.0@sha256:2b0c48b070f61e9d3969269ead600f62d00fb237b60ac849ef3d166ee7de9ad3"}]}
 # This file was automatically generated by gh-aw. DO NOT EDIT. To debug this workflow, load the skill at https://github.com/github/gh-aw/blob/main/debug.md
 #
 #    ___                   _   _
@@ -47,7 +47,7 @@
 #   - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
 #   - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
 #   - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 (source v9)
-#   - actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # b7ad1dad31e06c5925ef5d2fc7ad053ef454303e
+#   - actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
 #   - actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
 #   - anchore/sbom-action@e22c389904149dbc22b58101806040fa8d37a610 # v0.24.0
 #   - docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
@@ -1944,7 +1944,7 @@ jobs:
         env:
           RELEASE_TAG: ${{ needs.config.outputs.release_tag }}
       - name: Setup Go
-        uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # b7ad1dad31e06c5925ef5d2fc7ad053ef454303e
+        uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
         with:
           cache: false
           go-version-file: go.mod
diff --git a/.github/workflows/skillet.lock.yml b/.github/workflows/skillet.lock.yml
index 2c83c89a672..d718a6999b3 100644
--- a/.github/workflows/skillet.lock.yml
+++ b/.github/workflows/skillet.lock.yml
@@ -1,5 +1,5 @@
 # gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"2b7791e73899163b45a0881db45f5747495a6a7dbd2dc4e17f3f31af4ecf6898","body_hash":"ff6f6b1fbf4788ce998b5ddca9ed8f907259189ec1db98a5cd9768e4e0ed2f50","strict":true,"agent_id":"copilot","engine_versions":{"copilot":"1.0.70"}}
-# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GH_AW_OTEL_GRAFANA_AUTHORIZATION","GH_AW_OTEL_GRAFANA_ENDPOINT","GH_AW_OTEL_SENTRY_AUTHORIZATION","GH_AW_OTEL_SENTRY_ENDPOINT","GITHUB_TOKEN"],"actions":[{"repo":"actions/cache/restore","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/cache/save","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"3a2844b7e9c422d3c10d287c895573f7108da1b3"},{"repo":"actions/setup-node","sha":"820762786026740c76f36085b0efc47a31fe5020","version":"v7.0.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.35","digest":"sha256:2202f63e8650b2b8b0d38033b44a05387b2b71ad3e690c4d23a34786f5462aed","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.35@sha256:2202f63e8650b2b8b0d38033b44a05387b2b71ad3e690c4d23a34786f5462aed"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.35","digest":"sha256:755b79d0dfda82bd6b43a208d68666721e504110c5d342a4eeb199802644ff04","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.35@sha256:755b79d0dfda82bd6b43a208d68666721e504110c5d342a4eeb199802644ff04"},{"image":"ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.35","digest":"sha256:fe83cd274636efa9de3f456e2b078fae137328b9bb6ee4986ae510acaef0cec5","pinned_image":"ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.35@sha256:fe83cd274636efa9de3f456e2b078fae137328b9bb6ee4986ae510acaef0cec5"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.35","digest":"sha256:f69282ec7b1326ba53891c399cf5b10475c0d3ccf4e1519b33d234a5427b57d3","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.35@sha256:f69282ec7b1326ba53891c399cf5b10475c0d3ccf4e1519b33d234a5427b57d3"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.4.1","digest":"sha256:ad2a979c2cd8b50098e84938ca9c9c1580eb8e91526f101a90adfba7859b2c32","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.4.1@sha256:ad2a979c2cd8b50098e84938ca9c9c1580eb8e91526f101a90adfba7859b2c32"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b","pinned_image":"ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b"},{"image":"ghcr.io/github/github-mcp-server:v1.6.0","digest":"sha256:2b0c48b070f61e9d3969269ead600f62d00fb237b60ac849ef3d166ee7de9ad3","pinned_image":"ghcr.io/github/github-mcp-server:v1.6.0@sha256:2b0c48b070f61e9d3969269ead600f62d00fb237b60ac849ef3d166ee7de9ad3"}]}
+# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GH_AW_OTEL_GRAFANA_AUTHORIZATION","GH_AW_OTEL_GRAFANA_ENDPOINT","GH_AW_OTEL_SENTRY_AUTHORIZATION","GH_AW_OTEL_SENTRY_ENDPOINT","GITHUB_TOKEN"],"actions":[{"repo":"actions/cache/restore","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/cache/save","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"v7.0.0"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"3a2844b7e9c422d3c10d287c895573f7108da1b3"},{"repo":"actions/setup-node","sha":"820762786026740c76f36085b0efc47a31fe5020","version":"v7.0.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.35","digest":"sha256:2202f63e8650b2b8b0d38033b44a05387b2b71ad3e690c4d23a34786f5462aed","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.35@sha256:2202f63e8650b2b8b0d38033b44a05387b2b71ad3e690c4d23a34786f5462aed"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.35","digest":"sha256:755b79d0dfda82bd6b43a208d68666721e504110c5d342a4eeb199802644ff04","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.35@sha256:755b79d0dfda82bd6b43a208d68666721e504110c5d342a4eeb199802644ff04"},{"image":"ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.35","digest":"sha256:fe83cd274636efa9de3f456e2b078fae137328b9bb6ee4986ae510acaef0cec5","pinned_image":"ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.35@sha256:fe83cd274636efa9de3f456e2b078fae137328b9bb6ee4986ae510acaef0cec5"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.35","digest":"sha256:f69282ec7b1326ba53891c399cf5b10475c0d3ccf4e1519b33d234a5427b57d3","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.35@sha256:f69282ec7b1326ba53891c399cf5b10475c0d3ccf4e1519b33d234a5427b57d3"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.4.1","digest":"sha256:ad2a979c2cd8b50098e84938ca9c9c1580eb8e91526f101a90adfba7859b2c32","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.4.1@sha256:ad2a979c2cd8b50098e84938ca9c9c1580eb8e91526f101a90adfba7859b2c32"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b","pinned_image":"ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b"},{"image":"ghcr.io/github/github-mcp-server:v1.6.0","digest":"sha256:2b0c48b070f61e9d3969269ead600f62d00fb237b60ac849ef3d166ee7de9ad3","pinned_image":"ghcr.io/github/github-mcp-server:v1.6.0@sha256:2b0c48b070f61e9d3969269ead600f62d00fb237b60ac849ef3d166ee7de9ad3"}]}
 # This file was automatically generated by gh-aw. DO NOT EDIT. To debug this workflow, load the skill at https://github.com/github/gh-aw/blob/main/debug.md
 #
 #    ___                   _   _
@@ -45,7 +45,6 @@
 # Custom actions used:
 #   - actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
 #   - actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
-#   - actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # 9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
 #   - actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
 #   - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
 #   - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3
@@ -1728,7 +1727,7 @@ jobs:
           GH_AW_INFO_AWF_VERSION: "v0.27.35"
           GH_AW_INFO_ENGINE_ID: "copilot"
       - name: Checkout skills directory
-        uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # 9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
+        uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
         with:
           persist-credentials: false
           sparse-checkout: |

From e21b4d9b7d1ef8f0a7056a82586e63e7724ed692 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 16 Jul 2026 16:33:26 +0000
Subject: [PATCH 13/14] fix cjs typecheck for handler manager global github
 binding

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
 .../setup/js/safe_output_handler_manager.cjs  | 19 ++++++++++++-------
 1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/actions/setup/js/safe_output_handler_manager.cjs b/actions/setup/js/safe_output_handler_manager.cjs
index f40d0efed55..538cac42408 100644
--- a/actions/setup/js/safe_output_handler_manager.cjs
+++ b/actions/setup/js/safe_output_handler_manager.cjs
@@ -301,16 +301,18 @@ function wrapWithClientRebinding(type, messageHandler, handlerGithubClient) {
     return messageHandler;
   }
   return async (...args) => {
-    const hadGithub = Object.prototype.hasOwnProperty.call(global, "github");
-    const previousGithub = global.github;
-    global.github = handlerGithubClient;
+    /** @type {any} */
+    const globalState = global;
+    const hadGithub = Object.prototype.hasOwnProperty.call(globalState, "github");
+    const previousGithub = globalState.github;
+    globalState.github = handlerGithubClient;
     try {
       return await messageHandler(...args);
     } finally {
       if (hadGithub) {
-        global.github = previousGithub;
+        globalState.github = previousGithub;
       } else {
-        delete global.github;
+        delete globalState.github;
       }
     }
   };
@@ -357,9 +359,12 @@ async function loadHandlers(config, prReviewBufferRegistry, resolvedAllowedMenti
             handlerConfig._prReviewBufferRegistry = prReviewBufferRegistry;
           }
 
+          /** @type {any|null} */
           let handlerGithubClient = null;
-          if (handlerConfig[GITHUB_TOKEN_CONFIG_KEY] && typeof global.getOctokit === "function") {
-            handlerGithubClient = global.getOctokit(handlerConfig[GITHUB_TOKEN_CONFIG_KEY]);
+          /** @type {any} */
+          const globalState = global;
+          if (handlerConfig[GITHUB_TOKEN_CONFIG_KEY] && typeof globalState.getOctokit === "function") {
+            handlerGithubClient = globalState.getOctokit(handlerConfig[GITHUB_TOKEN_CONFIG_KEY]);
           }
           const messageHandler = await handlerModule.main(handlerConfig, handlerGithubClient);
 

From 6e445b0e05f364505b2d6c02d62948a6d00ac15b Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 16 Jul 2026 19:06:13 +0000
Subject: [PATCH 14/14] test: align mentions config spy expectations with
 handler client arg

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
 actions/setup/js/safe_output_handler_manager.test.cjs | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/actions/setup/js/safe_output_handler_manager.test.cjs b/actions/setup/js/safe_output_handler_manager.test.cjs
index d5df7b3e165..8fd1750adf9 100644
--- a/actions/setup/js/safe_output_handler_manager.test.cjs
+++ b/actions/setup/js/safe_output_handler_manager.test.cjs
@@ -277,14 +277,16 @@ describe("Safe Output Handler Manager", () => {
             max: 1,
             mentions: mentionsConfig,
             allowedMentionAliases: ["copilot", "octocat"],
-          })
+          }),
+          null
         );
         expect(createIssueMainSpy).toHaveBeenCalledWith(
           expect.objectContaining({
             max: 1,
             mentions: mentionsConfig,
             allowedMentionAliases: ["copilot", "octocat"],
-          })
+          }),
+          null
         );
       } finally {
         addCommentMainSpy.mockRestore();
