Conversation
…ixes - Strip HTML tags from recent-view title/subtitle/case-hit text before persisting to localStorage (new stripHtmlTags in sanitizeHtml.ts, applied in useRecordRecentView). Not exploitable today — every render site uses plain JSX text interpolation, which React already escapes — but this closes the gap against a future change that renders it less safely (e.g. dangerouslySetInnerHTML). - Shrink the QuickNav search trigger's width once something is pinned, so PinnedTabs (sharing the header's flexible middle slot) has room to show pinned chips instead of getting squeezed. - Prevent "CSM Portal" from wrapping onto a second line when several pinned tabs plus the search bar leave little room in the header row — Header.Brand now has flexShrink: 0 and Header.BrandTitle has whiteSpace: nowrap, so PinnedTabs' own horizontal scroll absorbs the squeeze instead. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Warning Review limit reached
Next review available in: 44 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughThe changes preserve portal header branding, resize the quick-navigation trigger when pinned items exist, and strip HTML tags from recent-view text before persistence. Blank HTML detection now reuses the shared tag-stripping helper, with tests covering sanitized recent-view fields. ChangesPortal layout updates
Recent-view text sanitization
Estimated code review effort: 3 (Moderate) | ~20 minutes Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/csm-portal/webapp/src/utils/sanitizeHtml.ts`:
- Around line 48-50: Replace the regex in stripHtmlTags with
DOMPurify.sanitize(text, { ALLOWED_TAGS: [] }) to remove HTML safely while
preserving legitimate bracketed text. In
apps/csm-portal/webapp/src/features/csm-recent/hooks/useRecentViews.test.ts
lines 89-94, update the stored title assertion to expect "Case 1 " to reflect
script-content removal.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 3d02a55c-9b09-4742-ae63-f73035a947fc
📒 Files selected for processing (5)
apps/csm-portal/webapp/src/components/header/Brand.tsxapps/csm-portal/webapp/src/features/csm-recent/components/QuickNav.tsxapps/csm-portal/webapp/src/features/csm-recent/hooks/useRecentViews.test.tsapps/csm-portal/webapp/src/features/csm-recent/hooks/useRecentViews.tsapps/csm-portal/webapp/src/utils/sanitizeHtml.ts
The <[^>]*> regex treated any <...> run as a tag, so plain text with
comparison operators (e.g. "x < y > z") would lose everything between
the brackets. Switch stripHtmlTags to DOMPurify.sanitize(text, {
ALLOWED_TAGS: [] }) for real HTML parsing instead.
DOMPurify's output alone isn't quite sufficient for plain-text use,
though: it HTML-entity-encodes a stray "<"/">" that isn't part of a real
tag (its output is meant for HTML re-insertion), which would otherwise
render as the literal text "<" through plain JSX interpolation.
Round-trip through a detached element's innerHTML -> textContent to
decode those entities back to plain characters — safe here specifically
because the input to that second innerHTML assignment has already been
fully tag-stripped by DOMPurify.
Adds a regression test for the angle-bracket case, and updates the
existing sanitization test's expectation (DOMPurify drops a <script>
element's text content along with its tags, not just the tag markup).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Summary
Follow-up to #1174 / #1175 (both merged) — the QuickNav search palette rework and its recent-views storage fix.
title/subtitle/case-hit text recorded into the recent-viewslocalStoragecache come from backend/customer free text (case subject, account/project name, assignee name). Every current render site uses plain JSX text interpolation, which React already escapes safely — but addedstripHtmlTags(src/utils/sanitizeHtml.ts) and apply it inuseRecordRecentViewas defense-in-depth, so stored text can't do anything if a future change ever renders it less safely (e.g.dangerouslySetInnerHTML).PinnedTabs(which shares the header's flexible middle slot) to actually show the pinned chips instead of getting squeezed.PinnedTabsrow.Header.Brandnow hasflexShrink: 0andHeader.BrandTitlehaswhiteSpace: "nowrap", so the brand never wraps.Test plan
tsc -b --noEmitpasseseslintpasses on all touched filesvitest runpasses, including a new regression test asserting HTML tags are stripped from title/subtitle/case-hit text before storagevite buildsucceeds🤖 Generated with Claude Code
Summary by CodeRabbit
Bug Fixes
Tests