diff --git a/actions/setup/js/safe_output_helpers.cjs b/actions/setup/js/safe_output_helpers.cjs index 40b696e30bd..0d97fa86b55 100644 --- a/actions/setup/js/safe_output_helpers.cjs +++ b/actions/setup/js/safe_output_helpers.cjs @@ -274,8 +274,10 @@ function resolveIssueNumber(message) { }; } } else { - // Use context issue if available - const contextIssue = context.payload?.issue?.number; + // Use context issue if available (guard against context being undefined in + // non-github-script environments such as schedule events or the MCP server) + const ctx = typeof context !== "undefined" ? context : null; + const contextIssue = ctx?.payload?.issue?.number; if (!contextIssue) { return { success: false, diff --git a/actions/setup/js/safe_output_helpers.test.cjs b/actions/setup/js/safe_output_helpers.test.cjs index 3987068f3e8..b7296a9ef2d 100644 --- a/actions/setup/js/safe_output_helpers.test.cjs +++ b/actions/setup/js/safe_output_helpers.test.cjs @@ -1,4 +1,4 @@ -import { describe, it, expect } from "vitest"; +import { describe, it, expect, beforeEach } from "vitest"; describe("safe_output_helpers", () => { let helpers; @@ -581,4 +581,55 @@ describe("safe_output_helpers", () => { expect(helpers.isUsernameBlocked("alice", blocked)).toBe(false); }); }); + + describe("resolveIssueNumber", () => { + it("should return issue number from message.issue_number", () => { + const result = helpers.resolveIssueNumber({ issue_number: 42 }); + expect(result.success).toBe(true); + if (result.success) { + expect(result.issueNumber).toBe(42); + } + }); + + it("should return error for invalid issue_number in message", () => { + const result = helpers.resolveIssueNumber({ issue_number: "not-a-number" }); + expect(result.success).toBe(false); + }); + + it("should fall back to global context payload issue number when message has no issue_number", () => { + global.context = { payload: { issue: { number: 99 } } }; + try { + const result = helpers.resolveIssueNumber({}); + expect(result.success).toBe(true); + if (result.success) { + expect(result.issueNumber).toBe(99); + } + } finally { + delete global.context; + } + }); + + it("should return error when context is not defined and message has no issue_number", () => { + const savedContext = global.context; + delete global.context; + try { + const result = helpers.resolveIssueNumber({}); + expect(result.success).toBe(false); + expect(result.error).toBe("No issue number available"); + } finally { + global.context = savedContext; + } + }); + + it("should return error when context has no issue in payload (e.g. schedule event)", () => { + global.context = { eventName: "schedule", payload: {} }; + try { + const result = helpers.resolveIssueNumber({}); + expect(result.success).toBe(false); + expect(result.error).toBe("No issue number available"); + } finally { + delete global.context; + } + }); + }); }); diff --git a/actions/setup/js/safe_outputs_mcp_server_http.cjs b/actions/setup/js/safe_outputs_mcp_server_http.cjs index de2756c50f2..8f6bbdf9300 100644 --- a/actions/setup/js/safe_outputs_mcp_server_http.cjs +++ b/actions/setup/js/safe_outputs_mcp_server_http.cjs @@ -1,6 +1,12 @@ // @ts-check /// +// Load the shim before any other module so that global.core and global.context +// are available even when this module is started directly (i.e. not through the +// safe-outputs-mcp-server.cjs entry point). The shim is a no-op when those +// globals are already provided by the github-script environment. +require("./shim.cjs"); + const { createLogger } = require("./mcp_logger.cjs"); const moduleLogger = createLogger("safe_outputs_mcp_server_http"); diff --git a/docs/src/content/docs/agent-factory-status.mdx b/docs/src/content/docs/agent-factory-status.mdx index 6282f39ff21..6fdc72e7091 100644 --- a/docs/src/content/docs/agent-factory-status.mdx +++ b/docs/src/content/docs/agent-factory-status.mdx @@ -63,7 +63,7 @@ These are experimental agentic workflows used by the GitHub Next team to learn, | [Daily MCP Tool Concurrency Analysis](https://github.com/github/gh-aw/blob/main/.github/workflows/daily-mcp-concurrency-analysis.md) | copilot | [![Daily MCP Tool Concurrency Analysis](https://github.com/github/gh-aw/actions/workflows/daily-mcp-concurrency-analysis.lock.yml/badge.svg)](https://github.com/github/gh-aw/actions/workflows/daily-mcp-concurrency-analysis.lock.yml) | `0 9 * * 1-5` | - | | [Daily News](https://github.com/github/gh-aw/blob/main/.github/workflows/daily-news.md) | copilot | [![Daily News](https://github.com/github/gh-aw/actions/workflows/daily-news.lock.yml/badge.svg)](https://github.com/github/gh-aw/actions/workflows/daily-news.lock.yml) | `0 9 * * 1-5` | - | | [Daily Observability Report for AWF Firewall and MCP Gateway](https://github.com/github/gh-aw/blob/main/.github/workflows/daily-observability-report.md) | codex | [![Daily Observability Report for AWF Firewall and MCP Gateway](https://github.com/github/gh-aw/actions/workflows/daily-observability-report.lock.yml/badge.svg)](https://github.com/github/gh-aw/actions/workflows/daily-observability-report.lock.yml) | - | - | -| [Daily Project Performance Summary Generator (Using Safe Inputs)](https://github.com/github/gh-aw/blob/main/.github/workflows/daily-performance-summary.md) | codex | [![Daily Project Performance Summary Generator (Using Safe Inputs)](https://github.com/github/gh-aw/actions/workflows/daily-performance-summary.lock.yml/badge.svg)](https://github.com/github/gh-aw/actions/workflows/daily-performance-summary.lock.yml) | - | - | +| [Daily Project Performance Summary Generator (Using Safe Inputs)](https://github.com/github/gh-aw/blob/main/.github/workflows/daily-performance-summary.md) | copilot | [![Daily Project Performance Summary Generator (Using Safe Inputs)](https://github.com/github/gh-aw/actions/workflows/daily-performance-summary.lock.yml/badge.svg)](https://github.com/github/gh-aw/actions/workflows/daily-performance-summary.lock.yml) | - | - | | [Daily Regulatory Report Generator](https://github.com/github/gh-aw/blob/main/.github/workflows/daily-regulatory.md) | copilot | [![Daily Regulatory Report Generator](https://github.com/github/gh-aw/actions/workflows/daily-regulatory.lock.yml/badge.svg)](https://github.com/github/gh-aw/actions/workflows/daily-regulatory.lock.yml) | - | - | | [Daily Rendering Scripts Verifier](https://github.com/github/gh-aw/blob/main/.github/workflows/daily-rendering-scripts-verifier.md) | claude | [![Daily Rendering Scripts Verifier](https://github.com/github/gh-aw/actions/workflows/daily-rendering-scripts-verifier.lock.yml/badge.svg)](https://github.com/github/gh-aw/actions/workflows/daily-rendering-scripts-verifier.lock.yml) | - | - | | [Daily Safe Output Tool Optimizer](https://github.com/github/gh-aw/blob/main/.github/workflows/daily-safe-output-optimizer.md) | claude | [![Daily Safe Output Tool Optimizer](https://github.com/github/gh-aw/actions/workflows/daily-safe-output-optimizer.lock.yml/badge.svg)](https://github.com/github/gh-aw/actions/workflows/daily-safe-output-optimizer.lock.yml) | - | - | @@ -142,10 +142,12 @@ These are experimental agentic workflows used by the GitHub Next team to learn, | [Smoke Codex](https://github.com/github/gh-aw/blob/main/.github/workflows/smoke-codex.md) | codex | [![Smoke Codex](https://github.com/github/gh-aw/actions/workflows/smoke-codex.lock.yml/badge.svg)](https://github.com/github/gh-aw/actions/workflows/smoke-codex.lock.yml) | - | - | | [Smoke Copilot](https://github.com/github/gh-aw/blob/main/.github/workflows/smoke-copilot.md) | copilot | [![Smoke Copilot](https://github.com/github/gh-aw/actions/workflows/smoke-copilot.lock.yml/badge.svg)](https://github.com/github/gh-aw/actions/workflows/smoke-copilot.lock.yml) | - | - | | [Smoke Copilot ARM64](https://github.com/github/gh-aw/blob/main/.github/workflows/smoke-copilot-arm.md) | copilot | [![Smoke Copilot ARM64](https://github.com/github/gh-aw/actions/workflows/smoke-copilot-arm.lock.yml/badge.svg)](https://github.com/github/gh-aw/actions/workflows/smoke-copilot-arm.lock.yml) | - | - | +| [Smoke Create Cross-Repo PR](https://github.com/github/gh-aw/blob/main/.github/workflows/smoke-create-cross-repo-pr.md) | copilot | [![Smoke Create Cross-Repo PR](https://github.com/github/gh-aw/actions/workflows/smoke-create-cross-repo-pr.lock.yml/badge.svg)](https://github.com/github/gh-aw/actions/workflows/smoke-create-cross-repo-pr.lock.yml) | - | - | | [Smoke Gemini](https://github.com/github/gh-aw/blob/main/.github/workflows/smoke-gemini.md) | gemini | [![Smoke Gemini](https://github.com/github/gh-aw/actions/workflows/smoke-gemini.lock.yml/badge.svg)](https://github.com/github/gh-aw/actions/workflows/smoke-gemini.lock.yml) | - | - | | [Smoke Multi PR](https://github.com/github/gh-aw/blob/main/.github/workflows/smoke-multi-pr.md) | copilot | [![Smoke Multi PR](https://github.com/github/gh-aw/actions/workflows/smoke-multi-pr.lock.yml/badge.svg)](https://github.com/github/gh-aw/actions/workflows/smoke-multi-pr.lock.yml) | - | - | | [Smoke Project](https://github.com/github/gh-aw/blob/main/.github/workflows/smoke-project.md) | copilot | [![Smoke Project](https://github.com/github/gh-aw/actions/workflows/smoke-project.lock.yml/badge.svg)](https://github.com/github/gh-aw/actions/workflows/smoke-project.lock.yml) | - | - | | [Smoke Temporary ID](https://github.com/github/gh-aw/blob/main/.github/workflows/smoke-temporary-id.md) | copilot | [![Smoke Temporary ID](https://github.com/github/gh-aw/actions/workflows/smoke-temporary-id.lock.yml/badge.svg)](https://github.com/github/gh-aw/actions/workflows/smoke-temporary-id.lock.yml) | - | - | +| [Smoke Update Cross-Repo PR](https://github.com/github/gh-aw/blob/main/.github/workflows/smoke-update-cross-repo-pr.md) | copilot | [![Smoke Update Cross-Repo PR](https://github.com/github/gh-aw/actions/workflows/smoke-update-cross-repo-pr.lock.yml/badge.svg)](https://github.com/github/gh-aw/actions/workflows/smoke-update-cross-repo-pr.lock.yml) | - | - | | [Smoke Workflow Call](https://github.com/github/gh-aw/blob/main/.github/workflows/smoke-workflow-call.md) | copilot | [![Smoke Workflow Call](https://github.com/github/gh-aw/actions/workflows/smoke-workflow-call.lock.yml/badge.svg)](https://github.com/github/gh-aw/actions/workflows/smoke-workflow-call.lock.yml) | - | - | | [Stale Repository Identifier](https://github.com/github/gh-aw/blob/main/.github/workflows/stale-repo-identifier.md) | copilot | [![Stale Repository Identifier](https://github.com/github/gh-aw/actions/workflows/stale-repo-identifier.lock.yml/badge.svg)](https://github.com/github/gh-aw/actions/workflows/stale-repo-identifier.lock.yml) | - | - | | [Static Analysis Report](https://github.com/github/gh-aw/blob/main/.github/workflows/static-analysis-report.md) | claude | [![Static Analysis Report](https://github.com/github/gh-aw/actions/workflows/static-analysis-report.lock.yml/badge.svg)](https://github.com/github/gh-aw/actions/workflows/static-analysis-report.lock.yml) | - | - | diff --git a/docs/src/content/docs/reference/frontmatter-full.md b/docs/src/content/docs/reference/frontmatter-full.md index c88f5c35f03..ae4523395de 100644 --- a/docs/src/content/docs/reference/frontmatter-full.md +++ b/docs/src/content/docs/reference/frontmatter-full.md @@ -683,9 +683,10 @@ on: status-comment: true # Custom GitHub token to use for pre-activation reactions and activation status - # comments. When specified, overrides the default GITHUB_TOKEN for these operations. + # comments. When specified, overrides the default GITHUB_TOKEN for these + # operations. # (optional) - github-token: "${{ secrets.MY_GITHUB_TOKEN }}" + github-token: "${{ secrets.GITHUB_TOKEN }}" # GitHub App configuration for minting a token used in pre-activation reactions # and activation status comments. When configured, a GitHub App installation @@ -693,11 +694,11 @@ on: # (optional) github-app: # GitHub App ID (e.g., '${{ vars.APP_ID }}'). Required to mint a GitHub App token. - app-id: "${{ vars.APP_ID }}" + app-id: "example-value" # GitHub App private key (e.g., '${{ secrets.APP_PRIVATE_KEY }}'). Required to # mint a GitHub App token. - private-key: "${{ secrets.APP_PRIVATE_KEY }}" + private-key: "example-value" # Optional owner of the GitHub App installation (defaults to current repository # owner if not specified) @@ -1536,27 +1537,6 @@ tools: repositories: [] # Array of strings - # Deprecated: Use github-app instead. GitHub App configuration for token minting. - # (optional) - app: - # GitHub App ID (e.g., '${{ vars.APP_ID }}'). Required to mint a GitHub App token. - app-id: "example-value" - - # GitHub App private key (e.g., '${{ secrets.APP_PRIVATE_KEY }}'). Required to - # mint a GitHub App token. - private-key: "example-value" - - # Optional owner of the GitHub App installation (defaults to current repository - # owner if not specified) - # (optional) - owner: "example-value" - - # Optional list of repositories to grant access to (defaults to current repository - # if not specified) - # (optional) - repositories: [] - # Array of strings - # Bash shell command execution tool. Supports wildcards: '*' (all commands), # 'command *' (command with any args, e.g., 'date *', 'echo *'). Default safe # commands: echo, ls, pwd, cat, head, tail, grep, wc, sort, uniq, date. @@ -4240,30 +4220,6 @@ safe-outputs: repositories: [] # Array of strings - # Deprecated: Use github-app instead. GitHub App credentials for minting - # installation access tokens. - # (optional) - app: - # GitHub App ID. Should reference a variable (e.g., ${{ vars.APP_ID }}). - app-id: "example-value" - - # GitHub App private key. Should reference a secret (e.g., ${{ - # secrets.APP_PRIVATE_KEY }}). - private-key: "example-value" - - # Optional: The owner of the GitHub App installation. If empty, defaults to the - # current repository owner. - # (optional) - owner: "example-value" - - # Optional: Comma or newline-separated list of repositories to grant access to. If - # owner is set and repositories is empty, access will be scoped to all - # repositories in the provided repository owner's installation. If owner and - # repositories are empty, access will be scoped to only the current repository. - # (optional) - repositories: [] - # Array of strings - # Maximum allowed size for git patches in kilobytes (KB). Defaults to 1024 KB (1 # MB). If patch exceeds this size, the job will fail. # (optional)