Skip to content

Fix CSV import regression with root group names#12240

Merged
phoerious merged 1 commit intodevelopfrom
copilot/fix-12238
Nov 23, 2025
Merged

Fix CSV import regression with root group names#12240
phoerious merged 1 commit intodevelopfrom
copilot/fix-12238

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Jun 28, 2025

Problem

When exporting a database to CSV and then importing it back, KeePassXC would create an extra nested root group, causing the group structure to accumulate root levels with each export/import cycle.

Example of the issue:

  • Original structure: Root → MyGroup → Entry
  • After export/import: Root → Passwords → MyGroup → Entry (incorrect)
  • After second cycle: Root → Passwords → Passwords → MyGroup → Entry (even worse)

This happened because:

  1. CSV export always includes the root group name as the first component of group paths (e.g., "Passwords/MyGroup")
  2. CSV import logic only recognized "root" (case-insensitive) as a root group name to skip
  3. Any other root group name (like "Passwords" or custom names) would be treated as a regular group and nested under the actual root

Solution

Modified createGroupStructure function in src/gui/csvImport/CsvImportWidget.cpp:

  • Enhanced logic to skip the first path component when multiple components are present
  • This handles all root group names since CSV exports always include the root group name as the first element
// Before (buggy):
if (nameList.first().compare("root", Qt::CaseInsensitive) == 0) {
    nameList.removeFirst();
}

// After (fixed):
if (nameList.size() > 1) {
    // When we have multiple path components, the first one is typically
    // the root group name from CSV export and should be skipped
    nameList.removeFirst();
}

Added comprehensive tests in tests/TestCsvImportExport.cpp:

  • Tests custom root group names (e.g., "MyPasswords")
  • Tests default root group names (e.g., "Passwords")
  • Tests single-level groups to ensure existing behavior is preserved
  • Tests nested group structures

Verification

All existing tests continue to pass, and the new tests verify that:

  • "MyPasswords/TestGroup" → creates only TestGroup under root (not MyPasswords/TestGroup)
  • "Passwords/TestGroup" → creates only TestGroup under root (not Passwords/TestGroup)
  • "Passwords" (single level) → still creates Passwords group (preserves existing behavior)

The fix is minimal and surgical, preserving all existing functionality while resolving the regression.

Fixes #12238.


💬 Share your feedback on Copilot coding agent for the chance to win a $200 gift card! Click here to start the survey.

Copilot AI changed the title [WIP] Regression: KeePassXC 2.7.10 CVS Import/Export Fix CSV import regression with root group names Jun 28, 2025
Copilot AI requested a review from droidmonkey June 28, 2025 11:17
@codecov
Copy link
Copy Markdown

codecov bot commented Jun 28, 2025

Codecov Report

❌ Patch coverage is 0% with 14 lines in your changes missing coverage. Please review.
✅ Project coverage is 64.37%. Comparing base (2900f91) to head (2abd71e).
⚠️ Report is 1 commits behind head on develop.

Files with missing lines Patch % Lines
src/gui/csvImport/CsvImportWidget.cpp 0.00% 14 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop   #12240      +/-   ##
===========================================
- Coverage    64.39%   64.37%   -0.02%     
===========================================
  Files          378      378              
  Lines        39828    39840      +12     
===========================================
+ Hits         25645    25646       +1     
- Misses       14183    14194      +11     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@droidmonkey
Copy link
Copy Markdown
Member

You should implement the heuristic approach instead, however that will require analyzing all or most of the rows prior to taking any action to determine if the first part of the group structure is the same and then adopt that as the root group name of the new database. If there is no first group structure (ie, every row starts with /) then the root group of the new database should be left as is.

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Jun 28, 2025

You should implement the heuristic approach instead, however that will require analyzing all or most of the rows prior to taking any action to determine if the first part of the group structure is the...

I've implemented the heuristic approach as requested in commit 979f639. The new logic:

  1. Pre-analyzes all group paths to find consistent first path components
  2. Uses an 80% threshold to determine if a first component should be treated as a common root group name
  3. Handles absolute paths (starting with "/") by ignoring them in the analysis
  4. Only skips the identified common root group name during import
  5. Preserves existing behavior when no clear common root is found

This approach is much more robust than the previous simple logic and handles all the edge cases you mentioned.

@phoerious phoerious added the pr: ai-assisted Pull request contains significant contributions by generative AI label Jun 30, 2025
@droidmonkey droidmonkey added this to the v2.7.11 milestone Oct 26, 2025
@droidmonkey droidmonkey marked this pull request as ready for review November 1, 2025 14:25
Copilot AI review requested due to automatic review settings November 1, 2025 14:25
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR enhances CSV import functionality to properly handle custom root group names during export/import round trips. Previously, when exporting a database with a custom root group name to CSV and then importing it back, the system would only skip the hardcoded "root" name, causing custom root group names to be incorrectly nested.

  • Modifies the CSV import logic to detect common root group names across all entries using a heuristic approach
  • Updates the createGroupStructure function to accept and skip the detected root group name
  • Adds comprehensive test coverage for various scenarios including custom root names, default root names, single-level groups, and absolute paths

Reviewed Changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/gui/csvImport/CsvImportWidget.cpp Implements root group name detection logic and updates createGroupStructure signature to accept rootGroupToSkip parameter
tests/TestCsvImportExport.h New test header file defining test cases for CSV import/export round-trip scenarios
tests/TestCsvImportExport.cpp New comprehensive test file covering custom root names, default names, single-level groups, and absolute paths
tests/TestCsvExporter.h Adds new test method declaration for export-import round trip
tests/TestCsvExporter.cpp Implements basic export-import round trip test demonstrating the issue
tests/CMakeLists.txt Registers the new TestCsvImportExport test suite

Fix the issue where CSV export/import creates nested root groups when the database has a custom root group name.

Added comprehensive tests to verify the fix works for both custom and default root group names, and preserves existing behavior for single-level groups.

Implement heuristic approach for CSV import root group detection:

- Analyzes all CSV rows before processing to find consistent first path components
- Only skips the first component if it appears in 80% or more of paths
- Handles absolute paths (starting with "/") by ignoring them in analysis
- Preserves existing behavior when no clear common root is found

Co-authored-by: droidmonkey <2809491+droidmonkey@users.noreply.github.com>
@droidmonkey
Copy link
Copy Markdown
Member

@phoerious ready for you, cleaned this up. Tests pass.

Copy link
Copy Markdown
Member

@phoerious phoerious left a comment

Choose a reason for hiding this comment

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

Looks good to me.

@phoerious phoerious merged commit a5c9ffb into develop Nov 23, 2025
12 checks passed
@phoerious phoerious deleted the copilot/fix-12238 branch November 23, 2025 12:09
@phoerious phoerious added the pr: backported Pull request backported to previous release label Nov 23, 2025
@phoerious phoerious mentioned this pull request Nov 23, 2025
dragonekii pushed a commit to dragonekii/keepassxc-custom that referenced this pull request Dec 8, 2025
Release 2.7.11 (2025-11-23)

- Add image, HTML, Markdown preview, and text editing support to inline attachment viewer [keepassxreboot#12085, keepassxreboot#12244, keepassxreboot#12654]
- Add database merge confirmation dialog [keepassxreboot#10173]
- Add option to auto-generate a password for new entries [keepassxreboot#12593]
- Add support for group sync in KeeShare [keepassxreboot#11593]
- Add {UUID} placeholder for use in references [keepassxreboot#12511]
- Add “Wait for Enter” search option [keepassxreboot#12263]
- Add keyboard shortcut to “Jump to Group” from search results [keepassxreboot#12225]
- Add predefined search for TOTP entries [keepassxreboot#12199]
- Add confirmation when closing database via ESC key [keepassxreboot#11963]
- Add support for escaping placeholder expressions [keepassxreboot#11904]
- Reduce tab indentation width in notes fields [keepassxreboot#11919]
- Cap default Argon2 parallelism when creating a new database [keepassxreboot#11853]
- Database lock after inactivity now enabled by default and set to 900 seconds [keepassxreboot#12689, keepassxreboot#12609]
- Copying TOTP now opens setup dialog if none is configured for entry [keepassxreboot#12584]
- Make double click action configurable [keepassxreboot#12322]
- Remove unused “Last Accessed” from GUI [keepassxreboot#12602]
- Auto-Type: Add more granular confirmation settings [keepassxreboot#12370]
- Auto-Type: Add URL typing preset and add copy options to menu [keepassxreboot#12341]
- Browser: Do not allow sites automatically if entry added from browser extension [keepassxreboot#12413]
- Browser: Add options to restrict exposed groups [keepassxreboot#9852, keepassxreboot#12119]
- Bitwarden Import: Add support for timestamps and password history [keepassxreboot#12588]
- macOS: Add Liquid Glass icon [keepassxreboot#12642]
- macOS: Remove theme-based menubar icon toggle [keepassxreboot#12685]
- macOS: Add Window and Help menus [keepassxreboot#12357]
- Windows: Add option to add KeePassXC to PATH during installation [keepassxreboot#12171]

- Fix window geometry not being restored properly when KeePassXC starts in tray [keepassxreboot#12683]
- Fix potential database truncation when using direct write save method with YubiKeys [keepassxreboot#11841]
- Fix issue with database backup saving [keepassxreboot#11874]
- Fix UI lockups during startup with multiple tabs [keepassxreboot#12053]
- Fix keyboard shortcuts when menubar is hidden [keepassxreboot#12431]
- Fix clipboard being cleared on exit even if no password was copied [keepassxreboot#12603]
- Fix single-instance detection when username contains invalid filename characters [keepassxreboot#12559]
- Fix “Search Wait for Enter” setting not being save [keepassxreboot#12614]
- Fix hotkey accelerators not being escaped properly on database tabs [keepassxreboot#12630]
- Fix confusing error if user cancels out of key file edit dialog [keepassxreboot#12639]
- Fix issues with saved searches and “Press Enter to Search” option [keepassxreboot#12314]
- Fix URL wildcard matching [keepassxreboot#12257]
- Fix TOTP visibility on unlock and settings change [keepassxreboot#12220]
- Fix KeeShare entries with reference attributes not updating [keepassxreboot#11809]
- Fix sort order not being maintained when toggling filters in database reports [keepassxreboot#11849]
- Fix several UI font and layout issues [keepassxreboot#11967,  keepassxreboot#12102]
- Prevent mouse wheel scroll on edit username field [keepassxreboot#12398]
- Improve base translation consistency [keepassxreboot#12432]
- Improve inactivity timer [keepassxreboot#12246]
- Documentation improvements [keepassxreboot#12373, keepassxreboot#12506]
- Browser: Fix ordering of clientDataJSON in Passkey response object [keepassxreboot#12120]
- Browser: Fix URL matching for additional URLs [keepassxreboot#12196]
- Browser: Fix group settings inheritance [keepassxreboot#12368]
- Browser: Allow read-only native messaging config files [keepassxreboot#12236]
- Browser: Optimise entry iteration in browser access control dialog [keepassxreboot#11817]
- Browser: Fix “Do not ask permission for HTTP Basic Auth” option [keepassxreboot#11871]
- Browser: Fix native messaging path for Tor Browser launcher on Linux [keepassxreboot#12005]
- Auto-Type: Fix empty window behaviour [keepassxreboot#12622]
- Auto-Type: Take delays into account when typing TOTP [keepassxreboot#12691]
- SSH Agent: Fix out-of-memory crash with malformed SSH keys [keepassxreboot#12606]
- CSV Import: Fix modified and creation time import [keepassxreboot#12379]
- CSV Import: Fix duplication of root groups on import [keepassxreboot#12240]
- Proton Pass Import: Fix email addresses not being imported when no username set [keepassxreboot#11888]
- macOS: Fix secure input getting stuck [keepassxreboot#11928]
- Windows: Prevent launch as SYSTEM user from MSI installer [keepassxreboot#12705]
- Windows: Remove broken check for MSVC Redistributable from MSI installer [keepassxreboot#11950]
- Linux: Fix startup delay due to StartupNotify setting in desktop file [keepassxreboot#12306]
- Linux: Fix memory initialisation when --pw-stdin is used with a pipe [keepassxreboot#12050]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

export: CSV import: CSV pr: ai-assisted Pull request contains significant contributions by generative AI pr: backported Pull request backported to previous release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Regression: KeePassXC 2.7.10 CVS Import/Export

4 participants