diff --git a/actions/setup/js/add_copilot_reviewer.cjs b/actions/setup/js/add_copilot_reviewer.cjs index ee10538677..7aec7ab842 100644 --- a/actions/setup/js/add_copilot_reviewer.cjs +++ b/actions/setup/js/add_copilot_reviewer.cjs @@ -3,6 +3,7 @@ const { getErrorMessage } = require("./error_helpers.cjs"); const { ERR_CONFIG, ERR_NOT_FOUND, ERR_VALIDATION } = require("./error_codes.cjs"); +const { COPILOT_REVIEWER_BOT } = require("./constants.cjs"); /** * Add Copilot as a reviewer to a pull request. @@ -15,9 +16,6 @@ const { ERR_CONFIG, ERR_NOT_FOUND, ERR_VALIDATION } = require("./error_codes.cjs * - PR_NUMBER: The pull request number to add the reviewer to */ -// GitHub Copilot reviewer bot username -const COPILOT_REVIEWER_BOT = "copilot-pull-request-reviewer[bot]"; - async function main() { // Validate required environment variables const prNumberStr = process.env.PR_NUMBER?.trim(); diff --git a/actions/setup/js/add_labels.cjs b/actions/setup/js/add_labels.cjs index 54b07b9709..06fab518bf 100644 --- a/actions/setup/js/add_labels.cjs +++ b/actions/setup/js/add_labels.cjs @@ -15,13 +15,7 @@ const { tryEnforceArrayLimit } = require("./limit_enforcement_helpers.cjs"); const { logStagedPreviewInfo } = require("./staged_preview.cjs"); const { createAuthenticatedGitHubClient } = require("./handler_auth.cjs"); const { resolveRepoIssueTarget, loadTemporaryIdMapFromResolved } = require("./temporary_id.cjs"); - -/** - * Maximum limits for label parameters to prevent resource exhaustion. - * These limits align with GitHub's API constraints and security best practices. - */ -/** @type {number} Maximum number of labels allowed per operation */ -const MAX_LABELS = 10; +const { MAX_LABELS } = require("./constants.cjs"); /** * Main handler factory for add_labels diff --git a/actions/setup/js/add_reviewer.cjs b/actions/setup/js/add_reviewer.cjs index 4ad267b79d..982a75ab87 100644 --- a/actions/setup/js/add_reviewer.cjs +++ b/actions/setup/js/add_reviewer.cjs @@ -10,9 +10,7 @@ const { getErrorMessage } = require("./error_helpers.cjs"); const { getPullRequestNumber } = require("./pr_helpers.cjs"); const { logStagedPreviewInfo } = require("./staged_preview.cjs"); const { createAuthenticatedGitHubClient } = require("./handler_auth.cjs"); - -// GitHub Copilot reviewer bot username -const COPILOT_REVIEWER_BOT = "copilot-pull-request-reviewer[bot]"; +const { COPILOT_REVIEWER_BOT } = require("./constants.cjs"); /** * Main handler factory for add_reviewer diff --git a/actions/setup/js/constants.cjs b/actions/setup/js/constants.cjs index 3b544cedfb..1d377c70b3 100644 --- a/actions/setup/js/constants.cjs +++ b/actions/setup/js/constants.cjs @@ -5,7 +5,8 @@ * Constants * * This module provides shared constants used across JavaScript actions. - * These constants should be kept in sync with the constants in pkg/constants/constants.go + * Where a constant has a counterpart in pkg/constants/constants.go, their values should be kept in sync. + * Some constants are specific to the JavaScript implementation and do not have Go equivalents. */ /** @@ -20,7 +21,73 @@ const AGENT_OUTPUT_FILENAME = "agent_output.json"; */ const TMP_GH_AW_PATH = "/tmp/gh-aw"; +// --------------------------------------------------------------------------- +// GitHub reviewer bot +// --------------------------------------------------------------------------- + +/** + * GitHub login name for the Copilot pull request reviewer bot + * @type {string} + */ +const COPILOT_REVIEWER_BOT = "copilot-pull-request-reviewer[bot]"; + +// --------------------------------------------------------------------------- +// Documentation URLs +// --------------------------------------------------------------------------- + +/** + * FAQ URL explaining why create-pull-request workflows may fail due to + * GitHub Actions not being permitted to create or approve pull requests + * @type {string} + */ +const FAQ_CREATE_PR_PERMISSIONS_URL = "https://github.github.com/gh-aw/reference/faq/#why-is-my-create-pull-request-workflow-failing-with-github-actions-is-not-permitted-to-create-or-approve-pull-requests"; + +// --------------------------------------------------------------------------- +// Array size limits +// --------------------------------------------------------------------------- + +/** + * Maximum number of labels that can be applied to an issue, PR, or discussion + * @type {number} + */ +const MAX_LABELS = 10; + +/** + * Maximum number of assignees for an issue or pull request + * @type {number} + */ +const MAX_ASSIGNEES = 5; + +// --------------------------------------------------------------------------- +// File paths +// --------------------------------------------------------------------------- + +/** + * Path to the MCP gateway JSONL log file + * @type {string} + */ +const GATEWAY_JSONL_PATH = `${TMP_GH_AW_PATH}/mcp-logs/gateway.jsonl`; + +/** + * Path to the MCP RPC messages JSONL log file + * @type {string} + */ +const RPC_MESSAGES_PATH = `${TMP_GH_AW_PATH}/mcp-logs/rpc-messages.jsonl`; + +/** + * Path to the safe-output manifest JSONL file + * @type {string} + */ +const MANIFEST_FILE_PATH = `${TMP_GH_AW_PATH}/safe-output-items.jsonl`; + module.exports = { AGENT_OUTPUT_FILENAME, TMP_GH_AW_PATH, + COPILOT_REVIEWER_BOT, + FAQ_CREATE_PR_PERMISSIONS_URL, + MAX_LABELS, + MAX_ASSIGNEES, + GATEWAY_JSONL_PATH, + RPC_MESSAGES_PATH, + MANIFEST_FILE_PATH, }; diff --git a/actions/setup/js/constants.test.cjs b/actions/setup/js/constants.test.cjs index 8d4718902c..e29cf1bb70 100644 --- a/actions/setup/js/constants.test.cjs +++ b/actions/setup/js/constants.test.cjs @@ -1,13 +1,69 @@ // @ts-check import { describe, it, expect } from "vitest"; -const { AGENT_OUTPUT_FILENAME, TMP_GH_AW_PATH } = require("./constants.cjs"); +const { AGENT_OUTPUT_FILENAME, TMP_GH_AW_PATH, COPILOT_REVIEWER_BOT, FAQ_CREATE_PR_PERMISSIONS_URL, MAX_LABELS, MAX_ASSIGNEES, GATEWAY_JSONL_PATH, RPC_MESSAGES_PATH, MANIFEST_FILE_PATH } = require("./constants.cjs"); describe("constants", () => { - it("should export AGENT_OUTPUT_FILENAME", () => { - expect(AGENT_OUTPUT_FILENAME).toBe("agent_output.json"); + describe("file names", () => { + it("should export AGENT_OUTPUT_FILENAME", () => { + expect(AGENT_OUTPUT_FILENAME).toBe("agent_output.json"); + }); }); - it("should export TMP_GH_AW_PATH", () => { - expect(TMP_GH_AW_PATH).toBe("/tmp/gh-aw"); + describe("paths", () => { + it("should export TMP_GH_AW_PATH", () => { + expect(TMP_GH_AW_PATH).toBe("/tmp/gh-aw"); + }); + + it("should export GATEWAY_JSONL_PATH under TMP_GH_AW_PATH", () => { + expect(GATEWAY_JSONL_PATH).toBe("/tmp/gh-aw/mcp-logs/gateway.jsonl"); + expect(GATEWAY_JSONL_PATH.startsWith(TMP_GH_AW_PATH)).toBe(true); + }); + + it("should export RPC_MESSAGES_PATH under TMP_GH_AW_PATH", () => { + expect(RPC_MESSAGES_PATH).toBe("/tmp/gh-aw/mcp-logs/rpc-messages.jsonl"); + expect(RPC_MESSAGES_PATH.startsWith(TMP_GH_AW_PATH)).toBe(true); + }); + + it("should export MANIFEST_FILE_PATH under TMP_GH_AW_PATH", () => { + expect(MANIFEST_FILE_PATH).toBe("/tmp/gh-aw/safe-output-items.jsonl"); + expect(MANIFEST_FILE_PATH.startsWith(TMP_GH_AW_PATH)).toBe(true); + }); + }); + + describe("GitHub bot names", () => { + it("should export COPILOT_REVIEWER_BOT", () => { + expect(COPILOT_REVIEWER_BOT).toBe("copilot-pull-request-reviewer[bot]"); + }); + }); + + describe("documentation URLs", () => { + it("should export FAQ_CREATE_PR_PERMISSIONS_URL as a valid URL", () => { + expect(typeof FAQ_CREATE_PR_PERMISSIONS_URL).toBe("string"); + expect(FAQ_CREATE_PR_PERMISSIONS_URL).toMatch(/^https:\/\//); + }); + }); + + describe("array size limits", () => { + it("should export MAX_LABELS as a positive integer", () => { + expect(MAX_LABELS).toBe(10); + expect(Number.isInteger(MAX_LABELS)).toBe(true); + expect(MAX_LABELS).toBeGreaterThan(0); + }); + + it("should export MAX_ASSIGNEES as a positive integer", () => { + expect(MAX_ASSIGNEES).toBe(5); + expect(Number.isInteger(MAX_ASSIGNEES)).toBe(true); + expect(MAX_ASSIGNEES).toBeGreaterThan(0); + }); + }); + + describe("module exports", () => { + it("should export all expected constants", () => { + const exported = require("./constants.cjs"); + const expectedKeys = ["AGENT_OUTPUT_FILENAME", "TMP_GH_AW_PATH", "COPILOT_REVIEWER_BOT", "FAQ_CREATE_PR_PERMISSIONS_URL", "MAX_LABELS", "MAX_ASSIGNEES", "GATEWAY_JSONL_PATH", "RPC_MESSAGES_PATH", "MANIFEST_FILE_PATH"]; + for (const key of expectedKeys) { + expect(exported).toHaveProperty(key); + } + }); }); }); diff --git a/actions/setup/js/create_discussion.cjs b/actions/setup/js/create_discussion.cjs index c0fd46975a..9cae18d34b 100644 --- a/actions/setup/js/create_discussion.cjs +++ b/actions/setup/js/create_discussion.cjs @@ -24,13 +24,7 @@ const { closeOlderDiscussions: closeOlderDiscussionsFunc } = require("./close_ol const { parseBoolTemplatable } = require("./templatable.cjs"); const { buildWorkflowRunUrl } = require("./workflow_metadata_helpers.cjs"); const { generateHistoryLink } = require("./generate_history_link.cjs"); - -/** - * Maximum limits for discussion parameters to prevent resource exhaustion. - * These limits align with GitHub's API constraints and security best practices. - */ -/** @type {number} Maximum number of labels allowed per discussion */ -const MAX_LABELS = 10; +const { MAX_LABELS } = require("./constants.cjs"); /** * Fetch repository ID and discussion categories for a repository diff --git a/actions/setup/js/create_issue.cjs b/actions/setup/js/create_issue.cjs index a0aa377891..c1b7a06633 100644 --- a/actions/setup/js/create_issue.cjs +++ b/actions/setup/js/create_issue.cjs @@ -45,6 +45,7 @@ const { tryEnforceArrayLimit } = require("./limit_enforcement_helpers.cjs"); const fs = require("fs"); const { logStagedPreviewInfo } = require("./staged_preview.cjs"); const { buildWorkflowRunUrl } = require("./workflow_metadata_helpers.cjs"); +const { MAX_LABELS, MAX_ASSIGNEES } = require("./constants.cjs"); /** * @typedef {import('./types/handler-factory').HandlerFactoryFunction} HandlerFactoryFunction @@ -59,16 +60,6 @@ const MAX_SUB_ISSUES_PER_PARENT = MAX_SUB_ISSUES; /** @type {number} Maximum number of parent issues to check when searching */ const MAX_PARENT_ISSUES_TO_CHECK = 10; -/** - * Maximum limits for issue parameters to prevent resource exhaustion. - * These limits align with GitHub's API constraints and security best practices. - */ -/** @type {number} Maximum number of labels allowed per issue */ -const MAX_LABELS = 10; - -/** @type {number} Maximum number of assignees allowed per issue */ -const MAX_ASSIGNEES = 5; - /** * Searches for an existing parent issue that can accept more sub-issues * @param {string} owner - Repository owner diff --git a/actions/setup/js/create_pull_request.cjs b/actions/setup/js/create_pull_request.cjs index f7d8297ab9..27399382ff 100644 --- a/actions/setup/js/create_pull_request.cjs +++ b/actions/setup/js/create_pull_request.cjs @@ -26,6 +26,7 @@ const { createAuthenticatedGitHubClient } = require("./handler_auth.cjs"); const { buildWorkflowRunUrl } = require("./workflow_metadata_helpers.cjs"); const { checkFileProtection } = require("./manifest_file_helpers.cjs"); const { renderTemplate } = require("./messages_core.cjs"); +const { COPILOT_REVIEWER_BOT, FAQ_CREATE_PR_PERMISSIONS_URL } = require("./constants.cjs"); /** * @typedef {import('./types/handler-factory').HandlerFactoryFunction} HandlerFactoryFunction @@ -37,12 +38,6 @@ const HANDLER_TYPE = "create_pull_request"; /** @type {string} Label always added to fallback issues so the triage system can find them */ const MANAGED_FALLBACK_ISSUE_LABEL = "agentic-workflows"; -/** @type {string} FAQ link for the "GitHub Actions is not permitted to create or approve pull requests" error */ -const FAQ_CREATE_PR_PERMISSIONS_URL = "https://github.github.com/gh-aw/reference/faq/#why-is-my-create-pull-request-workflow-failing-with-github-actions-is-not-permitted-to-create-or-approve-pull-requests"; - -// GitHub Copilot reviewer bot username -const COPILOT_REVIEWER_BOT = "copilot-pull-request-reviewer[bot]"; - /** * Merges the required fallback label with any workflow-configured labels, * deduplicating and filtering empty values. diff --git a/actions/setup/js/gateway_difc_filtered.cjs b/actions/setup/js/gateway_difc_filtered.cjs index a55f571376..d8fa34035a 100644 --- a/actions/setup/js/gateway_difc_filtered.cjs +++ b/actions/setup/js/gateway_difc_filtered.cjs @@ -9,9 +9,7 @@ */ const fs = require("fs"); - -const GATEWAY_JSONL_PATH = "/tmp/gh-aw/mcp-logs/gateway.jsonl"; -const RPC_MESSAGES_PATH = "/tmp/gh-aw/mcp-logs/rpc-messages.jsonl"; +const { GATEWAY_JSONL_PATH, RPC_MESSAGES_PATH } = require("./constants.cjs"); /** * Parses JSONL content and extracts DIFC_FILTERED events diff --git a/actions/setup/js/handle_create_pr_error.cjs b/actions/setup/js/handle_create_pr_error.cjs index c9328c7047..226c49faa9 100644 --- a/actions/setup/js/handle_create_pr_error.cjs +++ b/actions/setup/js/handle_create_pr_error.cjs @@ -3,9 +3,7 @@ const { sanitizeContent } = require("./sanitize_content.cjs"); const { getErrorMessage } = require("./error_helpers.cjs"); - -/** @type {string} FAQ link for the "GitHub Actions is not permitted to create or approve pull requests" error */ -const FAQ_CREATE_PR_PERMISSIONS_URL = "https://github.github.com/gh-aw/reference/faq/#why-is-my-create-pull-request-workflow-failing-with-github-actions-is-not-permitted-to-create-or-approve-pull-requests"; +const { FAQ_CREATE_PR_PERMISSIONS_URL } = require("./constants.cjs"); /** * Handle create_pull_request permission errors diff --git a/actions/setup/js/safe_output_manifest.cjs b/actions/setup/js/safe_output_manifest.cjs index 80bf37976b..eefb743b9d 100644 --- a/actions/setup/js/safe_output_manifest.cjs +++ b/actions/setup/js/safe_output_manifest.cjs @@ -3,12 +3,7 @@ const fs = require("fs"); const { getErrorMessage } = require("./error_helpers.cjs"); const { ERR_SYSTEM } = require("./error_codes.cjs"); - -/** - * Default path for the safe output items manifest file. - * This file records every item created in GitHub by safe output handlers. - */ -const MANIFEST_FILE_PATH = "/tmp/gh-aw/safe-output-items.jsonl"; +const { MANIFEST_FILE_PATH } = require("./constants.cjs"); /** * Safe output types that create new items in GitHub (these typically return a URL, diff --git a/actions/setup/js/update_issue.cjs b/actions/setup/js/update_issue.cjs index dc5df34e09..f5022e5da2 100644 --- a/actions/setup/js/update_issue.cjs +++ b/actions/setup/js/update_issue.cjs @@ -18,16 +18,7 @@ const { ERR_VALIDATION } = require("./error_codes.cjs"); const { parseBoolTemplatable } = require("./templatable.cjs"); const { buildWorkflowRunUrl } = require("./workflow_metadata_helpers.cjs"); const { generateHistoryUrl } = require("./generate_history_link.cjs"); - -/** - * Maximum limits for issue update parameters to prevent resource exhaustion. - * These limits align with GitHub's API constraints and security best practices. - */ -/** @type {number} Maximum number of labels allowed per issue */ -const MAX_LABELS = 10; - -/** @type {number} Maximum number of assignees allowed per issue */ -const MAX_ASSIGNEES = 5; +const { MAX_LABELS, MAX_ASSIGNEES } = require("./constants.cjs"); /** * Execute the issue update API call diff --git a/actions/setup/setup.sh b/actions/setup/setup.sh index 94f5aedeca..29a1761738 100755 --- a/actions/setup/setup.sh +++ b/actions/setup/setup.sh @@ -188,6 +188,7 @@ MCP_SCRIPTS_FILES=( "setup_globals.cjs" "error_helpers.cjs" "error_codes.cjs" + "constants.cjs" "mcp_enhanced_errors.cjs" "shim.cjs" "mcp-scripts-runner.cjs" @@ -256,6 +257,7 @@ SAFE_OUTPUTS_FILES=( "setup_globals.cjs" "error_helpers.cjs" "error_codes.cjs" + "constants.cjs" "git_helpers.cjs" "find_repo_checkout.cjs" "mcp_enhanced_errors.cjs"