Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
components have been scanned and how many warnings and errors there are.
* Adapt `getdependencies python` to the Poetry 2.x pyproject.toml format.
* `getdependencies python` now also supports uv and its `uv.lock` file.
* Have correct `file:///` uri for files in SBOM external references.

## 2.9.1

Expand Down
9 changes: 6 additions & 3 deletions capycli/bom/download_sources.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,14 +110,17 @@ def download_sources(self, sbom: Bom, source_folder: str) -> None:
new = False
ext_ref = CycloneDxSupport.get_ext_ref(
component, ExternalReferenceType.DISTRIBUTION, CaPyCliBom.SOURCE_FILE_COMMENT)
file_uri = path
if not file_uri.startswith("file://"):
file_uri = "file:///" + file_uri
if not ext_ref:
ext_ref = ExternalReference(
type=ExternalReferenceType.DISTRIBUTION,
comment=CaPyCliBom.SOURCE_FILE_COMMENT,
url=XsUri(path))
url=XsUri(file_uri))
new = True
else:
ext_ref.url = XsUri(path)
ext_ref.url = XsUri(file_uri)
ext_ref.hashes.add(HashType(
alg=HashAlgorithm.SHA_1,
content=sha1))
Expand Down Expand Up @@ -188,7 +191,7 @@ def run(self, args: Any) -> None:
sys.exit(ResultCode.RESULT_ERROR_READING_BOM)

if args.verbose:
print_text(" " + str(len(bom.components)) + "components written to SBOM file")
print_text(" " + str(len(bom.components)) + "components read from SBOM file")

source_folder = "./"
if args.source:
Expand Down
2 changes: 2 additions & 0 deletions capycli/bom/legacy.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,8 @@ def legacy_component_to_cdx(item: Dict[str, Any]) -> Component:

binaryFile = item.get("BinaryFile", "")
if binaryFile:
if not binaryFile.startswith("file://"):
binaryFile = "file:///" + binaryFile
ext_ref = ExternalReference(
type=ExternalReferenceType.DISTRIBUTION,
comment=CaPyCliBom.BINARY_FILE_COMMENT,
Expand Down
17 changes: 13 additions & 4 deletions capycli/bom/legacy_cx.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# -------------------------------------------------------------------------------
# Copyright (c) 2023 Siemens
# Copyright (c) 2023-2025 Siemens
# All Rights Reserved.
# Author: [email protected]
#
Expand Down Expand Up @@ -66,10 +66,13 @@ def _convert_component(cls, component: Component) -> Component:
# extra handling
prop = CycloneDxSupport.get_property(component, "source-file")
if prop:
file_uri = prop.value
if not file_uri.startswith("file://"):
file_uri = "file:///" + file_uri
ext_ref = ExternalReference(
type=ExternalReferenceType.DISTRIBUTION,
comment=CaPyCliBom.SOURCE_FILE_COMMENT,
url=XsUri(prop.value))
url=XsUri(file_uri))
prop2 = CycloneDxSupport.get_property(component, "source-file-hash")
if prop2:
ext_ref.hashes.add(HashType(
Expand All @@ -80,10 +83,13 @@ def _convert_component(cls, component: Component) -> Component:

prop = CycloneDxSupport.get_property(component, "source-file-url")
if prop:
file_uri = prop.value
if not file_uri.startswith("file://"):
file_uri = "file:///" + file_uri
ext_ref = ExternalReference(
type=ExternalReferenceType.DISTRIBUTION,
comment=CaPyCliBom.SOURCE_URL_COMMENT,
url=XsUri(prop.value))
url=XsUri(file_uri))
prop2 = CycloneDxSupport.get_property(component, "source-file-hash")
if prop2:
ext_ref.hashes.add(HashType(
Expand Down Expand Up @@ -112,10 +118,13 @@ def _convert_component(cls, component: Component) -> Component:

prop = CycloneDxSupport.get_property(component, "binary-file")
if prop:
file_uri = prop.value
if not file_uri.startswith("file://"):
file_uri = "file:///" + file_uri
ext_ref = ExternalReference(
type=ExternalReferenceType.DISTRIBUTION,
comment=CaPyCliBom.BINARY_FILE_COMMENT,
url=XsUri(prop.value))
url=XsUri(file_uri))
prop2 = CycloneDxSupport.get_property(component, "binary-file-hash")
if prop2:
ext_ref.hashes.add(HashType(
Expand Down
20 changes: 15 additions & 5 deletions capycli/common/capycli_bom_support.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,12 +163,18 @@ def update_or_set_ext_ref(comp: Component, type: ExternalReferenceType, comment:
@staticmethod
def have_relative_ext_ref_path(ext_ref: ExternalReference, rel_to: str) -> str:
if isinstance(ext_ref.url, str):
bip = pathlib.PurePath(ext_ref.url)
check_val = ext_ref.url._uri
if check_val.startswith("file:///"):
check_val = check_val[8:]
bip = pathlib.PurePath(check_val)
else:
bip = pathlib.PurePath(ext_ref.url._uri)
check_val = ext_ref.url._uri
if check_val.startswith("file:///"):
check_val = check_val[8:]
bip = pathlib.PurePath(check_val)
file = bip.as_posix()
if os.path.isfile(file):
ext_ref.url = XsUri("file://" + bip.relative_to(rel_to).as_posix())
ext_ref.url = XsUri("file:///" + bip.relative_to(rel_to).as_posix())
return bip.name

@staticmethod
Expand Down Expand Up @@ -223,7 +229,9 @@ def get_ext_ref_source_file(comp: Component) -> str:
if (ext_ref.type == ExternalReferenceType.DISTRIBUTION) \
and (ext_ref.comment == CaPyCliBom.SOURCE_FILE_COMMENT):
url = str(ext_ref.url)
if url.startswith("file://"):
if url.startswith("file:///"):
return url[8:]
elif url.startswith("file://"):
return url[7:]
else:
return url
Expand All @@ -245,7 +253,9 @@ def get_ext_ref_binary_file(comp: Component) -> str:
if (ext_ref.type == ExternalReferenceType.DISTRIBUTION) \
and (ext_ref.comment == CaPyCliBom.BINARY_FILE_COMMENT):
url = str(ext_ref.url)
if url.startswith("file://"):
if url.startswith("file:///"):
return url[8:]
elif url.startswith("file://"):
return url[7:]
else:
return url
Expand Down
4 changes: 4 additions & 0 deletions capycli/dependencies/javascript.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ def get_dependency(self, data: Dict[str, Any], sbom: Bom) -> Bom:

url = dep.get("resolved", "").split('/')[-1]
if url:
if not url.startswith("file://"):
url = "file:///" + url
ext_ref = ExternalReference(
type=ExternalReferenceType.DISTRIBUTION,
comment=CaPyCliBom.BINARY_FILE_COMMENT,
Expand Down Expand Up @@ -131,6 +133,8 @@ def get_dependency_lockversion3(self, data: Dict[str, Any], sbom: Bom) -> Bom:

url = dep.get("resolved", "").split('/')[-1]
if url:
if not url.startswith("file://"):
url = "file:///" + url
ext_ref = ExternalReference(
type=ExternalReferenceType.DISTRIBUTION,
comment=CaPyCliBom.BINARY_FILE_COMMENT,
Expand Down
10 changes: 8 additions & 2 deletions capycli/dependencies/python.py
Original file line number Diff line number Diff line change
Expand Up @@ -314,10 +314,13 @@ def add_meta_data_to_bomitem(self, cxcomp: Component, package_source: str = "")
for item in meta["urls"]:
if "packagetype" in item:
if item["packagetype"] == "bdist_wheel":
file_uri = item["filename"]
if not file_uri.startswith("file://"):
file_uri = "file:///" + file_uri
ext_ref = ExternalReference(
type=ExternalReferenceType.DISTRIBUTION,
comment=CaPyCliBom.BINARY_FILE_COMMENT,
url=XsUri(item["filename"]))
url=XsUri(file_uri))
cxcomp.external_references.add(ext_ref)
LOG.debug(" got binary file")

Expand All @@ -329,10 +332,13 @@ def add_meta_data_to_bomitem(self, cxcomp: Component, package_source: str = "")
LOG.debug(" got binary file url")

if item["packagetype"] == "sdist":
file_uri = item["filename"]
if not file_uri.startswith("file://"):
file_uri = "file:///" + file_uri
ext_ref = ExternalReference(
type=ExternalReferenceType.DISTRIBUTION,
comment=CaPyCliBom.SOURCE_FILE_COMMENT,
url=XsUri(item["filename"]))
url=XsUri(file_uri))
cxcomp.external_references.add(ext_ref)
LOG.debug(" got source file")

Expand Down
22 changes: 12 additions & 10 deletions tests/test_bom_downloadsources.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# -------------------------------------------------------------------------------
# Copyright (c) 2023-2024 Siemens
# Copyright (c) 2023-2025 Siemens
# All Rights Reserved.
# Author: [email protected]
#
Expand Down Expand Up @@ -130,7 +130,7 @@ def test_simple_bom(self) -> None:
try:
out = self.capture_stdout(sut.run, args)
out_bom = CaPyCliBom.read_sbom(args.outputfile)
# capycli.common.json_support.write_json_to_file(out, "STDOUT.TXT")
# json_support.write_json_to_file(out, "STDOUT.TXT")
self.assertTrue("Loading SBOM file" in out)
self.assertTrue("sbom_for_download.json" in out) # path may vary
self.assertIn("SBOM file is not relative to", out)
Expand All @@ -144,11 +144,10 @@ def test_simple_bom(self) -> None:
out_bom.components[0], ExternalReferenceType.DISTRIBUTION, CaPyCliBom.SOURCE_FILE_COMMENT)
self.assertIsNotNone(ext_ref)
if ext_ref: # only for mypy
self.assertEqual(ext_ref.url._uri, resultfile)
# if ext_ref.url is XsUri:
# self.assertEqual(ext_ref.url._uri, resultfile)
# else:
# self.assertEqual(ext_ref.url, resultfile)
check_val = ext_ref.url._uri
if check_val.startswith("file:///"):
check_val = check_val[8:]
self.assertEqual(check_val, resultfile)

self.delete_file(args.outputfile)
return
Expand Down Expand Up @@ -192,7 +191,7 @@ def test_simple_bom_relative_path(self) -> None:
out_bom.components[0], ExternalReferenceType.DISTRIBUTION, CaPyCliBom.SOURCE_FILE_COMMENT)
self.assertIsNotNone(ext_ref)
if ext_ref: # only for mypy
self.assertEqual(ext_ref.url._uri, "file://certifi-2022.12.7.tar.gz")
self.assertEqual(ext_ref.url._uri, "file:///certifi-2022.12.7.tar.gz")

self.delete_file(args.outputfile)
return
Expand Down Expand Up @@ -275,7 +274,10 @@ def test_simple_bom_no_url(self) -> None:
bom.components[0], ExternalReferenceType.DISTRIBUTION, CaPyCliBom.SOURCE_FILE_COMMENT)
self.assertIsNotNone(ext_ref)
if ext_ref: # only for mypy
self.assertEqual(str(ext_ref.url), resultfile)
check_val = ext_ref.url._uri
if check_val.startswith("file:///"):
check_val = check_val[8:]
self.assertEqual(check_val, resultfile)

self.assertEqual(len(bom.components[1].external_references), 0)
return
Expand All @@ -288,4 +290,4 @@ def test_simple_bom_no_url(self) -> None:

if __name__ == "__main__":
lib = TestBomDownloadsources()
lib.test_simple_bom()
lib.test_simple_bom_relative_path()
Loading