From 8284fb53314536dccd26c06609000d75f237e84c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 11 Apr 2026 16:18:37 +0000 Subject: [PATCH 1/2] Initial plan From 1b179a0b55cbf8d9f764d2091a91912fc60ee5c3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 11 Apr 2026 16:47:50 +0000 Subject: [PATCH 2/2] fix: skip boolean/null literal wrapping in runtime imports (#25800) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Boolean/null literals (true, false, null) in {{#if}} template conditionals are self-evaluating — the template renderer's isTruthy() handles them directly. Wrapping them created __GH_AW_TRUE__/__GH_AW_FALSE__/__GH_AW_NULL__ placeholders that couldn't be resolved at runtime (no corresponding env var set during compilation for runtime-imported content), causing the placeholder validator to flag them as unsubstituted. Fixes #25800 Agent-Logs-Url: https://github.com/github/gh-aw/sessions/814e96f7-ba24-4cb1-8bc5-41e2bb8cec1c Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/runtime_import.cjs | 20 ++++++++++---------- actions/setup/js/runtime_import.test.cjs | 15 +++++++++------ 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/actions/setup/js/runtime_import.cjs b/actions/setup/js/runtime_import.cjs index 8f3eb50f32e..5870887b5dc 100644 --- a/actions/setup/js/runtime_import.cjs +++ b/actions/setup/js/runtime_import.cjs @@ -650,20 +650,20 @@ function wrapExpressionsInTemplateConditionals(content) { return match; } + // Boolean/null literals are self-evaluating — the template renderer's isTruthy() + // handles them directly. Wrapping them would create __GH_AW_TRUE__/__GH_AW_FALSE__/__GH_AW_NULL__ + // placeholders that cannot be resolved at runtime (no corresponding env var is set), + // causing the placeholder validator to flag them as unsubstituted. + if (trimmed === "true" || trimmed === "false" || trimmed === "null") { + return match; + } + // Only wrap expressions that look like GitHub Actions expressions // GitHub Actions expressions typically start with a letter and contain dots - // (e.g., github.actor, github.event.issue.number) or specific keywords (true, false, null). + // (e.g., github.actor, github.event.issue.number). // Expressions starting with non-alphabetic characters (e.g., "...") are NOT GitHub expressions. const looksLikeGitHubExpr = - (/^[a-zA-Z]/.test(trimmed) && trimmed.includes(".")) || - trimmed === "true" || - trimmed === "false" || - trimmed === "null" || - trimmed.startsWith("github.") || - trimmed.startsWith("needs.") || - trimmed.startsWith("steps.") || - trimmed.startsWith("env.") || - trimmed.startsWith("inputs."); + (/^[a-zA-Z]/.test(trimmed) && trimmed.includes(".")) || trimmed.startsWith("github.") || trimmed.startsWith("needs.") || trimmed.startsWith("steps.") || trimmed.startsWith("env.") || trimmed.startsWith("inputs."); if (!looksLikeGitHubExpr) { // Not a GitHub Actions expression, leave as-is diff --git a/actions/setup/js/runtime_import.test.cjs b/actions/setup/js/runtime_import.test.cjs index 53c35c0b8f7..5ecf330eba5 100644 --- a/actions/setup/js/runtime_import.test.cjs +++ b/actions/setup/js/runtime_import.test.cjs @@ -1498,14 +1498,17 @@ describe("runtime_import", () => { it("should wrap {{#if steps.foo.outputs.bar}}", () => { expect(wrapExpressionsInTemplateConditionals("{{#if steps.foo.outputs.bar}}body{{/if}}")).toBe("{{#if ${{ steps.foo.outputs.bar }} }}body{{/if}}"); }); - it("should wrap {{#if true}}", () => { - expect(wrapExpressionsInTemplateConditionals("{{#if true}}body{{/if}}")).toBe("{{#if ${{ true }} }}body{{/if}}"); + }); + + describe("boolean/null literals — must be left unchanged for direct isTruthy() evaluation", () => { + it("should leave {{#if true}} unchanged", () => { + expect(wrapExpressionsInTemplateConditionals("{{#if true}}body{{/if}}")).toBe("{{#if true}}body{{/if}}"); }); - it("should wrap {{#if false}}", () => { - expect(wrapExpressionsInTemplateConditionals("{{#if false}}body{{/if}}")).toBe("{{#if ${{ false }} }}body{{/if}}"); + it("should leave {{#if false}} unchanged", () => { + expect(wrapExpressionsInTemplateConditionals("{{#if false}}body{{/if}}")).toBe("{{#if false}}body{{/if}}"); }); - it("should wrap {{#if null}}", () => { - expect(wrapExpressionsInTemplateConditionals("{{#if null}}body{{/if}}")).toBe("{{#if ${{ null }} }}body{{/if}}"); + it("should leave {{#if null}} unchanged", () => { + expect(wrapExpressionsInTemplateConditionals("{{#if null}}body{{/if}}")).toBe("{{#if null}}body{{/if}}"); }); });