From 9f26dd1bbe62e8ef9806e6876595be4fdaa04799 Mon Sep 17 00:00:00 2001 From: "Jiaxiao (mossaka) Zhou" Date: Tue, 25 Nov 2025 21:18:25 +0000 Subject: [PATCH 1/2] fix: firewall log parser incorrectly skipping blocked requests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The parseFirewallLogLine() function was using overly-strict regex validation that rejected valid Squid log entries for blocked requests. Root cause: Blocked requests have "-:-" in the destIpPort field (no backend resolved), but the regex only accepted "-" or "IP:port" format. Changes: - Simplified parseFirewallLogLine() to remove fragile regex validations - Now only validates timestamp (essential for log format detection) - Relies on isRequestAllowed() for robust classification logic Impact: - Before: Job summaries showed "No blocked requests detected" even when firewall was blocking domains - After: Blocked domains (example.com, google.com, etc.) are correctly detected and reported The permissive parsing is safe because isRequestAllowed() provides secondary validation and defaults to "denied" for unknown patterns. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .github/workflows/artifacts-summary.lock.yml | 54 +++---------------- .github/workflows/changeset.lock.yml | 54 +++---------------- .../cli-consistency-checker.lock.yml | 54 +++---------------- .../workflows/cli-version-checker.lock.yml | 54 +++---------------- .../copilot-pr-nlp-analysis.lock.yml | 54 +++---------------- .../copilot-pr-prompt-analysis.lock.yml | 54 +++---------------- .github/workflows/daily-news.lock.yml | 54 +++---------------- .../workflows/daily-repo-chronicle.lock.yml | 54 +++---------------- .github/workflows/docs-noob-tester.lock.yml | 54 +++---------------- .github/workflows/firewall.lock.yml | 54 +++---------------- .../workflows/glossary-maintainer.lock.yml | 54 +++---------------- .github/workflows/mcp-inspector.lock.yml | 54 +++---------------- .github/workflows/python-data-charts.lock.yml | 54 +++---------------- .github/workflows/release-highlights.lock.yml | 54 +++---------------- .github/workflows/research.lock.yml | 54 +++---------------- .github/workflows/smoke-copilot.lock.yml | 54 +++---------------- .../workflows/technical-doc-writer.lock.yml | 54 +++---------------- .../workflows/weekly-issue-summary.lock.yml | 54 +++---------------- pkg/workflow/js/parse_firewall_logs.cjs | 47 +++------------- 19 files changed, 134 insertions(+), 885 deletions(-) diff --git a/.github/workflows/artifacts-summary.lock.yml b/.github/workflows/artifacts-summary.lock.yml index 650535a3e3b..85520247d5d 100644 --- a/.github/workflows/artifacts-summary.lock.yml +++ b/.github/workflows/artifacts-summary.lock.yml @@ -3933,67 +3933,27 @@ jobs: } - const clientIpPort = fields[1]; - - if (clientIpPort !== "-" && !/^[\d.]+:\d+$/.test(clientIpPort)) { - - return null; - - } - - const domain = fields[2]; - - if (domain !== "-" && !/^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)*:\d+$/.test(domain)) { - - return null; - - } - - const destIpPort = fields[3]; - - if (destIpPort !== "-" && !/^[\d.]+:\d+$/.test(destIpPort)) { - - return null; - - } - - const status = fields[6]; - - if (status !== "-" && !/^\d+$/.test(status)) { - - return null; - - } - - const decision = fields[7]; - - if (decision !== "-" && !decision.includes(":")) { - - return null; - - } - return { - timestamp: timestamp, + timestamp, - clientIpPort: clientIpPort, + clientIpPort: fields[1], - domain: domain, + domain: fields[2], - destIpPort: destIpPort, + destIpPort: fields[3], proto: fields[4], method: fields[5], - status: status, + status: fields[6], - decision: decision, + decision: fields[7], url: fields[8], - userAgent: fields[9] ? fields[9].replace(/^"|"$/g, "") : "-", + userAgent: fields[9]?.replace(/^"|"$/g, "") || "-", }; diff --git a/.github/workflows/changeset.lock.yml b/.github/workflows/changeset.lock.yml index 8cd60203aa4..0d9c48135c4 100644 --- a/.github/workflows/changeset.lock.yml +++ b/.github/workflows/changeset.lock.yml @@ -4708,67 +4708,27 @@ jobs: } - const clientIpPort = fields[1]; - - if (clientIpPort !== "-" && !/^[\d.]+:\d+$/.test(clientIpPort)) { - - return null; - - } - - const domain = fields[2]; - - if (domain !== "-" && !/^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)*:\d+$/.test(domain)) { - - return null; - - } - - const destIpPort = fields[3]; - - if (destIpPort !== "-" && !/^[\d.]+:\d+$/.test(destIpPort)) { - - return null; - - } - - const status = fields[6]; - - if (status !== "-" && !/^\d+$/.test(status)) { - - return null; - - } - - const decision = fields[7]; - - if (decision !== "-" && !decision.includes(":")) { - - return null; - - } - return { - timestamp: timestamp, + timestamp, - clientIpPort: clientIpPort, + clientIpPort: fields[1], - domain: domain, + domain: fields[2], - destIpPort: destIpPort, + destIpPort: fields[3], proto: fields[4], method: fields[5], - status: status, + status: fields[6], - decision: decision, + decision: fields[7], url: fields[8], - userAgent: fields[9] ? fields[9].replace(/^"|"$/g, "") : "-", + userAgent: fields[9]?.replace(/^"|"$/g, "") || "-", }; diff --git a/.github/workflows/cli-consistency-checker.lock.yml b/.github/workflows/cli-consistency-checker.lock.yml index 7380aa2d80b..873e3117ca2 100644 --- a/.github/workflows/cli-consistency-checker.lock.yml +++ b/.github/workflows/cli-consistency-checker.lock.yml @@ -3995,67 +3995,27 @@ jobs: } - const clientIpPort = fields[1]; - - if (clientIpPort !== "-" && !/^[\d.]+:\d+$/.test(clientIpPort)) { - - return null; - - } - - const domain = fields[2]; - - if (domain !== "-" && !/^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)*:\d+$/.test(domain)) { - - return null; - - } - - const destIpPort = fields[3]; - - if (destIpPort !== "-" && !/^[\d.]+:\d+$/.test(destIpPort)) { - - return null; - - } - - const status = fields[6]; - - if (status !== "-" && !/^\d+$/.test(status)) { - - return null; - - } - - const decision = fields[7]; - - if (decision !== "-" && !decision.includes(":")) { - - return null; - - } - return { - timestamp: timestamp, + timestamp, - clientIpPort: clientIpPort, + clientIpPort: fields[1], - domain: domain, + domain: fields[2], - destIpPort: destIpPort, + destIpPort: fields[3], proto: fields[4], method: fields[5], - status: status, + status: fields[6], - decision: decision, + decision: fields[7], url: fields[8], - userAgent: fields[9] ? fields[9].replace(/^"|"$/g, "") : "-", + userAgent: fields[9]?.replace(/^"|"$/g, "") || "-", }; diff --git a/.github/workflows/cli-version-checker.lock.yml b/.github/workflows/cli-version-checker.lock.yml index ec968e301da..5e8e77adccf 100644 --- a/.github/workflows/cli-version-checker.lock.yml +++ b/.github/workflows/cli-version-checker.lock.yml @@ -4323,67 +4323,27 @@ jobs: } - const clientIpPort = fields[1]; - - if (clientIpPort !== "-" && !/^[\d.]+:\d+$/.test(clientIpPort)) { - - return null; - - } - - const domain = fields[2]; - - if (domain !== "-" && !/^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)*:\d+$/.test(domain)) { - - return null; - - } - - const destIpPort = fields[3]; - - if (destIpPort !== "-" && !/^[\d.]+:\d+$/.test(destIpPort)) { - - return null; - - } - - const status = fields[6]; - - if (status !== "-" && !/^\d+$/.test(status)) { - - return null; - - } - - const decision = fields[7]; - - if (decision !== "-" && !decision.includes(":")) { - - return null; - - } - return { - timestamp: timestamp, + timestamp, - clientIpPort: clientIpPort, + clientIpPort: fields[1], - domain: domain, + domain: fields[2], - destIpPort: destIpPort, + destIpPort: fields[3], proto: fields[4], method: fields[5], - status: status, + status: fields[6], - decision: decision, + decision: fields[7], url: fields[8], - userAgent: fields[9] ? fields[9].replace(/^"|"$/g, "") : "-", + userAgent: fields[9]?.replace(/^"|"$/g, "") || "-", }; diff --git a/.github/workflows/copilot-pr-nlp-analysis.lock.yml b/.github/workflows/copilot-pr-nlp-analysis.lock.yml index dc06f6369cd..65ce7aec425 100644 --- a/.github/workflows/copilot-pr-nlp-analysis.lock.yml +++ b/.github/workflows/copilot-pr-nlp-analysis.lock.yml @@ -5388,67 +5388,27 @@ jobs: } - const clientIpPort = fields[1]; - - if (clientIpPort !== "-" && !/^[\d.]+:\d+$/.test(clientIpPort)) { - - return null; - - } - - const domain = fields[2]; - - if (domain !== "-" && !/^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)*:\d+$/.test(domain)) { - - return null; - - } - - const destIpPort = fields[3]; - - if (destIpPort !== "-" && !/^[\d.]+:\d+$/.test(destIpPort)) { - - return null; - - } - - const status = fields[6]; - - if (status !== "-" && !/^\d+$/.test(status)) { - - return null; - - } - - const decision = fields[7]; - - if (decision !== "-" && !decision.includes(":")) { - - return null; - - } - return { - timestamp: timestamp, + timestamp, - clientIpPort: clientIpPort, + clientIpPort: fields[1], - domain: domain, + domain: fields[2], - destIpPort: destIpPort, + destIpPort: fields[3], proto: fields[4], method: fields[5], - status: status, + status: fields[6], - decision: decision, + decision: fields[7], url: fields[8], - userAgent: fields[9] ? fields[9].replace(/^"|"$/g, "") : "-", + userAgent: fields[9]?.replace(/^"|"$/g, "") || "-", }; diff --git a/.github/workflows/copilot-pr-prompt-analysis.lock.yml b/.github/workflows/copilot-pr-prompt-analysis.lock.yml index 8ee075973ed..f405053e574 100644 --- a/.github/workflows/copilot-pr-prompt-analysis.lock.yml +++ b/.github/workflows/copilot-pr-prompt-analysis.lock.yml @@ -4558,67 +4558,27 @@ jobs: } - const clientIpPort = fields[1]; - - if (clientIpPort !== "-" && !/^[\d.]+:\d+$/.test(clientIpPort)) { - - return null; - - } - - const domain = fields[2]; - - if (domain !== "-" && !/^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)*:\d+$/.test(domain)) { - - return null; - - } - - const destIpPort = fields[3]; - - if (destIpPort !== "-" && !/^[\d.]+:\d+$/.test(destIpPort)) { - - return null; - - } - - const status = fields[6]; - - if (status !== "-" && !/^\d+$/.test(status)) { - - return null; - - } - - const decision = fields[7]; - - if (decision !== "-" && !decision.includes(":")) { - - return null; - - } - return { - timestamp: timestamp, + timestamp, - clientIpPort: clientIpPort, + clientIpPort: fields[1], - domain: domain, + domain: fields[2], - destIpPort: destIpPort, + destIpPort: fields[3], proto: fields[4], method: fields[5], - status: status, + status: fields[6], - decision: decision, + decision: fields[7], url: fields[8], - userAgent: fields[9] ? fields[9].replace(/^"|"$/g, "") : "-", + userAgent: fields[9]?.replace(/^"|"$/g, "") || "-", }; diff --git a/.github/workflows/daily-news.lock.yml b/.github/workflows/daily-news.lock.yml index 4ec0dc060bf..79661b1b3ac 100644 --- a/.github/workflows/daily-news.lock.yml +++ b/.github/workflows/daily-news.lock.yml @@ -5323,67 +5323,27 @@ jobs: } - const clientIpPort = fields[1]; - - if (clientIpPort !== "-" && !/^[\d.]+:\d+$/.test(clientIpPort)) { - - return null; - - } - - const domain = fields[2]; - - if (domain !== "-" && !/^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)*:\d+$/.test(domain)) { - - return null; - - } - - const destIpPort = fields[3]; - - if (destIpPort !== "-" && !/^[\d.]+:\d+$/.test(destIpPort)) { - - return null; - - } - - const status = fields[6]; - - if (status !== "-" && !/^\d+$/.test(status)) { - - return null; - - } - - const decision = fields[7]; - - if (decision !== "-" && !decision.includes(":")) { - - return null; - - } - return { - timestamp: timestamp, + timestamp, - clientIpPort: clientIpPort, + clientIpPort: fields[1], - domain: domain, + domain: fields[2], - destIpPort: destIpPort, + destIpPort: fields[3], proto: fields[4], method: fields[5], - status: status, + status: fields[6], - decision: decision, + decision: fields[7], url: fields[8], - userAgent: fields[9] ? fields[9].replace(/^"|"$/g, "") : "-", + userAgent: fields[9]?.replace(/^"|"$/g, "") || "-", }; diff --git a/.github/workflows/daily-repo-chronicle.lock.yml b/.github/workflows/daily-repo-chronicle.lock.yml index cb357c841e0..f3fd16599d5 100644 --- a/.github/workflows/daily-repo-chronicle.lock.yml +++ b/.github/workflows/daily-repo-chronicle.lock.yml @@ -5050,67 +5050,27 @@ jobs: } - const clientIpPort = fields[1]; - - if (clientIpPort !== "-" && !/^[\d.]+:\d+$/.test(clientIpPort)) { - - return null; - - } - - const domain = fields[2]; - - if (domain !== "-" && !/^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)*:\d+$/.test(domain)) { - - return null; - - } - - const destIpPort = fields[3]; - - if (destIpPort !== "-" && !/^[\d.]+:\d+$/.test(destIpPort)) { - - return null; - - } - - const status = fields[6]; - - if (status !== "-" && !/^\d+$/.test(status)) { - - return null; - - } - - const decision = fields[7]; - - if (decision !== "-" && !decision.includes(":")) { - - return null; - - } - return { - timestamp: timestamp, + timestamp, - clientIpPort: clientIpPort, + clientIpPort: fields[1], - domain: domain, + domain: fields[2], - destIpPort: destIpPort, + destIpPort: fields[3], proto: fields[4], method: fields[5], - status: status, + status: fields[6], - decision: decision, + decision: fields[7], url: fields[8], - userAgent: fields[9] ? fields[9].replace(/^"|"$/g, "") : "-", + userAgent: fields[9]?.replace(/^"|"$/g, "") || "-", }; diff --git a/.github/workflows/docs-noob-tester.lock.yml b/.github/workflows/docs-noob-tester.lock.yml index 3cee05f2143..b7b5afc1c24 100644 --- a/.github/workflows/docs-noob-tester.lock.yml +++ b/.github/workflows/docs-noob-tester.lock.yml @@ -3994,67 +3994,27 @@ jobs: } - const clientIpPort = fields[1]; - - if (clientIpPort !== "-" && !/^[\d.]+:\d+$/.test(clientIpPort)) { - - return null; - - } - - const domain = fields[2]; - - if (domain !== "-" && !/^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)*:\d+$/.test(domain)) { - - return null; - - } - - const destIpPort = fields[3]; - - if (destIpPort !== "-" && !/^[\d.]+:\d+$/.test(destIpPort)) { - - return null; - - } - - const status = fields[6]; - - if (status !== "-" && !/^\d+$/.test(status)) { - - return null; - - } - - const decision = fields[7]; - - if (decision !== "-" && !decision.includes(":")) { - - return null; - - } - return { - timestamp: timestamp, + timestamp, - clientIpPort: clientIpPort, + clientIpPort: fields[1], - domain: domain, + domain: fields[2], - destIpPort: destIpPort, + destIpPort: fields[3], proto: fields[4], method: fields[5], - status: status, + status: fields[6], - decision: decision, + decision: fields[7], url: fields[8], - userAgent: fields[9] ? fields[9].replace(/^"|"$/g, "") : "-", + userAgent: fields[9]?.replace(/^"|"$/g, "") || "-", }; diff --git a/.github/workflows/firewall.lock.yml b/.github/workflows/firewall.lock.yml index 874633ff1b9..4980a445c26 100644 --- a/.github/workflows/firewall.lock.yml +++ b/.github/workflows/firewall.lock.yml @@ -1917,67 +1917,27 @@ jobs: } - const clientIpPort = fields[1]; - - if (clientIpPort !== "-" && !/^[\d.]+:\d+$/.test(clientIpPort)) { - - return null; - - } - - const domain = fields[2]; - - if (domain !== "-" && !/^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)*:\d+$/.test(domain)) { - - return null; - - } - - const destIpPort = fields[3]; - - if (destIpPort !== "-" && !/^[\d.]+:\d+$/.test(destIpPort)) { - - return null; - - } - - const status = fields[6]; - - if (status !== "-" && !/^\d+$/.test(status)) { - - return null; - - } - - const decision = fields[7]; - - if (decision !== "-" && !decision.includes(":")) { - - return null; - - } - return { - timestamp: timestamp, + timestamp, - clientIpPort: clientIpPort, + clientIpPort: fields[1], - domain: domain, + domain: fields[2], - destIpPort: destIpPort, + destIpPort: fields[3], proto: fields[4], method: fields[5], - status: status, + status: fields[6], - decision: decision, + decision: fields[7], url: fields[8], - userAgent: fields[9] ? fields[9].replace(/^"|"$/g, "") : "-", + userAgent: fields[9]?.replace(/^"|"$/g, "") || "-", }; diff --git a/.github/workflows/glossary-maintainer.lock.yml b/.github/workflows/glossary-maintainer.lock.yml index 5ec4974530e..4a65964778a 100644 --- a/.github/workflows/glossary-maintainer.lock.yml +++ b/.github/workflows/glossary-maintainer.lock.yml @@ -4960,67 +4960,27 @@ jobs: } - const clientIpPort = fields[1]; - - if (clientIpPort !== "-" && !/^[\d.]+:\d+$/.test(clientIpPort)) { - - return null; - - } - - const domain = fields[2]; - - if (domain !== "-" && !/^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)*:\d+$/.test(domain)) { - - return null; - - } - - const destIpPort = fields[3]; - - if (destIpPort !== "-" && !/^[\d.]+:\d+$/.test(destIpPort)) { - - return null; - - } - - const status = fields[6]; - - if (status !== "-" && !/^\d+$/.test(status)) { - - return null; - - } - - const decision = fields[7]; - - if (decision !== "-" && !decision.includes(":")) { - - return null; - - } - return { - timestamp: timestamp, + timestamp, - clientIpPort: clientIpPort, + clientIpPort: fields[1], - domain: domain, + domain: fields[2], - destIpPort: destIpPort, + destIpPort: fields[3], proto: fields[4], method: fields[5], - status: status, + status: fields[6], - decision: decision, + decision: fields[7], url: fields[8], - userAgent: fields[9] ? fields[9].replace(/^"|"$/g, "") : "-", + userAgent: fields[9]?.replace(/^"|"$/g, "") || "-", }; diff --git a/.github/workflows/mcp-inspector.lock.yml b/.github/workflows/mcp-inspector.lock.yml index eabb52bf00d..434540eee06 100644 --- a/.github/workflows/mcp-inspector.lock.yml +++ b/.github/workflows/mcp-inspector.lock.yml @@ -4597,67 +4597,27 @@ jobs: } - const clientIpPort = fields[1]; - - if (clientIpPort !== "-" && !/^[\d.]+:\d+$/.test(clientIpPort)) { - - return null; - - } - - const domain = fields[2]; - - if (domain !== "-" && !/^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)*:\d+$/.test(domain)) { - - return null; - - } - - const destIpPort = fields[3]; - - if (destIpPort !== "-" && !/^[\d.]+:\d+$/.test(destIpPort)) { - - return null; - - } - - const status = fields[6]; - - if (status !== "-" && !/^\d+$/.test(status)) { - - return null; - - } - - const decision = fields[7]; - - if (decision !== "-" && !decision.includes(":")) { - - return null; - - } - return { - timestamp: timestamp, + timestamp, - clientIpPort: clientIpPort, + clientIpPort: fields[1], - domain: domain, + domain: fields[2], - destIpPort: destIpPort, + destIpPort: fields[3], proto: fields[4], method: fields[5], - status: status, + status: fields[6], - decision: decision, + decision: fields[7], url: fields[8], - userAgent: fields[9] ? fields[9].replace(/^"|"$/g, "") : "-", + userAgent: fields[9]?.replace(/^"|"$/g, "") || "-", }; diff --git a/.github/workflows/python-data-charts.lock.yml b/.github/workflows/python-data-charts.lock.yml index 1194bffdf4d..e5d71973454 100644 --- a/.github/workflows/python-data-charts.lock.yml +++ b/.github/workflows/python-data-charts.lock.yml @@ -5694,67 +5694,27 @@ jobs: } - const clientIpPort = fields[1]; - - if (clientIpPort !== "-" && !/^[\d.]+:\d+$/.test(clientIpPort)) { - - return null; - - } - - const domain = fields[2]; - - if (domain !== "-" && !/^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)*:\d+$/.test(domain)) { - - return null; - - } - - const destIpPort = fields[3]; - - if (destIpPort !== "-" && !/^[\d.]+:\d+$/.test(destIpPort)) { - - return null; - - } - - const status = fields[6]; - - if (status !== "-" && !/^\d+$/.test(status)) { - - return null; - - } - - const decision = fields[7]; - - if (decision !== "-" && !decision.includes(":")) { - - return null; - - } - return { - timestamp: timestamp, + timestamp, - clientIpPort: clientIpPort, + clientIpPort: fields[1], - domain: domain, + domain: fields[2], - destIpPort: destIpPort, + destIpPort: fields[3], proto: fields[4], method: fields[5], - status: status, + status: fields[6], - decision: decision, + decision: fields[7], url: fields[8], - userAgent: fields[9] ? fields[9].replace(/^"|"$/g, "") : "-", + userAgent: fields[9]?.replace(/^"|"$/g, "") || "-", }; diff --git a/.github/workflows/release-highlights.lock.yml b/.github/workflows/release-highlights.lock.yml index b134cfdab39..7d3645a972e 100644 --- a/.github/workflows/release-highlights.lock.yml +++ b/.github/workflows/release-highlights.lock.yml @@ -3908,67 +3908,27 @@ jobs: } - const clientIpPort = fields[1]; - - if (clientIpPort !== "-" && !/^[\d.]+:\d+$/.test(clientIpPort)) { - - return null; - - } - - const domain = fields[2]; - - if (domain !== "-" && !/^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)*:\d+$/.test(domain)) { - - return null; - - } - - const destIpPort = fields[3]; - - if (destIpPort !== "-" && !/^[\d.]+:\d+$/.test(destIpPort)) { - - return null; - - } - - const status = fields[6]; - - if (status !== "-" && !/^\d+$/.test(status)) { - - return null; - - } - - const decision = fields[7]; - - if (decision !== "-" && !decision.includes(":")) { - - return null; - - } - return { - timestamp: timestamp, + timestamp, - clientIpPort: clientIpPort, + clientIpPort: fields[1], - domain: domain, + domain: fields[2], - destIpPort: destIpPort, + destIpPort: fields[3], proto: fields[4], method: fields[5], - status: status, + status: fields[6], - decision: decision, + decision: fields[7], url: fields[8], - userAgent: fields[9] ? fields[9].replace(/^"|"$/g, "") : "-", + userAgent: fields[9]?.replace(/^"|"$/g, "") || "-", }; diff --git a/.github/workflows/research.lock.yml b/.github/workflows/research.lock.yml index 26db464b643..9d3feb8cad3 100644 --- a/.github/workflows/research.lock.yml +++ b/.github/workflows/research.lock.yml @@ -3865,67 +3865,27 @@ jobs: } - const clientIpPort = fields[1]; - - if (clientIpPort !== "-" && !/^[\d.]+:\d+$/.test(clientIpPort)) { - - return null; - - } - - const domain = fields[2]; - - if (domain !== "-" && !/^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)*:\d+$/.test(domain)) { - - return null; - - } - - const destIpPort = fields[3]; - - if (destIpPort !== "-" && !/^[\d.]+:\d+$/.test(destIpPort)) { - - return null; - - } - - const status = fields[6]; - - if (status !== "-" && !/^\d+$/.test(status)) { - - return null; - - } - - const decision = fields[7]; - - if (decision !== "-" && !decision.includes(":")) { - - return null; - - } - return { - timestamp: timestamp, + timestamp, - clientIpPort: clientIpPort, + clientIpPort: fields[1], - domain: domain, + domain: fields[2], - destIpPort: destIpPort, + destIpPort: fields[3], proto: fields[4], method: fields[5], - status: status, + status: fields[6], - decision: decision, + decision: fields[7], url: fields[8], - userAgent: fields[9] ? fields[9].replace(/^"|"$/g, "") : "-", + userAgent: fields[9]?.replace(/^"|"$/g, "") || "-", }; diff --git a/.github/workflows/smoke-copilot.lock.yml b/.github/workflows/smoke-copilot.lock.yml index 6f18af885ba..c6ea33586c2 100644 --- a/.github/workflows/smoke-copilot.lock.yml +++ b/.github/workflows/smoke-copilot.lock.yml @@ -4196,67 +4196,27 @@ jobs: } - const clientIpPort = fields[1]; - - if (clientIpPort !== "-" && !/^[\d.]+:\d+$/.test(clientIpPort)) { - - return null; - - } - - const domain = fields[2]; - - if (domain !== "-" && !/^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)*:\d+$/.test(domain)) { - - return null; - - } - - const destIpPort = fields[3]; - - if (destIpPort !== "-" && !/^[\d.]+:\d+$/.test(destIpPort)) { - - return null; - - } - - const status = fields[6]; - - if (status !== "-" && !/^\d+$/.test(status)) { - - return null; - - } - - const decision = fields[7]; - - if (decision !== "-" && !decision.includes(":")) { - - return null; - - } - return { - timestamp: timestamp, + timestamp, - clientIpPort: clientIpPort, + clientIpPort: fields[1], - domain: domain, + domain: fields[2], - destIpPort: destIpPort, + destIpPort: fields[3], proto: fields[4], method: fields[5], - status: status, + status: fields[6], - decision: decision, + decision: fields[7], url: fields[8], - userAgent: fields[9] ? fields[9].replace(/^"|"$/g, "") : "-", + userAgent: fields[9]?.replace(/^"|"$/g, "") || "-", }; diff --git a/.github/workflows/technical-doc-writer.lock.yml b/.github/workflows/technical-doc-writer.lock.yml index 73b6468fc41..d3f1d2d0716 100644 --- a/.github/workflows/technical-doc-writer.lock.yml +++ b/.github/workflows/technical-doc-writer.lock.yml @@ -4986,67 +4986,27 @@ jobs: } - const clientIpPort = fields[1]; - - if (clientIpPort !== "-" && !/^[\d.]+:\d+$/.test(clientIpPort)) { - - return null; - - } - - const domain = fields[2]; - - if (domain !== "-" && !/^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)*:\d+$/.test(domain)) { - - return null; - - } - - const destIpPort = fields[3]; - - if (destIpPort !== "-" && !/^[\d.]+:\d+$/.test(destIpPort)) { - - return null; - - } - - const status = fields[6]; - - if (status !== "-" && !/^\d+$/.test(status)) { - - return null; - - } - - const decision = fields[7]; - - if (decision !== "-" && !decision.includes(":")) { - - return null; - - } - return { - timestamp: timestamp, + timestamp, - clientIpPort: clientIpPort, + clientIpPort: fields[1], - domain: domain, + domain: fields[2], - destIpPort: destIpPort, + destIpPort: fields[3], proto: fields[4], method: fields[5], - status: status, + status: fields[6], - decision: decision, + decision: fields[7], url: fields[8], - userAgent: fields[9] ? fields[9].replace(/^"|"$/g, "") : "-", + userAgent: fields[9]?.replace(/^"|"$/g, "") || "-", }; diff --git a/.github/workflows/weekly-issue-summary.lock.yml b/.github/workflows/weekly-issue-summary.lock.yml index 820099aa5e3..8405e50cf95 100644 --- a/.github/workflows/weekly-issue-summary.lock.yml +++ b/.github/workflows/weekly-issue-summary.lock.yml @@ -4912,67 +4912,27 @@ jobs: } - const clientIpPort = fields[1]; - - if (clientIpPort !== "-" && !/^[\d.]+:\d+$/.test(clientIpPort)) { - - return null; - - } - - const domain = fields[2]; - - if (domain !== "-" && !/^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)*:\d+$/.test(domain)) { - - return null; - - } - - const destIpPort = fields[3]; - - if (destIpPort !== "-" && !/^[\d.]+:\d+$/.test(destIpPort)) { - - return null; - - } - - const status = fields[6]; - - if (status !== "-" && !/^\d+$/.test(status)) { - - return null; - - } - - const decision = fields[7]; - - if (decision !== "-" && !decision.includes(":")) { - - return null; - - } - return { - timestamp: timestamp, + timestamp, - clientIpPort: clientIpPort, + clientIpPort: fields[1], - domain: domain, + domain: fields[2], - destIpPort: destIpPort, + destIpPort: fields[3], proto: fields[4], method: fields[5], - status: status, + status: fields[6], - decision: decision, + decision: fields[7], url: fields[8], - userAgent: fields[9] ? fields[9].replace(/^"|"$/g, "") : "-", + userAgent: fields[9]?.replace(/^"|"$/g, "") || "-", }; diff --git a/pkg/workflow/js/parse_firewall_logs.cjs b/pkg/workflow/js/parse_firewall_logs.cjs index 0498f456fa4..37578cff888 100644 --- a/pkg/workflow/js/parse_firewall_logs.cjs +++ b/pkg/workflow/js/parse_firewall_logs.cjs @@ -111,58 +111,27 @@ function parseFirewallLogLine(line) { // Split by whitespace but preserve quoted strings const fields = trimmed.match(/(?:[^\s"]+|"[^"]*")+/g); - if (!fields || fields.length < 10) { return null; } - // Validate timestamp format (should be numeric with optional decimal point) + // Only validate timestamp (essential for log format detection) const timestamp = fields[0]; if (!/^\d+(\.\d+)?$/.test(timestamp)) { return null; } - // Validate client IP:port format (should be IP:port or "-") - const clientIpPort = fields[1]; - if (clientIpPort !== "-" && !/^[\d.]+:\d+$/.test(clientIpPort)) { - return null; - } - - // Validate domain format (should be domain:port or "-") - const domain = fields[2]; - if (domain !== "-" && !/^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)*:\d+$/.test(domain)) { - return null; - } - - // Validate dest IP:port format (should be IP:port or "-") - const destIpPort = fields[3]; - if (destIpPort !== "-" && !/^[\d.]+:\d+$/.test(destIpPort)) { - return null; - } - - // Validate status code (should be numeric or "-") - const status = fields[6]; - if (status !== "-" && !/^\d+$/.test(status)) { - return null; - } - - // Validate decision format (should contain ":" or be "-") - const decision = fields[7]; - if (decision !== "-" && !decision.includes(":")) { - return null; - } - return { - timestamp: timestamp, - clientIpPort: clientIpPort, - domain: domain, - destIpPort: destIpPort, + timestamp, + clientIpPort: fields[1], + domain: fields[2], + destIpPort: fields[3], proto: fields[4], method: fields[5], - status: status, - decision: decision, + status: fields[6], + decision: fields[7], url: fields[8], - userAgent: fields[9] ? fields[9].replace(/^"|"$/g, "") : "-", + userAgent: fields[9]?.replace(/^"|"$/g, "") || "-", }; } From 20daea6dcd903fcb6c0e5a7915bb607a2416dd6b Mon Sep 17 00:00:00 2001 From: "Jiaxiao (mossaka) Zhou" Date: Tue, 25 Nov 2025 21:48:06 +0000 Subject: [PATCH 2/2] fix: update firewall log parser tests to validate non-standard formats Signed-off-by: Jiaxiao (mossaka) Zhou --- pkg/workflow/js/parse_firewall_logs.test.cjs | 78 +++++++++++--------- 1 file changed, 42 insertions(+), 36 deletions(-) diff --git a/pkg/workflow/js/parse_firewall_logs.test.cjs b/pkg/workflow/js/parse_firewall_logs.test.cjs index 409e5170069..4bf365afa95 100644 --- a/pkg/workflow/js/parse_firewall_logs.test.cjs +++ b/pkg/workflow/js/parse_firewall_logs.test.cjs @@ -71,20 +71,22 @@ describe("parse_firewall_logs.cjs", () => { ).toBeNull(); }); - test("should return null for invalid client IP:port format", () => { - expect( - parseFirewallLogLine( - '1761332530.474 Accepting api.github.com:443 140.82.112.22:443 1.1 CONNECT 200 TCP_TUNNEL:HIER_DIRECT api.github.com:443 "-"' - ) - ).toBeNull(); + test("should parse line with non-standard client IP:port format", () => { + const result = parseFirewallLogLine( + '1761332530.474 Accepting api.github.com:443 140.82.112.22:443 1.1 CONNECT 200 TCP_TUNNEL:HIER_DIRECT api.github.com:443 "-"' + ); + expect(result).not.toBeNull(); + expect(result.clientIpPort).toBe("Accepting"); + expect(result.domain).toBe("api.github.com:443"); }); - test("should return null for invalid domain format", () => { - expect( - parseFirewallLogLine( - '1761332530.474 172.30.0.20:35288 DNS 140.82.112.22:443 1.1 CONNECT 200 TCP_TUNNEL:HIER_DIRECT api.github.com:443 "-"' - ) - ).toBeNull(); + test("should parse line with non-standard domain format", () => { + const result = parseFirewallLogLine( + '1761332530.474 172.30.0.20:35288 DNS 140.82.112.22:443 1.1 CONNECT 200 TCP_TUNNEL:HIER_DIRECT api.github.com:443 "-"' + ); + expect(result).not.toBeNull(); + expect(result.domain).toBe("DNS"); + expect(result.clientIpPort).toBe("172.30.0.20:35288"); }); test("should return null for lines with fewer than 10 fields", () => { @@ -93,36 +95,40 @@ describe("parse_firewall_logs.cjs", () => { expect(parseFirewallLogLine("Accepting connection")).toBeNull(); }); - test("should return null for invalid dest IP:port format", () => { - expect( - parseFirewallLogLine( - '1761332530.474 172.30.0.20:35288 api.github.com:443 Local 1.1 CONNECT 200 TCP_TUNNEL:HIER_DIRECT api.github.com:443 "-"' - ) - ).toBeNull(); + test("should parse line with non-standard dest IP:port format", () => { + const result = parseFirewallLogLine( + '1761332530.474 172.30.0.20:35288 api.github.com:443 Local 1.1 CONNECT 200 TCP_TUNNEL:HIER_DIRECT api.github.com:443 "-"' + ); + expect(result).not.toBeNull(); + expect(result.destIpPort).toBe("Local"); + expect(result.domain).toBe("api.github.com:443"); }); - test("should return null for invalid status code", () => { - expect( - parseFirewallLogLine( - '1761332530.474 172.30.0.20:35288 api.github.com:443 140.82.112.22:443 1.1 CONNECT Swap TCP_TUNNEL:HIER_DIRECT api.github.com:443 "-"' - ) - ).toBeNull(); + test("should parse line with non-numeric status code", () => { + const result = parseFirewallLogLine( + '1761332530.474 172.30.0.20:35288 api.github.com:443 140.82.112.22:443 1.1 CONNECT Swap TCP_TUNNEL:HIER_DIRECT api.github.com:443 "-"' + ); + expect(result).not.toBeNull(); + expect(result.status).toBe("Swap"); + expect(result.decision).toBe("TCP_TUNNEL:HIER_DIRECT"); }); - test("should return null for invalid decision format", () => { - expect( - parseFirewallLogLine( - '1761332530.474 172.30.0.20:35288 api.github.com:443 140.82.112.22:443 1.1 CONNECT 200 Waiting api.github.com:443 "-"' - ) - ).toBeNull(); + test("should parse line with non-standard decision format", () => { + const result = parseFirewallLogLine( + '1761332530.474 172.30.0.20:35288 api.github.com:443 140.82.112.22:443 1.1 CONNECT 200 Waiting api.github.com:443 "-"' + ); + expect(result).not.toBeNull(); + expect(result.decision).toBe("Waiting"); + expect(result.status).toBe("200"); }); - test("should return null for line with pipe character in domain position", () => { - expect( - parseFirewallLogLine( - '1761332530.474 172.30.0.20:35288 pinger|test 140.82.112.22:443 1.1 CONNECT 200 TCP_TUNNEL:HIER_DIRECT api.github.com:443 "-"' - ) - ).toBeNull(); + test("should parse line with pipe character in domain position", () => { + const result = parseFirewallLogLine( + '1761332530.474 172.30.0.20:35288 pinger|test 140.82.112.22:443 1.1 CONNECT 200 TCP_TUNNEL:HIER_DIRECT api.github.com:443 "-"' + ); + expect(result).not.toBeNull(); + expect(result.domain).toBe("pinger|test"); + expect(result.decision).toBe("TCP_TUNNEL:HIER_DIRECT"); }); });