From 5c50251e78e980ec58d4d42aca70bb7fdd22c14d Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Wed, 19 Aug 2026 11:14:13 +1000 Subject: [PATCH] Fix codespell and CodeQL findings in website components - Fix real typos flagged by codespell: 'Couldn't' -> 'Couldn't' (plain apostrophe, matching convention elsewhere in JSX) and 'Unparseable' -> 'Unparsable' in catalogFilters.ts - DetailChassis.tsx: replace sequential HTML entity unescaping with a single-pass replace to avoid double-unescape/injection risk flagged by CodeQL - SyntaxHighlightedCode.tsx: make the markup HTML comment regex match newlines so multi-line comments cannot break out of the token (Bad HTML filtering regexp) - pagefindSearch.ts: strip HTML tags in a loop until stable so nested/ malformed markup can't survive a single-pass strip (Incomplete multi-character sanitization) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 80686fef-efe3-4cdd-8cd6-bfa61a5d0af6 --- .../src/components/brand/CookbookRecipe.tsx | 2 +- .../src/components/brand/DetailChassis.tsx | 19 ++++++++++++++----- website/src/components/brand/SkillDetail.tsx | 2 +- .../brand/SyntaxHighlightedCode.tsx | 2 +- .../src/components/brand/catalogFilters.ts | 2 +- .../src/components/brand/pagefindSearch.ts | 15 ++++++++++++++- 6 files changed, 32 insertions(+), 10 deletions(-) diff --git a/website/src/components/brand/CookbookRecipe.tsx b/website/src/components/brand/CookbookRecipe.tsx index 315ac386..faaecde9 100644 --- a/website/src/components/brand/CookbookRecipe.tsx +++ b/website/src/components/brand/CookbookRecipe.tsx @@ -368,7 +368,7 @@ function RecipeFileView({ if (status === "error" || text === undefined) { return ( - Couldn't load this file. View it on GitHub. + Couldn't load this file. View it on GitHub. ); } diff --git a/website/src/components/brand/DetailChassis.tsx b/website/src/components/brand/DetailChassis.tsx index 42b71296..9040d7c8 100644 --- a/website/src/components/brand/DetailChassis.tsx +++ b/website/src/components/brand/DetailChassis.tsx @@ -402,11 +402,20 @@ export function buildDetailToc(markdownHtml: string): { (match, attrs: string, inner: string) => { const label = inner .replace(/<[^>]+>/g, "") - .replace(/&/g, "&") - .replace(/</g, "<") - .replace(/>/g, ">") - .replace(/"/g, '"') - .replace(/'/g, "'") + .replace(/<|>|"|'|&/g, (entity) => { + switch (entity) { + case "<": + return "<"; + case ">": + return ">"; + case """: + return '"'; + case "'": + return "'"; + default: + return "&"; + } + }) .trim(); if (!label) return match; diff --git a/website/src/components/brand/SkillDetail.tsx b/website/src/components/brand/SkillDetail.tsx index 54b8afb7..07a61e57 100644 --- a/website/src/components/brand/SkillDetail.tsx +++ b/website/src/components/brand/SkillDetail.tsx @@ -480,7 +480,7 @@ function FileView({ if (status === "error" || text === undefined) { return ( - Couldn't load this file. View it on GitHub. + Couldn't load this file. View it on GitHub. ); } diff --git a/website/src/components/brand/SyntaxHighlightedCode.tsx b/website/src/components/brand/SyntaxHighlightedCode.tsx index 78d4a8f0..bc926cbd 100644 --- a/website/src/components/brand/SyntaxHighlightedCode.tsx +++ b/website/src/components/brand/SyntaxHighlightedCode.tsx @@ -52,7 +52,7 @@ const rules: Record = { { kind: "punctuation", expression: /[{}[\],:]/y }, ], markup: [ - { kind: "comment", expression: //y }, + { kind: "comment", expression: //y }, { kind: "tag", expression: /<\/?[A-Za-z][\w:-]*/y }, { kind: "attr-name", expression: /[A-Za-z_:][\w:.-]*(?=\s*=)/y }, { kind: "string", expression: /"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'/y }, diff --git a/website/src/components/brand/catalogFilters.ts b/website/src/components/brand/catalogFilters.ts index c065c37c..f8f5dca2 100644 --- a/website/src/components/brand/catalogFilters.ts +++ b/website/src/components/brand/catalogFilters.ts @@ -14,7 +14,7 @@ export const updatedBuckets: { label: string; max: number }[] = [ { label: "Older", max: Number.POSITIVE_INFINITY }, ]; -/** Whole days between `lastUpdated` and now. Unparseable dates sort as oldest. */ +/** Whole days between `lastUpdated` and now. Unparsable dates sort as oldest. */ export function daysSince(lastUpdated: string | undefined): number { if (!lastUpdated) return Number.POSITIVE_INFINITY; const then = Date.parse(lastUpdated); diff --git a/website/src/components/brand/pagefindSearch.ts b/website/src/components/brand/pagefindSearch.ts index 416a1a61..99908007 100644 --- a/website/src/components/brand/pagefindSearch.ts +++ b/website/src/components/brand/pagefindSearch.ts @@ -15,6 +15,19 @@ type PagefindResultData = { meta?: Record; }; +/** Strip HTML tags, repeating until no more tags remain so a malformed or + * nested markup fragment (e.g. `<