Skip to content

Commit

Permalink
refactor(bom downloadsources): narrow relpath helper
Browse files Browse the repository at this point in the history
Replace have_relative_source_file_path() helper function by a generic
have_relative_ext_ref_path() which can be re-used for other tasks.

To be sure we do the right thing, also add test cases for absolute and
relative paths.
  • Loading branch information
gernot-h committed Aug 5, 2023
1 parent c3171b5 commit 0e453ad
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 21 deletions.
31 changes: 12 additions & 19 deletions capycli/bom/download_sources.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
import requests
from cyclonedx.model import ExternalReference, ExternalReferenceType, HashAlgorithm, HashType
from cyclonedx.model.bom import Bom
from cyclonedx.model.component import Component

import capycli.common.json_support
import capycli.common.script_base
Expand Down Expand Up @@ -122,35 +121,29 @@ def download_sources(self, sbom: Bom, source_folder: str) -> None:
if new:
component.external_references.add(ext_ref)

def have_relative_source_file_path(self, component: Component, bompath: str):
ext_ref = CycloneDxSupport.get_ext_ref(
component, ExternalReferenceType.DISTRIBUTION, CaPyCliBom.SOURCE_FILE_COMMENT)
if not ext_ref:
return

def have_relative_ext_ref_path(self, ext_ref: ExternalReference, bompath: str):
bip = pathlib.PurePath(ext_ref.url)
try:
CycloneDxSupport.update_or_set_property(
component,
CycloneDxSupport.CDX_PROP_FILENAME,
bip.name)
file = bip.as_posix()
if os.path.isfile(file):
CycloneDxSupport.update_or_set_ext_ref(
component,
ExternalReferenceType.DISTRIBUTION,
CaPyCliBom.SOURCE_FILE_COMMENT,
"file://" + bip.relative_to(bompath).as_posix())
ext_ref.url = "file://" + bip.relative_to(bompath).as_posix()
except ValueError:
print_yellow(
" SBOM file is not relative to source file " + ext_ref.url)
# .relative_to
pass

return bip.name

def update_local_path(self, sbom: Bom, bomfile: str):
bompath = pathlib.Path(bomfile).parent
for component in sbom.components:
self.have_relative_source_file_path(component, bompath)
ext_ref = CycloneDxSupport.get_ext_ref(
component, ExternalReferenceType.DISTRIBUTION, CaPyCliBom.SOURCE_FILE_COMMENT)
if ext_ref:
name = self.have_relative_ext_ref_path(ext_ref, bompath)
CycloneDxSupport.update_or_set_property(
component,
CycloneDxSupport.CDX_PROP_FILENAME,
name)

def run(self, args):
"""Main method
Expand Down
55 changes: 53 additions & 2 deletions tests/test_bom_downloadsources.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@

import responses

from cyclonedx.model import ExternalReferenceType

from capycli.common.capycli_bom_support import CaPyCliBom, CycloneDxSupport
from capycli.bom.download_sources import BomDownloadSources
from capycli.main.result_codes import ResultCode
from tests.test_base import AppArguments, TestBase
Expand Down Expand Up @@ -126,20 +129,68 @@ 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")
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)
self.assertTrue("Downloading source files to folder" in out)
self.assertTrue("Downloading file certifi-2022.12.7.tar.gz" in out)

resultfile = os.path.join(tmpdirname, "certifi-2022.12.7.tar.gz")
self.assertTrue(os.path.isfile(resultfile))

ext_ref = CycloneDxSupport.get_ext_ref(
out_bom.components[0], ExternalReferenceType.DISTRIBUTION, CaPyCliBom.SOURCE_FILE_COMMENT)
self.assertEqual(ext_ref.url, resultfile)

self.delete_file(args.outputfile)
return
except: # noqa
except Exception as e: # noqa
# catch all exception to let Python cleanup the temp folder
pass
print(e)

self.assertTrue(False, "Error: we must never arrive here")

@responses.activate
def test_simple_bom_relative_path(self) -> None:
sut = BomDownloadSources()

# create argparse command line argument object
args = AppArguments()
args.command = []
args.command.append("bom")
args.command.append("downloadsources")
args.inputfile = os.path.join(os.path.dirname(__file__), "fixtures", TestBomDownloadsources.INPUTFILE)

with tempfile.TemporaryDirectory() as tmpdirname:
args.source = tmpdirname
args.outputfile = os.path.join(tmpdirname, TestBomDownloadsources.OUTPUTFILE)

# fake file content
responses.add(
responses.GET,
url="https://files.pythonhosted.org/packages/37/f7/2b1b/certifi-2022.12.7.tar.gz",
body="""
SOME DUMMY DATA
""",
status=200,
content_type="application/json",
)

try:
sut.run(args)
out_bom = CaPyCliBom.read_sbom(args.outputfile)

ext_ref = CycloneDxSupport.get_ext_ref(
out_bom.components[0], ExternalReferenceType.DISTRIBUTION, CaPyCliBom.SOURCE_FILE_COMMENT)
self.assertEqual(ext_ref.url, "file://certifi-2022.12.7.tar.gz")

self.delete_file(args.outputfile)
return
except Exception as e: # noqa
# catch all exception to let Python cleanup the temp folder
print(e)

self.assertTrue(False, "Error: we must never arrive here")

Expand Down

0 comments on commit 0e453ad

Please sign in to comment.