Skip to content

Commit 000fdee

Browse files
authored
Add add_tests and add_build on cycloneDX tool (#17695)
* add feat and test * add_test false by default | change import path * feat `add_tool_requires` and test * improve if * Turn add_build default to false
1 parent 85cf343 commit 000fdee

File tree

3 files changed

+75
-9
lines changed

3 files changed

+75
-9
lines changed

conan/tools/sbom/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from conan.tools.sbom.cyclonedx import cyclonedx_1_4

conan/tools/sbom/cyclonedx.py

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11

2-
def cyclonedx_1_4(graph, **kwargs):
2+
3+
def cyclonedx_1_4(graph, add_build=False, add_tests=False, **kwargs):
34
"""
45
(Experimental) Generate cyclone 1.4 sbom with json format
56
"""
@@ -9,8 +10,7 @@ def cyclonedx_1_4(graph, **kwargs):
910

1011
has_special_root_node = not (getattr(graph.root.ref, "name", False) and getattr(graph.root.ref, "version", False) and getattr(graph.root.ref, "revision", False))
1112
special_id = str(uuid.uuid4())
12-
13-
components = [node for node in graph.nodes]
13+
components = [node for node in graph.nodes if (node.context == "host" or add_build) and (not node.test or add_tests)]
1414
if has_special_root_node:
1515
components = components[1:]
1616

@@ -22,7 +22,9 @@ def cyclonedx_1_4(graph, **kwargs):
2222
dependencies.append(deps)
2323
for c in components:
2424
deps = {"ref": f"pkg:conan/{c.name}@{c.ref.version}?rref={c.ref.revision}"}
25-
depends_on = [f"pkg:conan/{d.dst.name}@{d.dst.ref.version}?rref={d.dst.ref.revision}" for d in c.dependencies]
25+
dep = [d for d in c.dependencies if (d.dst.context == "host" or add_build) and (not d.dst.test or add_tests)]
26+
27+
depends_on = [f"pkg:conan/{d.dst.name}@{d.dst.ref.version}?rref={d.dst.ref.revision}" for d in dep]
2628
if depends_on:
2729
deps["dependsOn"] = depends_on
2830
dependencies.append(deps)

test/functional/sbom/test_cyclonedx.py

+68-5
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@
1313
import os
1414
from conan.errors import ConanException
1515
from conan.api.output import ConanOutput
16-
from conan.tools.sbom.cyclonedx import cyclonedx_1_4
16+
from conan.tools.sbom import cyclonedx_1_4
1717
1818
def post_package(conanfile):
19-
sbom_cyclonedx_1_4 = cyclonedx_1_4(conanfile.subgraph)
19+
sbom_cyclonedx_1_4 = cyclonedx_1_4(conanfile.subgraph, add_build=%s, add_tests=%s)
2020
metadata_folder = conanfile.package_metadata_folder
2121
file_name = "sbom.cdx.json"
2222
with open(os.path.join(metadata_folder, file_name), 'w') as f:
@@ -28,14 +28,28 @@ def post_package(conanfile):
2828
def hook_setup_post_package():
2929
tc = TestClient()
3030
hook_path = os.path.join(tc.paths.hooks_path, "hook_sbom.py")
31-
save(hook_path, sbom_hook_post_package)
31+
save(hook_path, sbom_hook_post_package % ("True", "True"))
32+
return tc
33+
34+
@pytest.fixture()
35+
def hook_setup_post_package_no_tool_requires():
36+
tc = TestClient()
37+
hook_path = os.path.join(tc.paths.hooks_path, "hook_sbom.py")
38+
save(hook_path, sbom_hook_post_package % ("False", "True"))
39+
return tc
40+
41+
@pytest.fixture()
42+
def hook_setup_post_package_no_test():
43+
tc = TestClient()
44+
hook_path = os.path.join(tc.paths.hooks_path, "hook_sbom.py")
45+
save(hook_path, sbom_hook_post_package % ("True", "False"))
3246
return tc
3347

3448
@pytest.fixture()
3549
def hook_setup_post_package_tl(transitive_libraries):
3650
tc = transitive_libraries
3751
hook_path = os.path.join(tc.paths.hooks_path, "hook_sbom.py")
38-
save(hook_path, sbom_hook_post_package)
52+
save(hook_path, sbom_hook_post_package % ("True", "True"))
3953
return tc
4054

4155

@@ -65,14 +79,63 @@ def test_sbom_generation_skipped_dependencies(hook_setup_post_package):
6579
# A skipped dependency also shows up in the sbom
6680
assert "pkg:conan/[email protected]?rref=6a99f55e933fb6feeb96df134c33af44" in content
6781

82+
def test_sbom_generation_no_tool_requires(hook_setup_post_package_no_tool_requires):
83+
tc = hook_setup_post_package_no_tool_requires
84+
tc.save({"app/conanfile.py": GenConanfile("app", "1.0")
85+
.with_package_type("application"),
86+
"conanfile.py": GenConanfile("foo", "1.0").with_tool_requires("app/1.0")})
87+
tc.run("create app")
88+
tc.run("create .")
89+
create_layout = tc.created_layout()
90+
91+
cyclone_path = os.path.join(create_layout.metadata(), "sbom.cdx.json")
92+
content = tc.load(cyclone_path)
93+
94+
assert "pkg:conan/app" not in content
95+
96+
def test_sbom_generation_transitive_test_requires(hook_setup_post_package_no_test):
97+
tc = hook_setup_post_package_no_test
98+
tc.save({"test_re/conanfile.py": GenConanfile("test_re", "1.0"),
99+
"app/conanfile.py": GenConanfile("app", "1.0")
100+
.with_package_type("application")
101+
.with_test_requires("test_re/1.0"),
102+
"conanfile.py": GenConanfile("foo", "1.0").with_tool_requires("app/1.0")})
103+
tc.run("create test_re")
104+
105+
tc.run("create app")
106+
create_layout = tc.created_layout()
107+
cyclone_path = os.path.join(create_layout.metadata(), "sbom.cdx.json")
108+
content = tc.load(cyclone_path)
109+
assert "pkg:conan/[email protected]" not in content
110+
111+
tc.run("create .")
112+
create_layout = tc.created_layout()
113+
cyclone_path = os.path.join(create_layout.metadata(), "sbom.cdx.json")
114+
content = tc.load(cyclone_path)
115+
assert "pkg:conan/[email protected]" not in content
116+
117+
def test_sbom_generation_dependency_test_require(hook_setup_post_package_no_test):
118+
tc = hook_setup_post_package_no_test
119+
tc.save({"special/conanfile.py": GenConanfile("special", "1.0"),
120+
"foo/conanfile.py": GenConanfile("foo", "1.0")
121+
.with_test_requires("special/1.0"),
122+
"conanfile.py": GenConanfile("bar", "1.0").with_tool_requires("foo/1.0").with_require("special/1.0")})
123+
tc.run("create special")
124+
tc.run("create foo")
125+
126+
tc.run("create .")
127+
create_layout = tc.created_layout()
128+
cyclone_path = os.path.join(create_layout.metadata(), "sbom.cdx.json")
129+
content = tc.load(cyclone_path)
130+
assert "pkg:conan/[email protected]" in content
68131

69132
# Using the sbom tool with "conan install"
70133
sbom_hook_post_generate = """
71134
import json
72135
import os
73136
from conan.errors import ConanException
74137
from conan.api.output import ConanOutput
75-
from conan.tools.sbom.cyclonedx import cyclonedx_1_4
138+
from conan.tools.sbom import cyclonedx_1_4
76139
77140
def post_generate(conanfile):
78141
sbom_cyclonedx_1_4 = cyclonedx_1_4(conanfile.subgraph)

0 commit comments

Comments
 (0)