Commit 0dee7bc
authored
feat(parsers): add Qualys VMDR CSV parser (#14453)
* docs: add Qualys VMDR parser design document
Design document for new Qualys VMDR parser supporting QID and CVE
CSV export formats. Includes field mappings, architecture decisions,
and test strategy.
Authored by T. Walker - DefectDojo
* docs: add qualys_vmdr implementation plan
Detailed TDD implementation plan with 13 tasks covering:
- Package structure and test files
- helpers.py, qid_parser.py, cve_parser.py, parser.py
- Comprehensive test coverage
- Documentation following enhanced format structure
Authored by T. Walker - DefectDojo
* feat(parser): add qualys_vmdr package structure
Authored by T. Walker - DefectDojo
* test(parser): add QID format test files for qualys_vmdr
Authored by T. Walker - DefectDojo
* test(parser): add CVE format test files for qualys_vmdr
Authored by T. Walker - DefectDojo
* test(parser): add failing tests for qualys_vmdr basic structure
TDD: Tests written before implementation.
Authored by T. Walker - DefectDojo
* feat(parser): add helpers module for qualys_vmdr
Shared utilities for severity mapping, date parsing, description
building, endpoint parsing, and tag handling.
Authored by T. Walker - DefectDojo
* feat(parser): add QID format parser for qualys_vmdr
Parses QID-centric CSV exports from Qualys VMDR.
Authored by T. Walker - DefectDojo
* feat(parser): add CVE format parser for qualys_vmdr
Parses CVE-centric CSV exports with CVSS scores from NVD.
Authored by T. Walker - DefectDojo
* feat(parser): add main qualys_vmdr parser with format detection
Auto-detects QID vs CVE format and delegates to appropriate parser.
Authored by T. Walker - DefectDojo
* test(parser): add field validation tests for qualys_vmdr
Comprehensive tests for severity mapping, endpoints, tags, CVE fields.
Also fixed CSV test files to use standard format and updated parser
format detection for proper CVE format recognition.
Authored by T. Walker - DefectDojo
* docs(parser): add qualys_vmdr parser documentation
Includes field mapping tables, severity conversion, and processing notes.
Authored by T. Walker - DefectDojo
* fix: handle non-standard Qualys CSV format in VMDR parser
The Qualys VMDR export uses a non-standard CSV format where fields are
delimited by ,"" instead of the standard "," format. This caused the
parser to fail when processing real Qualys exports.
Changes:
- Add format detection to distinguish standard vs non-standard CSV
- Add custom parsing functions for non-standard Qualys format
- Handle multi-line records with embedded newlines
- Both parsers (QID and CVE) now use the unified parsing logic
The parser now correctly handles both test files (standard CSV) and
real Qualys exports (non-standard format).
Authored by T. Walker - DefectDojo
* fix: correctly parse escaped quotes in Qualys non-standard CSV format
The previous parsing logic used simple string splitting on ,"" which
failed when field values contained escaped quotes (""""). This caused
field misalignment and empty/default values in parsed findings.
The fix:
1. Remove outer quotes from the row
2. Unescape row-level quote doubling ("" -> ")
3. Parse the result as standard CSV using Python's csv module
This correctly handles fields containing embedded quotes like:
"Description with ""quoted text"" inside"
Authored by T. Walker - DefectDojo
* fix: correct multi-line record detection in Qualys CSV parser
The previous end-of-record detection incorrectly treated any line ending
with a single quote as a complete record. This caused multi-line records
(where Results field contains embedded newlines) to be split incorrectly.
In Qualys non-standard format, multi-field records always end with """
(the last field's closing "" plus the record's closing "). Single quote
endings within a record are just field content, not record terminators.
Authored by T. Walker - DefectDojo
* feat: add CVE to vulnerability_ids in CVE parser
Map the CVE field to unsaved_vulnerability_ids so it appears in the
Vulnerability IDs column in DefectDojo, in addition to vuln_id_from_tool.
Authored by T. Walker - DefectDojo
* docs: update Qualys VMDR documentation for vulnerability_ids mapping
Add documentation that CVE is mapped to both vuln_id_from_tool and
unsaved_vulnerability_ids for proper CVE tracking in DefectDojo.
Authored by T. Walker - DefectDojo
* fix: use trailing-quote heuristic for multi-line record boundary detection
Replace field-count-based record boundary detection in the Qualys VMDR
nonstandard CSV parser with a trailing-quote heuristic. The old approach
re-parsed accumulated rows each iteration and failed on malformed quote
patterns (e.g. #table cols=""3"") that produce incorrect field counts.
The new _is_record_end_line() helper counts trailing quotes: exactly 3
means record end, 4+ means record end only if preceded by a comma
(empty field). This is O(1) per line and correctly handles all known
Qualys export patterns. Also fixes pre-existing ruff lint issues in the
state machine parser.
Authored by T. Walker - DefectDojo
* chore: remove internal planning docs from branch
These design/plan files were used during development and should not
be included in the upstream PR.
Authored by T. Walker - DefectDojo
* docs: add CSV format handling and data cleaning details to Qualys VMDR docs
Document the non-standard CSV format, multi-line record support,
metadata line detection, HTML stripping, and null marker filtering.
Authored by T. Walker - DefectDojo
* fix(parser): support V3_FEATURE_LOCATIONS in Qualys VMDR parser
Replace direct Endpoint() instantiation with the new LocationData API when
V3_FEATURE_LOCATIONS is enabled, falling back to Endpoint for the legacy
code path. Tests pass under both flag states.
Authored by T. Walker - DefectDojo1 parent 29fb41e commit 0dee7bc
16 files changed
Lines changed: 1018 additions & 0 deletions
File tree
- docs/content/supported_tools/parsers/file
- dojo
- settings
- tools/qualys_vmdr
- unittests
- scans/qualys_vmdr
- tools
Lines changed: 149 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1096 | 1096 | | |
1097 | 1097 | | |
1098 | 1098 | | |
| 1099 | + | |
1099 | 1100 | | |
1100 | 1101 | | |
1101 | 1102 | | |
| |||
1365 | 1366 | | |
1366 | 1367 | | |
1367 | 1368 | | |
| 1369 | + | |
1368 | 1370 | | |
1369 | 1371 | | |
1370 | 1372 | | |
| |||
Whitespace-only changes.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
0 commit comments