From 58eec2be8c0a465e080ea23598a9ce52482cb251 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:00:57 +0000 Subject: [PATCH 1/2] simplify: dedup validateAllowedIssueFields and extract parseUnknownModelAICreditsFromAuditEntry - allowed_issue_fields.cjs: validateAllowedIssueFields now delegates to validateAllowedIssueFieldName per field, removing duplicated Set construction and wildcard/empty-list guard logic. - ai_credits_context.cjs: extract inline DFS object traversal from parseUnknownModelAICreditsFromAuditLog's accumulate callback into a named parseUnknownModelAICreditsFromAuditEntry function, consistent with the parseMaxAICreditsFromAuditEntry / parseAICreditsErrorInfoFromAuditEntry pattern. Behavior is unchanged in both files. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- actions/setup/js/ai_credits_context.cjs | 33 +++++++++++++---------- actions/setup/js/allowed_issue_fields.cjs | 15 ++--------- 2 files changed, 21 insertions(+), 27 deletions(-) diff --git a/actions/setup/js/ai_credits_context.cjs b/actions/setup/js/ai_credits_context.cjs index 54253052843..ac5eb7b4186 100644 --- a/actions/setup/js/ai_credits_context.cjs +++ b/actions/setup/js/ai_credits_context.cjs @@ -254,6 +254,24 @@ function parseMaxAICreditsExceededFromAuditLog(auditJsonlPathOverride) { ); } +/** + * @param {unknown} entry + * @returns {boolean} + */ +function parseUnknownModelAICreditsFromAuditEntry(entry) { + if (!entry || typeof entry !== "object") return false; + const stack = [entry]; + while (stack.length > 0) { + const node = stack.pop(); + if (!node || typeof node !== "object") continue; + for (const [, value] of Object.entries(node)) { + if (value === UNKNOWN_MODEL_AI_CREDITS_TYPE) return true; + if (value && typeof value === "object") stack.push(value); + } + } + return false; +} + /** * Detects an `unknown_model_ai_credits` error from the firewall audit log. * This HTTP 400 error is emitted by the AWF API proxy when `maxAiCredits` is active and @@ -268,20 +286,7 @@ function parseUnknownModelAICreditsFromAuditLog(auditJsonlPathOverride) { auditJsonlPathOverride, false, content => content.includes(UNKNOWN_MODEL_AI_CREDITS_TYPE), - (acc, entry) => { - if (acc) return true; - if (!entry || typeof entry !== "object") return false; - const stack = [entry]; - while (stack.length > 0) { - const node = stack.pop(); - if (!node || typeof node !== "object") continue; - for (const [, value] of Object.entries(node)) { - if (value === UNKNOWN_MODEL_AI_CREDITS_TYPE) return true; - if (value && typeof value === "object") stack.push(value); - } - } - return false; - } + (acc, entry) => acc || parseUnknownModelAICreditsFromAuditEntry(entry) ); } diff --git a/actions/setup/js/allowed_issue_fields.cjs b/actions/setup/js/allowed_issue_fields.cjs index 7436cc36c00..fd7ce8adbad 100644 --- a/actions/setup/js/allowed_issue_fields.cjs +++ b/actions/setup/js/allowed_issue_fields.cjs @@ -49,20 +49,9 @@ function validateAllowedIssueFieldName(fieldName, allowedFields) { * @returns {void} */ function validateAllowedIssueFields(issueFields, allowedFields) { - if (!Array.isArray(issueFields) || issueFields.length === 0) { - return; - } - if (!Array.isArray(allowedFields) || allowedFields.length === 0) { - return; - } - const allowedFieldSet = new Set(allowedFields.map(f => f.toLowerCase())); - if (allowedFieldSet.has("*")) { - return; - } + if (!Array.isArray(issueFields) || issueFields.length === 0) return; for (const field of issueFields) { - if (!allowedFieldSet.has(field.name.toLowerCase())) { - throw new Error(`${ERR_VALIDATION}: issue field "${field.name}" is not in the allowed-fields list: ${allowedFields.join(", ")}`); - } + validateAllowedIssueFieldName(field.name, allowedFields); } } From ee75179f088fbe2c86054300d217a467d6e7958c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 22 Jun 2026 14:54:52 +0000 Subject: [PATCH 2/2] fix review feedback in allowed issue field validation Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/allowed_issue_fields.cjs | 15 +++++++++++++-- actions/setup/js/allowed_issue_fields.test.cjs | 5 +++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/actions/setup/js/allowed_issue_fields.cjs b/actions/setup/js/allowed_issue_fields.cjs index fd7ce8adbad..54aafb1afad 100644 --- a/actions/setup/js/allowed_issue_fields.cjs +++ b/actions/setup/js/allowed_issue_fields.cjs @@ -49,9 +49,20 @@ function validateAllowedIssueFieldName(fieldName, allowedFields) { * @returns {void} */ function validateAllowedIssueFields(issueFields, allowedFields) { - if (!Array.isArray(issueFields) || issueFields.length === 0) return; + if (!Array.isArray(issueFields) || issueFields.length === 0) { + return; + } + if (!Array.isArray(allowedFields) || allowedFields.length === 0) { + return; + } + const allowedFieldSet = new Set(allowedFields.map(field => field.toLowerCase())); + if (allowedFieldSet.has("*")) { + return; + } for (const field of issueFields) { - validateAllowedIssueFieldName(field.name, allowedFields); + if (!allowedFieldSet.has(field.name.toLowerCase())) { + throw new Error(`${ERR_VALIDATION}: issue field "${field.name}" is not in the allowed-fields list: ${allowedFields.join(", ")}`); + } } } diff --git a/actions/setup/js/allowed_issue_fields.test.cjs b/actions/setup/js/allowed_issue_fields.test.cjs index 7fe9b420dd2..e2198a89310 100644 --- a/actions/setup/js/allowed_issue_fields.test.cjs +++ b/actions/setup/js/allowed_issue_fields.test.cjs @@ -107,6 +107,11 @@ describe("validateAllowedIssueFields", () => { expect(() => validateAllowedIssueFields(fields, ["title", "body"])).toThrow("ERR_VALIDATION"); }); + it("throws when a field name is an empty string", () => { + const fields = [{ name: "", value: "New Title" }]; + expect(() => validateAllowedIssueFields(fields, ["title", "body"])).toThrow("ERR_VALIDATION"); + }); + it("does not throw when allowedFields is empty (no restriction)", () => { const fields = [{ name: "milestone", value: "v1.0" }]; expect(() => validateAllowedIssueFields(fields, [])).not.toThrow();