From dfea38a637621bb1d313967f35cd24817088abdf Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 24 Nov 2025 12:12:57 +0000 Subject: [PATCH 1/3] Initial plan From 3917379bef9da6c74159c2d1578296005787f599 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 24 Nov 2025 12:17:20 +0000 Subject: [PATCH 2/3] Apply all TypeScript and security fixes to SearchResultsListItem Co-authored-by: reakaleek <16325797+reakaleek@users.noreply.github.com> --- .../SearchResults/SearchResultsListItem.tsx | 36 ++++++++----------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/src/Elastic.Documentation.Site/Assets/web-components/SearchOrAskAi/Search/SearchResults/SearchResultsListItem.tsx b/src/Elastic.Documentation.Site/Assets/web-components/SearchOrAskAi/Search/SearchResults/SearchResultsListItem.tsx index cafcc15d6..a14ace759 100644 --- a/src/Elastic.Documentation.Site/Assets/web-components/SearchOrAskAi/Search/SearchResults/SearchResultsListItem.tsx +++ b/src/Elastic.Documentation.Site/Assets/web-components/SearchOrAskAi/Search/SearchResults/SearchResultsListItem.tsx @@ -14,7 +14,7 @@ import { memo, useMemo } from 'react' interface SearchResultListItemProps { item: SearchResultItem index: number - onKeyDown?: (e: React.KeyboardEvent, index: number) => void + onKeyDown?: (e: React.KeyboardEvent, index: number) => void setRef?: (element: HTMLAnchorElement | null, index: number) => void } @@ -37,15 +37,8 @@ export function SearchResultListItem({ setRef?.(el, index)} onKeyDown={(e) => { - if (e.key === 'Enter') { - window.location.href = result.url - } else { - // Type mismatch: event is from anchor but handler expects HTMLLIElement - onKeyDown?.( - e as unknown as React.KeyboardEvent, - index - ) - } + // Pass key event to parent if needed + onKeyDown?.(e, index) }} css={css` display: flex; @@ -106,7 +99,7 @@ export function SearchResultListItem({ `} > {result.highlightedBody ? ( - ) : ( @@ -171,27 +164,28 @@ function Breadcrumbs({ parents }: { parents: SearchResultItem['parents'] }) { ) } -const SanitizedHtmlContent = memo( +const HighlightedContent = memo( ({ htmlContent }: { htmlContent: string }) => { const processed = useMemo(() => { if (!htmlContent) return '' - const sanitized = DOMPurify.sanitize(htmlContent, { - ALLOWED_TAGS: ['mark'], - ALLOWED_ATTR: [], - KEEP_CONTENT: true, - }) + let htmlToSanitize = htmlContent - const temp = document.createElement('div') - temp.innerHTML = sanitized - const text = temp.textContent || '' + // Extract text content by stripping HTML tags (only are allowed anyway) + const text = htmlContent.replace(/<[^>]+>/g, '') || '' const firstChar = text.trim()[0] // Add ellipsis when text starts mid-sentence to indicate continuation if (firstChar && /[a-z]/.test(firstChar)) { - return '… ' + sanitized + htmlToSanitize = '… ' + htmlContent } + const sanitized = DOMPurify.sanitize(htmlToSanitize, { + ALLOWED_TAGS: ['mark'], + ALLOWED_ATTR: [], + KEEP_CONTENT: true, + }) + return sanitized }, [htmlContent]) From bb287b21d953a91ba27bbbc2382020b4249dc294 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 24 Nov 2025 12:22:40 +0000 Subject: [PATCH 3/3] Add clarifying comments for security and code review feedback Co-authored-by: reakaleek <16325797+reakaleek@users.noreply.github.com> --- .../Search/SearchResults/SearchResultsListItem.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Elastic.Documentation.Site/Assets/web-components/SearchOrAskAi/Search/SearchResults/SearchResultsListItem.tsx b/src/Elastic.Documentation.Site/Assets/web-components/SearchOrAskAi/Search/SearchResults/SearchResultsListItem.tsx index a14ace759..3fff2261d 100644 --- a/src/Elastic.Documentation.Site/Assets/web-components/SearchOrAskAi/Search/SearchResults/SearchResultsListItem.tsx +++ b/src/Elastic.Documentation.Site/Assets/web-components/SearchOrAskAi/Search/SearchResults/SearchResultsListItem.tsx @@ -171,7 +171,9 @@ const HighlightedContent = memo( let htmlToSanitize = htmlContent - // Extract text content by stripping HTML tags (only are allowed anyway) + // Extract text content by stripping HTML tags for lowercase check only + // This text is NOT used for rendering - only for ellipsis detection logic + // lgtm[js/incomplete-multi-character-sanitization] const text = htmlContent.replace(/<[^>]+>/g, '') || '' const firstChar = text.trim()[0] @@ -180,6 +182,7 @@ const HighlightedContent = memo( htmlToSanitize = '… ' + htmlContent } + // All content is sanitized by DOMPurify before rendering const sanitized = DOMPurify.sanitize(htmlToSanitize, { ALLOWED_TAGS: ['mark'], ALLOWED_ATTR: [],