Skip to content

fix(csv): quote values with carriage returns and use correct MIME type#29783

Open
PedroHenrique0713 wants to merge 1 commit into
calcom:mainfrom
PedroHenrique0713:fix/csv-sanitize-carriage-return
Open

fix(csv): quote values with carriage returns and use correct MIME type#29783
PedroHenrique0713 wants to merge 1 commit into
calcom:mainfrom
PedroHenrique0713:fix/csv-sanitize-carriage-return

Conversation

@PedroHenrique0713

Copy link
Copy Markdown

What does this PR do?

Fixes two bugs in packages/lib/csvUtils.ts, which powers the Bookings CSV export (BookingsCsvDownload) and the Users CSV export (UserListTable):

  • sanitizeValue() did not quote values containing a bare carriage return (\r). Per RFC 4180, CR is a valid record separator in CSV. An unquoted \r splits the field across two records, silently corrupting the export. Values with \n or \r\n were already quoted; only lone \r was missed.
  • downloadAsCsv() created the Blob with type: "text/plain" instead of text/csv. The wrong MIME type can cause some browsers to open the content inline rather than triggering a .csv download. The codebase's own FileUploader already recognises text/csv as the correct type.

Visual Demo (For contributors especially)

N/A — no visual change. The fix prevents CSV corruption for values containing \r (e.g. user notes, attendee names with legacy line endings) and ensures the download is recognised as CSV by all browsers.

Mandatory Tasks (DO NOT REMOVE)

  • I have self-reviewed the code (A decent size PR without self-review might be rejected).
  • I have updated the developer docs if this PR makes changes that would require a documentation change. If N/A, write N/A here and check the checkbox.
  • I confirm automated tests are in place that prove my fix is effective or that my feature works.

How should this be tested?

  • Run TZ=UTC npx vitest run packages/lib/csvUtils.test.ts — 10 tests, all pass.
  • The test suite covers: \r quoting, \n quoting, \r\n quoting, comma quoting, double-quote doubling, and the Blob MIME type assertion.
  • The \r test fails on main (expected hello\rworld to be hellorworld) and passes with this fix.

Checklist

  • I have read the contributing guide
  • My code follows the style guidelines of this project (biome check passes)
  • I have commented my code, particularly in hard-to-understand areas
  • I have checked if my changes generate no new warnings
  • My PR is not too large (>500 lines or >10 files) and should be split into smaller PRs

…ME type

Two bugs in packages/lib/csvUtils.ts:

1. sanitizeValue() did not quote values containing a bare carriage return
   (\r). Per RFC 4180, CR is a valid record separator in CSV — an unquoted
   \r splits the field across two records, silently corrupting the export.
   Values with \n or \r\n were already quoted; only lone \r was missed.
   Used by BookingsCsvDownload and UserListTable CSV exports.

2. downloadAsCsv() created the Blob with type 'text/plain' instead of
   'text/csv'. The wrong MIME type can cause some browsers to open the
   content inline rather than triggering a .csv download. The codebase's
   own FileUploader already recognises 'text/csv' as the correct type.
@github-actions

Copy link
Copy Markdown
Contributor

Welcome to Cal.diy, @PedroHenrique0713! Thanks for opening this pull request.

A few things to keep in mind:

  • This is Cal.diy, not Cal.com. Cal.diy is a community-driven, fully open-source fork of Cal.com licensed under MIT. Your changes here will be part of Cal.diy — they will not be deployed to the Cal.com production app.
  • Please review our Contributing Guidelines if you haven't already.
  • Make sure your PR title follows the Conventional Commits format.

A maintainer will review your PR soon. Thanks for contributing!

@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Updated CSV escaping to quote values containing carriage returns, alongside commas and line breaks. Added tests for sanitizeValue, objectsToCsv, and embedded line handling. Changed downloaded CSV Blobs from text/plain to text/csv;charset=utf-8 and added MIME type coverage.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the two main CSV fixes: quoting carriage returns and using the correct MIME type.
Description check ✅ Passed The description is directly related to the changeset and matches the implemented CSV export fixes and tests.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
packages/lib/csvUtils.test.ts (1)

4-6: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Prevent test pollution by restoring stubbed globals.

vi.stubGlobal is used in this test file to overwrite the global URL and document objects. If Vitest is not configured to automatically unstub globals in your setup, these overridden objects will leak into other tests running in the same environment, potentially breaking tests that expect a full standard document or URL object. Add vi.unstubAllGlobals() to the cleanup hook to ensure isolation.

♻️ Proposed fix
 afterEach(() => {
   vi.restoreAllMocks();
+  vi.unstubAllGlobals();
 });
🤖 Prompt for 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.

In `@packages/lib/csvUtils.test.ts` around lines 4 - 6, Update the test file’s
afterEach cleanup hook to call vi.unstubAllGlobals() alongside
vi.restoreAllMocks(), ensuring globals stubbed by tests are restored after each
case.
🤖 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.

Nitpick comments:
In `@packages/lib/csvUtils.test.ts`:
- Around line 4-6: Update the test file’s afterEach cleanup hook to call
vi.unstubAllGlobals() alongside vi.restoreAllMocks(), ensuring globals stubbed
by tests are restored after each case.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 903efb13-7d58-4ad6-938e-9218874ba90d

📥 Commits

Reviewing files that changed from the base of the PR and between f004349 and 32c87c4.

📒 Files selected for processing (2)
  • packages/lib/csvUtils.test.ts
  • packages/lib/csvUtils.ts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant