Skip to content

Commit ac9a1ee

Browse files
authored
Merge pull request #162 from sw360/fix-sbom-file-url
fix: support file:// URLs in SBOMs
2 parents 633e275 + 1487b00 commit ac9a1ee

File tree

10 files changed

+36
-21
lines changed

10 files changed

+36
-21
lines changed

ChangeLog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
* `bom map` will provide the `purl` from SW360 in the output BOM's components
1111
(due to a missing code path, PURL from input BOM was copied to mapping result instead)
12+
* support file:// URLs for local paths in SBOMs
1213

1314
## 2.9.0
1415

capycli/bom/create_components.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -438,12 +438,12 @@ def upload_file(
438438
filehash = None
439439
if filetype in ["SOURCE", "SOURCE_SELF"]:
440440
url = str(CycloneDxSupport.get_ext_ref_source_url(cx_comp))
441-
filename = str(CycloneDxSupport.get_ext_ref_source_file(cx_comp))
441+
filename = CycloneDxSupport.get_ext_ref_source_file(cx_comp)
442442
filehash = str(CycloneDxSupport.get_source_file_hash(cx_comp))
443443

444444
if filetype in ["BINARY", "BINARY_SELF"]:
445445
url = str(CycloneDxSupport.get_ext_ref_binary_url(cx_comp))
446-
filename = str(CycloneDxSupport.get_ext_ref_binary_file(cx_comp))
446+
filename = CycloneDxSupport.get_ext_ref_binary_file(cx_comp)
447447
filehash = str(CycloneDxSupport.get_binary_file_hash(cx_comp))
448448

449449
# Note that we retrieve the SHA1 has from the CycloneDX data.

capycli/bom/legacy.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -274,9 +274,9 @@ def cdx_component_to_legacy(cls, cx_comp: Component) -> Dict[str, Any]:
274274
lcomp["Language"] = CycloneDxSupport.get_property_value(cx_comp, CycloneDxSupport.CDX_PROP_LANGUAGE)
275275
lcomp["SourceUrl"] = str(CycloneDxSupport.get_ext_ref_source_url(cx_comp))
276276
lcomp["RepositoryUrl"] = str(CycloneDxSupport.get_ext_ref_repository(cx_comp))
277-
lcomp["SourceFile"] = str(CycloneDxSupport.get_ext_ref_source_file(cx_comp))
277+
lcomp["SourceFile"] = CycloneDxSupport.get_ext_ref_source_file(cx_comp)
278278
lcomp["SourceFileHash"] = CycloneDxSupport.get_source_file_hash(cx_comp)
279-
lcomp["BinaryFile"] = str(CycloneDxSupport.get_ext_ref_binary_file(cx_comp))
279+
lcomp["BinaryFile"] = CycloneDxSupport.get_ext_ref_binary_file(cx_comp)
280280
lcomp["BinaryFileHash"] = CycloneDxSupport.get_binary_file_hash(cx_comp)
281281
lcomp["BinaryFileUrl"] = str(CycloneDxSupport.get_ext_ref_binary_url(cx_comp))
282282
lcomp["Homepage"] = str(CycloneDxSupport.get_ext_ref_website(cx_comp))

capycli/bom/map_bom.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ def map_bom_item(self, component: Component, check_similar: bool, result_require
229229
break
230230

231231
# fourth check: source filename
232-
cmp_src_file = str(CycloneDxSupport.get_ext_ref_source_file(component))
232+
cmp_src_file = CycloneDxSupport.get_ext_ref_source_file(component)
233233
if (("SourceFile" in release)
234234
and cmp_src_file
235235
and release["SourceFile"]):

capycli/common/capycli_bom_support.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -217,11 +217,15 @@ def get_ext_ref_source_url(comp: Component) -> Any:
217217
return ""
218218

219219
@staticmethod
220-
def get_ext_ref_source_file(comp: Component) -> Any:
220+
def get_ext_ref_source_file(comp: Component) -> str:
221221
for ext_ref in comp.external_references:
222222
if (ext_ref.type == ExternalReferenceType.DISTRIBUTION) \
223223
and (ext_ref.comment == CaPyCliBom.SOURCE_FILE_COMMENT):
224-
return ext_ref.url
224+
url = str(ext_ref.url)
225+
if url.startswith("file://"):
226+
return url[7:]
227+
else:
228+
return url
225229

226230
return ""
227231

@@ -235,11 +239,15 @@ def get_ext_ref_binary_url(comp: Component) -> Any:
235239
return ""
236240

237241
@staticmethod
238-
def get_ext_ref_binary_file(comp: Component) -> Any:
242+
def get_ext_ref_binary_file(comp: Component) -> str:
239243
for ext_ref in comp.external_references:
240244
if (ext_ref.type == ExternalReferenceType.DISTRIBUTION) \
241245
and (ext_ref.comment == CaPyCliBom.BINARY_FILE_COMMENT):
242-
return ext_ref.url
246+
url = str(ext_ref.url)
247+
if url.startswith("file://"):
248+
return url[7:]
249+
else:
250+
return url
243251

244252
return ""
245253

tests/test_bom_create_releases.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -664,6 +664,12 @@ def test_upload_file_local(self) -> None:
664664
CaPyCliBom.SOURCE_URL_COMMENT, my_url)
665665
self.app.upload_file(item, {}, "06a6e7", "SOURCE_SELF", "")
666666

667+
# local filename with file:// prefix
668+
CycloneDxSupport.update_or_set_ext_ref(
669+
item, ExternalReferenceType.DISTRIBUTION,
670+
CaPyCliBom.SOURCE_FILE_COMMENT, "file://Readme.md")
671+
self.app.upload_file(item, {}, "06a6e7", "SOURCE_SELF", "")
672+
667673
# local filename guessed from remote url
668674
item = Component(
669675
name="activemodel",
@@ -675,9 +681,10 @@ def test_upload_file_local(self) -> None:
675681
CaPyCliBom.SOURCE_URL_COMMENT, my_url)
676682
self.app.upload_file(item, {}, "06a6e7", "SOURCE_SELF", "")
677683

678-
assert len(responses.calls) == 2
684+
assert len(responses.calls) == 3
679685
captured = self.capsys.readouterr() # type: ignore
680686
assert "Error" not in captured.out
687+
assert "not found" not in captured.out
681688
assert captured.err == ""
682689

683690
@responses.activate

tests/test_bom_filter.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,7 @@ def test_update_single_item(self) -> None:
401401
self.assertEqual(component["Version"], bom.components[2].version)
402402
self.assertEqual(component["RepositoryId"], bom.components[2].purl.to_string())
403403
self.assertEqual(component["SourceFileUrl"], str(CycloneDxSupport.get_ext_ref_source_url(bom.components[2])))
404-
self.assertEqual(component["SourceFile"], str(CycloneDxSupport.get_ext_ref_source_file(bom.components[2])))
404+
self.assertEqual(component["SourceFile"], CycloneDxSupport.get_ext_ref_source_file(bom.components[2]))
405405
self.assertEqual(
406406
component["Language"],
407407
CycloneDxSupport.get_property_value(bom.components[2], CycloneDxSupport.CDX_PROP_LANGUAGE))

tests/test_bom_map2.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3000,8 +3000,8 @@ def test_update_bom_item(self) -> None:
30003000
for ext_ref in updated.external_references:
30013001
self.assertIsInstance(ext_ref.url, XsUri)
30023002
self.assertEqual("http://123", str(CycloneDxSupport.get_ext_ref_source_url(updated)))
3003-
self.assertEqual("123%251.zip", str(CycloneDxSupport.get_ext_ref_source_file(updated)))
3004-
self.assertEqual("123%25.dll", str(CycloneDxSupport.get_ext_ref_binary_file(updated)))
3003+
self.assertEqual("123%251.zip", CycloneDxSupport.get_ext_ref_source_file(updated))
3004+
self.assertEqual("123%25.dll", CycloneDxSupport.get_ext_ref_binary_file(updated))
30053005
self.assertEqual("http://somewhere", str(CycloneDxSupport.get_ext_ref_website(updated)))
30063006
self.assertEqual("007", CycloneDxSupport.get_property_value(updated, CycloneDxSupport.CDX_PROP_SW360ID))
30073007

@@ -3025,8 +3025,8 @@ def test_update_bom_item(self) -> None:
30253025
self.assertEqual("http://456", str(CycloneDxSupport.get_ext_ref_source_url(comp)))
30263026
for ext_ref in updated.external_references:
30273027
self.assertIsInstance(ext_ref.url, XsUri)
3028-
self.assertEqual("456.zip", str(CycloneDxSupport.get_ext_ref_source_file(updated)))
3029-
self.assertEqual("456.dll", str(CycloneDxSupport.get_ext_ref_binary_file(updated)))
3028+
self.assertEqual("456.zip", CycloneDxSupport.get_ext_ref_source_file(updated))
3029+
self.assertEqual("456.dll", CycloneDxSupport.get_ext_ref_binary_file(updated))
30303030
self.assertEqual("http://somewhereelse", str(CycloneDxSupport.get_ext_ref_website(updated)))
30313031
self.assertEqual("888", CycloneDxSupport.get_property_value(updated, CycloneDxSupport.CDX_PROP_SW360ID))
30323032

@@ -3051,8 +3051,8 @@ def test_update_bom_item(self) -> None:
30513051
for ext_ref in updated.external_references:
30523052
self.assertIsInstance(ext_ref.url, XsUri)
30533053
self.assertEqual("http://123", str(CycloneDxSupport.get_ext_ref_source_url(updated)))
3054-
self.assertEqual("123%251.zip", str(CycloneDxSupport.get_ext_ref_source_file(updated)))
3055-
self.assertEqual("123%25.dll", str(CycloneDxSupport.get_ext_ref_binary_file(updated)))
3054+
self.assertEqual("123%251.zip", CycloneDxSupport.get_ext_ref_source_file(updated))
3055+
self.assertEqual("123%25.dll", CycloneDxSupport.get_ext_ref_binary_file(updated))
30563056
self.assertEqual("http://somewhere", str(CycloneDxSupport.get_ext_ref_website(updated)))
30573057
self.assertEqual("007", CycloneDxSupport.get_property_value(updated, CycloneDxSupport.CDX_PROP_SW360ID))
30583058
self.assertEqual("0815", CycloneDxSupport.get_property_value(updated, CycloneDxSupport.CDX_PROP_COMPONENT_ID))

tests/test_get_dependencies_python.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -222,14 +222,14 @@ def test_get_metadata(self) -> None:
222222
str(CycloneDxSupport.get_ext_ref_binary_url(sbom.components[0])))
223223
self.assertEqual(
224224
"chardet-3.0.4-py2.py3-none-any.whl",
225-
str(CycloneDxSupport.get_ext_ref_binary_file(sbom.components[0])))
225+
CycloneDxSupport.get_ext_ref_binary_file(sbom.components[0]))
226226

227227
self.assertEqual(
228228
"https://files.pythonhosted.org/packages/fc/bb/a5768c230/chardet-3.0.4.tar.gz",
229229
str(CycloneDxSupport.get_ext_ref_source_url(sbom.components[0])))
230230
self.assertEqual(
231231
"chardet-3.0.4.tar.gz",
232-
str(CycloneDxSupport.get_ext_ref_source_file(sbom.components[0])))
232+
CycloneDxSupport.get_ext_ref_source_file(sbom.components[0]))
233233

234234
self.delete_file(self.OUTPUTFILE1)
235235
self.delete_file(self.OUTPUTFILE2)

tests/test_legacy_cx.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88

99
import os
1010

11-
from cyclonedx.model import XsUri
1211
from cyclonedx.model.bom_ref import BomRef
1312
from sortedcontainers import SortedSet
1413

@@ -40,7 +39,7 @@ def assert_components(self, cx_components: SortedSet) -> None:
4039
cx_components[0], CycloneDxSupport.CDX_PROP_SRC_FILE_TYPE))
4140
self.assertEqual("James Bond", CycloneDxSupport.get_property_value(
4241
cx_components[0], CycloneDxSupport.CDX_PROP_SRC_FILE_COMMENT))
43-
self.assertEqual(XsUri("colorama-0.4.3.tar.gz"), CycloneDxSupport.get_ext_ref_source_file(
42+
self.assertEqual("colorama-0.4.3.tar.gz", CycloneDxSupport.get_ext_ref_source_file(
4443
cx_components[0]))
4544

4645
self.assertEqual("python", cx_components[1].name)

0 commit comments

Comments
 (0)