32
32
from cyclonedx .schema import SchemaVersion
33
33
from cyclonedx .validation import ValidationError
34
34
from cyclonedx .validation .json import JsonStrictValidator
35
+ from defusedxml import ElementTree as SafeElementTree
35
36
from packageurl import PackageURL
36
37
37
38
@@ -121,10 +122,18 @@ def validate_document(document):
121
122
122
123
def is_cyclonedx_bom (input_location ):
123
124
"""Return True if the file at `input_location` is a CycloneDX BOM."""
124
- with suppress (Exception ):
125
- data = json .loads (Path (input_location ).read_text ())
126
- if data .get ("bomFormat" ) == "CycloneDX" :
127
- return True
125
+ if str (input_location ).endswith (".json" ):
126
+ with suppress (Exception ):
127
+ data = json .loads (Path (input_location ).read_text ())
128
+ if data .get ("bomFormat" ) == "CycloneDX" :
129
+ return True
130
+
131
+ elif str (input_location ).endswith (".xml" ):
132
+ with suppress (Exception ):
133
+ et = SafeElementTree .parse (input_location )
134
+ if "cyclonedx" in et .getroot ().tag :
135
+ return True
136
+
128
137
return False
129
138
130
139
@@ -164,11 +173,6 @@ def cyclonedx_component_to_package_data(cdx_component):
164
173
}
165
174
166
175
167
- def get_bom (cyclonedx_document ):
168
- """Return CycloneDX BOM object."""
169
- return Bom .from_json (data = cyclonedx_document )
170
-
171
-
172
176
def get_components (bom ):
173
177
"""Return list of components from CycloneDX BOM."""
174
178
return list (bom ._get_all_components ())
@@ -177,13 +181,23 @@ def get_components(bom):
177
181
def resolve_cyclonedx_packages (input_location ):
178
182
"""Resolve the packages from the `input_location` CycloneDX document file."""
179
183
input_path = Path (input_location )
180
- cyclonedx_document = json . loads ( input_path .read_text () )
184
+ document_data = input_path .read_text ()
181
185
182
- if errors := validate_document ( cyclonedx_document ):
183
- error_msg = f'CycloneDX document " { input_path . name } " is not valid: \n { errors } '
184
- raise ValueError ( error_msg )
186
+ if str ( input_location ). endswith ( ".xml" ):
187
+ cyclonedx_document = SafeElementTree . fromstring ( document_data )
188
+ cyclonedx_bom = Bom . from_xml ( cyclonedx_document )
185
189
186
- cyclonedx_bom = get_bom (cyclonedx_document )
187
- components = get_components (cyclonedx_bom )
190
+ elif str (input_location ).endswith (".json" ):
191
+ cyclonedx_document = json .loads (document_data )
192
+ if errors := validate_document (cyclonedx_document ):
193
+ error_msg = (
194
+ f'CycloneDX document "{ input_path .name } " is not valid:\n { errors } '
195
+ )
196
+ raise ValueError (error_msg )
197
+ cyclonedx_bom = Bom .from_json (data = cyclonedx_document )
198
+
199
+ else :
200
+ return []
188
201
202
+ components = get_components (cyclonedx_bom )
189
203
return [cyclonedx_component_to_package_data (component ) for component in components ]
0 commit comments