From b827104d87f1f572396f3f76d6969ac25c9ee268 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 22 Jun 2026 05:36:09 +0000 Subject: [PATCH 1/4] jsweep: add JSDoc and tests for validate_lockdown_requirements_templates.cjs - Add @returns JSDoc annotations to the three exported render functions - Create validate_lockdown_requirements_templates.test.cjs with 29 tests covering all three render functions (lockdown token, strict mode, pull_request_target) and cross-function invariants Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- ...lidate_lockdown_requirements_templates.cjs | 3 + ...e_lockdown_requirements_templates.test.cjs | 165 ++++++++++++++++++ 2 files changed, 168 insertions(+) create mode 100644 actions/setup/js/validate_lockdown_requirements_templates.test.cjs diff --git a/actions/setup/js/validate_lockdown_requirements_templates.cjs b/actions/setup/js/validate_lockdown_requirements_templates.cjs index ac564c22cec..e553ca159ff 100644 --- a/actions/setup/js/validate_lockdown_requirements_templates.cjs +++ b/actions/setup/js/validate_lockdown_requirements_templates.cjs @@ -40,14 +40,17 @@ const TEMPLATE_CONTEXT = { strict_compile_command: "gh aw compile --strict", }; +/** @returns {string} Rendered lockdown token error message with documentation URL */ function renderLockdownTokenErrorMessage() { return renderTemplate(LOCKDOWN_TOKEN_ERROR_TEMPLATE, TEMPLATE_CONTEXT); } +/** @returns {string} Rendered public strict mode error message with compile command and documentation URL */ function renderPublicStrictModeErrorMessage() { return renderTemplate(PUBLIC_STRICT_MODE_ERROR_TEMPLATE, TEMPLATE_CONTEXT); } +/** @returns {string} Rendered pull_request_target security error message with documentation URL */ function renderPullRequestTargetErrorMessage() { return renderTemplate(PULL_REQUEST_TARGET_ERROR_TEMPLATE, TEMPLATE_CONTEXT); } diff --git a/actions/setup/js/validate_lockdown_requirements_templates.test.cjs b/actions/setup/js/validate_lockdown_requirements_templates.test.cjs new file mode 100644 index 00000000000..06f45ecc05a --- /dev/null +++ b/actions/setup/js/validate_lockdown_requirements_templates.test.cjs @@ -0,0 +1,165 @@ +// @ts-check +import { describe, it, expect } from "vitest"; +import { createRequire } from "module"; + +const req = createRequire(import.meta.url); +const { renderLockdownTokenErrorMessage, renderPublicStrictModeErrorMessage, renderPullRequestTargetErrorMessage } = req("./validate_lockdown_requirements_templates.cjs"); + +describe("validate_lockdown_requirements_templates", () => { + describe("renderLockdownTokenErrorMessage", () => { + it("returns a non-empty string", () => { + expect(typeof renderLockdownTokenErrorMessage()).toBe("string"); + expect(renderLockdownTokenErrorMessage().length).toBeGreaterThan(0); + }); + + it("includes the auth documentation URL", () => { + const message = renderLockdownTokenErrorMessage(); + expect(message).toContain("https://github.com/github/gh-aw/blob/main/docs/src/content/docs/reference/auth.mdx"); + }); + + it("includes GH_AW_GITHUB_TOKEN recommendation", () => { + const message = renderLockdownTokenErrorMessage(); + expect(message).toContain("GH_AW_GITHUB_TOKEN (recommended)"); + }); + + it("includes GH_AW_GITHUB_MCP_SERVER_TOKEN as alternative", () => { + const message = renderLockdownTokenErrorMessage(); + expect(message).toContain("GH_AW_GITHUB_MCP_SERVER_TOKEN (alternative)"); + }); + + it("includes the gh aw secrets set command", () => { + const message = renderLockdownTokenErrorMessage(); + expect(message).toContain("gh aw secrets set GH_AW_GITHUB_TOKEN"); + }); + + it("mentions lockdown mode is enabled", () => { + const message = renderLockdownTokenErrorMessage(); + expect(message).toContain("Lockdown mode is enabled"); + }); + + it("does not contain unreplaced {auth_docs_url} placeholder", () => { + const message = renderLockdownTokenErrorMessage(); + expect(message).not.toContain("{auth_docs_url}"); + }); + + it("does not contain unreplaced {security_docs_url} placeholder", () => { + const message = renderLockdownTokenErrorMessage(); + expect(message).not.toContain("{security_docs_url}"); + }); + + it("returns the same value on repeated calls", () => { + expect(renderLockdownTokenErrorMessage()).toBe(renderLockdownTokenErrorMessage()); + }); + }); + + describe("renderPublicStrictModeErrorMessage", () => { + it("returns a non-empty string", () => { + expect(typeof renderPublicStrictModeErrorMessage()).toBe("string"); + expect(renderPublicStrictModeErrorMessage().length).toBeGreaterThan(0); + }); + + it("includes the security documentation URL", () => { + const message = renderPublicStrictModeErrorMessage(); + expect(message).toContain("https://github.com/github/gh-aw/blob/main/docs/src/content/docs/reference/security.mdx"); + }); + + it("includes the strict compile command", () => { + const message = renderPublicStrictModeErrorMessage(); + expect(message).toContain("gh aw compile --strict"); + }); + + it("mentions public repository context", () => { + const message = renderPublicStrictModeErrorMessage(); + expect(message).toContain("public repository"); + }); + + it("mentions strict mode", () => { + const message = renderPublicStrictModeErrorMessage(); + expect(message).toContain("strict mode"); + }); + + it("does not contain unreplaced {strict_compile_command} placeholder", () => { + const message = renderPublicStrictModeErrorMessage(); + expect(message).not.toContain("{strict_compile_command}"); + }); + + it("does not contain unreplaced {security_docs_url} placeholder", () => { + const message = renderPublicStrictModeErrorMessage(); + expect(message).not.toContain("{security_docs_url}"); + }); + + it("returns the same value on repeated calls", () => { + expect(renderPublicStrictModeErrorMessage()).toBe(renderPublicStrictModeErrorMessage()); + }); + }); + + describe("renderPullRequestTargetErrorMessage", () => { + it("returns a non-empty string", () => { + expect(typeof renderPullRequestTargetErrorMessage()).toBe("string"); + expect(renderPullRequestTargetErrorMessage().length).toBeGreaterThan(0); + }); + + it("includes the security documentation URL", () => { + const message = renderPullRequestTargetErrorMessage(); + expect(message).toContain("https://github.com/github/gh-aw/blob/main/docs/src/content/docs/reference/security.mdx"); + }); + + it("mentions the pull_request_target event", () => { + const message = renderPullRequestTargetErrorMessage(); + expect(message).toContain("pull_request_target"); + }); + + it("mentions pwn request security risk", () => { + const message = renderPullRequestTargetErrorMessage(); + expect(message).toContain("pwn request"); + }); + + it("mentions public repositories", () => { + const message = renderPullRequestTargetErrorMessage(); + expect(message).toContain("public repositories"); + }); + + it("suggests using the pull_request event instead", () => { + const message = renderPullRequestTargetErrorMessage(); + expect(message).toContain("pull_request event instead"); + }); + + it("does not contain unreplaced {security_docs_url} placeholder", () => { + const message = renderPullRequestTargetErrorMessage(); + expect(message).not.toContain("{security_docs_url}"); + }); + + it("returns the same value on repeated calls", () => { + expect(renderPullRequestTargetErrorMessage()).toBe(renderPullRequestTargetErrorMessage()); + }); + }); + + describe("cross-function checks", () => { + it("each render function returns a distinct message", () => { + const lockdown = renderLockdownTokenErrorMessage(); + const strictMode = renderPublicStrictModeErrorMessage(); + const prTarget = renderPullRequestTargetErrorMessage(); + + expect(lockdown).not.toBe(strictMode); + expect(lockdown).not.toBe(prTarget); + expect(strictMode).not.toBe(prTarget); + }); + + it("lockdown message does not contain strict mode content", () => { + const message = renderLockdownTokenErrorMessage(); + expect(message).not.toContain("gh aw compile --strict"); + }); + + it("strict mode message does not contain lockdown token content", () => { + const message = renderPublicStrictModeErrorMessage(); + expect(message).not.toContain("GH_AW_GITHUB_TOKEN"); + }); + + it("no message contains unreplaced placeholders", () => { + const messages = [renderLockdownTokenErrorMessage(), renderPublicStrictModeErrorMessage(), renderPullRequestTargetErrorMessage()]; + for (const message of messages) { + expect(message).not.toMatch(/\{[a-z_]+\}/); + } + }); + }); +}); From 6f6b00887737a1fcaefb5de1dad6e7aa8578a6f3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 22 Jun 2026 14:48:27 +0000 Subject: [PATCH 2/4] fix: address review feedback on validate_lockdown_requirements_templates.test.cjs - Replace ESM imports with require() (globals: true means describe/it/expect are already available) - Split destructuring import across lines - Use toBeTypeOf() and single-call Arrange-Act-Assert pattern in non-empty string tests - Remove trivially-passing {security_docs_url} assertion in lockdown token section - Replace three idempotency tests with one module-surface export check - Broaden placeholder regex to /\{[A-Za-z][A-Za-z0-9_]*\}/ to cover all identifier conventions 26/26 tests pass, format and lint clean. Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- ...e_lockdown_requirements_templates.test.cjs | 45 +++++++------------ 1 file changed, 16 insertions(+), 29 deletions(-) diff --git a/actions/setup/js/validate_lockdown_requirements_templates.test.cjs b/actions/setup/js/validate_lockdown_requirements_templates.test.cjs index 06f45ecc05a..2e83b22efff 100644 --- a/actions/setup/js/validate_lockdown_requirements_templates.test.cjs +++ b/actions/setup/js/validate_lockdown_requirements_templates.test.cjs @@ -1,15 +1,12 @@ // @ts-check -import { describe, it, expect } from "vitest"; -import { createRequire } from "module"; - -const req = createRequire(import.meta.url); -const { renderLockdownTokenErrorMessage, renderPublicStrictModeErrorMessage, renderPullRequestTargetErrorMessage } = req("./validate_lockdown_requirements_templates.cjs"); +const { renderLockdownTokenErrorMessage, renderPublicStrictModeErrorMessage, renderPullRequestTargetErrorMessage } = require("./validate_lockdown_requirements_templates.cjs"); describe("validate_lockdown_requirements_templates", () => { describe("renderLockdownTokenErrorMessage", () => { it("returns a non-empty string", () => { - expect(typeof renderLockdownTokenErrorMessage()).toBe("string"); - expect(renderLockdownTokenErrorMessage().length).toBeGreaterThan(0); + const message = renderLockdownTokenErrorMessage(); + expect(message).toBeTypeOf("string"); + expect(message.length).toBeGreaterThan(0); }); it("includes the auth documentation URL", () => { @@ -41,21 +38,13 @@ describe("validate_lockdown_requirements_templates", () => { const message = renderLockdownTokenErrorMessage(); expect(message).not.toContain("{auth_docs_url}"); }); - - it("does not contain unreplaced {security_docs_url} placeholder", () => { - const message = renderLockdownTokenErrorMessage(); - expect(message).not.toContain("{security_docs_url}"); - }); - - it("returns the same value on repeated calls", () => { - expect(renderLockdownTokenErrorMessage()).toBe(renderLockdownTokenErrorMessage()); - }); }); describe("renderPublicStrictModeErrorMessage", () => { it("returns a non-empty string", () => { - expect(typeof renderPublicStrictModeErrorMessage()).toBe("string"); - expect(renderPublicStrictModeErrorMessage().length).toBeGreaterThan(0); + const message = renderPublicStrictModeErrorMessage(); + expect(message).toBeTypeOf("string"); + expect(message.length).toBeGreaterThan(0); }); it("includes the security documentation URL", () => { @@ -87,16 +76,13 @@ describe("validate_lockdown_requirements_templates", () => { const message = renderPublicStrictModeErrorMessage(); expect(message).not.toContain("{security_docs_url}"); }); - - it("returns the same value on repeated calls", () => { - expect(renderPublicStrictModeErrorMessage()).toBe(renderPublicStrictModeErrorMessage()); - }); }); describe("renderPullRequestTargetErrorMessage", () => { it("returns a non-empty string", () => { - expect(typeof renderPullRequestTargetErrorMessage()).toBe("string"); - expect(renderPullRequestTargetErrorMessage().length).toBeGreaterThan(0); + const message = renderPullRequestTargetErrorMessage(); + expect(message).toBeTypeOf("string"); + expect(message.length).toBeGreaterThan(0); }); it("includes the security documentation URL", () => { @@ -128,10 +114,6 @@ describe("validate_lockdown_requirements_templates", () => { const message = renderPullRequestTargetErrorMessage(); expect(message).not.toContain("{security_docs_url}"); }); - - it("returns the same value on repeated calls", () => { - expect(renderPullRequestTargetErrorMessage()).toBe(renderPullRequestTargetErrorMessage()); - }); }); describe("cross-function checks", () => { @@ -155,10 +137,15 @@ describe("validate_lockdown_requirements_templates", () => { expect(message).not.toContain("GH_AW_GITHUB_TOKEN"); }); + it("module exposes exactly the expected exports", () => { + const mod = require("./validate_lockdown_requirements_templates.cjs"); + expect(Object.keys(mod)).toEqual(["renderLockdownTokenErrorMessage", "renderPublicStrictModeErrorMessage", "renderPullRequestTargetErrorMessage"]); + }); + it("no message contains unreplaced placeholders", () => { const messages = [renderLockdownTokenErrorMessage(), renderPublicStrictModeErrorMessage(), renderPullRequestTargetErrorMessage()]; for (const message of messages) { - expect(message).not.toMatch(/\{[a-z_]+\}/); + expect(message).not.toMatch(/\{[A-Za-z][A-Za-z0-9_]*\}/); } }); }); From d37b6a902edab48f94a71d21cabd8cde12f04017 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 22 Jun 2026 14:49:59 +0000 Subject: [PATCH 3/4] fix: use arrayContaining + toHaveLength for module-surface export check Makes the assertion order-independent and more robust against future additions (toHaveLength catches any extra exports). Also inline-format the messages array in the placeholder test. Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- ...date_lockdown_requirements_templates.test.cjs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/actions/setup/js/validate_lockdown_requirements_templates.test.cjs b/actions/setup/js/validate_lockdown_requirements_templates.test.cjs index 2e83b22efff..f06e359fe46 100644 --- a/actions/setup/js/validate_lockdown_requirements_templates.test.cjs +++ b/actions/setup/js/validate_lockdown_requirements_templates.test.cjs @@ -139,11 +139,23 @@ describe("validate_lockdown_requirements_templates", () => { it("module exposes exactly the expected exports", () => { const mod = require("./validate_lockdown_requirements_templates.cjs"); - expect(Object.keys(mod)).toEqual(["renderLockdownTokenErrorMessage", "renderPublicStrictModeErrorMessage", "renderPullRequestTargetErrorMessage"]); + const keys = Object.keys(mod); + expect(keys).toHaveLength(3); + expect(keys).toEqual( + expect.arrayContaining([ + "renderLockdownTokenErrorMessage", + "renderPublicStrictModeErrorMessage", + "renderPullRequestTargetErrorMessage", + ]), + ); }); it("no message contains unreplaced placeholders", () => { - const messages = [renderLockdownTokenErrorMessage(), renderPublicStrictModeErrorMessage(), renderPullRequestTargetErrorMessage()]; + const messages = [ + renderLockdownTokenErrorMessage(), + renderPublicStrictModeErrorMessage(), + renderPullRequestTargetErrorMessage(), + ]; for (const message of messages) { expect(message).not.toMatch(/\{[A-Za-z][A-Za-z0-9_]*\}/); } From 5e5ccdd4525a4ed9b9d283527ccab3cfab17f7f6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 22 Jun 2026 16:48:03 +0000 Subject: [PATCH 4/4] fix: add content-contract comment to address static-phrase brittleness thread Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- ...date_lockdown_requirements_templates.test.cjs | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/actions/setup/js/validate_lockdown_requirements_templates.test.cjs b/actions/setup/js/validate_lockdown_requirements_templates.test.cjs index f06e359fe46..f05526d206c 100644 --- a/actions/setup/js/validate_lockdown_requirements_templates.test.cjs +++ b/actions/setup/js/validate_lockdown_requirements_templates.test.cjs @@ -1,6 +1,8 @@ // @ts-check const { renderLockdownTokenErrorMessage, renderPublicStrictModeErrorMessage, renderPullRequestTargetErrorMessage } = require("./validate_lockdown_requirements_templates.cjs"); +// Content-contract tests below assert specific phrasing and key terms from each template. +// They document intentional wording and will fail on purposeful rewording — that is the intent. describe("validate_lockdown_requirements_templates", () => { describe("renderLockdownTokenErrorMessage", () => { it("returns a non-empty string", () => { @@ -141,21 +143,11 @@ describe("validate_lockdown_requirements_templates", () => { const mod = require("./validate_lockdown_requirements_templates.cjs"); const keys = Object.keys(mod); expect(keys).toHaveLength(3); - expect(keys).toEqual( - expect.arrayContaining([ - "renderLockdownTokenErrorMessage", - "renderPublicStrictModeErrorMessage", - "renderPullRequestTargetErrorMessage", - ]), - ); + expect(keys).toEqual(expect.arrayContaining(["renderLockdownTokenErrorMessage", "renderPublicStrictModeErrorMessage", "renderPullRequestTargetErrorMessage"])); }); it("no message contains unreplaced placeholders", () => { - const messages = [ - renderLockdownTokenErrorMessage(), - renderPublicStrictModeErrorMessage(), - renderPullRequestTargetErrorMessage(), - ]; + const messages = [renderLockdownTokenErrorMessage(), renderPublicStrictModeErrorMessage(), renderPullRequestTargetErrorMessage()]; for (const message of messages) { expect(message).not.toMatch(/\{[A-Za-z][A-Za-z0-9_]*\}/); }