From d4ebe697f3e7c770864fc3472f72fbe087e8dfad Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 18 Mar 2026 23:40:20 +0000 Subject: [PATCH 1/4] feat: update github mcp guard policy step summary to use details element Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .../setup/js/determine_automatic_lockdown.cjs | 17 ++---- .../js/determine_automatic_lockdown.test.cjs | 54 +++++++++---------- 2 files changed, 29 insertions(+), 42 deletions(-) diff --git a/actions/setup/js/determine_automatic_lockdown.cjs b/actions/setup/js/determine_automatic_lockdown.cjs index 0af3452b3de..aa38b2c1b56 100644 --- a/actions/setup/js/determine_automatic_lockdown.cjs +++ b/actions/setup/js/determine_automatic_lockdown.cjs @@ -87,18 +87,11 @@ async function determineAutomaticLockdown(github, context, core) { // Write resolved guard policy values to the step summary const autoLabel = isPrivate ? "automatic (private repo)" : "automatic (public repo)"; - await core.summary - .addHeading("GitHub MCP Guard Policy", 3) - .addTable([ - [ - { data: "Field", header: true }, - { data: "Value", header: true }, - { data: "Source", header: true }, - ], - ["min-integrity", resolvedMinIntegrity, configuredMinIntegrity ? "workflow config" : autoLabel], - ["repos", resolvedRepos, configuredRepos ? "workflow config" : autoLabel], - ]) - .write(); + const minIntegritySource = configuredMinIntegrity ? "workflow config" : autoLabel; + const reposSource = configuredRepos ? "workflow config" : autoLabel; + const tableRows = ["| Field | Value | Source |", "|-------|-------|--------|", `| min-integrity | ${resolvedMinIntegrity} | ${minIntegritySource} |`, `| repos | ${resolvedRepos} | ${reposSource} |`].join("\n"); + const details = `
\nGitHub MCP Guard Policy\n\n${tableRows}\n\n
\n`; + await core.summary.addRaw(details).write(); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); core.error(`Failed to determine automatic guard policy: ${errorMessage}`); diff --git a/actions/setup/js/determine_automatic_lockdown.test.cjs b/actions/setup/js/determine_automatic_lockdown.test.cjs index e34e0f17cee..3e87066a28d 100644 --- a/actions/setup/js/determine_automatic_lockdown.test.cjs +++ b/actions/setup/js/determine_automatic_lockdown.test.cjs @@ -33,8 +33,7 @@ describe("determine_automatic_lockdown", () => { error: vi.fn(), setOutput: vi.fn(), summary: { - addHeading: vi.fn().mockReturnThis(), - addTable: vi.fn().mockReturnThis(), + addRaw: vi.fn().mockReturnThis(), write: vi.fn().mockResolvedValue(undefined), }, }; @@ -218,16 +217,15 @@ describe("determine_automatic_lockdown", () => { await determineAutomaticLockdown(mockGithub, mockContext, mockCore); - expect(mockCore.summary.addHeading).toHaveBeenCalledWith("GitHub MCP Guard Policy", 3); - expect(mockCore.summary.addTable).toHaveBeenCalledWith([ - [ - { data: "Field", header: true }, - { data: "Value", header: true }, - { data: "Source", header: true }, - ], - ["min-integrity", "approved", "automatic (public repo)"], - ["repos", "all", "automatic (public repo)"], - ]); + expect(mockCore.summary.addRaw).toHaveBeenCalledTimes(1); + const publicSummaryArg = mockCore.summary.addRaw.mock.calls[0][0]; + expect(publicSummaryArg).toContain("
"); + expect(publicSummaryArg).toContain("GitHub MCP Guard Policy"); + expect(publicSummaryArg).toContain("min-integrity"); + expect(publicSummaryArg).toContain("approved"); + expect(publicSummaryArg).toContain("automatic (public repo)"); + expect(publicSummaryArg).toContain("repos"); + expect(publicSummaryArg).toContain("all"); expect(mockCore.summary.write).toHaveBeenCalled(); }); @@ -244,15 +242,13 @@ describe("determine_automatic_lockdown", () => { await determineAutomaticLockdown(mockGithub, mockContext, mockCore); - expect(mockCore.summary.addTable).toHaveBeenCalledWith([ - [ - { data: "Field", header: true }, - { data: "Value", header: true }, - { data: "Source", header: true }, - ], - ["min-integrity", "merged", "workflow config"], - ["repos", "public", "workflow config"], - ]); + expect(mockCore.summary.addRaw).toHaveBeenCalledTimes(1); + const configuredSummaryArg = mockCore.summary.addRaw.mock.calls[0][0]; + expect(configuredSummaryArg).toContain("min-integrity"); + expect(configuredSummaryArg).toContain("merged"); + expect(configuredSummaryArg).toContain("workflow config"); + expect(configuredSummaryArg).toContain("repos"); + expect(configuredSummaryArg).toContain("public"); expect(mockCore.summary.write).toHaveBeenCalled(); }); @@ -266,15 +262,13 @@ describe("determine_automatic_lockdown", () => { await determineAutomaticLockdown(mockGithub, mockContext, mockCore); - expect(mockCore.summary.addTable).toHaveBeenCalledWith([ - [ - { data: "Field", header: true }, - { data: "Value", header: true }, - { data: "Source", header: true }, - ], - ["min-integrity", "none", "automatic (private repo)"], - ["repos", "all", "automatic (private repo)"], - ]); + expect(mockCore.summary.addRaw).toHaveBeenCalledTimes(1); + const privateSummaryArg = mockCore.summary.addRaw.mock.calls[0][0]; + expect(privateSummaryArg).toContain("min-integrity"); + expect(privateSummaryArg).toContain("none"); + expect(privateSummaryArg).toContain("automatic (private repo)"); + expect(privateSummaryArg).toContain("repos"); + expect(privateSummaryArg).toContain("all"); expect(mockCore.summary.write).toHaveBeenCalled(); }); }); From f9f005f20dcfea0fa23aa08b9f297c7ebe09d512 Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Wed, 18 Mar 2026 16:59:07 -0700 Subject: [PATCH 2/4] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../setup/js/determine_automatic_lockdown.cjs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/actions/setup/js/determine_automatic_lockdown.cjs b/actions/setup/js/determine_automatic_lockdown.cjs index aa38b2c1b56..96225eaae3d 100644 --- a/actions/setup/js/determine_automatic_lockdown.cjs +++ b/actions/setup/js/determine_automatic_lockdown.cjs @@ -89,9 +89,20 @@ async function determineAutomaticLockdown(github, context, core) { const autoLabel = isPrivate ? "automatic (private repo)" : "automatic (public repo)"; const minIntegritySource = configuredMinIntegrity ? "workflow config" : autoLabel; const reposSource = configuredRepos ? "workflow config" : autoLabel; - const tableRows = ["| Field | Value | Source |", "|-------|-------|--------|", `| min-integrity | ${resolvedMinIntegrity} | ${minIntegritySource} |`, `| repos | ${resolvedRepos} | ${reposSource} |`].join("\n"); - const details = `
\nGitHub MCP Guard Policy\n\n${tableRows}\n\n
\n`; - await core.summary.addRaw(details).write(); + + await core.summary + .addRaw("
\nGitHub MCP Guard Policy\n\n") + .addTable([ + [ + { data: "Field", header: true }, + { data: "Value", header: true }, + { data: "Source", header: true }, + ], + ["min-integrity", resolvedMinIntegrity, minIntegritySource], + ["repos", resolvedRepos, reposSource], + ]) + .addRaw("\n
\n") + .write(); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); core.error(`Failed to determine automatic guard policy: ${errorMessage}`); From 30cecd1ffbc83b54de3ff67d40b3f84f577ecf54 Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Wed, 18 Mar 2026 16:59:15 -0700 Subject: [PATCH 3/4] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../js/determine_automatic_lockdown.test.cjs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/actions/setup/js/determine_automatic_lockdown.test.cjs b/actions/setup/js/determine_automatic_lockdown.test.cjs index 3e87066a28d..8136a712eb9 100644 --- a/actions/setup/js/determine_automatic_lockdown.test.cjs +++ b/actions/setup/js/determine_automatic_lockdown.test.cjs @@ -221,6 +221,12 @@ describe("determine_automatic_lockdown", () => { const publicSummaryArg = mockCore.summary.addRaw.mock.calls[0][0]; expect(publicSummaryArg).toContain("
"); expect(publicSummaryArg).toContain("GitHub MCP Guard Policy"); + // Ensure we have a well-formed
block with a and closing
+ expect(publicSummaryArg).toMatch(/
[\\s\\S]*<\\/details>/); + expect(publicSummaryArg).toMatch(/[\\s\\S]*GitHub MCP Guard Policy[\\s\\S]*<\\/summary>/); + // Ensure the markdown table header and separator are present + expect(publicSummaryArg).toMatch(/\\| *Field *\\| *Value *\\| *Source *\\|/); + expect(publicSummaryArg).toMatch(/\\|[- ]+\\|[- ]+\\|[- ]+\\|/); expect(publicSummaryArg).toContain("min-integrity"); expect(publicSummaryArg).toContain("approved"); expect(publicSummaryArg).toContain("automatic (public repo)"); @@ -244,6 +250,11 @@ describe("determine_automatic_lockdown", () => { expect(mockCore.summary.addRaw).toHaveBeenCalledTimes(1); const configuredSummaryArg = mockCore.summary.addRaw.mock.calls[0][0]; + // Ensure we have a well-formed
block with closing
+ expect(configuredSummaryArg).toMatch(/
[\\s\\S]*<\\/details>/); + // Ensure the markdown table header and separator are present + expect(configuredSummaryArg).toMatch(/\\| *Field *\\| *Value *\\| *Source *\\|/); + expect(configuredSummaryArg).toMatch(/\\|[- ]+\\|[- ]+\\|[- ]+\\|/); expect(configuredSummaryArg).toContain("min-integrity"); expect(configuredSummaryArg).toContain("merged"); expect(configuredSummaryArg).toContain("workflow config"); @@ -264,6 +275,11 @@ describe("determine_automatic_lockdown", () => { expect(mockCore.summary.addRaw).toHaveBeenCalledTimes(1); const privateSummaryArg = mockCore.summary.addRaw.mock.calls[0][0]; + // Ensure we have a well-formed
block with closing
+ expect(privateSummaryArg).toMatch(/
[\\s\\S]*<\\/details>/); + // Ensure the markdown table header and separator are present + expect(privateSummaryArg).toMatch(/\\| *Field *\\| *Value *\\| *Source *\\|/); + expect(privateSummaryArg).toMatch(/\\|[- ]+\\|[- ]+\\|[- ]+\\|/); expect(privateSummaryArg).toContain("min-integrity"); expect(privateSummaryArg).toContain("none"); expect(privateSummaryArg).toContain("automatic (private repo)"); From 56025bfc80f30faa1f7b7b8f3d7609ba2204dd37 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Mar 2026 00:08:10 +0000 Subject: [PATCH 4/4] fix: restore pure addRaw approach, add cell sanitization, fix regex patterns in tests Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .../setup/js/determine_automatic_lockdown.cjs | 29 ++++++++++--------- .../js/determine_automatic_lockdown.test.cjs | 20 ++++++------- 2 files changed, 26 insertions(+), 23 deletions(-) diff --git a/actions/setup/js/determine_automatic_lockdown.cjs b/actions/setup/js/determine_automatic_lockdown.cjs index 96225eaae3d..be17474d777 100644 --- a/actions/setup/js/determine_automatic_lockdown.cjs +++ b/actions/setup/js/determine_automatic_lockdown.cjs @@ -90,19 +90,22 @@ async function determineAutomaticLockdown(github, context, core) { const minIntegritySource = configuredMinIntegrity ? "workflow config" : autoLabel; const reposSource = configuredRepos ? "workflow config" : autoLabel; - await core.summary - .addRaw("
\nGitHub MCP Guard Policy\n\n") - .addTable([ - [ - { data: "Field", header: true }, - { data: "Value", header: true }, - { data: "Source", header: true }, - ], - ["min-integrity", resolvedMinIntegrity, minIntegritySource], - ["repos", resolvedRepos, reposSource], - ]) - .addRaw("\n
\n") - .write(); + /** + * Escapes a value for safe embedding in a markdown table cell. + * Replaces HTML-special characters and pipe characters that would break the table. + * @param {string} value + * @returns {string} + */ + const escapeCell = value => value.replace(/&/g, "&").replace(//g, ">").replace(/\|/g, "\\|").replace(/\n/g, " "); + + const tableRows = [ + "| Field | Value | Source |", + "|-------|-------|--------|", + `| min-integrity | ${escapeCell(resolvedMinIntegrity)} | ${escapeCell(minIntegritySource)} |`, + `| repos | ${escapeCell(resolvedRepos)} | ${escapeCell(reposSource)} |`, + ].join("\n"); + const details = `
\nGitHub MCP Guard Policy\n\n${tableRows}\n\n
\n`; + await core.summary.addRaw(details).write(); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); core.error(`Failed to determine automatic guard policy: ${errorMessage}`); diff --git a/actions/setup/js/determine_automatic_lockdown.test.cjs b/actions/setup/js/determine_automatic_lockdown.test.cjs index 8136a712eb9..54c4caba788 100644 --- a/actions/setup/js/determine_automatic_lockdown.test.cjs +++ b/actions/setup/js/determine_automatic_lockdown.test.cjs @@ -222,11 +222,11 @@ describe("determine_automatic_lockdown", () => { expect(publicSummaryArg).toContain("
"); expect(publicSummaryArg).toContain("GitHub MCP Guard Policy"); // Ensure we have a well-formed
block with a and closing
- expect(publicSummaryArg).toMatch(/
[\\s\\S]*<\\/details>/); - expect(publicSummaryArg).toMatch(/[\\s\\S]*GitHub MCP Guard Policy[\\s\\S]*<\\/summary>/); + expect(publicSummaryArg).toMatch(/
[\s\S]*<\/details>/); + expect(publicSummaryArg).toMatch(/[\s\S]*GitHub MCP Guard Policy[\s\S]*<\/summary>/); // Ensure the markdown table header and separator are present - expect(publicSummaryArg).toMatch(/\\| *Field *\\| *Value *\\| *Source *\\|/); - expect(publicSummaryArg).toMatch(/\\|[- ]+\\|[- ]+\\|[- ]+\\|/); + expect(publicSummaryArg).toMatch(/\| *Field *\| *Value *\| *Source *\|/); + expect(publicSummaryArg).toMatch(/\|[- ]+\|[- ]+\|[- ]+\|/); expect(publicSummaryArg).toContain("min-integrity"); expect(publicSummaryArg).toContain("approved"); expect(publicSummaryArg).toContain("automatic (public repo)"); @@ -251,10 +251,10 @@ describe("determine_automatic_lockdown", () => { expect(mockCore.summary.addRaw).toHaveBeenCalledTimes(1); const configuredSummaryArg = mockCore.summary.addRaw.mock.calls[0][0]; // Ensure we have a well-formed
block with closing
- expect(configuredSummaryArg).toMatch(/
[\\s\\S]*<\\/details>/); + expect(configuredSummaryArg).toMatch(/
[\s\S]*<\/details>/); // Ensure the markdown table header and separator are present - expect(configuredSummaryArg).toMatch(/\\| *Field *\\| *Value *\\| *Source *\\|/); - expect(configuredSummaryArg).toMatch(/\\|[- ]+\\|[- ]+\\|[- ]+\\|/); + expect(configuredSummaryArg).toMatch(/\| *Field *\| *Value *\| *Source *\|/); + expect(configuredSummaryArg).toMatch(/\|[- ]+\|[- ]+\|[- ]+\|/); expect(configuredSummaryArg).toContain("min-integrity"); expect(configuredSummaryArg).toContain("merged"); expect(configuredSummaryArg).toContain("workflow config"); @@ -276,10 +276,10 @@ describe("determine_automatic_lockdown", () => { expect(mockCore.summary.addRaw).toHaveBeenCalledTimes(1); const privateSummaryArg = mockCore.summary.addRaw.mock.calls[0][0]; // Ensure we have a well-formed
block with closing
- expect(privateSummaryArg).toMatch(/
[\\s\\S]*<\\/details>/); + expect(privateSummaryArg).toMatch(/
[\s\S]*<\/details>/); // Ensure the markdown table header and separator are present - expect(privateSummaryArg).toMatch(/\\| *Field *\\| *Value *\\| *Source *\\|/); - expect(privateSummaryArg).toMatch(/\\|[- ]+\\|[- ]+\\|[- ]+\\|/); + expect(privateSummaryArg).toMatch(/\| *Field *\| *Value *\| *Source *\|/); + expect(privateSummaryArg).toMatch(/\|[- ]+\|[- ]+\|[- ]+\|/); expect(privateSummaryArg).toContain("min-integrity"); expect(privateSummaryArg).toContain("none"); expect(privateSummaryArg).toContain("automatic (private repo)");