@mitre/hdf-converters 2.12.2 → 2.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -24
- package/lib/data/converters/csv2json.d.ts +1 -0
- package/lib/data/converters/csv2json.d.ts.map +1 -0
- package/lib/data/converters/csv2json.js +1 -1
- package/lib/data/converters/csv2json.js.map +1 -1
- package/lib/data/converters/xml2json.d.ts +1 -0
- package/lib/data/converters/xml2json.d.ts.map +1 -0
- package/lib/data/converters/xml2json.js +6 -25
- package/lib/data/converters/xml2json.js.map +1 -1
- package/lib/data/reverse-html-mapper/convert-to-embedded-strings.d.ts +2 -0
- package/lib/data/reverse-html-mapper/convert-to-embedded-strings.d.ts.map +1 -0
- package/lib/data/reverse-html-mapper/convert-to-embedded-strings.js +13 -0
- package/lib/data/reverse-html-mapper/convert-to-embedded-strings.js.map +1 -0
- package/lib/index.d.ts +6 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +23 -8
- package/lib/index.js.map +1 -1
- package/lib/package.json +28 -45
- package/lib/src/anchore-grype-mapper.d.ts +1 -0
- package/lib/src/anchore-grype-mapper.d.ts.map +1 -0
- package/lib/src/anchore-grype-mapper.js +7 -1
- package/lib/src/anchore-grype-mapper.js.map +1 -1
- package/lib/src/asff-mapper/asff-mapper.d.ts +1 -0
- package/lib/src/asff-mapper/asff-mapper.d.ts.map +1 -0
- package/lib/src/asff-mapper/asff-mapper.js +276 -242
- package/lib/src/asff-mapper/asff-mapper.js.map +1 -1
- package/lib/src/asff-mapper/case-cms-inspec.d.ts +1 -0
- package/lib/src/asff-mapper/case-cms-inspec.d.ts.map +1 -0
- package/lib/src/asff-mapper/case-cms-inspec.js +18 -9
- package/lib/src/asff-mapper/case-cms-inspec.js.map +1 -1
- package/lib/src/asff-mapper/case-firewall-manager.d.ts +1 -0
- package/lib/src/asff-mapper/case-firewall-manager.d.ts.map +1 -0
- package/lib/src/asff-mapper/case-firewall-manager.js +18 -9
- package/lib/src/asff-mapper/case-firewall-manager.js.map +1 -1
- package/lib/src/asff-mapper/case-guardduty.d.ts +1 -0
- package/lib/src/asff-mapper/case-guardduty.d.ts.map +1 -0
- package/lib/src/asff-mapper/case-guardduty.js +18 -9
- package/lib/src/asff-mapper/case-guardduty.js.map +1 -1
- package/lib/src/asff-mapper/case-inspector.d.ts +1 -0
- package/lib/src/asff-mapper/case-inspector.d.ts.map +1 -0
- package/lib/src/asff-mapper/case-inspector.js +18 -9
- package/lib/src/asff-mapper/case-inspector.js.map +1 -1
- package/lib/src/asff-mapper/case-previously-hdf.d.ts +1 -0
- package/lib/src/asff-mapper/case-previously-hdf.d.ts.map +1 -0
- package/lib/src/asff-mapper/case-previously-hdf.js +28 -15
- package/lib/src/asff-mapper/case-previously-hdf.js.map +1 -1
- package/lib/src/asff-mapper/case-prowler.d.ts +1 -0
- package/lib/src/asff-mapper/case-prowler.d.ts.map +1 -0
- package/lib/src/asff-mapper/case-prowler.js +19 -9
- package/lib/src/asff-mapper/case-prowler.js.map +1 -1
- package/lib/src/asff-mapper/case-security-hub.d.ts +1 -0
- package/lib/src/asff-mapper/case-security-hub.d.ts.map +1 -0
- package/lib/src/asff-mapper/case-security-hub.js +24 -9
- package/lib/src/asff-mapper/case-security-hub.js.map +1 -1
- package/lib/src/asff-mapper/case-trivy.d.ts +1 -0
- package/lib/src/asff-mapper/case-trivy.d.ts.map +1 -0
- package/lib/src/asff-mapper/case-trivy.js +18 -9
- package/lib/src/asff-mapper/case-trivy.js.map +1 -1
- package/lib/src/aws-config-mapper.d.ts +1 -0
- package/lib/src/aws-config-mapper.d.ts.map +1 -0
- package/lib/src/aws-config-mapper.js +38 -22
- package/lib/src/aws-config-mapper.js.map +1 -1
- package/lib/src/base-converter.d.ts +2 -1
- package/lib/src/base-converter.d.ts.map +1 -0
- package/lib/src/base-converter.js +51 -33
- package/lib/src/base-converter.js.map +1 -1
- package/lib/src/burpsuite-mapper.d.ts +7 -0
- package/lib/src/burpsuite-mapper.d.ts.map +1 -0
- package/lib/src/burpsuite-mapper.js +115 -88
- package/lib/src/burpsuite-mapper.js.map +1 -1
- package/lib/src/checkov-mapper.d.ts +67 -0
- package/lib/src/checkov-mapper.d.ts.map +1 -0
- package/lib/src/checkov-mapper.js +240 -0
- package/lib/src/checkov-mapper.js.map +1 -0
- package/lib/src/ckl-mapper/checklist-jsonix-converter.d.ts +17 -0
- package/lib/src/ckl-mapper/checklist-jsonix-converter.d.ts.map +1 -0
- package/lib/src/ckl-mapper/checklist-jsonix-converter.js +59 -25
- package/lib/src/ckl-mapper/checklist-jsonix-converter.js.map +1 -1
- package/lib/src/ckl-mapper/checklist-mapper.d.ts +35 -0
- package/lib/src/ckl-mapper/checklist-mapper.d.ts.map +1 -0
- package/lib/src/ckl-mapper/checklist-mapper.js +264 -155
- package/lib/src/ckl-mapper/checklist-mapper.js.map +1 -1
- package/lib/src/ckl-mapper/checklist-metadata-utils.d.ts +1 -0
- package/lib/src/ckl-mapper/checklist-metadata-utils.d.ts.map +1 -0
- package/lib/src/ckl-mapper/checklist-metadata-utils.js +38 -16
- package/lib/src/ckl-mapper/checklist-metadata-utils.js.map +1 -1
- package/lib/src/ckl-mapper/checklistJsonix.d.ts +6 -0
- package/lib/src/ckl-mapper/checklistJsonix.d.ts.map +1 -0
- package/lib/src/ckl-mapper/checklistJsonix.js +8 -8
- package/lib/src/ckl-mapper/checklistJsonix.js.map +1 -1
- package/lib/src/ckl-mapper/jsonixMapping.d.ts +5 -0
- package/lib/src/ckl-mapper/jsonixMapping.d.ts.map +1 -0
- package/lib/src/ckl-mapper/jsonixMapping.js +4 -0
- package/lib/src/ckl-mapper/jsonixMapping.js.map +1 -1
- package/lib/src/converters-from-hdf/asff/asff-types.d.ts +1 -0
- package/lib/src/converters-from-hdf/asff/asff-types.d.ts.map +1 -0
- package/lib/src/converters-from-hdf/asff/asff-types.js +1 -0
- package/lib/src/converters-from-hdf/asff/asff-types.js.map +1 -1
- package/lib/src/converters-from-hdf/asff/reverse-asff-mapper.d.ts +1 -0
- package/lib/src/converters-from-hdf/asff/reverse-asff-mapper.d.ts.map +1 -0
- package/lib/src/converters-from-hdf/asff/reverse-asff-mapper.js +110 -84
- package/lib/src/converters-from-hdf/asff/reverse-asff-mapper.js.map +1 -1
- package/lib/src/converters-from-hdf/asff/transformers.d.ts +1 -0
- package/lib/src/converters-from-hdf/asff/transformers.d.ts.map +1 -0
- package/lib/src/converters-from-hdf/asff/transformers.js +82 -55
- package/lib/src/converters-from-hdf/asff/transformers.js.map +1 -1
- package/lib/src/converters-from-hdf/caat/reverse-caat-mapper.d.ts +1 -0
- package/lib/src/converters-from-hdf/caat/reverse-caat-mapper.d.ts.map +1 -0
- package/lib/src/converters-from-hdf/caat/reverse-caat-mapper.js +65 -38
- package/lib/src/converters-from-hdf/caat/reverse-caat-mapper.js.map +1 -1
- package/lib/src/converters-from-hdf/html/embedded-assets.d.ts +4 -0
- package/lib/src/converters-from-hdf/html/embedded-assets.d.ts.map +1 -0
- package/lib/src/converters-from-hdf/html/embedded-assets.js +8 -0
- package/lib/src/converters-from-hdf/html/embedded-assets.js.map +1 -0
- package/lib/src/converters-from-hdf/html/html-types.d.ts +1 -0
- package/lib/src/converters-from-hdf/html/html-types.d.ts.map +1 -0
- package/lib/src/converters-from-hdf/html/html-types.js +1 -0
- package/lib/src/converters-from-hdf/html/html-types.js.map +1 -1
- package/lib/src/converters-from-hdf/html/reverse-html-mapper.d.ts +3 -2
- package/lib/src/converters-from-hdf/html/reverse-html-mapper.d.ts.map +1 -0
- package/lib/src/converters-from-hdf/html/reverse-html-mapper.js +151 -107
- package/lib/src/converters-from-hdf/html/reverse-html-mapper.js.map +1 -1
- package/lib/src/converters-from-hdf/reverse-any-base-converter.d.ts +1 -0
- package/lib/src/converters-from-hdf/reverse-any-base-converter.d.ts.map +1 -0
- package/lib/src/converters-from-hdf/reverse-any-base-converter.js +3 -0
- package/lib/src/converters-from-hdf/reverse-any-base-converter.js.map +1 -1
- package/lib/src/converters-from-hdf/reverse-base-converter.d.ts +1 -0
- package/lib/src/converters-from-hdf/reverse-base-converter.d.ts.map +1 -0
- package/lib/src/converters-from-hdf/reverse-base-converter.js +29 -9
- package/lib/src/converters-from-hdf/reverse-base-converter.js.map +1 -1
- package/lib/src/converters-from-hdf/splunk/reverse-splunk-mapper.d.ts +1 -0
- package/lib/src/converters-from-hdf/splunk/reverse-splunk-mapper.d.ts.map +1 -0
- package/lib/src/converters-from-hdf/splunk/reverse-splunk-mapper.js +40 -16
- package/lib/src/converters-from-hdf/splunk/reverse-splunk-mapper.js.map +1 -1
- package/lib/src/converters-from-hdf/xccdf/reverse-xccdf-mapper.d.ts +1 -0
- package/lib/src/converters-from-hdf/xccdf/reverse-xccdf-mapper.d.ts.map +1 -0
- package/lib/src/converters-from-hdf/xccdf/reverse-xccdf-mapper.js +33 -12
- package/lib/src/converters-from-hdf/xccdf/reverse-xccdf-mapper.js.map +1 -1
- package/lib/src/conveyor-mapper.d.ts +1 -0
- package/lib/src/conveyor-mapper.d.ts.map +1 -0
- package/lib/src/conveyor-mapper.js +85 -40
- package/lib/src/conveyor-mapper.js.map +1 -1
- package/lib/src/cyclonedx-sbom-mapper.d.ts +1 -0
- package/lib/src/cyclonedx-sbom-mapper.d.ts.map +1 -0
- package/lib/src/cyclonedx-sbom-mapper.js +377 -309
- package/lib/src/cyclonedx-sbom-mapper.js.map +1 -1
- package/lib/src/dbprotect-mapper.d.ts +1 -0
- package/lib/src/dbprotect-mapper.d.ts.map +1 -0
- package/lib/src/dbprotect-mapper.js +74 -63
- package/lib/src/dbprotect-mapper.js.map +1 -1
- package/lib/src/dependency-track-mapper.d.ts +1 -0
- package/lib/src/dependency-track-mapper.d.ts.map +1 -0
- package/lib/src/dependency-track-mapper.js +144 -130
- package/lib/src/dependency-track-mapper.js.map +1 -1
- package/lib/src/fortify-mapper.d.ts +7 -0
- package/lib/src/fortify-mapper.d.ts.map +1 -0
- package/lib/src/fortify-mapper.js +118 -92
- package/lib/src/fortify-mapper.js.map +1 -1
- package/lib/src/gosec-mapper.d.ts +1 -0
- package/lib/src/gosec-mapper.d.ts.map +1 -0
- package/lib/src/gosec-mapper.js +90 -72
- package/lib/src/gosec-mapper.js.map +1 -1
- package/lib/src/ionchannel-mapper.d.ts +1 -0
- package/lib/src/ionchannel-mapper.d.ts.map +1 -0
- package/lib/src/ionchannel-mapper.js +130 -110
- package/lib/src/ionchannel-mapper.js.map +1 -1
- package/lib/src/jfrog-xray-mapper.d.ts +1 -0
- package/lib/src/jfrog-xray-mapper.d.ts.map +1 -0
- package/lib/src/jfrog-xray-mapper.js +92 -78
- package/lib/src/jfrog-xray-mapper.js.map +1 -1
- package/lib/src/jsonix-converter.d.ts +1 -0
- package/lib/src/jsonix-converter.d.ts.map +1 -0
- package/lib/src/jsonix-converter.js +1 -0
- package/lib/src/jsonix-converter.js.map +1 -1
- package/lib/src/jsonix-intermediate-converter.d.ts +1 -0
- package/lib/src/jsonix-intermediate-converter.d.ts.map +1 -0
- package/lib/src/jsonix-intermediate-converter.js.map +1 -1
- package/lib/src/mappings/AwsConfigMapping.d.ts +1 -0
- package/lib/src/mappings/AwsConfigMapping.d.ts.map +1 -0
- package/lib/src/mappings/AwsConfigMapping.js +19 -9
- package/lib/src/mappings/AwsConfigMapping.js.map +1 -1
- package/lib/src/mappings/AwsConfigMappingData.d.ts +1 -0
- package/lib/src/mappings/AwsConfigMappingData.d.ts.map +1 -0
- package/lib/src/mappings/AwsConfigMappingData.js.map +1 -1
- package/lib/src/mappings/CciNistMapping.d.ts +1 -0
- package/lib/src/mappings/CciNistMapping.d.ts.map +1 -0
- package/lib/src/mappings/CciNistMapping.js +6 -2
- package/lib/src/mappings/CciNistMapping.js.map +1 -1
- package/lib/src/mappings/CciNistMappingData.d.ts +1 -0
- package/lib/src/mappings/CciNistMappingData.d.ts.map +1 -0
- package/lib/src/mappings/CciNistMappingData.js.map +1 -1
- package/lib/src/mappings/CciNistMappingItem.d.ts +1 -0
- package/lib/src/mappings/CciNistMappingItem.d.ts.map +1 -0
- package/lib/src/mappings/CciNistMappingItem.js +2 -0
- package/lib/src/mappings/CciNistMappingItem.js.map +1 -1
- package/lib/src/mappings/CheckovToCciAndNistMappingData.d.ts +5 -0
- package/lib/src/mappings/CheckovToCciAndNistMappingData.d.ts.map +1 -0
- package/lib/src/mappings/CheckovToCciAndNistMappingData.js +2695 -0
- package/lib/src/mappings/CheckovToCciAndNistMappingData.js.map +1 -0
- package/lib/src/mappings/CweNistMapping.d.ts +1 -0
- package/lib/src/mappings/CweNistMapping.d.ts.map +1 -0
- package/lib/src/mappings/CweNistMapping.js +1 -0
- package/lib/src/mappings/CweNistMapping.js.map +1 -1
- package/lib/src/mappings/CweNistMappingData.d.ts +1 -0
- package/lib/src/mappings/CweNistMappingData.d.ts.map +1 -0
- package/lib/src/mappings/CweNistMappingData.js.map +1 -1
- package/lib/src/mappings/CweNistMappingItem.d.ts +1 -0
- package/lib/src/mappings/CweNistMappingItem.d.ts.map +1 -0
- package/lib/src/mappings/CweNistMappingItem.js +5 -0
- package/lib/src/mappings/CweNistMappingItem.js.map +1 -1
- package/lib/src/mappings/NessusPluginNistMappingData.d.ts +1 -0
- package/lib/src/mappings/NessusPluginNistMappingData.d.ts.map +1 -0
- package/lib/src/mappings/NessusPluginNistMappingData.js.map +1 -1
- package/lib/src/mappings/NessusPluginsNistMapping.d.ts +1 -0
- package/lib/src/mappings/NessusPluginsNistMapping.d.ts.map +1 -0
- package/lib/src/mappings/NessusPluginsNistMapping.js +1 -0
- package/lib/src/mappings/NessusPluginsNistMapping.js.map +1 -1
- package/lib/src/mappings/NessusPluginsNistMappingItem.d.ts +1 -0
- package/lib/src/mappings/NessusPluginsNistMappingItem.d.ts.map +1 -0
- package/lib/src/mappings/NessusPluginsNistMappingItem.js +4 -0
- package/lib/src/mappings/NessusPluginsNistMappingItem.js.map +1 -1
- package/lib/src/mappings/NiktoNistMapping.d.ts +1 -0
- package/lib/src/mappings/NiktoNistMapping.d.ts.map +1 -0
- package/lib/src/mappings/NiktoNistMapping.js.map +1 -1
- package/lib/src/mappings/NiktoNistMappingData.d.ts +1 -0
- package/lib/src/mappings/NiktoNistMappingData.d.ts.map +1 -0
- package/lib/src/mappings/NiktoNistMappingData.js.map +1 -1
- package/lib/src/mappings/NiktoNistMappingItem.d.ts +1 -0
- package/lib/src/mappings/NiktoNistMappingItem.d.ts.map +1 -0
- package/lib/src/mappings/NiktoNistMappingItem.js +4 -0
- package/lib/src/mappings/NiktoNistMappingItem.js.map +1 -1
- package/lib/src/mappings/NistCciMappingData.d.ts +1 -0
- package/lib/src/mappings/NistCciMappingData.d.ts.map +1 -0
- package/lib/src/mappings/NistCciMappingData.js.map +1 -1
- package/lib/src/mappings/OwaspNistMapping.d.ts +1 -0
- package/lib/src/mappings/OwaspNistMapping.d.ts.map +1 -0
- package/lib/src/mappings/OwaspNistMapping.js +19 -8
- package/lib/src/mappings/OwaspNistMapping.js.map +1 -1
- package/lib/src/mappings/OwaspNistMappingData.d.ts +1 -0
- package/lib/src/mappings/OwaspNistMappingData.d.ts.map +1 -0
- package/lib/src/mappings/OwaspNistMappingData.js.map +1 -1
- package/lib/src/mappings/OwaspNistMappingItem.d.ts +1 -0
- package/lib/src/mappings/OwaspNistMappingItem.d.ts.map +1 -0
- package/lib/src/mappings/OwaspNistMappingItem.js +5 -0
- package/lib/src/mappings/OwaspNistMappingItem.js.map +1 -1
- package/lib/src/mappings/ScoutsuiteNistMapping.d.ts +1 -0
- package/lib/src/mappings/ScoutsuiteNistMapping.d.ts.map +1 -0
- package/lib/src/mappings/ScoutsuiteNistMapping.js +1 -0
- package/lib/src/mappings/ScoutsuiteNistMapping.js.map +1 -1
- package/lib/src/mappings/ScoutsuiteNistMappingData.d.ts +1 -0
- package/lib/src/mappings/ScoutsuiteNistMappingData.d.ts.map +1 -0
- package/lib/src/mappings/ScoutsuiteNistMappingData.js.map +1 -1
- package/lib/src/mappings/ScoutsuiteNistMappingItem.d.ts +1 -0
- package/lib/src/mappings/ScoutsuiteNistMappingItem.d.ts.map +1 -0
- package/lib/src/mappings/ScoutsuiteNistMappingItem.js +2 -0
- package/lib/src/mappings/ScoutsuiteNistMappingItem.js.map +1 -1
- package/lib/src/msft-secure-score-mapper.d.ts +1 -0
- package/lib/src/msft-secure-score-mapper.d.ts.map +1 -0
- package/lib/src/msft-secure-score-mapper.js +202 -185
- package/lib/src/msft-secure-score-mapper.js.map +1 -1
- package/lib/src/nessus-mapper.d.ts +2 -1
- package/lib/src/nessus-mapper.d.ts.map +1 -0
- package/lib/src/nessus-mapper.js +122 -105
- package/lib/src/nessus-mapper.js.map +1 -1
- package/lib/src/netsparker-mapper.d.ts +7 -0
- package/lib/src/netsparker-mapper.d.ts.map +1 -0
- package/lib/src/netsparker-mapper.js +34 -9
- package/lib/src/netsparker-mapper.js.map +1 -1
- package/lib/src/neuvector-mapper.d.ts +1 -0
- package/lib/src/neuvector-mapper.d.ts.map +1 -0
- package/lib/src/neuvector-mapper.js +123 -124
- package/lib/src/neuvector-mapper.js.map +1 -1
- package/lib/src/nikto-mapper.d.ts +1 -0
- package/lib/src/nikto-mapper.d.ts.map +1 -0
- package/lib/src/nikto-mapper.js +85 -74
- package/lib/src/nikto-mapper.js.map +1 -1
- package/lib/src/prisma-mapper.d.ts +1 -0
- package/lib/src/prisma-mapper.d.ts.map +1 -0
- package/lib/src/prisma-mapper.js +138 -128
- package/lib/src/prisma-mapper.js.map +1 -1
- package/lib/src/sarif-mapper.d.ts +1 -0
- package/lib/src/sarif-mapper.d.ts.map +1 -0
- package/lib/src/sarif-mapper.js +116 -105
- package/lib/src/sarif-mapper.js.map +1 -1
- package/lib/src/scoutsuite-mapper.d.ts +1 -0
- package/lib/src/scoutsuite-mapper.d.ts.map +1 -0
- package/lib/src/scoutsuite-mapper.js +174 -163
- package/lib/src/scoutsuite-mapper.js.map +1 -1
- package/lib/src/snyk-mapper.d.ts +1 -0
- package/lib/src/snyk-mapper.d.ts.map +1 -0
- package/lib/src/snyk-mapper.js +112 -100
- package/lib/src/snyk-mapper.js.map +1 -1
- package/lib/src/sonarqube-mapper.d.ts +18 -5
- package/lib/src/sonarqube-mapper.d.ts.map +1 -0
- package/lib/src/sonarqube-mapper.js +526 -278
- package/lib/src/sonarqube-mapper.js.map +1 -1
- package/lib/src/splunk-mapper.d.ts +3 -2
- package/lib/src/splunk-mapper.d.ts.map +1 -0
- package/lib/src/splunk-mapper.js +72 -16
- package/lib/src/splunk-mapper.js.map +1 -1
- package/lib/src/trufflehog-mapper.d.ts +1 -0
- package/lib/src/trufflehog-mapper.d.ts.map +1 -0
- package/lib/src/trufflehog-mapper.js +72 -69
- package/lib/src/trufflehog-mapper.js.map +1 -1
- package/lib/src/twistlock-mapper.d.ts +1 -0
- package/lib/src/twistlock-mapper.d.ts.map +1 -0
- package/lib/src/twistlock-mapper.js +140 -126
- package/lib/src/twistlock-mapper.js.map +1 -1
- package/lib/src/utils/CCI_List.d.ts +1 -0
- package/lib/src/utils/CCI_List.d.ts.map +1 -0
- package/lib/src/utils/CCI_List.js.map +1 -1
- package/lib/src/utils/attestations.d.ts +1 -0
- package/lib/src/utils/attestations.d.ts.map +1 -0
- package/lib/src/utils/attestations.js +28 -13
- package/lib/src/utils/attestations.js.map +1 -1
- package/lib/src/utils/compliance.d.ts +1 -0
- package/lib/src/utils/compliance.d.ts.map +1 -0
- package/lib/src/utils/compliance.js +11 -3
- package/lib/src/utils/compliance.js.map +1 -1
- package/lib/src/utils/fingerprinting.d.ts +2 -0
- package/lib/src/utils/fingerprinting.d.ts.map +1 -0
- package/lib/src/utils/fingerprinting.js +28 -11
- package/lib/src/utils/fingerprinting.js.map +1 -1
- package/lib/src/utils/global.d.ts +3 -1
- package/lib/src/utils/global.d.ts.map +1 -0
- package/lib/src/utils/global.js +35 -17
- package/lib/src/utils/global.js.map +1 -1
- package/lib/src/utils/parseJson.d.ts +1 -0
- package/lib/src/utils/parseJson.d.ts.map +1 -0
- package/lib/src/utils/parseJson.js +7 -3
- package/lib/src/utils/parseJson.js.map +1 -1
- package/lib/src/utils/result.d.ts +1 -0
- package/lib/src/utils/result.d.ts.map +1 -0
- package/lib/src/utils/result.js.map +1 -1
- package/lib/src/utils/splunk-tools.d.ts +2 -1
- package/lib/src/utils/splunk-tools.d.ts.map +1 -0
- package/lib/src/utils/splunk-tools.js +52 -32
- package/lib/src/utils/splunk-tools.js.map +1 -1
- package/lib/src/veracode-mapper.d.ts +1 -0
- package/lib/src/veracode-mapper.d.ts.map +1 -0
- package/lib/src/veracode-mapper.js +50 -7
- package/lib/src/veracode-mapper.js.map +1 -1
- package/lib/src/xccdf-results-mapper.d.ts +7 -0
- package/lib/src/xccdf-results-mapper.d.ts.map +1 -0
- package/lib/src/xccdf-results-mapper.js +336 -301
- package/lib/src/xccdf-results-mapper.js.map +1 -1
- package/lib/src/zap-mapper.d.ts +8 -0
- package/lib/src/zap-mapper.d.ts.map +1 -0
- package/lib/src/zap-mapper.js +119 -90
- package/lib/src/zap-mapper.js.map +1 -1
- package/lib/tsconfig.build.tsbuildinfo +1 -0
- package/lib/types/neuvector-types.d.ts +1 -0
- package/lib/types/neuvector-types.d.ts.map +1 -0
- package/lib/types/neuvector-types.js +80 -0
- package/lib/types/neuvector-types.js.map +1 -1
- package/lib/types/splunk-config-types.d.ts +1 -0
- package/lib/types/splunk-config-types.d.ts.map +1 -0
- package/lib/types/splunk-config-types.js.map +1 -1
- package/lib/types/splunk-control-types.d.ts +1 -0
- package/lib/types/splunk-control-types.d.ts.map +1 -0
- package/lib/types/splunk-control-types.js.map +1 -1
- package/lib/types/splunk-profile-types.d.ts +1 -0
- package/lib/types/splunk-profile-types.d.ts.map +1 -0
- package/lib/types/splunk-profile-types.js.map +1 -1
- package/lib/types/splunk-report-types.d.ts +1 -0
- package/lib/types/splunk-report-types.d.ts.map +1 -0
- package/lib/types/splunk-report-types.js.map +1 -1
- package/package.json +29 -46
- package/lib/data/converters/csv2json.ts +0 -36
- package/lib/data/converters/xml2json.ts +0 -57
|
@@ -15,19 +15,30 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
|
|
|
15
15
|
}) : function(o, v) {
|
|
16
16
|
o["default"] = v;
|
|
17
17
|
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
};
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
25
35
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
37
|
};
|
|
28
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
39
|
exports.SonarqubeResults = exports.SonarqubeMapper = void 0;
|
|
30
40
|
const axios_1 = __importDefault(require("axios"));
|
|
41
|
+
const rax = __importStar(require("retry-axios"));
|
|
31
42
|
const _ = __importStar(require("lodash"));
|
|
32
43
|
const semver_1 = require("semver");
|
|
33
44
|
const inspecjs_1 = require("inspecjs");
|
|
@@ -38,6 +49,7 @@ const CweNistMapping_1 = require("./mappings/CweNistMapping");
|
|
|
38
49
|
const OwaspNistMapping_1 = require("./mappings/OwaspNistMapping");
|
|
39
50
|
const global_1 = require("./utils/global");
|
|
40
51
|
const logger = (0, global_1.createWinstonLogger)('SonarQube2HDF');
|
|
52
|
+
// the Sonarqube schema typings are meant to support the four versions out right now (8, 9, 10, and 2025/25). 9 and 25 are supposed to be LTS releases. 8 is currently used by the Sonarcloud deployment though Sonarqube POCs say that it is no longer supported / they do not see many deployments of it.
|
|
41
53
|
var SonarqubeVersion;
|
|
42
54
|
(function (SonarqubeVersion) {
|
|
43
55
|
SonarqubeVersion["Eight"] = "8.0.0";
|
|
@@ -45,6 +57,7 @@ var SonarqubeVersion;
|
|
|
45
57
|
SonarqubeVersion["Ten"] = "10.0.0";
|
|
46
58
|
SonarqubeVersion["Twenty_five"] = "2025.0.0";
|
|
47
59
|
})(SonarqubeVersion || (SonarqubeVersion = {}));
|
|
60
|
+
// intentionally open ended to support versions less than 8, but it is unlikely that they will be out there based on discussions with Sonar engineers
|
|
48
61
|
function isSonarqubeVersionEight(version) {
|
|
49
62
|
const nextHigherVersion = SonarqubeVersion.Nine;
|
|
50
63
|
const v = (0, semver_1.coerce)(version);
|
|
@@ -70,13 +83,25 @@ function isSonarqubeVersionTen(version) {
|
|
|
70
83
|
return (0, semver_1.lt)(v, nextHigherVersion);
|
|
71
84
|
}
|
|
72
85
|
function isSonarqubeVersionTwenty_five(version) {
|
|
73
|
-
const nextHigherVersion = '2026.0.0';
|
|
86
|
+
const nextHigherVersion = '2026.0.0'; // using 26 for now, but I am unsure what the actual next major version will be - this function can be changed once we identify the next version that contains impactful breaking changes
|
|
74
87
|
const v = (0, semver_1.coerce)(version);
|
|
75
88
|
if (v === null) {
|
|
76
89
|
throw new Error(`Was not able to coerce ${version} into a semver compatible version string`);
|
|
77
90
|
}
|
|
78
91
|
return (0, semver_1.lt)(v, nextHigherVersion);
|
|
79
92
|
}
|
|
93
|
+
function isBeforeSonarqubeVersion(version, comparisonVersion) {
|
|
94
|
+
const v = (0, semver_1.coerce)(version);
|
|
95
|
+
if (v === null) {
|
|
96
|
+
throw new Error(`Was not able to coerce ${version} into a semver compatible version string`);
|
|
97
|
+
}
|
|
98
|
+
const cv = (0, semver_1.coerce)(comparisonVersion);
|
|
99
|
+
if (cv === null) {
|
|
100
|
+
throw new Error(`Was not able to coerce ${comparisonVersion} into a semver compatible version string`);
|
|
101
|
+
}
|
|
102
|
+
return (0, semver_1.lt)(v, cv);
|
|
103
|
+
}
|
|
104
|
+
// https://docs.sonarsource.com/sonarqube-server/latest/user-guide/rules/overview/#how-severities-are-assigned
|
|
80
105
|
const IMPACT_MAPPING = new Map([
|
|
81
106
|
['blocker', 1.0],
|
|
82
107
|
['critical', 0.7],
|
|
@@ -89,7 +114,7 @@ const OWASP_NIST_MAPPING = new OwaspNistMapping_1.OwaspNistMapping();
|
|
|
89
114
|
function parseOwaspInSysTags(issue) {
|
|
90
115
|
return issue.ruleInformation.rule.sysTags
|
|
91
116
|
.filter((s) => s.toLowerCase().startsWith('owasp-'))
|
|
92
|
-
.map((t) => t.substring('owasp-'.length).toUpperCase());
|
|
117
|
+
.map((t) => t.substring('owasp-'.length).toUpperCase()); // this will just look like 'A3'
|
|
93
118
|
}
|
|
94
119
|
function parseOwaspTags(issue) {
|
|
95
120
|
let searchSpace = '';
|
|
@@ -102,7 +127,7 @@ function parseOwaspTags(issue) {
|
|
|
102
127
|
}
|
|
103
128
|
const searchSpaceMatches = [
|
|
104
129
|
...searchSpace.matchAll(/> ?OWASP.*?(Top .*?A\d\d?)/gu)
|
|
105
|
-
].map((m) => m[1]);
|
|
130
|
+
].map((m) => m[1]); // get the capture group which looks like 'Top 10 2021 Category A1'
|
|
106
131
|
const sysTagMatches = parseOwaspInSysTags(issue);
|
|
107
132
|
const totalMatches = searchSpaceMatches.concat(sysTagMatches);
|
|
108
133
|
if (totalMatches.length) {
|
|
@@ -119,270 +144,285 @@ function parseCweTags(issue) {
|
|
|
119
144
|
if (rule.descriptionSections) {
|
|
120
145
|
searchSpace += rule.descriptionSections.map((s) => s.content).join('');
|
|
121
146
|
}
|
|
122
|
-
const uniqueCwes = _.uniq(searchSpace.match(/CWE-\d\d\d?\d?\d?\d?\d/gi));
|
|
147
|
+
const uniqueCwes = _.uniq(searchSpace.match(/CWE-\d\d\d?\d?\d?\d?\d/gi)); // CWE IDs are embedded inside of the HTML
|
|
123
148
|
if (uniqueCwes.length) {
|
|
124
149
|
return uniqueCwes;
|
|
125
150
|
}
|
|
126
151
|
return undefined;
|
|
127
152
|
}
|
|
128
153
|
function parseNistTags(issue) {
|
|
129
|
-
|
|
130
|
-
const uniqueNist = _.uniq(((_a = parseCweTags(issue)) !== null && _a !== void 0 ? _a : [])
|
|
154
|
+
const uniqueNist = _.uniq((parseCweTags(issue) ?? [])
|
|
131
155
|
.flatMap((t) => CWE_NIST_MAPPING.nistFilter(t.split('-')[1]))
|
|
132
|
-
.concat(
|
|
156
|
+
.concat(
|
|
157
|
+
// adding in the systags' owasp tag since in older sonarqube versions sometimes no other guidance alignment is provided
|
|
158
|
+
(parseOwaspInSysTags(issue) ?? []).flatMap((t) => OWASP_NIST_MAPPING.nistFilterNoDefault(t))));
|
|
133
159
|
if (uniqueNist.length) {
|
|
134
160
|
return uniqueNist;
|
|
135
161
|
}
|
|
136
|
-
return ['SA-11'];
|
|
162
|
+
return ['SA-11']; // Sonarqube is a static code analysis tool so we'll use SA-11 (DEVELOPER SECURITY TESTING AND EVALUATION) to handle all the bugs and code smells as a default for whenever it doesn't have security guidance to give us. Explicitly not using RA-5 (VULNERABILITY SCANNING) since all of those seem to have guidance associated with them.
|
|
137
163
|
}
|
|
138
164
|
class SonarqubeMapper extends base_converter_1.BaseConverter {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
return rule.htmlDesc;
|
|
180
|
-
}
|
|
181
|
-
if (!rule.descriptionSections) {
|
|
182
|
-
return '';
|
|
183
|
-
}
|
|
184
|
-
const def = rule.descriptionSections.find((d) => d.key === 'default');
|
|
185
|
-
if (def) {
|
|
186
|
-
return def.content;
|
|
187
|
-
}
|
|
188
|
-
const introduction = rule.descriptionSections.find((d) => d.key === 'introduction');
|
|
189
|
-
const rootcause = rule.descriptionSections.find((d) => d.key === 'root_cause');
|
|
190
|
-
return [introduction, rootcause]
|
|
191
|
-
.filter((s) => s !== undefined)
|
|
192
|
-
.map((s) => s.content)
|
|
193
|
-
.join('\n');
|
|
165
|
+
data;
|
|
166
|
+
withRaw;
|
|
167
|
+
mappings = {
|
|
168
|
+
platform: {
|
|
169
|
+
name: 'Heimdall Tools',
|
|
170
|
+
release: package_json_1.version
|
|
171
|
+
},
|
|
172
|
+
version: package_json_1.version,
|
|
173
|
+
statistics: {},
|
|
174
|
+
profiles: [
|
|
175
|
+
{
|
|
176
|
+
name: 'SonarQube Scan',
|
|
177
|
+
version: {
|
|
178
|
+
transformer: (data) => `SonarQube v${data.sonarqubeVersion}`
|
|
179
|
+
},
|
|
180
|
+
title: {
|
|
181
|
+
transformer: (data) => {
|
|
182
|
+
const branch = data.branchName ? ` branch ${data.branchName}` : '';
|
|
183
|
+
const pullrequest = data.pullRequestID
|
|
184
|
+
? ` pull request ${data.pullRequestID}`
|
|
185
|
+
: '';
|
|
186
|
+
const org = data.organization
|
|
187
|
+
? ` organization ${data.organization}`
|
|
188
|
+
: '';
|
|
189
|
+
return `SonarQube Scan of project ${data.projectKey} on ${data.sonarqubeHost} at ${new Date().toISOString()}${data.branchName || data.pullRequestID || data.organization ? ' using' : ''}${[branch, pullrequest, org].filter((s) => s).join(',')}`;
|
|
190
|
+
}
|
|
191
|
+
},
|
|
192
|
+
supports: [],
|
|
193
|
+
attributes: [],
|
|
194
|
+
groups: [],
|
|
195
|
+
status: 'loaded',
|
|
196
|
+
controls: [
|
|
197
|
+
{
|
|
198
|
+
path: 'search.issues',
|
|
199
|
+
key: 'id',
|
|
200
|
+
desc: {
|
|
201
|
+
transformer: (issue) => {
|
|
202
|
+
const rule = issue.ruleInformation.rule;
|
|
203
|
+
if ('htmlDesc' in rule) {
|
|
204
|
+
return rule.htmlDesc;
|
|
194
205
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
source_location: {},
|
|
198
|
-
id: { path: 'rule' },
|
|
199
|
-
title: { path: 'ruleInformation.rule.name' },
|
|
200
|
-
impact: {
|
|
201
|
-
path: 'severity',
|
|
202
|
-
transformer: (0, base_converter_1.impactMapping)(IMPACT_MAPPING)
|
|
203
|
-
},
|
|
204
|
-
tags: {
|
|
205
|
-
cci: {
|
|
206
|
-
transformer: (issue) => { var _a; return (0, global_1.getCCIsForNISTTags)((_a = parseNistTags(issue)) !== null && _a !== void 0 ? _a : []); }
|
|
207
|
-
},
|
|
208
|
-
nist: { transformer: parseNistTags },
|
|
209
|
-
cweid: { transformer: parseCweTags },
|
|
210
|
-
owasp: { transformer: parseOwaspTags },
|
|
211
|
-
createdAt: { path: 'ruleInformation.rule.createdAt' },
|
|
212
|
-
debtRemFnType: { path: 'ruleInformation.rule.debtRemFnType' },
|
|
213
|
-
defaultDebtRemFnType: {
|
|
214
|
-
path: 'ruleInformation.rule.defaultDebtRemFnType'
|
|
215
|
-
},
|
|
216
|
-
isExternal: { path: 'ruleInformation.rule.isExternal' },
|
|
217
|
-
isTemplate: { path: 'ruleInformation.rule.isTemplate' },
|
|
218
|
-
langName: { path: 'ruleInformation.rule.langName' },
|
|
219
|
-
remFnBaseEffort: { path: 'ruleInformation.rule.remFnBaseEffort' },
|
|
220
|
-
remFnOverloaded: { path: 'ruleInformation.rule.remFnOverloaded' },
|
|
221
|
-
remFnType: { path: 'ruleInformation.rule.remFnType' },
|
|
222
|
-
repo: { path: 'ruleInformation.rule.repo' },
|
|
223
|
-
scope: { path: 'ruleInformation.rule.scope' },
|
|
224
|
-
ruleSeverity: { path: 'ruleInformation.rule.severity' },
|
|
225
|
-
status: { path: 'ruleInformation.rule.status' },
|
|
226
|
-
transformer: (issue) => {
|
|
227
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
228
|
-
return ({
|
|
229
|
-
...(0, global_1.conditionallyProvideAttribute)('Actives', issue.ruleInformation.actives, issue.ruleInformation.actives.length !== 0),
|
|
230
|
-
...(0, global_1.conditionallyProvideAttribute)('Clean Code Attribute', issue.ruleInformation.rule.cleanCodeAttribute, ((_a = issue.ruleInformation.rule.cleanCodeAttribute) === null || _a === void 0 ? void 0 : _a.length) !== 0),
|
|
231
|
-
...(0, global_1.conditionallyProvideAttribute)('Clean Code Attribute Category', issue.ruleInformation.rule.cleanCodeAttributeCategory, ((_b = issue.ruleInformation.rule.cleanCodeAttributeCategory) === null || _b === void 0 ? void 0 : _b.length) !== 0),
|
|
232
|
-
...(0, global_1.conditionallyProvideAttribute)('Debt Overloaded', 'debtOverloaded' in issue.ruleInformation.rule &&
|
|
233
|
-
issue.ruleInformation.rule.debtOverloaded, 'debtOverloaded' in issue.ruleInformation.rule &&
|
|
234
|
-
issue.ruleInformation.rule.debtOverloaded !== undefined),
|
|
235
|
-
...(0, global_1.conditionallyProvideAttribute)('Debt Rem Fn Coeff', 'debtRemFnCoeff' in issue.ruleInformation.rule &&
|
|
236
|
-
issue.ruleInformation.rule.debtRemFnCoeff, 'debtRemFnCoeff' in issue.ruleInformation.rule &&
|
|
237
|
-
issue.ruleInformation.rule.debtRemFnCoeff !== undefined),
|
|
238
|
-
...(0, global_1.conditionallyProvideAttribute)('Debt Rem Fn Offset', 'debtRemFnOffset' in issue.ruleInformation.rule &&
|
|
239
|
-
issue.ruleInformation.rule.debtRemFnOffset, 'debtRemFnOffset' in issue.ruleInformation.rule),
|
|
240
|
-
...(0, global_1.conditionallyProvideAttribute)('Default Debt Rem Fn Coeff', 'defaultDebtRemFnCoeff' in issue.ruleInformation.rule &&
|
|
241
|
-
issue.ruleInformation.rule.defaultDebtRemFnCoeff, 'defaultDebtRemFnCoeff' in issue.ruleInformation.rule &&
|
|
242
|
-
issue.ruleInformation.rule.defaultDebtRemFnCoeff !==
|
|
243
|
-
undefined),
|
|
244
|
-
...(0, global_1.conditionallyProvideAttribute)('Default Debt Rem Fn Offset', 'defaultDebtRemFnOffset' in issue.ruleInformation.rule &&
|
|
245
|
-
issue.ruleInformation.rule.defaultDebtRemFnOffset, 'defaultDebtRemFnOffset' in issue.ruleInformation.rule),
|
|
246
|
-
...(0, global_1.conditionallyProvideAttribute)('Education Principles', 'educationPrinciples' in issue.ruleInformation.rule &&
|
|
247
|
-
issue.ruleInformation.rule.educationPrinciples, 'educationPrinciples' in issue.ruleInformation.rule &&
|
|
248
|
-
((_c = issue.ruleInformation.rule.educationPrinciples) === null || _c === void 0 ? void 0 : _c.length) !== 0),
|
|
249
|
-
...(0, global_1.conditionallyProvideAttribute)('Effort To Fix Description', 'effortToFixDescription' in issue.ruleInformation.rule &&
|
|
250
|
-
issue.ruleInformation.rule.effortToFixDescription, 'effortToFixDescription' in issue.ruleInformation.rule &&
|
|
251
|
-
issue.ruleInformation.rule.effortToFixDescription !==
|
|
252
|
-
undefined),
|
|
253
|
-
...(0, global_1.conditionallyProvideAttribute)('Impacts', issue.ruleInformation.rule.impacts, ((_d = issue.ruleInformation.rule.impacts) === null || _d === void 0 ? void 0 : _d.length) !== 0),
|
|
254
|
-
...(0, global_1.conditionallyProvideAttribute)('Issue Type Vulnerability', true, issue.type === 'VULNERABILITY'),
|
|
255
|
-
...(0, global_1.conditionallyProvideAttribute)('Issue Type Bug', true, issue.type === 'BUG'),
|
|
256
|
-
...(0, global_1.conditionallyProvideAttribute)('Issue Type Code Smell', true, issue.type === 'CODE_SMELL'),
|
|
257
|
-
...(0, global_1.conditionallyProvideAttribute)('Params', issue.ruleInformation.rule.params, ((_e = issue.ruleInformation.rule.params) === null || _e === void 0 ? void 0 : _e.length) !== 0),
|
|
258
|
-
...(0, global_1.conditionallyProvideAttribute)('Security Standards', issue.ruleInformation.rule.securityStandards, ((_f = issue.ruleInformation.rule.securityStandards) === null || _f === void 0 ? void 0 : _f.length) !== 0),
|
|
259
|
-
...(0, global_1.conditionallyProvideAttribute)('Sys Tags', issue.ruleInformation.rule.sysTags, ((_g = issue.ruleInformation.rule.sysTags) === null || _g === void 0 ? void 0 : _g.length) !== 0),
|
|
260
|
-
...(0, global_1.conditionallyProvideAttribute)('Tags', issue.ruleInformation.rule.tags, ((_h = issue.ruleInformation.rule.tags) === null || _h === void 0 ? void 0 : _h.length) !== 0),
|
|
261
|
-
...(0, global_1.conditionallyProvideAttribute)('Updated At', 'updatedAt' in issue.ruleInformation.rule &&
|
|
262
|
-
issue.ruleInformation.rule.updatedAt, 'updatedAt' in issue.ruleInformation.rule)
|
|
263
|
-
});
|
|
206
|
+
if (!rule.descriptionSections) {
|
|
207
|
+
return '';
|
|
264
208
|
}
|
|
209
|
+
const def = rule.descriptionSections.find((d) => d.key === 'default');
|
|
210
|
+
if (def) {
|
|
211
|
+
return def.content;
|
|
212
|
+
}
|
|
213
|
+
const introduction = rule.descriptionSections.find((d) => d.key === 'introduction');
|
|
214
|
+
const rootcause = rule.descriptionSections.find((d) => d.key === 'root_cause');
|
|
215
|
+
return [introduction, rootcause]
|
|
216
|
+
.filter((s) => s !== undefined)
|
|
217
|
+
.map((s) => s.content)
|
|
218
|
+
.join('\n');
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
refs: [],
|
|
222
|
+
source_location: {},
|
|
223
|
+
id: { path: 'rule' },
|
|
224
|
+
title: { path: 'ruleInformation.rule.name' },
|
|
225
|
+
impact: {
|
|
226
|
+
path: 'severity',
|
|
227
|
+
transformer: (0, base_converter_1.impactMapping)(IMPACT_MAPPING)
|
|
228
|
+
},
|
|
229
|
+
tags: {
|
|
230
|
+
cci: {
|
|
231
|
+
transformer: (issue) => (0, global_1.getCCIsForNISTTags)(parseNistTags(issue) ?? [])
|
|
265
232
|
},
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
233
|
+
nist: { transformer: parseNistTags },
|
|
234
|
+
cweid: { transformer: parseCweTags },
|
|
235
|
+
owasp: { transformer: parseOwaspTags },
|
|
236
|
+
createdAt: { path: 'ruleInformation.rule.createdAt' },
|
|
237
|
+
debtRemFnType: { path: 'ruleInformation.rule.debtRemFnType' },
|
|
238
|
+
defaultDebtRemFnType: {
|
|
239
|
+
path: 'ruleInformation.rule.defaultDebtRemFnType'
|
|
240
|
+
},
|
|
241
|
+
isExternal: { path: 'ruleInformation.rule.isExternal' },
|
|
242
|
+
isTemplate: { path: 'ruleInformation.rule.isTemplate' },
|
|
243
|
+
langName: { path: 'ruleInformation.rule.langName' },
|
|
244
|
+
remFnBaseEffort: { path: 'ruleInformation.rule.remFnBaseEffort' },
|
|
245
|
+
remFnOverloaded: { path: 'ruleInformation.rule.remFnOverloaded' },
|
|
246
|
+
remFnType: { path: 'ruleInformation.rule.remFnType' },
|
|
247
|
+
repo: { path: 'ruleInformation.rule.repo' },
|
|
248
|
+
scope: { path: 'ruleInformation.rule.scope' },
|
|
249
|
+
ruleSeverity: { path: 'ruleInformation.rule.severity' },
|
|
250
|
+
status: { path: 'ruleInformation.rule.status' },
|
|
251
|
+
transformer: (issue) => ({
|
|
252
|
+
...(0, global_1.conditionallyProvideAttribute)('Actives', issue.ruleInformation.actives, issue.ruleInformation.actives.length !== 0),
|
|
253
|
+
...(0, global_1.conditionallyProvideAttribute)('Clean Code Attribute', issue.ruleInformation.rule.cleanCodeAttribute, issue.ruleInformation.rule.cleanCodeAttribute?.length !== 0),
|
|
254
|
+
...(0, global_1.conditionallyProvideAttribute)('Clean Code Attribute Category', issue.ruleInformation.rule.cleanCodeAttributeCategory, issue.ruleInformation.rule.cleanCodeAttributeCategory
|
|
255
|
+
?.length !== 0),
|
|
256
|
+
...(0, global_1.conditionallyProvideAttribute)('Debt Overloaded', 'debtOverloaded' in issue.ruleInformation.rule &&
|
|
257
|
+
issue.ruleInformation.rule.debtOverloaded, 'debtOverloaded' in issue.ruleInformation.rule &&
|
|
258
|
+
issue.ruleInformation.rule.debtOverloaded !== undefined),
|
|
259
|
+
...(0, global_1.conditionallyProvideAttribute)('Debt Rem Fn Coeff', 'debtRemFnCoeff' in issue.ruleInformation.rule &&
|
|
260
|
+
issue.ruleInformation.rule.debtRemFnCoeff, 'debtRemFnCoeff' in issue.ruleInformation.rule &&
|
|
261
|
+
issue.ruleInformation.rule.debtRemFnCoeff !== undefined),
|
|
262
|
+
...(0, global_1.conditionallyProvideAttribute)('Debt Rem Fn Offset', 'debtRemFnOffset' in issue.ruleInformation.rule &&
|
|
263
|
+
issue.ruleInformation.rule.debtRemFnOffset, 'debtRemFnOffset' in issue.ruleInformation.rule),
|
|
264
|
+
...(0, global_1.conditionallyProvideAttribute)('Default Debt Rem Fn Coeff', 'defaultDebtRemFnCoeff' in issue.ruleInformation.rule &&
|
|
265
|
+
issue.ruleInformation.rule.defaultDebtRemFnCoeff, 'defaultDebtRemFnCoeff' in issue.ruleInformation.rule &&
|
|
266
|
+
issue.ruleInformation.rule.defaultDebtRemFnCoeff !==
|
|
267
|
+
undefined),
|
|
268
|
+
...(0, global_1.conditionallyProvideAttribute)('Default Debt Rem Fn Offset', 'defaultDebtRemFnOffset' in issue.ruleInformation.rule &&
|
|
269
|
+
issue.ruleInformation.rule.defaultDebtRemFnOffset, 'defaultDebtRemFnOffset' in issue.ruleInformation.rule),
|
|
270
|
+
...(0, global_1.conditionallyProvideAttribute)('Education Principles', 'educationPrinciples' in issue.ruleInformation.rule &&
|
|
271
|
+
issue.ruleInformation.rule.educationPrinciples, 'educationPrinciples' in issue.ruleInformation.rule &&
|
|
272
|
+
issue.ruleInformation.rule.educationPrinciples?.length !== 0),
|
|
273
|
+
...(0, global_1.conditionallyProvideAttribute)('Effort To Fix Description', 'effortToFixDescription' in issue.ruleInformation.rule &&
|
|
274
|
+
issue.ruleInformation.rule.effortToFixDescription, 'effortToFixDescription' in issue.ruleInformation.rule &&
|
|
275
|
+
issue.ruleInformation.rule.effortToFixDescription !==
|
|
276
|
+
undefined),
|
|
277
|
+
...(0, global_1.conditionallyProvideAttribute)('Impacts', issue.ruleInformation.rule.impacts, issue.ruleInformation.rule.impacts?.length !== 0),
|
|
278
|
+
...(0, global_1.conditionallyProvideAttribute)('Issue Type Vulnerability', true, issue.type === 'VULNERABILITY'),
|
|
279
|
+
...(0, global_1.conditionallyProvideAttribute)('Issue Type Bug', true, issue.type === 'BUG'),
|
|
280
|
+
...(0, global_1.conditionallyProvideAttribute)('Issue Type Code Smell', true, issue.type === 'CODE_SMELL'),
|
|
281
|
+
...(0, global_1.conditionallyProvideAttribute)('Params', issue.ruleInformation.rule.params, issue.ruleInformation.rule.params?.length !== 0),
|
|
282
|
+
...(0, global_1.conditionallyProvideAttribute)('Security Standards', issue.ruleInformation.rule.securityStandards, issue.ruleInformation.rule.securityStandards?.length !== 0),
|
|
283
|
+
...(0, global_1.conditionallyProvideAttribute)('Sys Tags', issue.ruleInformation.rule.sysTags, issue.ruleInformation.rule.sysTags?.length !== 0),
|
|
284
|
+
...(0, global_1.conditionallyProvideAttribute)('Tags', issue.ruleInformation.rule.tags, issue.ruleInformation.rule.tags?.length !== 0),
|
|
285
|
+
...(0, global_1.conditionallyProvideAttribute)('Updated At', 'updatedAt' in issue.ruleInformation.rule &&
|
|
286
|
+
issue.ruleInformation.rule.updatedAt, 'updatedAt' in issue.ruleInformation.rule)
|
|
287
|
+
})
|
|
288
|
+
},
|
|
289
|
+
results: [
|
|
290
|
+
{
|
|
291
|
+
status: inspecjs_1.ExecJSON.ControlResultStatus.Failed,
|
|
292
|
+
code_desc: { path: 'codeSnippet' },
|
|
293
|
+
start_time: { path: 'creationDate' },
|
|
294
|
+
message: {
|
|
295
|
+
transformer: (issue) => JSON.stringify({
|
|
296
|
+
// Explanation of the violation
|
|
297
|
+
Message: issue.message,
|
|
298
|
+
// Useful information
|
|
299
|
+
Author: issue.author,
|
|
300
|
+
'Creation Date': issue.creationDate,
|
|
301
|
+
Debt: issue.debt,
|
|
302
|
+
Effort: issue.effort,
|
|
303
|
+
...(0, global_1.conditionallyProvideAttribute)('Issue Status', issue.issueStatus, issue.issueStatus?.length !== 0),
|
|
304
|
+
...(0, global_1.conditionallyProvideAttribute)('Resolution', issue.resolution, issue.resolution?.length !== 0),
|
|
305
|
+
Status: issue.status,
|
|
306
|
+
'Update Date': issue.updateDate,
|
|
307
|
+
// all the rest
|
|
308
|
+
...(0, global_1.conditionallyProvideAttribute)('Actions', issue.actions, issue.actions?.length !== 0),
|
|
309
|
+
...(0, global_1.conditionallyProvideAttribute)('Attr', issue.attr, issue.attr !== undefined),
|
|
310
|
+
...(0, global_1.conditionallyProvideAttribute)('Code Variants', 'codeVariants' in issue && issue.codeVariants, 'codeVariants' in issue &&
|
|
311
|
+
issue.codeVariants?.length !== 0),
|
|
312
|
+
...(0, global_1.conditionallyProvideAttribute)('Comments', issue.comments, issue.comments?.length !== 0),
|
|
313
|
+
...(0, global_1.conditionallyProvideAttribute)('Flows', issue.flows, issue.flows?.length !== 0),
|
|
314
|
+
...(0, global_1.conditionallyProvideAttribute)('From Hotspot', 'fromHotspot' in issue && issue.fromHotspot, 'fromHotspot' in issue &&
|
|
315
|
+
issue.fromHotspot !== undefined &&
|
|
316
|
+
issue.fromHotspot !== null),
|
|
317
|
+
Hash: issue.hash,
|
|
318
|
+
Key: issue.key,
|
|
319
|
+
...(0, global_1.conditionallyProvideAttribute)('Message Formattings', issue.messageFormattings, issue.messageFormattings?.length !== 0),
|
|
320
|
+
...(0, global_1.conditionallyProvideAttribute)('Prioritized Rule', 'prioritizedRule' in issue && issue.prioritizedRule, 'prioritizedRule' in issue),
|
|
321
|
+
...(0, global_1.conditionallyProvideAttribute)('Project Name', issue.projectName, issue.projectName?.length !== 0),
|
|
322
|
+
...(0, global_1.conditionallyProvideAttribute)('Quick Fix Available', 'quickFixAvailable' in issue &&
|
|
323
|
+
issue.quickFixAvailable, 'quickFixAvailable' in issue &&
|
|
324
|
+
issue.quickFixAvailable !== undefined),
|
|
325
|
+
...(0, global_1.conditionallyProvideAttribute)('Rule Description Context Key', 'ruleDescriptionContextKey' in issue &&
|
|
326
|
+
issue.ruleDescriptionContextKey, 'ruleDescriptionContextKey' in issue &&
|
|
327
|
+
issue.ruleDescriptionContextKey?.length !== 0),
|
|
328
|
+
...(0, global_1.conditionallyProvideAttribute)('Tags', issue.tags, issue.tags?.length !== 0),
|
|
329
|
+
...(0, global_1.conditionallyProvideAttribute)('Transitions', issue.transitions, issue.transitions?.length !== 0)
|
|
330
|
+
}, null, 2)
|
|
309
331
|
}
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
332
|
+
}
|
|
333
|
+
],
|
|
334
|
+
transformer: () => ({
|
|
335
|
+
descriptions: {
|
|
336
|
+
transformer: (issue) => {
|
|
337
|
+
const rule = issue.ruleInformation.rule;
|
|
338
|
+
if (rule.descriptionSections &&
|
|
339
|
+
rule.descriptionSections.length > 0) {
|
|
340
|
+
const def = rule.descriptionSections.find((d) => d.key === 'default');
|
|
341
|
+
const introduction = rule.descriptionSections.find((d) => d.key === 'introduction');
|
|
342
|
+
const rootcause = rule.descriptionSections.find((d) => d.key === 'root_cause');
|
|
343
|
+
const check = rule.descriptionSections.find((d) => d.key === 'assess_the_problem');
|
|
344
|
+
const fix = rule.descriptionSections.find((d) => d.key === 'how_to_fix');
|
|
345
|
+
const remainder = rule.descriptionSections.filter((d) => ![
|
|
346
|
+
'default',
|
|
347
|
+
'introduction',
|
|
348
|
+
'root_cause',
|
|
349
|
+
'assess_the_problem',
|
|
350
|
+
'how_to_fix'
|
|
351
|
+
].includes(d.key));
|
|
352
|
+
const sections = [
|
|
353
|
+
def,
|
|
354
|
+
def ? introduction : undefined,
|
|
355
|
+
def ? rootcause : undefined,
|
|
356
|
+
check,
|
|
357
|
+
fix,
|
|
358
|
+
...remainder
|
|
359
|
+
]
|
|
360
|
+
.filter((s) => s !== undefined)
|
|
361
|
+
.map((s) => ({
|
|
362
|
+
data: s.content,
|
|
363
|
+
label: s.key === 'assess_the_problem'
|
|
364
|
+
? 'check'
|
|
365
|
+
: s.key === 'how_to_fix'
|
|
366
|
+
? 'fix'
|
|
367
|
+
: s.key
|
|
368
|
+
}));
|
|
369
|
+
if (sections) {
|
|
370
|
+
return sections;
|
|
349
371
|
}
|
|
350
|
-
return null;
|
|
351
372
|
}
|
|
373
|
+
return null;
|
|
352
374
|
}
|
|
353
|
-
}
|
|
375
|
+
}
|
|
376
|
+
})
|
|
377
|
+
}
|
|
378
|
+
],
|
|
379
|
+
sha256: ''
|
|
380
|
+
}
|
|
381
|
+
],
|
|
382
|
+
passthrough: {
|
|
383
|
+
transformer: (data) => {
|
|
384
|
+
return {
|
|
385
|
+
auxiliary_data: [
|
|
386
|
+
{
|
|
387
|
+
name: 'SonarQube',
|
|
388
|
+
data: {
|
|
389
|
+
..._.omit(data, 'search.issues')
|
|
390
|
+
}
|
|
354
391
|
}
|
|
355
392
|
],
|
|
356
|
-
|
|
357
|
-
}
|
|
358
|
-
],
|
|
359
|
-
passthrough: {
|
|
360
|
-
transformer: (data) => {
|
|
361
|
-
return {
|
|
362
|
-
auxiliary_data: [
|
|
363
|
-
{
|
|
364
|
-
name: 'SonarQube',
|
|
365
|
-
data: {
|
|
366
|
-
..._.omit(data, 'search.issues')
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
],
|
|
370
|
-
...(0, global_1.conditionallyProvideAttribute)('raw', data, this.withRaw)
|
|
371
|
-
};
|
|
372
|
-
}
|
|
393
|
+
...(0, global_1.conditionallyProvideAttribute)('raw', data, this.withRaw)
|
|
394
|
+
};
|
|
373
395
|
}
|
|
374
|
-
}
|
|
396
|
+
}
|
|
397
|
+
};
|
|
398
|
+
constructor(data, withRaw = false) {
|
|
399
|
+
super(data);
|
|
400
|
+
this.data = data;
|
|
375
401
|
this.withRaw = withRaw;
|
|
376
402
|
}
|
|
377
403
|
}
|
|
378
404
|
exports.SonarqubeMapper = SonarqubeMapper;
|
|
405
|
+
// Sonarqube used to require using the user token as the username and supplying no password, but added the bearer token method as an option in 10.x. The bearer token method became the only allowed version in 25.x.
|
|
379
406
|
var AuthenticationMethod;
|
|
380
407
|
(function (AuthenticationMethod) {
|
|
381
408
|
AuthenticationMethod[AuthenticationMethod["TokenAsUsername"] = 0] = "TokenAsUsername";
|
|
382
409
|
AuthenticationMethod[AuthenticationMethod["BearerToken"] = 1] = "BearerToken";
|
|
383
410
|
})(AuthenticationMethod || (AuthenticationMethod = {}));
|
|
384
411
|
class SonarqubeResults {
|
|
385
|
-
|
|
412
|
+
sonarqubeHost;
|
|
413
|
+
projectKey;
|
|
414
|
+
userToken;
|
|
415
|
+
branchName;
|
|
416
|
+
pullRequestID;
|
|
417
|
+
organization;
|
|
418
|
+
withRaw;
|
|
419
|
+
excludeIssueStatuses;
|
|
420
|
+
authMethod;
|
|
421
|
+
axiosClient;
|
|
422
|
+
constructor(sonarqubeHost, projectKey, userToken, branchName, // if branch/pr are not specified, then sonarqube uses the default branch
|
|
423
|
+
pullRequestID, organization, // sometimes the organization parameter is required for the api/rules/show endpoint - we try to grab it from the issue, but this is here to ensure a fallback if necessary
|
|
424
|
+
withRaw = false, excludeIssueStatuses // user-supplied comma-separated list of additional issue statuses to EXCLUDE from results
|
|
425
|
+
) {
|
|
386
426
|
this.sonarqubeHost = sonarqubeHost;
|
|
387
427
|
this.projectKey = projectKey;
|
|
388
428
|
this.userToken = userToken;
|
|
@@ -390,12 +430,29 @@ class SonarqubeResults {
|
|
|
390
430
|
this.pullRequestID = pullRequestID;
|
|
391
431
|
this.organization = organization;
|
|
392
432
|
this.withRaw = withRaw;
|
|
433
|
+
this.excludeIssueStatuses = excludeIssueStatuses;
|
|
434
|
+
this.axiosClient = axios_1.default.create();
|
|
435
|
+
const MAX_RETRIES = 5;
|
|
436
|
+
this.axiosClient.defaults.raxConfig = {
|
|
437
|
+
retry: MAX_RETRIES,
|
|
438
|
+
onError: async (e) => {
|
|
439
|
+
const cfg = rax.getConfig(e);
|
|
440
|
+
if (cfg?.currentRetryAttempt !== null &&
|
|
441
|
+
cfg?.currentRetryAttempt !== undefined) {
|
|
442
|
+
logger.debug(`Error occurred: retry attempt #${cfg?.currentRetryAttempt}/${MAX_RETRIES} will happen after backoff`);
|
|
443
|
+
}
|
|
444
|
+
else {
|
|
445
|
+
this.logAxiosError(e);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
};
|
|
449
|
+
rax.attach(this.axiosClient);
|
|
393
450
|
}
|
|
394
451
|
logAxiosError(e) {
|
|
395
452
|
if (e.response) {
|
|
396
453
|
logger.debug('response');
|
|
397
454
|
logger.debug(e.response.status);
|
|
398
|
-
logger.debug(e.response.data);
|
|
455
|
+
logger.debug((0, util_1.inspect)(e.response.data, { depth: 3 }));
|
|
399
456
|
}
|
|
400
457
|
if (e.request) {
|
|
401
458
|
logger.debug('request');
|
|
@@ -406,19 +463,121 @@ class SonarqubeResults {
|
|
|
406
463
|
logger.debug('Error', e.message);
|
|
407
464
|
}
|
|
408
465
|
}
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
466
|
+
// Default statuses to exclude from results (deny-list approach)
|
|
467
|
+
// Pre-10.4 legacy: CLOSED issues are end-of-life (rule deleted/disabled or component removed)
|
|
468
|
+
// 10.4+: FALSE_POSITIVE (user says not real), FIXED (no longer in code, purged after 30 days)
|
|
469
|
+
static DEFAULT_DENY_LIST_LEGACY = ['CLOSED'];
|
|
470
|
+
static DEFAULT_DENY_LIST_MODERN = ['FALSE_POSITIVE', 'FIXED'];
|
|
471
|
+
async discoverIssueStatuses(sonarqubeVersion) {
|
|
472
|
+
const isLegacy = isBeforeSonarqubeVersion(sonarqubeVersion, '10.4.0');
|
|
473
|
+
const statusParamKey = isLegacy ? 'statuses' : 'issueStatuses';
|
|
474
|
+
// Step 1: Discover all valid statuses from the server via /api/webservices/list
|
|
475
|
+
let allStatuses;
|
|
476
|
+
try {
|
|
477
|
+
const response = await this.axiosClient.get(`${this.sonarqubeHost}/api/webservices/list`, {
|
|
478
|
+
...(this.authMethod === AuthenticationMethod.TokenAsUsername && {
|
|
479
|
+
auth: { username: this.userToken, password: '' }
|
|
480
|
+
}),
|
|
481
|
+
...(this.authMethod === AuthenticationMethod.BearerToken && {
|
|
482
|
+
headers: { Authorization: `Bearer ${this.userToken}` }
|
|
483
|
+
})
|
|
484
|
+
});
|
|
485
|
+
const issuesService = response.data.webServices?.find((ws) => ws.path === 'api/issues');
|
|
486
|
+
const searchAction = issuesService?.actions?.find((a) => a.key === 'search');
|
|
487
|
+
const statusParam = searchAction?.params?.find((p) => p.key === statusParamKey);
|
|
488
|
+
if (statusParam?.possibleValues?.length) {
|
|
489
|
+
allStatuses = statusParam.possibleValues.map((s) => s.toUpperCase());
|
|
490
|
+
logger.info(`Available issue statuses from server: ${allStatuses.join(',')}`);
|
|
491
|
+
}
|
|
492
|
+
else {
|
|
493
|
+
throw new Error(`Webservices list returned no possibleValues for ${statusParamKey}. ` +
|
|
494
|
+
`Raw param data: ${JSON.stringify(statusParam)}`);
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
catch (e) {
|
|
498
|
+
// Step 2: Fallback to hardcoded full status list if discovery fails
|
|
499
|
+
allStatuses = isLegacy
|
|
500
|
+
? ['OPEN', 'REOPENED', 'CONFIRMED', 'RESOLVED', 'CLOSED']
|
|
501
|
+
: [
|
|
502
|
+
'OPEN',
|
|
503
|
+
'CONFIRMED',
|
|
504
|
+
'FALSE_POSITIVE',
|
|
505
|
+
'ACCEPTED',
|
|
506
|
+
'FIXED',
|
|
507
|
+
'IN_SANDBOX'
|
|
508
|
+
];
|
|
509
|
+
logger.warn(`Could not discover statuses from server, using fallback: ${allStatuses.join(',')}`);
|
|
510
|
+
logger.debug((0, util_1.inspect)(e, { depth: 3 }));
|
|
511
|
+
}
|
|
512
|
+
// Step 3: Determine which deny-list to use
|
|
513
|
+
const defaultDenyList = isLegacy
|
|
514
|
+
? SonarqubeResults.DEFAULT_DENY_LIST_LEGACY
|
|
515
|
+
: SonarqubeResults.DEFAULT_DENY_LIST_MODERN;
|
|
516
|
+
let denySet;
|
|
517
|
+
if (this.excludeIssueStatuses) {
|
|
518
|
+
// User-supplied deny-list REPLACES the defaults entirely
|
|
519
|
+
const userExclusions = this.excludeIssueStatuses
|
|
520
|
+
.split(',')
|
|
521
|
+
.map((s) => s.trim().toUpperCase())
|
|
522
|
+
.filter((s) => s.length > 0);
|
|
523
|
+
denySet = new Set(userExclusions);
|
|
524
|
+
// Smart nag: compare user list against defaults
|
|
525
|
+
const defaultSet = new Set(defaultDenyList);
|
|
526
|
+
const sameAsDefault = defaultSet.symmetricDifference(denySet).size === 0;
|
|
527
|
+
if (sameAsDefault) {
|
|
528
|
+
logger.info(`Exclusion list matches the defaults (${[...defaultSet].join(',')}). ` +
|
|
529
|
+
`You can omit --excludeIssueStatuses unless you want to be explicit.`);
|
|
530
|
+
}
|
|
531
|
+
else {
|
|
532
|
+
logger.warn(`Custom status exclusions applied: ${userExclusions.join(',')} ` +
|
|
533
|
+
`(replaces defaults: ${defaultDenyList.join(',')}). ` +
|
|
534
|
+
`If this exclusion should be a default, please consider filing an issue at ` +
|
|
535
|
+
`https://github.com/mitre/heimdall2/issues`);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
else {
|
|
539
|
+
// No user override — use defaults
|
|
540
|
+
denySet = new Set(defaultDenyList);
|
|
541
|
+
logger.info(`Using default status exclusions: ${defaultDenyList.join(',')}`);
|
|
542
|
+
}
|
|
543
|
+
// Step 4: Filter statuses and log the result
|
|
544
|
+
const excluded = allStatuses.filter((s) => denySet.has(s));
|
|
545
|
+
const result = allStatuses.filter((s) => !denySet.has(s));
|
|
546
|
+
if (result.length === 0) {
|
|
547
|
+
logger.warn(`All statuses were excluded by the deny-list. This will likely return no results. ` +
|
|
548
|
+
`Available: ${allStatuses.join(',')} | Excluded: ${excluded.join(',')}`);
|
|
549
|
+
}
|
|
550
|
+
logger.info(`Querying with issue statuses: ${result.join(',')} (excluded: ${excluded.join(',')})`);
|
|
551
|
+
return result.join(',');
|
|
552
|
+
}
|
|
553
|
+
async getSearchResults(sonarqubeVersion) {
|
|
554
|
+
const UPPER_LIMIT = 10000; // there is an upper limit of 10000 search results provided for any given search query (i.e. everything aside from the paging information): https://community.sonarsource.com/t/cannot-get-more-than-10000-results-through-web-api/3662
|
|
555
|
+
const discoveredStatuses = await this.discoverIssueStatuses(sonarqubeVersion);
|
|
556
|
+
const PAGE_SIZE = 100;
|
|
557
|
+
const createSearch = async (component, page, pageSize = PAGE_SIZE) => {
|
|
558
|
+
return this.axiosClient.get(`${this.sonarqubeHost}/api/issues/search`, {
|
|
559
|
+
...(this.authMethod === AuthenticationMethod.TokenAsUsername && {
|
|
560
|
+
auth: { username: this.userToken, password: '' }
|
|
561
|
+
}),
|
|
562
|
+
...(this.authMethod === AuthenticationMethod.BearerToken && {
|
|
563
|
+
headers: { Authorization: `Bearer ${this.userToken}` }
|
|
564
|
+
}),
|
|
565
|
+
params: {
|
|
566
|
+
[isBeforeSonarqubeVersion(sonarqubeVersion, '10.2.0')
|
|
567
|
+
? 'componentKeys'
|
|
568
|
+
: 'components']: component,
|
|
569
|
+
...(isBeforeSonarqubeVersion(sonarqubeVersion, '10.4.0')
|
|
570
|
+
? { statuses: discoveredStatuses }
|
|
571
|
+
: { issueStatuses: discoveredStatuses }),
|
|
572
|
+
p: page,
|
|
573
|
+
ps: pageSize,
|
|
574
|
+
...(this.branchName && { branch: this.branchName }),
|
|
575
|
+
...(this.pullRequestID && { pullRequest: this.pullRequestID })
|
|
576
|
+
}
|
|
577
|
+
});
|
|
418
578
|
};
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
.get(`${this.sonarqubeHost}/api/issues/search`, {
|
|
579
|
+
const createComponentSearch = async (component, page, pageSize = PAGE_SIZE) => {
|
|
580
|
+
return this.axiosClient.get(`${this.sonarqubeHost}/api/components/tree`, {
|
|
422
581
|
...(this.authMethod === AuthenticationMethod.TokenAsUsername && {
|
|
423
582
|
auth: { username: this.userToken, password: '' }
|
|
424
583
|
}),
|
|
@@ -426,29 +585,110 @@ class SonarqubeResults {
|
|
|
426
585
|
headers: { Authorization: `Bearer ${this.userToken}` }
|
|
427
586
|
}),
|
|
428
587
|
params: {
|
|
429
|
-
|
|
430
|
-
|
|
588
|
+
component: component,
|
|
589
|
+
strategy: 'children',
|
|
431
590
|
p: page,
|
|
591
|
+
ps: pageSize,
|
|
432
592
|
...(this.branchName && { branch: this.branchName }),
|
|
433
593
|
...(this.pullRequestID && { pullRequest: this.pullRequestID })
|
|
434
594
|
}
|
|
435
|
-
})
|
|
436
|
-
.then(({ data }) => {
|
|
437
|
-
_.mergeWith(results, data, (objValue, srcValue) => _.isArray(objValue) ? objValue.concat(srcValue) : undefined);
|
|
438
|
-
paging =
|
|
439
|
-
data.paging.pageIndex * data.paging.pageSize <= data.paging.total;
|
|
440
|
-
page += 1;
|
|
441
|
-
})
|
|
442
|
-
.catch((e) => {
|
|
443
|
-
this.logAxiosError(e);
|
|
444
|
-
return Promise.reject(new Error('Failed at getting Sonarqube issue'));
|
|
445
595
|
});
|
|
596
|
+
};
|
|
597
|
+
// intentionally doing the await in a loop so as to slow down requests a tad bit in order to avoid any rate limit issues
|
|
598
|
+
const collectPagedSearch = async (component, sizeCheck = false) => {
|
|
599
|
+
let paging = true;
|
|
600
|
+
let page = 1;
|
|
601
|
+
const results = {
|
|
602
|
+
components: [],
|
|
603
|
+
effortTotal: 0,
|
|
604
|
+
facets: [],
|
|
605
|
+
issues: [],
|
|
606
|
+
paging: { pageIndex: 0, pageSize: 0, total: 0 }
|
|
607
|
+
};
|
|
608
|
+
while (sizeCheck ? page === 1 : paging) {
|
|
609
|
+
console.log(results);
|
|
610
|
+
await createSearch(component, page)
|
|
611
|
+
.then(({ data }) => {
|
|
612
|
+
_.mergeWith(results, data, (objValue, srcValue) => _.isArray(objValue) ? objValue.concat(srcValue) : undefined);
|
|
613
|
+
// only need to check if it exceeds the upper limit, if it's less than the upper limit and we request a page that goes past the page total then it just returns fewer results without throwing an error
|
|
614
|
+
paging =
|
|
615
|
+
data.paging.pageIndex * data.paging.pageSize <= data.paging.total;
|
|
616
|
+
page += 1;
|
|
617
|
+
})
|
|
618
|
+
.catch((e) => {
|
|
619
|
+
this.logAxiosError(e);
|
|
620
|
+
throw new Error('Failed at retrieving Sonarqube issues');
|
|
621
|
+
});
|
|
622
|
+
if (page * PAGE_SIZE > UPPER_LIMIT) {
|
|
623
|
+
logger.warn(`Exceeded SonarQube cap of ${UPPER_LIMIT} results for findings of or under the ${component} component. Remaining findings may be truncated.`);
|
|
624
|
+
paging = false;
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
results.components = _.uniqBy(results.components, 'key'); // sometimes components will be duplicated if an issue on one page applies to the same component as an issue on another page. additionally at minimum the top level project will show up in every search result
|
|
628
|
+
return results;
|
|
629
|
+
};
|
|
630
|
+
const collectPagedComponentSearch = async (component) => {
|
|
631
|
+
let paging = true;
|
|
632
|
+
let page = 1;
|
|
633
|
+
const results = {
|
|
634
|
+
paging: { pageIndex: 0, pageSize: 0, total: 0 },
|
|
635
|
+
baseComponent: {
|
|
636
|
+
key: 'fake',
|
|
637
|
+
description: 'fake',
|
|
638
|
+
qualifier: 'fake',
|
|
639
|
+
tags: [],
|
|
640
|
+
visibility: 'false'
|
|
641
|
+
},
|
|
642
|
+
components: []
|
|
643
|
+
};
|
|
644
|
+
while (paging) {
|
|
645
|
+
await createComponentSearch(component, page)
|
|
646
|
+
.then(({ data }) => {
|
|
647
|
+
_.mergeWith(results, data, (objValue, srcValue) => _.isArray(objValue) ? objValue.concat(srcValue) : undefined);
|
|
648
|
+
paging =
|
|
649
|
+
data.paging.pageIndex * data.paging.pageSize <= data.paging.total;
|
|
650
|
+
page += 1;
|
|
651
|
+
})
|
|
652
|
+
.catch((e) => {
|
|
653
|
+
this.logAxiosError(e);
|
|
654
|
+
throw new Error('Failed at retrieving the list of components');
|
|
655
|
+
});
|
|
656
|
+
if (page * PAGE_SIZE > UPPER_LIMIT) {
|
|
657
|
+
logger.warn(`Exceeded SonarQube cap of ${UPPER_LIMIT} results for the search for children of the ${component} component. Remaining set of components may be truncated.`);
|
|
658
|
+
paging = false;
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
return results;
|
|
662
|
+
};
|
|
663
|
+
const results = await collectPagedSearch(this.projectKey, true);
|
|
664
|
+
const queue = [this.projectKey];
|
|
665
|
+
while (queue.length > 0) {
|
|
666
|
+
const component = queue.shift();
|
|
667
|
+
if (component === undefined) {
|
|
668
|
+
// unreachable code since we check that there are items in the queue; however, it helps typescript narrow the type properly
|
|
669
|
+
continue;
|
|
670
|
+
}
|
|
671
|
+
const sizeCheck = await collectPagedSearch(component, true);
|
|
672
|
+
if (sizeCheck.paging.total > UPPER_LIMIT) {
|
|
673
|
+
const componentSearch = await collectPagedComponentSearch(component);
|
|
674
|
+
queue.push(...componentSearch.components.map((c) => c.key));
|
|
675
|
+
}
|
|
676
|
+
const componentResults = await collectPagedSearch(component);
|
|
677
|
+
_.mergeWith(results, componentResults, (objValue, srcValue) => _.isArray(objValue) ? objValue.concat(srcValue) : objValue);
|
|
678
|
+
}
|
|
679
|
+
results.components = _.uniqBy(results.components, 'key');
|
|
680
|
+
results.issues = _.uniqBy(results.issues, 'key');
|
|
681
|
+
if (results.paging.total === results.issues.length) {
|
|
682
|
+
logger.warn('Alternative search queries were able to retrieve all findings.');
|
|
683
|
+
}
|
|
684
|
+
else {
|
|
685
|
+
logger.warn(`Alternative search queries were not able to retrieve all findings - ${results.paging.total - results.issues.length} findings were not retrieved.`);
|
|
446
686
|
}
|
|
447
687
|
return results;
|
|
448
688
|
}
|
|
449
689
|
async getCodeSnippets(issues) {
|
|
450
690
|
const getFullFile = async (component) => {
|
|
451
|
-
return
|
|
691
|
+
return this.axiosClient
|
|
452
692
|
.get(`${this.sonarqubeHost}/api/sources/raw`, {
|
|
453
693
|
...(this.authMethod === AuthenticationMethod.TokenAsUsername && {
|
|
454
694
|
auth: { username: this.userToken, password: '' }
|
|
@@ -477,7 +717,7 @@ class SonarqubeResults {
|
|
|
477
717
|
const linenumberedFile = applyLineNumber(fullFiles[component]);
|
|
478
718
|
const snippet = linenumberedFile
|
|
479
719
|
.split('\n')
|
|
480
|
-
.slice(Math.max(startLine - 3, 0), endLine + 3)
|
|
720
|
+
.slice(Math.max(startLine - 3, 0), endLine + 3) // slice wraps around if the start is less than 0 so we want to put a bounds check there to ensure we start at the top of the file; however, if the end is past the end of the array then it just goes until the end of the array so no bounds check is required there
|
|
481
721
|
.join('\n')
|
|
482
722
|
.trim();
|
|
483
723
|
const location = `${component}:${startLine}-${endLine}\n`;
|
|
@@ -489,15 +729,23 @@ class SonarqubeResults {
|
|
|
489
729
|
: [issue.component]));
|
|
490
730
|
const fullFilePromises = await Promise.all(components.map((component) => getFullFile(component)));
|
|
491
731
|
const fullFiles = Object.fromEntries(_.zip(components, fullFilePromises));
|
|
492
|
-
const snippets = issues.map((issue) =>
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
732
|
+
const snippets = issues.map((issue) => {
|
|
733
|
+
if (issue.flows.length) {
|
|
734
|
+
return issue.flows
|
|
735
|
+
.flatMap((flow) => flow.locations.map((location) => getContextualizedSnippet(fullFiles, location.component, location.textRange.startLine, location.textRange.endLine, location.msg)))
|
|
736
|
+
.join('\n');
|
|
737
|
+
}
|
|
738
|
+
else if (issue.textRange) {
|
|
739
|
+
return getContextualizedSnippet(fullFiles, issue.component, issue.textRange.startLine, issue.textRange.endLine);
|
|
740
|
+
}
|
|
741
|
+
else {
|
|
742
|
+
return '';
|
|
743
|
+
}
|
|
744
|
+
});
|
|
497
745
|
return snippets;
|
|
498
746
|
}
|
|
499
747
|
async getRules(issues) {
|
|
500
|
-
const getRule = async (rule, organization) =>
|
|
748
|
+
const getRule = async (rule, organization) => this.axiosClient
|
|
501
749
|
.get(`${this.sonarqubeHost}/api/rules/show`, {
|
|
502
750
|
...(this.authMethod === AuthenticationMethod.TokenAsUsername && {
|
|
503
751
|
auth: { username: this.userToken, password: '' }
|
|
@@ -509,7 +757,7 @@ class SonarqubeResults {
|
|
|
509
757
|
key: rule,
|
|
510
758
|
...((organization || this.organization) && {
|
|
511
759
|
organization: organization || this.organization
|
|
512
|
-
})
|
|
760
|
+
}) // seems to be required for sonarcloud at least
|
|
513
761
|
}
|
|
514
762
|
})
|
|
515
763
|
.then(({ data }) => data)
|
|
@@ -524,7 +772,7 @@ class SonarqubeResults {
|
|
|
524
772
|
return rules;
|
|
525
773
|
}
|
|
526
774
|
async generateHdf(sonarqubeVersion) {
|
|
527
|
-
const searchResults = await this.getSearchResults();
|
|
775
|
+
const searchResults = await this.getSearchResults(sonarqubeVersion);
|
|
528
776
|
logger.debug(`Got ${searchResults.issues.length} issues`);
|
|
529
777
|
const codeSnippets = await this.getCodeSnippets(searchResults.issues);
|
|
530
778
|
logger.debug(`Got ${codeSnippets.length} code snippets`);
|
|
@@ -549,7 +797,7 @@ class SonarqubeResults {
|
|
|
549
797
|
return new SonarqubeMapper(data, this.withRaw).toHdf();
|
|
550
798
|
}
|
|
551
799
|
async toHdf() {
|
|
552
|
-
const sonarqubeVersion = await
|
|
800
|
+
const sonarqubeVersion = await this.axiosClient
|
|
553
801
|
.get(`${this.sonarqubeHost}/api/server/version`)
|
|
554
802
|
.then(({ data }) => data);
|
|
555
803
|
logger.debug(`Generating HDF for ${this.sonarqubeHost} version: ${sonarqubeVersion}`);
|