Skip to content

Commit

Permalink
use metadata folder and split sbom tests
Browse files Browse the repository at this point in the history
  • Loading branch information
ErniGH committed Jan 14, 2025
1 parent efbd44d commit 96d2337
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 47 deletions.
101 changes: 62 additions & 39 deletions test/functional/sbom/test_cycloneDX.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@
from conans.util.files import save
import os

sbom_hook = """
# Using the sbom tool with "conan create"
sbom_hook_post_package = """
import json
import os
from conan.errors import ConanException
from conan.api.output import ConanOutput
from conan.tools.sbom.cycloneDX import cyclonedx_1_4
def _generate_cyclonedx_1_4_file(conanfile):
def post_package(conanfile):
try:
sbom_cyclonedx_1_4 = cyclonedx_1_4(conanfile.subgraph)
metadata_folder = conanfile.package_metadata_folder
Expand All @@ -25,23 +25,18 @@ def _generate_cyclonedx_1_4_file(conanfile):
ConanOutput().success(f"CYCLONEDX CREATED - {conanfile.package_metadata_folder}")
except Exception as e:
ConanException("error generating CYCLONEDX file")
def post_package(conanfile):
_generate_cyclonedx_1_4_file(conanfile)
def post_generate(conanfile):
_generate_cyclonedx_1_4_file(conanfile)
"""

@pytest.fixture()
def hook_setup():
def hook_setup_post_package():
tc = TestClient()
hook_path = os.path.join(tc.paths.hooks_path, "hook_sbom.py")
save(hook_path, sbom_hook)
save(hook_path, sbom_hook_post_package)
return tc

def test_sbom_generation_create(hook_setup):
tc = hook_setup

def test_sbom_generation_create(hook_setup_post_package):
tc = hook_setup_post_package
tc.run("new cmake_lib -d name=dep -d version=1.0")
tc.run("export .")
tc.run("new cmake_lib -d name=foo -d version=1.0 -d requires=dep/1.0 -f")
Expand All @@ -50,10 +45,55 @@ def test_sbom_generation_create(hook_setup):
# bar -> foo -> dep
tc.run("create . --build=missing")
bar_layout = tc.created_layout()
assert os.path.exists(os.path.join(bar_layout.build(),"..", "d", "metadata", "cyclonedx_1_4.json"))
assert os.path.exists(os.path.join(bar_layout.metadata(), "cyclonedx_1_4.json"))

def test_sbom_generation_install_requires(hook_setup):
tc = hook_setup
def test_sbom_generation_skipped_dependencies(hook_setup_post_package):
tc = hook_setup_post_package
tc.save({"dep/conanfile.py": GenConanfile("dep", "1.0"),
"app/conanfile.py": GenConanfile("app", "1.0")
.with_package_type("application")
.with_requires("dep/1.0"),
"conanfile.py": GenConanfile("foo", "1.0").with_tool_requires("app/1.0")})
tc.run("create dep")
tc.run("create app")
tc.run("create .")
create_layout = tc.created_layout()

cyclone_path = os.path.join(create_layout.metadata(), "cyclonedx_1_4.json")
content = tc.load(cyclone_path)
# A skipped dependency also shows up in the sbom
assert "pkg:conan/[email protected]?rref=6a99f55e933fb6feeb96df134c33af44" in content


# Using the sbom tool with "conan install"
sbom_hook_post_generate = """
import json
import os
from conan.errors import ConanException
from conan.api.output import ConanOutput
from conan.tools.sbom.cycloneDX import cyclonedx_1_4
def post_generate(conanfile):
try:
sbom_cyclonedx_1_4 = cyclonedx_1_4(conanfile.subgraph)
metadata_folder = conanfile.package_metadata_folder
file_name = "cyclonedx_1_4.json"
with open(os.path.join(metadata_folder, file_name), 'w') as f:
json.dump(sbom_cyclonedx_1_4, f, indent=4)
ConanOutput().success(f"CYCLONEDX CREATED - {conanfile.package_metadata_folder}")
except Exception as e:
ConanException("error generating CYCLONEDX file")
"""

@pytest.fixture()
def hook_setup_post_generate():
tc = TestClient()
hook_path = os.path.join(tc.paths.hooks_path, "hook_sbom.py")
save(hook_path, sbom_hook_post_generate)
return tc

def test_sbom_generation_install_requires(hook_setup_post_generate):
tc = hook_setup_post_generate
tc.save({"dep/conanfile.py": GenConanfile("dep", "1.0"),
"conanfile.py": GenConanfile("foo", "1.0").with_requires("dep/1.0")})
tc.run("export dep")
Expand All @@ -63,8 +103,8 @@ def test_sbom_generation_install_requires(hook_setup):
tc.run("install --requires=foo/1.0")
assert os.path.exists(os.path.join(tc.current_folder, "cyclonedx_1_4.json"))

def test_sbom_generation_install_path(hook_setup):
tc = hook_setup
def test_sbom_generation_install_path(hook_setup_post_generate):
tc = hook_setup_post_generate
tc.save({"dep/conanfile.py": GenConanfile("dep", "1.0"),
"conanfile.py": GenConanfile("foo", "1.0").with_requires("dep/1.0")})
tc.run("create dep")
Expand All @@ -73,8 +113,8 @@ def test_sbom_generation_install_path(hook_setup):
tc.run("install .")
assert os.path.exists(os.path.join(tc.current_folder, "cyclonedx_1_4.json"))

def test_sbom_generation_install_path_consumer(hook_setup):
tc = hook_setup
def test_sbom_generation_install_path_consumer(hook_setup_post_generate):
tc = hook_setup_post_generate
tc.save({"dep/conanfile.py": GenConanfile("dep", "1.0"),
"conanfile.py": GenConanfile().with_requires("dep/1.0")})
tc.run("create dep")
Expand All @@ -83,8 +123,8 @@ def test_sbom_generation_install_path_consumer(hook_setup):
tc.run("install .")
assert os.path.exists(os.path.join(tc.current_folder, "cyclonedx_1_4.json"))

def test_sbom_generation_install_path_txt(hook_setup):
tc = hook_setup
def test_sbom_generation_install_path_txt(hook_setup_post_generate):
tc = hook_setup_post_generate
tc.save({"dep/conanfile.py": GenConanfile("dep", "1.0"),
"conanfile.txt": textwrap.dedent(
"""
Expand All @@ -97,20 +137,3 @@ def test_sbom_generation_install_path_txt(hook_setup):
#foo -> dep
tc.run("install .")
assert os.path.exists(os.path.join(tc.current_folder, "cyclonedx_1_4.json"))

def test_sbom_generation_skipped_dependencies(hook_setup):
tc = hook_setup
tc.save({"dep/conanfile.py": GenConanfile("dep", "1.0"),
"app/conanfile.py": GenConanfile("app", "1.0")
.with_package_type("application")
.with_requires("dep/1.0"),
"conanfile.py": GenConanfile("foo", "1.0").with_tool_requires("app/1.0")})
tc.run("create dep")
tc.run("create app")
tc.run("create .")
create_layout = tc.created_layout()

cyclone_path = os.path.join(create_layout.build(), "..", "d", "metadata", "cyclonedx_1_4.json")
content = tc.load(cyclone_path)
# A skipped dependency also shows up in the sbom
assert "pkg:conan/[email protected]?rref=6a99f55e933fb6feeb96df134c33af44" in content
21 changes: 13 additions & 8 deletions test/integration/graph/test_subgraph_reports.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,14 @@

from conan.test.assets.genconanfile import GenConanfile
from conan.test.utils.tools import TestClient
from conans.model.recipe_ref import RecipeReference
from conans.util.files import load


def _metadata(c, ref):
pref = c.get_latest_package_reference(RecipeReference.loads(ref))
return c.get_latest_pkg_layout(pref).metadata()

def test_subgraph_reports():
c = TestClient()
subgraph_hook = textwrap.dedent("""\
Expand All @@ -15,9 +20,9 @@ def test_subgraph_reports():
from conans.model.graph_lock import Lockfile
def post_package(conanfile):
subgraph = conanfile.subgraph
save(conanfile, os.path.join(conanfile.package_folder, "..", "..", f"{conanfile.name}-conangraph.json"),
save(conanfile, os.path.join(conanfile.package_metadata_folder, f"conangraph.json"),
json.dumps(subgraph.serialize(), indent=2))
save(conanfile, os.path.join(conanfile.package_folder, "..", "..", f"{conanfile.name}-conan.lock"),
save(conanfile, os.path.join(conanfile.package_metadata_folder, f"conan.lock"),
Lockfile(subgraph).dumps())
""")

Expand All @@ -30,13 +35,13 @@ def post_package(conanfile):
# app -> pkg -> dep
c.run("create app --build=missing --format=json")

app_graph = json.loads(load(os.path.join(c.cache.builds_folder, "app-conangraph.json")))
pkg_graph = json.loads(load(os.path.join(c.cache.builds_folder, "pkg-conangraph.json")))
dep_graph = json.loads(load(os.path.join(c.cache.builds_folder, "dep-conangraph.json")))
app_graph = json.loads(load(os.path.join(_metadata(c, "app/0.1"), "conangraph.json")))
pkg_graph = json.loads(load(os.path.join(_metadata(c, "pkg/0.1"), "conangraph.json")))
dep_graph = json.loads(load(os.path.join(_metadata(c, "dep/0.1"), "conangraph.json")))

app_lock = json.loads(load(os.path.join(c.cache.builds_folder, "app-conan.lock")))
pkg_lock = json.loads(load(os.path.join(c.cache.builds_folder, "pkg-conan.lock")))
dep_lock = json.loads(load(os.path.join(c.cache.builds_folder, "dep-conan.lock")))
app_lock = json.loads(load(os.path.join(_metadata(c, "app/0.1"), "conan.lock")))
pkg_lock = json.loads(load(os.path.join(_metadata(c, "pkg/0.1"), "conan.lock")))
dep_lock = json.loads(load(os.path.join(_metadata(c, "dep/0.1"), "conan.lock")))

assert len(app_graph["nodes"]) == len(app_lock["requires"])
assert len(pkg_graph["nodes"]) == len(pkg_lock["requires"])
Expand Down

0 comments on commit 96d2337

Please sign in to comment.