diff --git a/.github/workflows/code-scanning-fixer.lock.yml b/.github/workflows/code-scanning-fixer.lock.yml index 20e91880671..37da7e1aa26 100644 --- a/.github/workflows/code-scanning-fixer.lock.yml +++ b/.github/workflows/code-scanning-fixer.lock.yml @@ -1,4 +1,4 @@ -# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"8a59c0bb83242965406350fe63d8fb49737cb295e161371fd84b96c25cc24d92","body_hash":"97b0480ab57d0e36a7a2ad24eefd66f4ce9b2cfeefa110967ca91fc106dcb867","strict":true,"agent_id":"copilot","engine_versions":{"copilot":"1.0.77","copilot-sdk":"1.0.8"}} +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"73911f5d6672da512a5f5771308e431ab715cf366d4d7233b8d497feafaec83b","body_hash":"2af041b4093beda2e7577796227d6ffb930092cb508b07ccb90cb0d155260e6f","strict":true,"agent_id":"copilot","engine_versions":{"copilot":"1.0.77","copilot-sdk":"1.0.8"}} # gh-aw-manifest: {"version":1,"secrets":["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":"3d3c42e5aac5ba805825da76410c181273ba90b1","version":"v7.0.1"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.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.43","digest":"sha256:04e2d1987a565000a8f114b89d806ae7a3864dd4f944be65275b28c93d8690e6","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.43@sha256:04e2d1987a565000a8f114b89d806ae7a3864dd4f944be65275b28c93d8690e6"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.43","digest":"sha256:d85f57975af5ea23af4996e41ed73fbc8f5b4a47402472bfe82e508f352cb0c1","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.43@sha256:d85f57975af5ea23af4996e41ed73fbc8f5b4a47402472bfe82e508f352cb0c1"},{"image":"ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.43","digest":"sha256:65c45ea2967984d0024f3df61bc71335658a77ede96c8d9665da7a5f33a795ab","pinned_image":"ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.43@sha256:65c45ea2967984d0024f3df61bc71335658a77ede96c8d9665da7a5f33a795ab"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.43","digest":"sha256:26be5e0b8c8f4c41c8a59126b29bb5d80b07253597472ded2a16bdd75abcbf9d","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.43@sha256:26be5e0b8c8f4c41c8a59126b29bb5d80b07253597472ded2a16bdd75abcbf9d"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.4.7","digest":"sha256:7545220a9aca134b71e51193ee0eaf4c50756ebf8fbd25a63ae7556e62815c00","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.4.7@sha256:7545220a9aca134b71e51193ee0eaf4c50756ebf8fbd25a63ae7556e62815c00"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:0d9f1fb5fd6610c0ac1f5194a38e45a8a1e81f8a390d5142d8e4e6f26a4b3196","pinned_image":"ghcr.io/github/gh-aw-node@sha256:0d9f1fb5fd6610c0ac1f5194a38e45a8a1e81f8a390d5142d8e4e6f26a4b3196"},{"image":"ghcr.io/github/github-mcp-server:v1.8.0","digest":"sha256:d5a18c04b92714c309eb46a2305087e91a4dbd80420f6e462656699f95093520","pinned_image":"ghcr.io/github/github-mcp-server:v1.8.0@sha256:d5a18c04b92714c309eb46a2305087e91a4dbd80420f6e462656699f95093520"}]} # 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 # @@ -865,6 +865,34 @@ jobs: - name: Execute GitHub Copilot CLI id: agentic_execution # Copilot CLI tool arguments (sorted): + # --allow-tool github + # --allow-tool safeoutputs + # --allow-tool shell(cat) + # --allow-tool shell(date) + # --allow-tool shell(echo) + # --allow-tool shell(gh:*) + # --allow-tool shell(git add:*) + # --allow-tool shell(git branch:*) + # --allow-tool shell(git checkout:*) + # --allow-tool shell(git commit:*) + # --allow-tool shell(git diff:*) + # --allow-tool shell(git merge:*) + # --allow-tool shell(git restore:*) + # --allow-tool shell(git rm:*) + # --allow-tool shell(git status) + # --allow-tool shell(git switch:*) + # --allow-tool shell(grep) + # --allow-tool shell(head) + # --allow-tool shell(ls) + # --allow-tool shell(printf) + # --allow-tool shell(pwd) + # --allow-tool shell(safeoutputs:*) + # --allow-tool shell(sort) + # --allow-tool shell(tail) + # --allow-tool shell(uniq) + # --allow-tool shell(wc) + # --allow-tool shell(yq) + # --allow-tool write timeout-minutes: 20 run: | set -o pipefail @@ -908,7 +936,7 @@ jobs: COPILOT_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'auto' }} COPILOT_SDK_URI: http://127.0.0.1:3002 GH_AW_COPILOT_SDK_DRIVER: 1 - GH_AW_COPILOT_SDK_SERVER_ARGS: '["--headless","--no-auto-update","--port","3002","--add-dir","/tmp/gh-aw/","--log-level","all","--log-dir","/tmp/gh-aw/sandbox/agent/logs/","--disable-builtin-mcps","--no-ask-user","--allow-all-tools","--add-dir","/tmp/gh-aw/cache-memory/","--allow-all-paths"]' + GH_AW_COPILOT_SDK_SERVER_ARGS: '["--headless","--no-auto-update","--port","3002","--add-dir","/tmp/gh-aw/","--log-level","all","--log-dir","/tmp/gh-aw/sandbox/agent/logs/","--disable-builtin-mcps","--no-ask-user","--allow-tool","github","--allow-tool","safeoutputs","--allow-tool","shell(cat)","--allow-tool","shell(date)","--allow-tool","shell(echo)","--allow-tool","shell(gh:*)","--allow-tool","shell(git add:*)","--allow-tool","shell(git branch:*)","--allow-tool","shell(git checkout:*)","--allow-tool","shell(git commit:*)","--allow-tool","shell(git diff:*)","--allow-tool","shell(git merge:*)","--allow-tool","shell(git restore:*)","--allow-tool","shell(git rm:*)","--allow-tool","shell(git status)","--allow-tool","shell(git switch:*)","--allow-tool","shell(grep)","--allow-tool","shell(head)","--allow-tool","shell(ls)","--allow-tool","shell(printf)","--allow-tool","shell(pwd)","--allow-tool","shell(safeoutputs:*)","--allow-tool","shell(sort)","--allow-tool","shell(tail)","--allow-tool","shell(uniq)","--allow-tool","shell(wc)","--allow-tool","shell(yq)","--allow-tool","write","--add-dir","/tmp/gh-aw/cache-memory/","--allow-all-paths"]' GH_AW_LLM_PROVIDER: github GH_AW_MAX_AI_CREDITS: ${{ vars.GH_AW_DEFAULT_MAX_AI_CREDITS || '1000' }} GH_AW_MAX_TOOL_DENIALS: 3 diff --git a/actions/setup/js/update_pull_request.cjs b/actions/setup/js/update_pull_request.cjs index f35809fe1c4..0dfd6044e90 100644 --- a/actions/setup/js/update_pull_request.cjs +++ b/actions/setup/js/update_pull_request.cjs @@ -52,7 +52,7 @@ function isNonFatalUpdateBranchError(error) { if (status === 403 && (hasWorkflowsPermissionError || hasWorkflowsScopeRequired)) { return true; } - if (status !== 422) { + if (status !== 422 && !message.includes("head ref does not exist")) { return false; } } @@ -62,12 +62,15 @@ function isNonFatalUpdateBranchError(error) { // - cannot auto-update due to conflict ("merge conflict between base and head") // - stale merged targets where the head branch was deleted ("head ref does not exist") // These should not fail safe output processing. - // Restrict to status === 422 to avoid silently swallowing the same phrases from proxy/network - // errors that lack a numeric status. hasWorkflowsPermissionError / hasWorkflowsScopeRequired - // are only checked for errors with no numeric status (status === undefined); the explicit 403 - // case is already handled by the if-block above. + // A deleted head ref is a stale target regardless of which numeric status the API/proxy reports. + // Keep requiring some numeric status so transport/proxy failures with no HTTP response still fail. + // Restrict the other phrases to status === 422 to avoid silently swallowing proxy/network + // errors. hasWorkflowsPermissionError / hasWorkflowsScopeRequired are only checked for errors + // with no numeric status (status === undefined); the explicit 403 case is already handled by + // the if-block above. return ( - (status === 422 && (message.includes("there are no new commits on the base branch") || message.includes("merge conflict between base and head") || message.includes("head ref does not exist"))) || + (status !== undefined && message.includes("head ref does not exist")) || + (status === 422 && (message.includes("there are no new commits on the base branch") || message.includes("merge conflict between base and head"))) || ((hasWorkflowsPermissionError || hasWorkflowsScopeRequired) && status === undefined) ); } diff --git a/actions/setup/js/update_pull_request.test.cjs b/actions/setup/js/update_pull_request.test.cjs index 523810f97fd..57e57229661 100644 --- a/actions/setup/js/update_pull_request.test.cjs +++ b/actions/setup/js/update_pull_request.test.cjs @@ -960,7 +960,7 @@ describe("update_pull_request.cjs - update_branch behavior", () => { expect(mockCore.warning).toHaveBeenCalledWith(expect.stringContaining("branch from base (non-fatal)")); }); - it("should treat head-ref-missing as fatal when updateBranch returns a non-422 status", async () => { + it("should treat head-ref-missing as non-fatal regardless of updateBranch status", async () => { const unexpectedStatusError = new Error("head ref does not exist - https://docs.github.com/rest/pulls/pulls#update-a-pull-request-branch"); unexpectedStatusError.status = 404; mockGithub.rest.pulls.updateBranch.mockRejectedValueOnce(unexpectedStatusError); @@ -968,9 +968,23 @@ describe("update_pull_request.cjs - update_branch behavior", () => { const handler = await updatePRModule.main({ update_branch: true }); const result = await handler({ pull_request_number: 100 }); - expect(result.success).toBe(false); + expect(result.success).toBe(true); expect(mockGithub.rest.pulls.updateBranch).toHaveBeenCalledTimes(1); expect(mockGithub.rest.pulls.update).not.toHaveBeenCalled(); + expect(mockCore.warning).toHaveBeenCalledWith(expect.stringContaining("branch from base (non-fatal)")); + }); + + it("should keep head-ref-missing fatal when updateBranch has no numeric status", async () => { + const missingStatusError = new Error("head ref does not exist - https://docs.github.com/rest/pulls/pulls#update-a-pull-request-branch"); + mockGithub.rest.pulls.updateBranch.mockRejectedValueOnce(missingStatusError); + + const handler = await updatePRModule.main({ update_branch: true }); + const result = await handler({ pull_request_number: 100 }); + + expect(result.success).toBe(false); + expect(result.error).toContain("update pull request #100 branch from base failed"); + expect(mockGithub.rest.pulls.updateBranch).toHaveBeenCalledTimes(1); + expect(mockCore.warning).toHaveBeenCalledWith(expect.not.stringContaining("(non-fatal)")); }); it("should continue title/body updates when updateBranch gets workflows-permission 403", async () => {