From 13d5c0bf449266b33cb60b1267542d22b00070fc Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 4 Nov 2025 15:08:31 +0000
Subject: [PATCH 1/4] Initial plan
From f49694d0917de06aa616ab613fc02d99df2086df Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 4 Nov 2025 15:19:58 +0000
Subject: [PATCH 2/4] Extract sanitizeLabelContent to dedicated helper file
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
pkg/workflow/js/add_labels.cjs | 15 +-
pkg/workflow/js/create_issue.cjs | 15 +-
pkg/workflow/js/sanitize_label_content.cjs | 32 ++++
.../js/sanitize_label_content.test.cjs | 142 ++++++++++++++++++
4 files changed, 176 insertions(+), 28 deletions(-)
create mode 100644 pkg/workflow/js/sanitize_label_content.cjs
create mode 100644 pkg/workflow/js/sanitize_label_content.test.cjs
diff --git a/pkg/workflow/js/add_labels.cjs b/pkg/workflow/js/add_labels.cjs
index b371354ab0a..ce3cfdfcefa 100644
--- a/pkg/workflow/js/add_labels.cjs
+++ b/pkg/workflow/js/add_labels.cjs
@@ -1,20 +1,7 @@
// @ts-check
///
-function sanitizeLabelContent(content) {
- if (!content || typeof content !== "string") {
- return "";
- }
- let sanitized = content.trim();
- sanitized = sanitized.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
- sanitized = sanitized.replace(/\x1b\[[0-9;]*[mGKH]/g, "");
- sanitized = sanitized.replace(
- /(^|[^\w`])@([A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?(?:\/[A-Za-z0-9._-]+)?)/g,
- (_m, p1, p2) => `${p1}\`@${p2}\``
- );
- sanitized = sanitized.replace(/[<>&'"]/g, "");
- return sanitized.trim();
-}
+const { sanitizeLabelContent } = require("./sanitize_label_content.cjs");
async function main() {
const agentOutputFile = process.env.GH_AW_AGENT_OUTPUT;
if (!agentOutputFile) {
diff --git a/pkg/workflow/js/create_issue.cjs b/pkg/workflow/js/create_issue.cjs
index bd832624e2c..51d55dcbb12 100644
--- a/pkg/workflow/js/create_issue.cjs
+++ b/pkg/workflow/js/create_issue.cjs
@@ -1,20 +1,7 @@
// @ts-check
///
-function sanitizeLabelContent(content) {
- if (!content || typeof content !== "string") {
- return "";
- }
- let sanitized = content.trim();
- sanitized = sanitized.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
- sanitized = sanitized.replace(/\x1b\[[0-9;]*[mGKH]/g, "");
- sanitized = sanitized.replace(
- /(^|[^\w`])@([A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?(?:\/[A-Za-z0-9._-]+)?)/g,
- (_m, p1, p2) => `${p1}\`@${p2}\``
- );
- sanitized = sanitized.replace(/[<>&'"]/g, "");
- return sanitized.trim();
-}
+const { sanitizeLabelContent } = require("./sanitize_label_content.cjs");
/**
* Generate footer with AI attribution and workflow installation instructions
diff --git a/pkg/workflow/js/sanitize_label_content.cjs b/pkg/workflow/js/sanitize_label_content.cjs
new file mode 100644
index 00000000000..04041069b3f
--- /dev/null
+++ b/pkg/workflow/js/sanitize_label_content.cjs
@@ -0,0 +1,32 @@
+// @ts-check
+/**
+ * Sanitize label content for GitHub API
+ * Removes control characters, ANSI codes, and neutralizes @mentions
+ * @module sanitize_label_content
+ */
+
+/**
+ * Sanitizes label content by removing control characters, ANSI escape codes,
+ * and neutralizing @mentions to prevent unintended notifications.
+ *
+ * @param {string} content - The label content to sanitize
+ * @returns {string} The sanitized label content
+ */
+function sanitizeLabelContent(content) {
+ if (!content || typeof content !== "string") {
+ return "";
+ }
+ let sanitized = content.trim();
+ // Remove ANSI escape sequences FIRST (before removing control chars)
+ sanitized = sanitized.replace(/\x1b\[[0-9;]*[mGKH]/g, "");
+ // Then remove control characters (except newlines and tabs)
+ sanitized = sanitized.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
+ sanitized = sanitized.replace(
+ /(^|[^\w`])@([A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?(?:\/[A-Za-z0-9._-]+)?)/g,
+ (_m, p1, p2) => `${p1}\`@${p2}\``
+ );
+ sanitized = sanitized.replace(/[<>&'"]/g, "");
+ return sanitized.trim();
+}
+
+module.exports = { sanitizeLabelContent };
diff --git a/pkg/workflow/js/sanitize_label_content.test.cjs b/pkg/workflow/js/sanitize_label_content.test.cjs
new file mode 100644
index 00000000000..57edec6ec82
--- /dev/null
+++ b/pkg/workflow/js/sanitize_label_content.test.cjs
@@ -0,0 +1,142 @@
+import { describe, it, expect } from "vitest";
+
+// Import the function to test
+const { sanitizeLabelContent } = require("./sanitize_label_content.cjs");
+
+describe("sanitize_label_content.cjs", () => {
+ describe("sanitizeLabelContent", () => {
+ it("should return empty string for null input", () => {
+ expect(sanitizeLabelContent(null)).toBe("");
+ });
+
+ it("should return empty string for undefined input", () => {
+ expect(sanitizeLabelContent(undefined)).toBe("");
+ });
+
+ it("should return empty string for non-string input", () => {
+ expect(sanitizeLabelContent(123)).toBe("");
+ expect(sanitizeLabelContent({})).toBe("");
+ expect(sanitizeLabelContent([])).toBe("");
+ });
+
+ it("should trim whitespace from input", () => {
+ expect(sanitizeLabelContent(" test ")).toBe("test");
+ expect(sanitizeLabelContent("\n\ttest\n\t")).toBe("test");
+ });
+
+ it("should remove control characters", () => {
+ const input = "test\x00\x01\x02\x03\x04\x05\x06\x07\x08label";
+ expect(sanitizeLabelContent(input)).toBe("testlabel");
+ });
+
+ it("should remove DEL character (0x7F)", () => {
+ const input = "test\x7Flabel";
+ expect(sanitizeLabelContent(input)).toBe("testlabel");
+ });
+
+ it("should preserve newline character", () => {
+ const input = "test\nlabel";
+ expect(sanitizeLabelContent(input)).toBe("test\nlabel");
+ });
+
+ it("should remove ANSI escape codes", () => {
+ const input = "\x1b[31mred text\x1b[0m";
+ expect(sanitizeLabelContent(input)).toBe("red text");
+ });
+
+ it("should remove various ANSI codes", () => {
+ const input = "\x1b[1;32mBold Green\x1b[0m\x1b[4mUnderline\x1b[0m";
+ expect(sanitizeLabelContent(input)).toBe("Bold GreenUnderline");
+ });
+
+ it("should neutralize @mentions by wrapping in backticks", () => {
+ expect(sanitizeLabelContent("Hello @user")).toBe("Hello `@user`");
+ expect(sanitizeLabelContent("@user said something")).toBe("`@user` said something");
+ });
+
+ it("should neutralize @org/team mentions", () => {
+ expect(sanitizeLabelContent("Hello @myorg/myteam")).toBe("Hello `@myorg/myteam`");
+ });
+
+ it("should not neutralize @mentions already in backticks", () => {
+ const input = "Already `@user` handled";
+ expect(sanitizeLabelContent(input)).toBe("Already `@user` handled");
+ });
+
+ it("should neutralize multiple @mentions", () => {
+ const input = "@user1 and @user2 are here";
+ expect(sanitizeLabelContent(input)).toBe("`@user1` and `@user2` are here");
+ });
+
+ it("should remove HTML special characters", () => {
+ expect(sanitizeLabelContent("test<>&'\"label")).toBe("testlabel");
+ });
+
+ it("should remove less-than signs", () => {
+ expect(sanitizeLabelContent("a < b")).toBe("a b");
+ });
+
+ it("should remove greater-than signs", () => {
+ expect(sanitizeLabelContent("a > b")).toBe("a b");
+ });
+
+ it("should remove ampersands", () => {
+ expect(sanitizeLabelContent("test & label")).toBe("test label");
+ });
+
+ it("should remove single and double quotes", () => {
+ expect(sanitizeLabelContent('test\'s "label"')).toBe("tests label");
+ });
+
+ it("should handle complex input with multiple sanitizations", () => {
+ const input = " @user \x1b[31mred\x1b[0m test&label ";
+ expect(sanitizeLabelContent(input)).toBe("`@user` red tag testlabel");
+ });
+
+ it("should handle empty string input", () => {
+ expect(sanitizeLabelContent("")).toBe("");
+ });
+
+ it("should handle whitespace-only input", () => {
+ expect(sanitizeLabelContent(" \n\t ")).toBe("");
+ });
+
+ it("should preserve normal alphanumeric characters", () => {
+ expect(sanitizeLabelContent("bug123")).toBe("bug123");
+ expect(sanitizeLabelContent("feature-request")).toBe("feature-request");
+ });
+
+ it("should preserve hyphens and underscores", () => {
+ expect(sanitizeLabelContent("test-label_123")).toBe("test-label_123");
+ });
+
+ it("should handle consecutive control characters", () => {
+ const input = "test\x00\x01\x02\x03\x04\x05label";
+ expect(sanitizeLabelContent(input)).toBe("testlabel");
+ });
+
+ it("should handle @mentions at various positions", () => {
+ expect(sanitizeLabelContent("start @user end")).toBe("start `@user` end");
+ expect(sanitizeLabelContent("@user at start")).toBe("`@user` at start");
+ expect(sanitizeLabelContent("at end @user")).toBe("at end `@user`");
+ });
+
+ it("should not treat email-like patterns as @mentions after alphanumerics", () => {
+ const input = "email@example.com";
+ // The regex has [^\w`] which requires non-word character before @
+ // so 'email@' won't match because 'l' is a word character
+ expect(sanitizeLabelContent(input)).toBe("email@example.com");
+ });
+
+ it("should handle username edge cases", () => {
+ // Valid GitHub usernames can be 1-39 chars, alphanumeric + hyphens
+ expect(sanitizeLabelContent("@a")).toBe("`@a`");
+ expect(sanitizeLabelContent("@user-name-123")).toBe("`@user-name-123`");
+ });
+
+ it("should combine all sanitization rules correctly", () => {
+ const input = ' \x1b[31m@user\x1b[0m says & "goodbye" ';
+ expect(sanitizeLabelContent(input)).toBe("`@user` says hello goodbye");
+ });
+ });
+});
From f6efff4f23510f70f5587614c3c2d1ad9bcb2ad9 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 4 Nov 2025 15:37:05 +0000
Subject: [PATCH 3/4] Recompile workflows after extracting sanitizeLabelContent
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
.github/workflows/ci-doctor.lock.yml | 15 +---------
.../workflows/cli-version-checker.lock.yml | 15 +---------
.../duplicate-code-detector.lock.yml | 15 +---------
.../workflows/go-pattern-detector.lock.yml | 15 +---------
.github/workflows/issue-classifier.lock.yml | 15 +---------
.github/workflows/plan.lock.yml | 15 +---------
.github/workflows/poem-bot.lock.yml | 30 ++-----------------
.../semantic-function-refactor.lock.yml | 15 +---------
.github/workflows/smoke-claude.lock.yml | 15 +---------
.github/workflows/smoke-codex.lock.yml | 15 +---------
.../workflows/smoke-copilot.firewall.lock.yml | 15 +---------
.github/workflows/smoke-copilot.lock.yml | 15 +---------
.github/workflows/smoke-detector.lock.yml | 15 +---------
.github/workflows/smoke-opencode.lock.yml | 15 +---------
.../test-ollama-threat-detection.lock.yml | 15 +---------
.github/workflows/video-analyzer.lock.yml | 15 +---------
16 files changed, 17 insertions(+), 238 deletions(-)
diff --git a/.github/workflows/ci-doctor.lock.yml b/.github/workflows/ci-doctor.lock.yml
index 23f4d1d93da..450a359542b 100644
--- a/.github/workflows/ci-doctor.lock.yml
+++ b/.github/workflows/ci-doctor.lock.yml
@@ -4052,20 +4052,7 @@ jobs:
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
- function sanitizeLabelContent(content) {
- if (!content || typeof content !== "string") {
- return "";
- }
- let sanitized = content.trim();
- sanitized = sanitized.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
- sanitized = sanitized.replace(/\x1b\[[0-9;]*[mGKH]/g, "");
- sanitized = sanitized.replace(
- /(^|[^\w`])@([A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?(?:\/[A-Za-z0-9._-]+)?)/g,
- (_m, p1, p2) => `${p1}\`@${p2}\``
- );
- sanitized = sanitized.replace(/[<>&'"]/g, "");
- return sanitized.trim();
- }
+ const { sanitizeLabelContent } = require("./sanitize_label_content.cjs");
function generateFooter(
workflowName,
runUrl,
diff --git a/.github/workflows/cli-version-checker.lock.yml b/.github/workflows/cli-version-checker.lock.yml
index d8347bb2a9d..939b0614169 100644
--- a/.github/workflows/cli-version-checker.lock.yml
+++ b/.github/workflows/cli-version-checker.lock.yml
@@ -4086,20 +4086,7 @@ jobs:
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
- function sanitizeLabelContent(content) {
- if (!content || typeof content !== "string") {
- return "";
- }
- let sanitized = content.trim();
- sanitized = sanitized.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
- sanitized = sanitized.replace(/\x1b\[[0-9;]*[mGKH]/g, "");
- sanitized = sanitized.replace(
- /(^|[^\w`])@([A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?(?:\/[A-Za-z0-9._-]+)?)/g,
- (_m, p1, p2) => `${p1}\`@${p2}\``
- );
- sanitized = sanitized.replace(/[<>&'"]/g, "");
- return sanitized.trim();
- }
+ const { sanitizeLabelContent } = require("./sanitize_label_content.cjs");
function generateFooter(
workflowName,
runUrl,
diff --git a/.github/workflows/duplicate-code-detector.lock.yml b/.github/workflows/duplicate-code-detector.lock.yml
index d37a14c1d3a..2f32258eb65 100644
--- a/.github/workflows/duplicate-code-detector.lock.yml
+++ b/.github/workflows/duplicate-code-detector.lock.yml
@@ -3057,20 +3057,7 @@ jobs:
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
- function sanitizeLabelContent(content) {
- if (!content || typeof content !== "string") {
- return "";
- }
- let sanitized = content.trim();
- sanitized = sanitized.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
- sanitized = sanitized.replace(/\x1b\[[0-9;]*[mGKH]/g, "");
- sanitized = sanitized.replace(
- /(^|[^\w`])@([A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?(?:\/[A-Za-z0-9._-]+)?)/g,
- (_m, p1, p2) => `${p1}\`@${p2}\``
- );
- sanitized = sanitized.replace(/[<>&'"]/g, "");
- return sanitized.trim();
- }
+ const { sanitizeLabelContent } = require("./sanitize_label_content.cjs");
function generateFooter(
workflowName,
runUrl,
diff --git a/.github/workflows/go-pattern-detector.lock.yml b/.github/workflows/go-pattern-detector.lock.yml
index 13b67fa6c1c..1ff880e264a 100644
--- a/.github/workflows/go-pattern-detector.lock.yml
+++ b/.github/workflows/go-pattern-detector.lock.yml
@@ -3298,20 +3298,7 @@ jobs:
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
- function sanitizeLabelContent(content) {
- if (!content || typeof content !== "string") {
- return "";
- }
- let sanitized = content.trim();
- sanitized = sanitized.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
- sanitized = sanitized.replace(/\x1b\[[0-9;]*[mGKH]/g, "");
- sanitized = sanitized.replace(
- /(^|[^\w`])@([A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?(?:\/[A-Za-z0-9._-]+)?)/g,
- (_m, p1, p2) => `${p1}\`@${p2}\``
- );
- sanitized = sanitized.replace(/[<>&'"]/g, "");
- return sanitized.trim();
- }
+ const { sanitizeLabelContent } = require("./sanitize_label_content.cjs");
function generateFooter(
workflowName,
runUrl,
diff --git a/.github/workflows/issue-classifier.lock.yml b/.github/workflows/issue-classifier.lock.yml
index a0785e1b84b..6776f1e7f2b 100644
--- a/.github/workflows/issue-classifier.lock.yml
+++ b/.github/workflows/issue-classifier.lock.yml
@@ -716,20 +716,7 @@ jobs:
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
- function sanitizeLabelContent(content) {
- if (!content || typeof content !== "string") {
- return "";
- }
- let sanitized = content.trim();
- sanitized = sanitized.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
- sanitized = sanitized.replace(/\x1b\[[0-9;]*[mGKH]/g, "");
- sanitized = sanitized.replace(
- /(^|[^\w`])@([A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?(?:\/[A-Za-z0-9._-]+)?)/g,
- (_m, p1, p2) => `${p1}\`@${p2}\``
- );
- sanitized = sanitized.replace(/[<>&'"]/g, "");
- return sanitized.trim();
- }
+ const { sanitizeLabelContent } = require("./sanitize_label_content.cjs");
async function main() {
const agentOutputFile = process.env.GH_AW_AGENT_OUTPUT;
if (!agentOutputFile) {
diff --git a/.github/workflows/plan.lock.yml b/.github/workflows/plan.lock.yml
index 64b04979a64..e9e1191905f 100644
--- a/.github/workflows/plan.lock.yml
+++ b/.github/workflows/plan.lock.yml
@@ -4121,20 +4121,7 @@ jobs:
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
- function sanitizeLabelContent(content) {
- if (!content || typeof content !== "string") {
- return "";
- }
- let sanitized = content.trim();
- sanitized = sanitized.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
- sanitized = sanitized.replace(/\x1b\[[0-9;]*[mGKH]/g, "");
- sanitized = sanitized.replace(
- /(^|[^\w`])@([A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?(?:\/[A-Za-z0-9._-]+)?)/g,
- (_m, p1, p2) => `${p1}\`@${p2}\``
- );
- sanitized = sanitized.replace(/[<>&'"]/g, "");
- return sanitized.trim();
- }
+ const { sanitizeLabelContent } = require("./sanitize_label_content.cjs");
function generateFooter(
workflowName,
runUrl,
diff --git a/.github/workflows/poem-bot.lock.yml b/.github/workflows/poem-bot.lock.yml
index cd273615663..089f0b400e3 100644
--- a/.github/workflows/poem-bot.lock.yml
+++ b/.github/workflows/poem-bot.lock.yml
@@ -1156,20 +1156,7 @@ jobs:
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
- function sanitizeLabelContent(content) {
- if (!content || typeof content !== "string") {
- return "";
- }
- let sanitized = content.trim();
- sanitized = sanitized.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
- sanitized = sanitized.replace(/\x1b\[[0-9;]*[mGKH]/g, "");
- sanitized = sanitized.replace(
- /(^|[^\w`])@([A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?(?:\/[A-Za-z0-9._-]+)?)/g,
- (_m, p1, p2) => `${p1}\`@${p2}\``
- );
- sanitized = sanitized.replace(/[<>&'"]/g, "");
- return sanitized.trim();
- }
+ const { sanitizeLabelContent } = require("./sanitize_label_content.cjs");
async function main() {
const agentOutputFile = process.env.GH_AW_AGENT_OUTPUT;
if (!agentOutputFile) {
@@ -4995,20 +4982,7 @@ jobs:
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
- function sanitizeLabelContent(content) {
- if (!content || typeof content !== "string") {
- return "";
- }
- let sanitized = content.trim();
- sanitized = sanitized.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
- sanitized = sanitized.replace(/\x1b\[[0-9;]*[mGKH]/g, "");
- sanitized = sanitized.replace(
- /(^|[^\w`])@([A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?(?:\/[A-Za-z0-9._-]+)?)/g,
- (_m, p1, p2) => `${p1}\`@${p2}\``
- );
- sanitized = sanitized.replace(/[<>&'"]/g, "");
- return sanitized.trim();
- }
+ const { sanitizeLabelContent } = require("./sanitize_label_content.cjs");
function generateFooter(
workflowName,
runUrl,
diff --git a/.github/workflows/semantic-function-refactor.lock.yml b/.github/workflows/semantic-function-refactor.lock.yml
index 1743b9eb76d..43c0a6a9fd1 100644
--- a/.github/workflows/semantic-function-refactor.lock.yml
+++ b/.github/workflows/semantic-function-refactor.lock.yml
@@ -3698,20 +3698,7 @@ jobs:
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
- function sanitizeLabelContent(content) {
- if (!content || typeof content !== "string") {
- return "";
- }
- let sanitized = content.trim();
- sanitized = sanitized.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
- sanitized = sanitized.replace(/\x1b\[[0-9;]*[mGKH]/g, "");
- sanitized = sanitized.replace(
- /(^|[^\w`])@([A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?(?:\/[A-Za-z0-9._-]+)?)/g,
- (_m, p1, p2) => `${p1}\`@${p2}\``
- );
- sanitized = sanitized.replace(/[<>&'"]/g, "");
- return sanitized.trim();
- }
+ const { sanitizeLabelContent } = require("./sanitize_label_content.cjs");
function generateFooter(
workflowName,
runUrl,
diff --git a/.github/workflows/smoke-claude.lock.yml b/.github/workflows/smoke-claude.lock.yml
index 663850a7880..30fd1f183d2 100644
--- a/.github/workflows/smoke-claude.lock.yml
+++ b/.github/workflows/smoke-claude.lock.yml
@@ -3148,20 +3148,7 @@ jobs:
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
- function sanitizeLabelContent(content) {
- if (!content || typeof content !== "string") {
- return "";
- }
- let sanitized = content.trim();
- sanitized = sanitized.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
- sanitized = sanitized.replace(/\x1b\[[0-9;]*[mGKH]/g, "");
- sanitized = sanitized.replace(
- /(^|[^\w`])@([A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?(?:\/[A-Za-z0-9._-]+)?)/g,
- (_m, p1, p2) => `${p1}\`@${p2}\``
- );
- sanitized = sanitized.replace(/[<>&'"]/g, "");
- return sanitized.trim();
- }
+ const { sanitizeLabelContent } = require("./sanitize_label_content.cjs");
function generateFooter(
workflowName,
runUrl,
diff --git a/.github/workflows/smoke-codex.lock.yml b/.github/workflows/smoke-codex.lock.yml
index fb19bbeebe2..0525375782b 100644
--- a/.github/workflows/smoke-codex.lock.yml
+++ b/.github/workflows/smoke-codex.lock.yml
@@ -2797,20 +2797,7 @@ jobs:
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
- function sanitizeLabelContent(content) {
- if (!content || typeof content !== "string") {
- return "";
- }
- let sanitized = content.trim();
- sanitized = sanitized.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
- sanitized = sanitized.replace(/\x1b\[[0-9;]*[mGKH]/g, "");
- sanitized = sanitized.replace(
- /(^|[^\w`])@([A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?(?:\/[A-Za-z0-9._-]+)?)/g,
- (_m, p1, p2) => `${p1}\`@${p2}\``
- );
- sanitized = sanitized.replace(/[<>&'"]/g, "");
- return sanitized.trim();
- }
+ const { sanitizeLabelContent } = require("./sanitize_label_content.cjs");
function generateFooter(
workflowName,
runUrl,
diff --git a/.github/workflows/smoke-copilot.firewall.lock.yml b/.github/workflows/smoke-copilot.firewall.lock.yml
index 15cfe62f19d..a78ff172eae 100644
--- a/.github/workflows/smoke-copilot.firewall.lock.yml
+++ b/.github/workflows/smoke-copilot.firewall.lock.yml
@@ -3851,20 +3851,7 @@ jobs:
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
- function sanitizeLabelContent(content) {
- if (!content || typeof content !== "string") {
- return "";
- }
- let sanitized = content.trim();
- sanitized = sanitized.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
- sanitized = sanitized.replace(/\x1b\[[0-9;]*[mGKH]/g, "");
- sanitized = sanitized.replace(
- /(^|[^\w`])@([A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?(?:\/[A-Za-z0-9._-]+)?)/g,
- (_m, p1, p2) => `${p1}\`@${p2}\``
- );
- sanitized = sanitized.replace(/[<>&'"]/g, "");
- return sanitized.trim();
- }
+ const { sanitizeLabelContent } = require("./sanitize_label_content.cjs");
function generateFooter(
workflowName,
runUrl,
diff --git a/.github/workflows/smoke-copilot.lock.yml b/.github/workflows/smoke-copilot.lock.yml
index 75f239866f5..5b1af0ac79b 100644
--- a/.github/workflows/smoke-copilot.lock.yml
+++ b/.github/workflows/smoke-copilot.lock.yml
@@ -3851,20 +3851,7 @@ jobs:
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
- function sanitizeLabelContent(content) {
- if (!content || typeof content !== "string") {
- return "";
- }
- let sanitized = content.trim();
- sanitized = sanitized.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
- sanitized = sanitized.replace(/\x1b\[[0-9;]*[mGKH]/g, "");
- sanitized = sanitized.replace(
- /(^|[^\w`])@([A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?(?:\/[A-Za-z0-9._-]+)?)/g,
- (_m, p1, p2) => `${p1}\`@${p2}\``
- );
- sanitized = sanitized.replace(/[<>&'"]/g, "");
- return sanitized.trim();
- }
+ const { sanitizeLabelContent } = require("./sanitize_label_content.cjs");
function generateFooter(
workflowName,
runUrl,
diff --git a/.github/workflows/smoke-detector.lock.yml b/.github/workflows/smoke-detector.lock.yml
index 1852c123da6..6ae2b841ca2 100644
--- a/.github/workflows/smoke-detector.lock.yml
+++ b/.github/workflows/smoke-detector.lock.yml
@@ -4289,20 +4289,7 @@ jobs:
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
- function sanitizeLabelContent(content) {
- if (!content || typeof content !== "string") {
- return "";
- }
- let sanitized = content.trim();
- sanitized = sanitized.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
- sanitized = sanitized.replace(/\x1b\[[0-9;]*[mGKH]/g, "");
- sanitized = sanitized.replace(
- /(^|[^\w`])@([A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?(?:\/[A-Za-z0-9._-]+)?)/g,
- (_m, p1, p2) => `${p1}\`@${p2}\``
- );
- sanitized = sanitized.replace(/[<>&'"]/g, "");
- return sanitized.trim();
- }
+ const { sanitizeLabelContent } = require("./sanitize_label_content.cjs");
function generateFooter(
workflowName,
runUrl,
diff --git a/.github/workflows/smoke-opencode.lock.yml b/.github/workflows/smoke-opencode.lock.yml
index 4fc6423d7d5..091ab4969da 100644
--- a/.github/workflows/smoke-opencode.lock.yml
+++ b/.github/workflows/smoke-opencode.lock.yml
@@ -2321,20 +2321,7 @@ jobs:
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
- function sanitizeLabelContent(content) {
- if (!content || typeof content !== "string") {
- return "";
- }
- let sanitized = content.trim();
- sanitized = sanitized.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
- sanitized = sanitized.replace(/\x1b\[[0-9;]*[mGKH]/g, "");
- sanitized = sanitized.replace(
- /(^|[^\w`])@([A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?(?:\/[A-Za-z0-9._-]+)?)/g,
- (_m, p1, p2) => `${p1}\`@${p2}\``
- );
- sanitized = sanitized.replace(/[<>&'"]/g, "");
- return sanitized.trim();
- }
+ const { sanitizeLabelContent } = require("./sanitize_label_content.cjs");
function generateFooter(
workflowName,
runUrl,
diff --git a/.github/workflows/test-ollama-threat-detection.lock.yml b/.github/workflows/test-ollama-threat-detection.lock.yml
index 2e9920f7f47..7c94b0a4758 100644
--- a/.github/workflows/test-ollama-threat-detection.lock.yml
+++ b/.github/workflows/test-ollama-threat-detection.lock.yml
@@ -3423,20 +3423,7 @@ jobs:
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
- function sanitizeLabelContent(content) {
- if (!content || typeof content !== "string") {
- return "";
- }
- let sanitized = content.trim();
- sanitized = sanitized.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
- sanitized = sanitized.replace(/\x1b\[[0-9;]*[mGKH]/g, "");
- sanitized = sanitized.replace(
- /(^|[^\w`])@([A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?(?:\/[A-Za-z0-9._-]+)?)/g,
- (_m, p1, p2) => `${p1}\`@${p2}\``
- );
- sanitized = sanitized.replace(/[<>&'"]/g, "");
- return sanitized.trim();
- }
+ const { sanitizeLabelContent } = require("./sanitize_label_content.cjs");
function generateFooter(
workflowName,
runUrl,
diff --git a/.github/workflows/video-analyzer.lock.yml b/.github/workflows/video-analyzer.lock.yml
index a538258faed..5d53a85877e 100644
--- a/.github/workflows/video-analyzer.lock.yml
+++ b/.github/workflows/video-analyzer.lock.yml
@@ -3714,20 +3714,7 @@ jobs:
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
- function sanitizeLabelContent(content) {
- if (!content || typeof content !== "string") {
- return "";
- }
- let sanitized = content.trim();
- sanitized = sanitized.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
- sanitized = sanitized.replace(/\x1b\[[0-9;]*[mGKH]/g, "");
- sanitized = sanitized.replace(
- /(^|[^\w`])@([A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?(?:\/[A-Za-z0-9._-]+)?)/g,
- (_m, p1, p2) => `${p1}\`@${p2}\``
- );
- sanitized = sanitized.replace(/[<>&'"]/g, "");
- return sanitized.trim();
- }
+ const { sanitizeLabelContent } = require("./sanitize_label_content.cjs");
function generateFooter(
workflowName,
runUrl,
From 5e39bb861c31bd31d5b64b211390775fd8fdece9 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 4 Nov 2025 16:07:13 +0000
Subject: [PATCH 4/4] Configure bundler to inline sanitize_label_content helper
- Add sanitize_label_content.cjs to embedded JavaScript sources
- Convert createIssueScript and addLabelsScript to bundled scripts
- Update GetJavaScriptSources to include sanitize_label_content.cjs
- Update all usages to call getter functions for proper bundling
- Fix test file to keep ES6 import for vitest (not CommonJS)
This ensures the helper function is properly inlined in compiled workflows
instead of leaving require() statements that would fail at runtime.
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
.github/workflows/ci-doctor.lock.yml | 15 ++++-
.../workflows/cli-version-checker.lock.yml | 15 ++++-
.../duplicate-code-detector.lock.yml | 15 ++++-
.../workflows/go-pattern-detector.lock.yml | 15 ++++-
.github/workflows/issue-classifier.lock.yml | 15 ++++-
.github/workflows/plan.lock.yml | 15 ++++-
.github/workflows/poem-bot.lock.yml | 30 +++++++++-
.../semantic-function-refactor.lock.yml | 15 ++++-
.github/workflows/smoke-claude.lock.yml | 15 ++++-
.github/workflows/smoke-codex.lock.yml | 15 ++++-
.../workflows/smoke-copilot.firewall.lock.yml | 15 ++++-
.github/workflows/smoke-copilot.lock.yml | 15 ++++-
.github/workflows/smoke-detector.lock.yml | 15 ++++-
.github/workflows/smoke-opencode.lock.yml | 15 ++++-
.../test-ollama-threat-detection.lock.yml | 15 ++++-
.github/workflows/video-analyzer.lock.yml | 15 ++++-
pkg/workflow/add_labels.go | 2 +-
pkg/workflow/create_issue.go | 2 +-
pkg/workflow/create_issue_subissue_test.go | 23 ++++----
pkg/workflow/js.go | 56 ++++++++++++++++---
pkg/workflow/js_test.go | 4 +-
21 files changed, 303 insertions(+), 39 deletions(-)
diff --git a/.github/workflows/ci-doctor.lock.yml b/.github/workflows/ci-doctor.lock.yml
index 450a359542b..8d74a8ed15b 100644
--- a/.github/workflows/ci-doctor.lock.yml
+++ b/.github/workflows/ci-doctor.lock.yml
@@ -4052,7 +4052,20 @@ jobs:
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
- const { sanitizeLabelContent } = require("./sanitize_label_content.cjs");
+ function sanitizeLabelContent(content) {
+ if (!content || typeof content !== "string") {
+ return "";
+ }
+ let sanitized = content.trim();
+ sanitized = sanitized.replace(/\x1b\[[0-9;]*[mGKH]/g, "");
+ sanitized = sanitized.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
+ sanitized = sanitized.replace(
+ /(^|[^\w`])@([A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?(?:\/[A-Za-z0-9._-]+)?)/g,
+ (_m, p1, p2) => `${p1}\`@${p2}\``
+ );
+ sanitized = sanitized.replace(/[<>&'"]/g, "");
+ return sanitized.trim();
+ }
function generateFooter(
workflowName,
runUrl,
diff --git a/.github/workflows/cli-version-checker.lock.yml b/.github/workflows/cli-version-checker.lock.yml
index 939b0614169..c5847c86005 100644
--- a/.github/workflows/cli-version-checker.lock.yml
+++ b/.github/workflows/cli-version-checker.lock.yml
@@ -4086,7 +4086,20 @@ jobs:
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
- const { sanitizeLabelContent } = require("./sanitize_label_content.cjs");
+ function sanitizeLabelContent(content) {
+ if (!content || typeof content !== "string") {
+ return "";
+ }
+ let sanitized = content.trim();
+ sanitized = sanitized.replace(/\x1b\[[0-9;]*[mGKH]/g, "");
+ sanitized = sanitized.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
+ sanitized = sanitized.replace(
+ /(^|[^\w`])@([A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?(?:\/[A-Za-z0-9._-]+)?)/g,
+ (_m, p1, p2) => `${p1}\`@${p2}\``
+ );
+ sanitized = sanitized.replace(/[<>&'"]/g, "");
+ return sanitized.trim();
+ }
function generateFooter(
workflowName,
runUrl,
diff --git a/.github/workflows/duplicate-code-detector.lock.yml b/.github/workflows/duplicate-code-detector.lock.yml
index 2f32258eb65..ce2328dc829 100644
--- a/.github/workflows/duplicate-code-detector.lock.yml
+++ b/.github/workflows/duplicate-code-detector.lock.yml
@@ -3057,7 +3057,20 @@ jobs:
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
- const { sanitizeLabelContent } = require("./sanitize_label_content.cjs");
+ function sanitizeLabelContent(content) {
+ if (!content || typeof content !== "string") {
+ return "";
+ }
+ let sanitized = content.trim();
+ sanitized = sanitized.replace(/\x1b\[[0-9;]*[mGKH]/g, "");
+ sanitized = sanitized.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
+ sanitized = sanitized.replace(
+ /(^|[^\w`])@([A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?(?:\/[A-Za-z0-9._-]+)?)/g,
+ (_m, p1, p2) => `${p1}\`@${p2}\``
+ );
+ sanitized = sanitized.replace(/[<>&'"]/g, "");
+ return sanitized.trim();
+ }
function generateFooter(
workflowName,
runUrl,
diff --git a/.github/workflows/go-pattern-detector.lock.yml b/.github/workflows/go-pattern-detector.lock.yml
index 1ff880e264a..5fc8654b86f 100644
--- a/.github/workflows/go-pattern-detector.lock.yml
+++ b/.github/workflows/go-pattern-detector.lock.yml
@@ -3298,7 +3298,20 @@ jobs:
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
- const { sanitizeLabelContent } = require("./sanitize_label_content.cjs");
+ function sanitizeLabelContent(content) {
+ if (!content || typeof content !== "string") {
+ return "";
+ }
+ let sanitized = content.trim();
+ sanitized = sanitized.replace(/\x1b\[[0-9;]*[mGKH]/g, "");
+ sanitized = sanitized.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
+ sanitized = sanitized.replace(
+ /(^|[^\w`])@([A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?(?:\/[A-Za-z0-9._-]+)?)/g,
+ (_m, p1, p2) => `${p1}\`@${p2}\``
+ );
+ sanitized = sanitized.replace(/[<>&'"]/g, "");
+ return sanitized.trim();
+ }
function generateFooter(
workflowName,
runUrl,
diff --git a/.github/workflows/issue-classifier.lock.yml b/.github/workflows/issue-classifier.lock.yml
index 6776f1e7f2b..09a15711bc6 100644
--- a/.github/workflows/issue-classifier.lock.yml
+++ b/.github/workflows/issue-classifier.lock.yml
@@ -716,7 +716,20 @@ jobs:
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
- const { sanitizeLabelContent } = require("./sanitize_label_content.cjs");
+ function sanitizeLabelContent(content) {
+ if (!content || typeof content !== "string") {
+ return "";
+ }
+ let sanitized = content.trim();
+ sanitized = sanitized.replace(/\x1b\[[0-9;]*[mGKH]/g, "");
+ sanitized = sanitized.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
+ sanitized = sanitized.replace(
+ /(^|[^\w`])@([A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?(?:\/[A-Za-z0-9._-]+)?)/g,
+ (_m, p1, p2) => `${p1}\`@${p2}\``
+ );
+ sanitized = sanitized.replace(/[<>&'"]/g, "");
+ return sanitized.trim();
+ }
async function main() {
const agentOutputFile = process.env.GH_AW_AGENT_OUTPUT;
if (!agentOutputFile) {
diff --git a/.github/workflows/plan.lock.yml b/.github/workflows/plan.lock.yml
index e9e1191905f..f1a335e4afd 100644
--- a/.github/workflows/plan.lock.yml
+++ b/.github/workflows/plan.lock.yml
@@ -4121,7 +4121,20 @@ jobs:
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
- const { sanitizeLabelContent } = require("./sanitize_label_content.cjs");
+ function sanitizeLabelContent(content) {
+ if (!content || typeof content !== "string") {
+ return "";
+ }
+ let sanitized = content.trim();
+ sanitized = sanitized.replace(/\x1b\[[0-9;]*[mGKH]/g, "");
+ sanitized = sanitized.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
+ sanitized = sanitized.replace(
+ /(^|[^\w`])@([A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?(?:\/[A-Za-z0-9._-]+)?)/g,
+ (_m, p1, p2) => `${p1}\`@${p2}\``
+ );
+ sanitized = sanitized.replace(/[<>&'"]/g, "");
+ return sanitized.trim();
+ }
function generateFooter(
workflowName,
runUrl,
diff --git a/.github/workflows/poem-bot.lock.yml b/.github/workflows/poem-bot.lock.yml
index 089f0b400e3..9885e40254c 100644
--- a/.github/workflows/poem-bot.lock.yml
+++ b/.github/workflows/poem-bot.lock.yml
@@ -1156,7 +1156,20 @@ jobs:
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
- const { sanitizeLabelContent } = require("./sanitize_label_content.cjs");
+ function sanitizeLabelContent(content) {
+ if (!content || typeof content !== "string") {
+ return "";
+ }
+ let sanitized = content.trim();
+ sanitized = sanitized.replace(/\x1b\[[0-9;]*[mGKH]/g, "");
+ sanitized = sanitized.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
+ sanitized = sanitized.replace(
+ /(^|[^\w`])@([A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?(?:\/[A-Za-z0-9._-]+)?)/g,
+ (_m, p1, p2) => `${p1}\`@${p2}\``
+ );
+ sanitized = sanitized.replace(/[<>&'"]/g, "");
+ return sanitized.trim();
+ }
async function main() {
const agentOutputFile = process.env.GH_AW_AGENT_OUTPUT;
if (!agentOutputFile) {
@@ -4982,7 +4995,20 @@ jobs:
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
- const { sanitizeLabelContent } = require("./sanitize_label_content.cjs");
+ function sanitizeLabelContent(content) {
+ if (!content || typeof content !== "string") {
+ return "";
+ }
+ let sanitized = content.trim();
+ sanitized = sanitized.replace(/\x1b\[[0-9;]*[mGKH]/g, "");
+ sanitized = sanitized.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
+ sanitized = sanitized.replace(
+ /(^|[^\w`])@([A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?(?:\/[A-Za-z0-9._-]+)?)/g,
+ (_m, p1, p2) => `${p1}\`@${p2}\``
+ );
+ sanitized = sanitized.replace(/[<>&'"]/g, "");
+ return sanitized.trim();
+ }
function generateFooter(
workflowName,
runUrl,
diff --git a/.github/workflows/semantic-function-refactor.lock.yml b/.github/workflows/semantic-function-refactor.lock.yml
index 43c0a6a9fd1..e6a60027439 100644
--- a/.github/workflows/semantic-function-refactor.lock.yml
+++ b/.github/workflows/semantic-function-refactor.lock.yml
@@ -3698,7 +3698,20 @@ jobs:
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
- const { sanitizeLabelContent } = require("./sanitize_label_content.cjs");
+ function sanitizeLabelContent(content) {
+ if (!content || typeof content !== "string") {
+ return "";
+ }
+ let sanitized = content.trim();
+ sanitized = sanitized.replace(/\x1b\[[0-9;]*[mGKH]/g, "");
+ sanitized = sanitized.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
+ sanitized = sanitized.replace(
+ /(^|[^\w`])@([A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?(?:\/[A-Za-z0-9._-]+)?)/g,
+ (_m, p1, p2) => `${p1}\`@${p2}\``
+ );
+ sanitized = sanitized.replace(/[<>&'"]/g, "");
+ return sanitized.trim();
+ }
function generateFooter(
workflowName,
runUrl,
diff --git a/.github/workflows/smoke-claude.lock.yml b/.github/workflows/smoke-claude.lock.yml
index 30fd1f183d2..73b49dae1ed 100644
--- a/.github/workflows/smoke-claude.lock.yml
+++ b/.github/workflows/smoke-claude.lock.yml
@@ -3148,7 +3148,20 @@ jobs:
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
- const { sanitizeLabelContent } = require("./sanitize_label_content.cjs");
+ function sanitizeLabelContent(content) {
+ if (!content || typeof content !== "string") {
+ return "";
+ }
+ let sanitized = content.trim();
+ sanitized = sanitized.replace(/\x1b\[[0-9;]*[mGKH]/g, "");
+ sanitized = sanitized.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
+ sanitized = sanitized.replace(
+ /(^|[^\w`])@([A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?(?:\/[A-Za-z0-9._-]+)?)/g,
+ (_m, p1, p2) => `${p1}\`@${p2}\``
+ );
+ sanitized = sanitized.replace(/[<>&'"]/g, "");
+ return sanitized.trim();
+ }
function generateFooter(
workflowName,
runUrl,
diff --git a/.github/workflows/smoke-codex.lock.yml b/.github/workflows/smoke-codex.lock.yml
index 0525375782b..cf1a3d75d91 100644
--- a/.github/workflows/smoke-codex.lock.yml
+++ b/.github/workflows/smoke-codex.lock.yml
@@ -2797,7 +2797,20 @@ jobs:
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
- const { sanitizeLabelContent } = require("./sanitize_label_content.cjs");
+ function sanitizeLabelContent(content) {
+ if (!content || typeof content !== "string") {
+ return "";
+ }
+ let sanitized = content.trim();
+ sanitized = sanitized.replace(/\x1b\[[0-9;]*[mGKH]/g, "");
+ sanitized = sanitized.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
+ sanitized = sanitized.replace(
+ /(^|[^\w`])@([A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?(?:\/[A-Za-z0-9._-]+)?)/g,
+ (_m, p1, p2) => `${p1}\`@${p2}\``
+ );
+ sanitized = sanitized.replace(/[<>&'"]/g, "");
+ return sanitized.trim();
+ }
function generateFooter(
workflowName,
runUrl,
diff --git a/.github/workflows/smoke-copilot.firewall.lock.yml b/.github/workflows/smoke-copilot.firewall.lock.yml
index a78ff172eae..609d3e021d6 100644
--- a/.github/workflows/smoke-copilot.firewall.lock.yml
+++ b/.github/workflows/smoke-copilot.firewall.lock.yml
@@ -3851,7 +3851,20 @@ jobs:
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
- const { sanitizeLabelContent } = require("./sanitize_label_content.cjs");
+ function sanitizeLabelContent(content) {
+ if (!content || typeof content !== "string") {
+ return "";
+ }
+ let sanitized = content.trim();
+ sanitized = sanitized.replace(/\x1b\[[0-9;]*[mGKH]/g, "");
+ sanitized = sanitized.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
+ sanitized = sanitized.replace(
+ /(^|[^\w`])@([A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?(?:\/[A-Za-z0-9._-]+)?)/g,
+ (_m, p1, p2) => `${p1}\`@${p2}\``
+ );
+ sanitized = sanitized.replace(/[<>&'"]/g, "");
+ return sanitized.trim();
+ }
function generateFooter(
workflowName,
runUrl,
diff --git a/.github/workflows/smoke-copilot.lock.yml b/.github/workflows/smoke-copilot.lock.yml
index 5b1af0ac79b..62c2a60631c 100644
--- a/.github/workflows/smoke-copilot.lock.yml
+++ b/.github/workflows/smoke-copilot.lock.yml
@@ -3851,7 +3851,20 @@ jobs:
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
- const { sanitizeLabelContent } = require("./sanitize_label_content.cjs");
+ function sanitizeLabelContent(content) {
+ if (!content || typeof content !== "string") {
+ return "";
+ }
+ let sanitized = content.trim();
+ sanitized = sanitized.replace(/\x1b\[[0-9;]*[mGKH]/g, "");
+ sanitized = sanitized.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
+ sanitized = sanitized.replace(
+ /(^|[^\w`])@([A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?(?:\/[A-Za-z0-9._-]+)?)/g,
+ (_m, p1, p2) => `${p1}\`@${p2}\``
+ );
+ sanitized = sanitized.replace(/[<>&'"]/g, "");
+ return sanitized.trim();
+ }
function generateFooter(
workflowName,
runUrl,
diff --git a/.github/workflows/smoke-detector.lock.yml b/.github/workflows/smoke-detector.lock.yml
index 6ae2b841ca2..de8716b49d1 100644
--- a/.github/workflows/smoke-detector.lock.yml
+++ b/.github/workflows/smoke-detector.lock.yml
@@ -4289,7 +4289,20 @@ jobs:
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
- const { sanitizeLabelContent } = require("./sanitize_label_content.cjs");
+ function sanitizeLabelContent(content) {
+ if (!content || typeof content !== "string") {
+ return "";
+ }
+ let sanitized = content.trim();
+ sanitized = sanitized.replace(/\x1b\[[0-9;]*[mGKH]/g, "");
+ sanitized = sanitized.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
+ sanitized = sanitized.replace(
+ /(^|[^\w`])@([A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?(?:\/[A-Za-z0-9._-]+)?)/g,
+ (_m, p1, p2) => `${p1}\`@${p2}\``
+ );
+ sanitized = sanitized.replace(/[<>&'"]/g, "");
+ return sanitized.trim();
+ }
function generateFooter(
workflowName,
runUrl,
diff --git a/.github/workflows/smoke-opencode.lock.yml b/.github/workflows/smoke-opencode.lock.yml
index 091ab4969da..41a898e42ba 100644
--- a/.github/workflows/smoke-opencode.lock.yml
+++ b/.github/workflows/smoke-opencode.lock.yml
@@ -2321,7 +2321,20 @@ jobs:
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
- const { sanitizeLabelContent } = require("./sanitize_label_content.cjs");
+ function sanitizeLabelContent(content) {
+ if (!content || typeof content !== "string") {
+ return "";
+ }
+ let sanitized = content.trim();
+ sanitized = sanitized.replace(/\x1b\[[0-9;]*[mGKH]/g, "");
+ sanitized = sanitized.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
+ sanitized = sanitized.replace(
+ /(^|[^\w`])@([A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?(?:\/[A-Za-z0-9._-]+)?)/g,
+ (_m, p1, p2) => `${p1}\`@${p2}\``
+ );
+ sanitized = sanitized.replace(/[<>&'"]/g, "");
+ return sanitized.trim();
+ }
function generateFooter(
workflowName,
runUrl,
diff --git a/.github/workflows/test-ollama-threat-detection.lock.yml b/.github/workflows/test-ollama-threat-detection.lock.yml
index 7c94b0a4758..b1fc182e8a2 100644
--- a/.github/workflows/test-ollama-threat-detection.lock.yml
+++ b/.github/workflows/test-ollama-threat-detection.lock.yml
@@ -3423,7 +3423,20 @@ jobs:
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
- const { sanitizeLabelContent } = require("./sanitize_label_content.cjs");
+ function sanitizeLabelContent(content) {
+ if (!content || typeof content !== "string") {
+ return "";
+ }
+ let sanitized = content.trim();
+ sanitized = sanitized.replace(/\x1b\[[0-9;]*[mGKH]/g, "");
+ sanitized = sanitized.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
+ sanitized = sanitized.replace(
+ /(^|[^\w`])@([A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?(?:\/[A-Za-z0-9._-]+)?)/g,
+ (_m, p1, p2) => `${p1}\`@${p2}\``
+ );
+ sanitized = sanitized.replace(/[<>&'"]/g, "");
+ return sanitized.trim();
+ }
function generateFooter(
workflowName,
runUrl,
diff --git a/.github/workflows/video-analyzer.lock.yml b/.github/workflows/video-analyzer.lock.yml
index 5d53a85877e..f1151b50d85 100644
--- a/.github/workflows/video-analyzer.lock.yml
+++ b/.github/workflows/video-analyzer.lock.yml
@@ -3714,7 +3714,20 @@ jobs:
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
- const { sanitizeLabelContent } = require("./sanitize_label_content.cjs");
+ function sanitizeLabelContent(content) {
+ if (!content || typeof content !== "string") {
+ return "";
+ }
+ let sanitized = content.trim();
+ sanitized = sanitized.replace(/\x1b\[[0-9;]*[mGKH]/g, "");
+ sanitized = sanitized.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
+ sanitized = sanitized.replace(
+ /(^|[^\w`])@([A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?(?:\/[A-Za-z0-9._-]+)?)/g,
+ (_m, p1, p2) => `${p1}\`@${p2}\``
+ );
+ sanitized = sanitized.replace(/[<>&'"]/g, "");
+ return sanitized.trim();
+ }
function generateFooter(
workflowName,
runUrl,
diff --git a/pkg/workflow/add_labels.go b/pkg/workflow/add_labels.go
index 4c00c8f2ad8..7a0452d5fb2 100644
--- a/pkg/workflow/add_labels.go
+++ b/pkg/workflow/add_labels.go
@@ -62,7 +62,7 @@ func (c *Compiler) buildAddLabelsJob(data *WorkflowData, mainJobName string) (*J
StepID: "add_labels",
MainJobName: mainJobName,
CustomEnvVars: customEnvVars,
- Script: addLabelsScript,
+ Script: getAddLabelsScript(),
Token: token,
})
diff --git a/pkg/workflow/create_issue.go b/pkg/workflow/create_issue.go
index 96bd3246af8..243168af6b7 100644
--- a/pkg/workflow/create_issue.go
+++ b/pkg/workflow/create_issue.go
@@ -112,7 +112,7 @@ func (c *Compiler) buildCreateOutputIssueJob(data *WorkflowData, mainJobName str
StepID: "create_issue",
MainJobName: mainJobName,
CustomEnvVars: customEnvVars,
- Script: createIssueScript,
+ Script: getCreateIssueScript(),
Token: token,
})
steps = append(steps, scriptSteps...)
diff --git a/pkg/workflow/create_issue_subissue_test.go b/pkg/workflow/create_issue_subissue_test.go
index 02cb18a3330..0d931308dcb 100644
--- a/pkg/workflow/create_issue_subissue_test.go
+++ b/pkg/workflow/create_issue_subissue_test.go
@@ -9,58 +9,59 @@ import (
// TestCreateIssueSubissueFeature tests that the create_issue.js script includes subissue functionality
func TestCreateIssueSubissueFeature(t *testing.T) {
+ script := getCreateIssueScript()
// Test that the script contains the subissue detection logic
- if !strings.Contains(createIssueScript, "context.payload?.issue?.number") {
+ if !strings.Contains(script, "context.payload?.issue?.number") {
t.Error("Expected create_issue.js to check for parent issue context")
}
// Test that the script modifies the body when in issue context
- if !strings.Contains(createIssueScript, "Related to #${effectiveParentIssueNumber}") {
+ if !strings.Contains(script, "Related to #${effectiveParentIssueNumber}") {
t.Error("Expected create_issue.js to add parent issue reference to body")
}
// Test that the script supports explicit parent field
- if !strings.Contains(createIssueScript, "createIssueItem.parent") {
+ if !strings.Contains(script, "createIssueItem.parent") {
t.Error("Expected create_issue.js to support explicit parent field")
}
// Test that the script uses effectiveParentIssueNumber
- if !strings.Contains(createIssueScript, "effectiveParentIssueNumber") {
+ if !strings.Contains(script, "effectiveParentIssueNumber") {
t.Error("Expected create_issue.js to use effectiveParentIssueNumber variable")
}
// Test that the script includes GraphQL sub-issue linking
- if !strings.Contains(createIssueScript, "addSubIssue") {
+ if !strings.Contains(script, "addSubIssue") {
t.Error("Expected create_issue.js to include addSubIssue GraphQL mutation")
}
// Test that the script calls github.graphql for sub-issue linking
- if !strings.Contains(createIssueScript, "github.graphql(addSubIssueMutation") {
+ if !strings.Contains(script, "github.graphql(addSubIssueMutation") {
t.Error("Expected create_issue.js to call github.graphql for sub-issue linking")
}
// Test that the script fetches node IDs before linking
- if !strings.Contains(createIssueScript, "getIssueNodeIdQuery") {
+ if !strings.Contains(script, "getIssueNodeIdQuery") {
t.Error("Expected create_issue.js to fetch issue node IDs before linking")
}
// Test that the script creates a comment on the parent issue
- if !strings.Contains(createIssueScript, "github.rest.issues.createComment") {
+ if !strings.Contains(script, "github.rest.issues.createComment") {
t.Error("Expected create_issue.js to create comment on parent issue")
}
// Test that the script has proper error handling for sub-issue linking
- if !strings.Contains(createIssueScript, "Warning: Could not link sub-issue to parent") {
+ if !strings.Contains(script, "Warning: Could not link sub-issue to parent") {
t.Error("Expected create_issue.js to have error handling for sub-issue linking")
}
// Test console logging for debugging
- if !strings.Contains(createIssueScript, "Detected issue context, parent issue") {
+ if !strings.Contains(script, "Detected issue context, parent issue") {
t.Error("Expected create_issue.js to log when issue context is detected")
}
// Test that it logs successful sub-issue linking
- if !strings.Contains(createIssueScript, "Successfully linked issue #") {
+ if !strings.Contains(script, "Successfully linked issue #") {
t.Error("Expected create_issue.js to log successful sub-issue linking")
}
}
diff --git a/pkg/workflow/js.go b/pkg/workflow/js.go
index 4450dbb1989..9bcb7481cc2 100644
--- a/pkg/workflow/js.go
+++ b/pkg/workflow/js.go
@@ -10,9 +10,6 @@ import (
//go:embed js/create_pull_request.cjs
var createPullRequestScript string
-//go:embed js/create_issue.cjs
-var createIssueScript string
-
//go:embed js/create_agent_task.cjs
var createAgentTaskScript string
@@ -28,9 +25,6 @@ var createPRReviewCommentScript string
//go:embed js/create_code_scanning_alert.cjs
var createCodeScanningAlertScript string
-//go:embed js/add_labels.cjs
-var addLabelsScript string
-
//go:embed js/assign_issue.cjs
var assignIssueScript string
@@ -94,6 +88,9 @@ var notifyCommentErrorScript string
//go:embed js/sanitize.cjs
var sanitizeLibScript string
+//go:embed js/sanitize_label_content.cjs
+var sanitizeLabelContentScript string
+
// Source scripts that may contain local requires
//
//go:embed js/collect_ndjson_output.cjs
@@ -105,6 +102,12 @@ var computeTextScriptSource string
//go:embed js/sanitize_output.cjs
var sanitizeOutputScriptSource string
+//go:embed js/create_issue.cjs
+var createIssueScriptSource string
+
+//go:embed js/add_labels.cjs
+var addLabelsScriptSource string
+
// Bundled scripts (lazily bundled on-demand and cached)
var (
collectJSONLOutputScript string
@@ -115,6 +118,12 @@ var (
sanitizeOutputScript string
sanitizeOutputScriptOnce sync.Once
+
+ createIssueScript string
+ createIssueScriptOnce sync.Once
+
+ addLabelsScript string
+ addLabelsScriptOnce sync.Once
)
// getCollectJSONLOutputScript returns the bundled collect_ndjson_output script
@@ -165,11 +174,44 @@ func getSanitizeOutputScript() string {
return sanitizeOutputScript
}
+// getCreateIssueScript returns the bundled create_issue script
+// Bundling is performed on first access and cached for subsequent calls
+func getCreateIssueScript() string {
+ createIssueScriptOnce.Do(func() {
+ sources := GetJavaScriptSources()
+ bundled, err := BundleJavaScriptFromSources(createIssueScriptSource, sources, "")
+ if err != nil {
+ // If bundling fails, use the source as-is
+ createIssueScript = createIssueScriptSource
+ } else {
+ createIssueScript = bundled
+ }
+ })
+ return createIssueScript
+}
+
+// getAddLabelsScript returns the bundled add_labels script
+// Bundling is performed on first access and cached for subsequent calls
+func getAddLabelsScript() string {
+ addLabelsScriptOnce.Do(func() {
+ sources := GetJavaScriptSources()
+ bundled, err := BundleJavaScriptFromSources(addLabelsScriptSource, sources, "")
+ if err != nil {
+ // If bundling fails, use the source as-is
+ addLabelsScript = addLabelsScriptSource
+ } else {
+ addLabelsScript = bundled
+ }
+ })
+ return addLabelsScript
+}
+
// GetJavaScriptSources returns a map of all embedded JavaScript sources
// The keys are the relative paths from the js directory
func GetJavaScriptSources() map[string]string {
return map[string]string{
- "sanitize.cjs": sanitizeLibScript,
+ "sanitize.cjs": sanitizeLibScript,
+ "sanitize_label_content.cjs": sanitizeLabelContentScript,
}
}
diff --git a/pkg/workflow/js_test.go b/pkg/workflow/js_test.go
index 42ed9324679..fe0c05804fb 100644
--- a/pkg/workflow/js_test.go
+++ b/pkg/workflow/js_test.go
@@ -238,11 +238,11 @@ func TestEmbeddedScriptsNotEmpty(t *testing.T) {
script string
}{
{"createPullRequestScript", createPullRequestScript},
- {"createIssueScript", createIssueScript},
+ {"createIssueScript", getCreateIssueScript()},
{"createDiscussionScript", createDiscussionScript},
{"createCommentScript", createCommentScript},
{"collectJSONLOutputScript", getCollectJSONLOutputScript()},
- {"addLabelsScript", addLabelsScript},
+ {"addLabelsScript", getAddLabelsScript()},
{"updateIssueScript", updateIssueScript},
{"addReactionAndEditCommentScript", addReactionAndEditCommentScript},
{"missingToolScript", missingToolScript},