Skip to content

Commit

Permalink
Support also python 3.6
Browse files Browse the repository at this point in the history
  • Loading branch information
hedtke committed Aug 24, 2023
1 parent 21634ca commit 4002763
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 30 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test_conan_extensions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
- name: Install dependencies
run: |
pip install -U pip
pip install pytest "cyclonedx-python-lib>=4.0.1,<5.0.0"
pip install pytest "cyclonedx-python-lib>=3.1.5,<5.0.0"
- name: Install Conan latest
run: |
pip install conan
Expand Down
2 changes: 1 addition & 1 deletion extensions/commands/recipe/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ The command requires the package `cyclonedx-python-lib`.
You can install it via
<!-- keep in sync with the error message that asks for requirements/dependencies in `cmd_create_sbom.py` -->
```shellSession
$ pip install 'cyclonedx-python-lib>=4.0.1,<5.0.0'
$ pip install 'cyclonedx-python-lib>=3.1.5,<5.0.0'
```

Usage:
Expand Down
63 changes: 44 additions & 19 deletions extensions/commands/recipe/cmd_create_sbom.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from importlib.metadata import version
import os.path
import sys
from typing import TYPE_CHECKING, Any, Iterable, List, Optional, Set, Tuple, Union, Dict
Expand All @@ -11,6 +12,10 @@
from cyclonedx.model.bom import Bom


def cyclonedx_major_version_is_4() -> int:
return version('cyclonedx-python-lib')[0] == '4'


def format_text(output: Dict[str, Any]) -> None:
serialized = output['formatters'][output['sbom_format']](output['bom']).output_as_string()
cli_out_write(serialized)
Expand All @@ -35,7 +40,7 @@ def create_sbom(conan_api: ConanAPI, parser, *args) -> Dict[str, Any]:
# if loading dependencies is performed outside the actual conan-command in global/module scope.
print('The sbom extension needs an additional package, please run:',
# keep in synk with the instructions in `README.md`
"pip install 'cyclonedx-python-lib>=4.0.1,<5.0.0'",
"pip install 'cyclonedx-python-lib>=3.1.5,<5.0.0'",
sep='\n', file=sys.stderr)
sys.exit(1)

Expand All @@ -53,7 +58,10 @@ def licenses(ls: Optional[Union[Tuple[str, ...], Set[str], List[str], str]]) ->
return None
if not isinstance(ls, (tuple, set, list)):
ls = [ls]
return [LicenseChoice(license=LicenseFactory().make_from_string(i)) for i in ls]
if cyclonedx_major_version_is_4():
return [LicenseChoice(license=LicenseFactory().make_from_string(i)) for i in ls] # noqa
else:
return [LicenseChoice(license_=LicenseFactory().make_from_string(i)) for i in ls]

def package_url(node: 'Node') -> Optional[PackageURL]:
"""
Expand All @@ -74,27 +82,43 @@ def package_url(node: 'Node') -> Optional[PackageURL]:

def create_component(node: 'Node') -> Component:
purl = package_url(node)
component = Component(
type=package_type_to_component_type(node.conanfile.package_type),
name=node.name or f'UNKNOWN.{id(node)}',
version=node.conanfile.version,
licenses=licenses(node.conanfile.license),
bom_ref=purl.to_string() if purl else None,
purl=purl,
description=node.conanfile.description
)
if node.conanfile.homepage:
if cyclonedx_major_version_is_4():
component = Component(
type=package_type_to_component_type(node.conanfile.package_type), # noqa
name=node.name or f'UNKNOWN.{id(node)}',
version=node.conanfile.version,
licenses=licenses(node.conanfile.license),
bom_ref=purl.to_string() if purl else None,
purl=purl,
description=node.conanfile.description
)
else:
component = Component(
component_type=package_type_to_component_type(node.conanfile.package_type),
name=node.name or f'UNKNOWN.{id(node)}',
version=node.conanfile.version,
licenses=licenses(node.conanfile.license),
bom_ref=purl.to_string() if purl else None,
purl=purl,
description=node.conanfile.description
)
if node.conanfile.homepage and cyclonedx_major_version_is_4(): # bug in cyclonedx 3 enforces hashes
component.external_references.add(ExternalReference(
type=ExternalReferenceType.WEBSITE,
type=ExternalReferenceType.WEBSITE, # noqa
url=XsUri(node.conanfile.homepage),
))
)) # noqa
return component

def me_as_tool() -> Tool:
tool = Tool(name="conan extension recipe:create-sbom")
tool.external_references.add(ExternalReference(
type=ExternalReferenceType.WEBSITE,
url=XsUri("https://github.com/conan-io/conan-extensions")))
if cyclonedx_major_version_is_4():
tool.external_references.add(ExternalReference(
type=ExternalReferenceType.WEBSITE, # noqa
url=XsUri("https://github.com/conan-io/conan-extensions"))) # noqa
else:
tool.external_references.add(ExternalReference(
reference_type=ExternalReferenceType.WEBSITE,
url=XsUri("https://github.com/conan-io/conan-extensions")))
return tool

formatters = {
Expand Down Expand Up @@ -140,6 +164,7 @@ def me_as_tool() -> Tool:
bom.metadata.tools.add(me_as_tool())
for node in deps_graph.nodes[1:]: # node 0 is the root
bom.components.add(components[node])
for dep in deps_graph.nodes:
bom.register_dependency(components[dep], [components[dep_dep.dst] for dep_dep in dep.dependencies])
if cyclonedx_major_version_is_4():
for dep in deps_graph.nodes:
bom.register_dependency(components[dep], [components[dep_dep.dst] for dep_dep in dep.dependencies]) # noqa
return {'bom': bom, 'sbom_format': args.sbom_format, 'formatters': formatters}
27 changes: 18 additions & 9 deletions tests/test_create_sbom.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import importlib.metadata
import json
import xml.dom.minidom
import os
Expand All @@ -12,6 +13,10 @@
REQ_DEP = "m4"


def cyclonedx_major_version_is_4() -> int:
return importlib.metadata.version('cyclonedx-python-lib')[0] == '4'


@pytest.fixture(autouse=True)
def conan_test():
old_env = dict(os.environ)
Expand Down Expand Up @@ -43,31 +48,35 @@ def _test_generated_sbom_json(sbom, test_metadata_name, spec_version):


def _test_generated_sbom_xml(sbom, test_metadata_name, spec_version):
schema = sbom.getAttribute("xmlns:ns0")
def with_ns(key: str) -> str:
ns = "ns0:" if cyclonedx_major_version_is_4() else ""
return ns + key

schema = sbom.getAttribute("xmlns:ns0" if cyclonedx_major_version_is_4() else "xmlns")
assert "cyclonedx" in schema
assert schema.split("/")[-1] == spec_version

if spec_version not in ['1.1', '1.0']:
metadata = sbom.getElementsByTagName("ns0:metadata")
metadata = sbom.getElementsByTagName(with_ns("metadata"))
assert metadata
component = metadata[0].getElementsByTagName("ns0:component")
component = metadata[0].getElementsByTagName(with_ns("component"))
assert component
if test_metadata_name:
assert component[0].getElementsByTagName("ns0:name")[0].firstChild.nodeValue == "TestPackage"
assert component[0].getElementsByTagName(with_ns("name"))[0].firstChild.nodeValue == "TestPackage"

components = sbom.getElementsByTagName("ns0:components")
components = sbom.getElementsByTagName(with_ns("components"))
assert components
components = components[0].getElementsByTagName("ns0:component")
components = components[0].getElementsByTagName(with_ns("component"))
assert components
assert 1 == len([
c for c in components if
c.getElementsByTagName("ns0:name")[0].firstChild.nodeValue == REQ_LIB
c.getElementsByTagName(with_ns("name"))[0].firstChild.nodeValue == REQ_LIB
and
c.getElementsByTagName("ns0:version")[0].firstChild.nodeValue == REQ_VER
c.getElementsByTagName(with_ns("version"))[0].firstChild.nodeValue == REQ_VER
])
assert 1 == len([
c for c in components if
c.getElementsByTagName("ns0:name")[0].firstChild.nodeValue == REQ_DEP
c.getElementsByTagName(with_ns("name"))[0].firstChild.nodeValue == REQ_DEP
])


Expand Down

0 comments on commit 4002763

Please sign in to comment.