Sat, 04 Jun 2022 16:57:02 +0200
CycloneDX
- added capability to list dependencies in the SBOM file
--- a/eric7/CycloneDXInterface/CycloneDXConfigDialog.py Sat Jun 04 16:56:22 2022 +0200 +++ b/eric7/CycloneDXInterface/CycloneDXConfigDialog.py Sat Jun 04 16:57:02 2022 +0200 @@ -141,8 +141,9 @@ @return tuple containing the input source, the input file name, the file format, the schema version, the path of the SBOM file to be - written and a flag indicating to include vulnerability information - @rtype tuple of (str, str, str, str, str, bool) + written, a flag indicating to include vulnerability information + and a flag indicating to include dependency information + @rtype tuple of (str, str, str, str, str, bool, bool) """ if self.environmentButton.isChecked(): inputSource = "environment" @@ -186,4 +187,5 @@ return ( inputSource, inputFile, fileFormat, schemaVersion, sbomFile, self.vulnerabilityCheckBox.isChecked(), + self.dependenciesCheckBox.isChecked(), )
--- a/eric7/CycloneDXInterface/CycloneDXConfigDialog.ui Sat Jun 04 16:56:22 2022 +0200 +++ b/eric7/CycloneDXInterface/CycloneDXConfigDialog.ui Sat Jun 04 16:57:02 2022 +0200 @@ -7,7 +7,7 @@ <x>0</x> <y>0</y> <width>650</width> - <height>308</height> + <height>338</height> </rect> </property> <property name="windowTitle"> @@ -99,21 +99,41 @@ <string>SBOM Output</string> </property> <layout class="QGridLayout" name="gridLayout"> - <item row="1" column="0"> - <widget class="QLabel" name="label_2"> - <property name="text"> - <string>File Format:</string> - </property> - </widget> - </item> - <item row="2" column="0"> + <item row="3" column="0"> <widget class="QLabel" name="label_3"> <property name="text"> <string>Schema Version:</string> </property> </widget> </item> - <item row="1" column="1"> + <item row="4" column="0"> + <widget class="QLabel" name="label_4"> + <property name="text"> + <string>File Name:</string> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="QComboBox" name="schemaVersionComboBox"> + <property name="toolTip"> + <string>Select the SBOM schema version of the SBOM file</string> + </property> + </widget> + </item> + <item row="2" column="2"> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>413</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="2" column="1"> <widget class="QComboBox" name="fileFormatComboBox"> <property name="toolTip"> <string>Select the format of the SBOM file</string> @@ -130,27 +150,14 @@ </item> </widget> </item> - <item row="3" column="0"> - <widget class="QLabel" name="label_4"> + <item row="2" column="0"> + <widget class="QLabel" name="label_2"> <property name="text"> - <string>File Name:</string> + <string>File Format:</string> </property> </widget> </item> - <item row="1" column="2"> - <spacer name="horizontalSpacer"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>413</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item row="3" column="1" colspan="2"> + <item row="4" column="1" colspan="2"> <widget class="EricPathPicker" name="filePicker" native="true"> <property name="focusPolicy"> <enum>Qt::StrongFocus</enum> @@ -160,13 +167,6 @@ </property> </widget> </item> - <item row="2" column="1"> - <widget class="QComboBox" name="schemaVersionComboBox"> - <property name="toolTip"> - <string>Select the SBOM schema version of the SBOM file</string> - </property> - </widget> - </item> <item row="0" column="0" colspan="3"> <widget class="QCheckBox" name="vulnerabilityCheckBox"> <property name="toolTip"> @@ -180,6 +180,19 @@ </property> </widget> </item> + <item row="1" column="0" colspan="3"> + <widget class="QCheckBox" name="dependenciesCheckBox"> + <property name="toolTip"> + <string>Select to include dependency information in the generated SBOM</string> + </property> + <property name="text"> + <string>Include Dependencies</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> </layout> </widget> </item> @@ -209,6 +222,7 @@ <tabstop>poetryButton</tabstop> <tabstop>requirementsButton</tabstop> <tabstop>vulnerabilityCheckBox</tabstop> + <tabstop>dependenciesCheckBox</tabstop> <tabstop>fileFormatComboBox</tabstop> <tabstop>schemaVersionComboBox</tabstop> <tabstop>filePicker</tabstop>
--- a/eric7/CycloneDXInterface/CycloneDXUtilities.py Sat Jun 04 16:56:22 2022 +0200 +++ b/eric7/CycloneDXInterface/CycloneDXUtilities.py Sat Jun 04 16:57:02 2022 +0200 @@ -82,7 +82,7 @@ dlg = CycloneDXConfigDialog(venvName) if dlg.exec() == QDialog.DialogCode.Accepted: (inputSource, inputFile, fileFormat, schemaVersion, sbomFile, - withVulnerabilities) = dlg.getData() + withVulnerabilities, withDependencies) = dlg.getData() # check error conditions first if inputSource not in ("environment", "pipenv", "poetry", @@ -118,6 +118,9 @@ if withVulnerabilities: addCycloneDXVulnerabilities(parser) + if withDependencies: + addCycloneDXDependencies(parser, venvName) + if fileFormat == "XML": outputFormat = OutputFormat.XML elif fileFormat == "JSON": @@ -191,6 +194,46 @@ )) +def addCycloneDXDependencies(parser, venvName): + """ + Function to add dependency data to the list of created components. + + @param parser reference to the parser object containing the list of + components + @type BaseParser + @param venvName name of the virtual environment + @type str + """ + components = parser.get_components() + + pip = ericApp().getObject("Pip") + dependencies = pip.getDependencyTree(venvName) + for dependency in dependencies: + _addCycloneDXDependency(dependency, components) + + +def _addCycloneDXDependency(dependency, components): + """ + Function to add a dependency to the given list of components. + + @param dependency dependency to be added + @type dict + @param components list of components + @type list of Component + """ + component = findCyccloneDXComponent(components, dependency["package_name"]) + if component is not None: + bomRefs = component.dependencies + for dep in dependency["dependencies"]: + depComponent = findCyccloneDXComponent( + components, dep["package_name"]) + if depComponent is not None: + bomRefs.add(depComponent.bom_ref) + # recursively add sub-dependencies + _addCycloneDXDependency(dep, components) + component.dependencies = bomRefs + + def findCyccloneDXComponent(components, name): """ Function to find a component in a given list of components.