-
Notifications
You must be signed in to change notification settings - Fork 424
[jsweep] Clean validate_lockdown_requirements.cjs #39498
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
52122d0
0c964b4
4052555
22aa72f
625bc90
c6cd0ba
6c7309c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,8 +22,17 @@ | |
| * @param {any} core - GitHub Actions core library | ||
| * @returns {void} | ||
| */ | ||
| const { ERR_VALIDATION } = require("./error_codes.cjs"); | ||
| function validateLockdownRequirements(core) { | ||
| /** | ||
| * @param {string} message | ||
| * @returns {never} | ||
| */ | ||
| function failWithError(message) { | ||
| core.setOutput("lockdown_check_failed", "true"); | ||
| core.setFailed(message); | ||
| throw new Error(message); | ||
| } | ||
|
|
||
| // Check if lockdown mode is explicitly enabled (set to "true" in frontmatter) | ||
| const lockdownEnabled = process.env.GITHUB_MCP_LOCKDOWN_EXPLICIT === "true"; | ||
|
|
||
|
|
@@ -46,22 +55,19 @@ function validateLockdownRequirements(core) { | |
| core.info(`Custom github-token configured: ${hasCustomToken}`); | ||
|
|
||
| if (!hasAnyCustomToken) { | ||
| const errorMessage = | ||
| "Lockdown mode is enabled (lockdown: true) but no custom GitHub token is configured.\\n" + | ||
| "\\n" + | ||
| "Please configure one of the following as a repository secret:\\n" + | ||
| " - GH_AW_GITHUB_TOKEN (recommended)\\n" + | ||
| " - GH_AW_GITHUB_MCP_SERVER_TOKEN (alternative)\\n" + | ||
| " - Custom github-token in your workflow frontmatter\\n" + | ||
| "\\n" + | ||
| "See: https://github.com/github/gh-aw/blob/main/docs/src/content/docs/reference/auth.mdx\\n" + | ||
| "\\n" + | ||
| "To set a token:\\n" + | ||
| ' gh aw secrets set GH_AW_GITHUB_TOKEN --value "YOUR_FINE_GRAINED_PAT"'; | ||
|
|
||
| core.setOutput("lockdown_check_failed", "true"); | ||
| core.setFailed(errorMessage); | ||
| throw new Error(errorMessage); | ||
| failWithError( | ||
| `Lockdown mode is enabled (lockdown: true) but no custom GitHub token is configured.\n` + | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @copilot refactor to template file and renderTemplate
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Addressed in commit 6c9ce2b. I moved the lockdown/strict/pull_request_target error text into a dedicated template module and render it via |
||
| `\n` + | ||
| `Please configure one of the following as a repository secret:\n` + | ||
| ` - GH_AW_GITHUB_TOKEN (recommended)\n` + | ||
| ` - GH_AW_GITHUB_MCP_SERVER_TOKEN (alternative)\n` + | ||
| ` - Custom github-token in your workflow frontmatter\n` + | ||
| `\n` + | ||
| `See: https://github.com/github/gh-aw/blob/main/docs/src/content/docs/reference/auth.mdx\n` + | ||
| `\n` + | ||
| `To set a token:\n` + | ||
| ` gh aw secrets set GH_AW_GITHUB_TOKEN --value "YOUR_FINE_GRAINED_PAT"` | ||
| ); | ||
| } | ||
|
|
||
| core.info("✓ Lockdown mode requirements validated: Custom GitHub token is configured"); | ||
|
|
@@ -77,20 +83,17 @@ function validateLockdownRequirements(core) { | |
| core.info(`Compiled with strict mode: ${isStrict}`); | ||
|
|
||
| if (isPublic && !isStrict) { | ||
| const errorMessage = | ||
| "This workflow is running on a public repository but was not compiled with strict mode.\\n" + | ||
| "\\n" + | ||
| "Public repository workflows must be compiled with strict mode enabled to meet\\n" + | ||
| "the security requirements for public exposure.\\n" + | ||
| "\\n" + | ||
| "To fix this, recompile the workflow with strict mode:\\n" + | ||
| " gh aw compile --strict\\n" + | ||
| "\\n" + | ||
| "See: https://github.com/github/gh-aw/blob/main/docs/src/content/docs/reference/security.mdx"; | ||
|
|
||
| core.setOutput("lockdown_check_failed", "true"); | ||
| core.setFailed(errorMessage); | ||
| throw new Error(errorMessage); | ||
| failWithError( | ||
| `This workflow is running on a public repository but was not compiled with strict mode.\n` + | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @copilot refactor to template file
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Addressed in commit 6c9ce2b. The strict-mode public-repo failure message now comes from the new template module and is rendered through |
||
| `\n` + | ||
| `Public repository workflows must be compiled with strict mode enabled to meet\n` + | ||
| `the security requirements for public exposure.\n` + | ||
| `\n` + | ||
| `To fix this, recompile the workflow with strict mode:\n` + | ||
| ` gh aw compile --strict\n` + | ||
| `\n` + | ||
| `See: https://github.com/github/gh-aw/blob/main/docs/src/content/docs/reference/security.mdx` | ||
| ); | ||
| } | ||
|
|
||
| if (isPublic && isStrict) { | ||
|
|
@@ -104,20 +107,17 @@ function validateLockdownRequirements(core) { | |
| // and potentially exfiltrate secrets or cause unintended side effects. | ||
| const eventName = process.env.GITHUB_EVENT_NAME; | ||
| if (isPublic && eventName === "pull_request_target") { | ||
| const errorMessage = | ||
| "This workflow is triggered by the pull_request_target event on a public repository.\\n" + | ||
| "\\n" + | ||
| "The pull_request_target event is not allowed on public repositories because it runs\\n" + | ||
| "workflows with access to repository secrets even when triggered from a fork, which\\n" + | ||
| 'creates a significant security risk (known as a "pwn request").\\n' + | ||
| "\\n" + | ||
| "To fix this, use the pull_request event instead, or migrate to a private repository.\\n" + | ||
| "\\n" + | ||
| "See: https://github.com/github/gh-aw/blob/main/docs/src/content/docs/reference/security.mdx"; | ||
|
|
||
| core.setOutput("lockdown_check_failed", "true"); | ||
| core.setFailed(errorMessage); | ||
| throw new Error(errorMessage); | ||
| failWithError( | ||
| `This workflow is triggered by the pull_request_target event on a public repository.\n` + | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @copilot refactor to template file
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Addressed in commit 6c9ce2b. The pull_request_target public-repo failure message was moved to the template module and rendered through |
||
| `\n` + | ||
| `The pull_request_target event is not allowed on public repositories because it runs\n` + | ||
| `workflows with access to repository secrets even when triggered from a fork, which\n` + | ||
| `creates a significant security risk (known as a "pwn request").\n` + | ||
| `\n` + | ||
| `To fix this, use the pull_request event instead, or migrate to a private repository.\n` + | ||
| `\n` + | ||
| `See: https://github.com/github/gh-aw/blob/main/docs/src/content/docs/reference/security.mdx` | ||
| ); | ||
| } | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -304,4 +304,86 @@ describe("validate_lockdown_requirements", () => { | |
| expect(mockCore.setFailed).toHaveBeenCalledWith(expect.stringContaining("not compiled with strict mode")); | ||
| }); | ||
| }); | ||
|
|
||
| describe("setOutput side effects", () => { | ||
| it("should not set lockdown_check_failed output on a fully successful run", () => { | ||
| // All conditions pass: no lockdown, private repo, no special event | ||
| process.env.GITHUB_REPOSITORY_VISIBILITY = "private"; | ||
| process.env.GITHUB_EVENT_NAME = "push"; | ||
|
|
||
| validateLockdownRequirements(mockCore); | ||
|
|
||
| expect(mockCore.setOutput).not.toHaveBeenCalled(); | ||
| expect(mockCore.setFailed).not.toHaveBeenCalled(); | ||
| }); | ||
|
|
||
| it("should not set lockdown_check_failed when lockdown is enabled with token and repo is private", () => { | ||
| process.env.GITHUB_MCP_LOCKDOWN_EXPLICIT = "true"; | ||
| process.env.GH_AW_GITHUB_TOKEN = "ghp_test"; | ||
| process.env.GITHUB_REPOSITORY_VISIBILITY = "private"; | ||
|
|
||
| validateLockdownRequirements(mockCore); | ||
|
|
||
| expect(mockCore.setOutput).not.toHaveBeenCalled(); | ||
| }); | ||
| }); | ||
|
|
||
| describe("multiple tokens", () => { | ||
| it("should pass when all three tokens are configured simultaneously", () => { | ||
| process.env.GITHUB_MCP_LOCKDOWN_EXPLICIT = "true"; | ||
| process.env.GH_AW_GITHUB_TOKEN = "ghp_token1"; | ||
| process.env.GH_AW_GITHUB_MCP_SERVER_TOKEN = "ghp_token2"; | ||
| process.env.CUSTOM_GITHUB_TOKEN = "ghp_token3"; | ||
|
|
||
| validateLockdownRequirements(mockCore); | ||
|
|
||
| expect(mockCore.setFailed).not.toHaveBeenCalled(); | ||
| expect(mockCore.info).toHaveBeenCalledWith("GH_AW_GITHUB_TOKEN configured: true"); | ||
| expect(mockCore.info).toHaveBeenCalledWith("GH_AW_GITHUB_MCP_SERVER_TOKEN configured: true"); | ||
| expect(mockCore.info).toHaveBeenCalledWith("Custom github-token configured: true"); | ||
| expect(mockCore.info).toHaveBeenCalledWith("✓ Lockdown mode requirements validated: Custom GitHub token is configured"); | ||
| }); | ||
| }); | ||
|
|
||
| describe("error message formatting", () => { | ||
| it("should include newlines in lockdown error message for readability", () => { | ||
| process.env.GITHUB_MCP_LOCKDOWN_EXPLICIT = "true"; | ||
|
|
||
| expect(() => { | ||
| validateLockdownRequirements(mockCore); | ||
| }).toThrow(); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [/tdd] 💡 Match the specificity of existing testsThe pre-existing test block uses: }).toThrow("not compiled with strict mode");Applying the same pattern here makes all three new formatting tests consistent and catches regressions in the thrown message, not just the fact that something was thrown: // lockdown test
}).toThrow("no custom GitHub token is configured");
// strict mode test
}).toThrow("not compiled with strict mode");
// pull_request_target test
}).toThrow("pwn request"); |
||
|
|
||
| const errorMsg = mockCore.setFailed.mock.calls[0][0]; | ||
| expect(errorMsg).toContain("\n"); | ||
| expect(errorMsg).toContain("GH_AW_GITHUB_TOKEN (recommended)"); | ||
| expect(errorMsg).toContain("GH_AW_GITHUB_MCP_SERVER_TOKEN (alternative)"); | ||
| }); | ||
|
|
||
| it("should include newlines in strict mode error message for readability", () => { | ||
| process.env.GITHUB_REPOSITORY_VISIBILITY = "public"; | ||
| process.env.GH_AW_COMPILED_STRICT = "false"; | ||
|
|
||
| expect(() => { | ||
| validateLockdownRequirements(mockCore); | ||
| }).toThrow(); | ||
|
|
||
| const errorMsg = mockCore.setFailed.mock.calls[0][0]; | ||
| expect(errorMsg).toContain("\n"); | ||
| expect(errorMsg).toContain("gh aw compile --strict"); | ||
| }); | ||
|
|
||
| it("should include newlines in pull_request_target error message for readability", () => { | ||
| process.env.GITHUB_REPOSITORY_VISIBILITY = "public"; | ||
| process.env.GH_AW_COMPILED_STRICT = "true"; | ||
| process.env.GITHUB_EVENT_NAME = "pull_request_target"; | ||
|
|
||
| expect(() => { | ||
| validateLockdownRequirements(mockCore); | ||
| }).toThrow(); | ||
|
|
||
| const errorMsg = mockCore.setFailed.mock.calls[0][0]; | ||
| expect(errorMsg).toContain("\n"); | ||
| expect(errorMsg).toContain("pwn request"); | ||
| }); | ||
| }); | ||
| }); | ||
Uh oh!
There was an error while loading. Please reload this page.