diff --git a/elbepack/commands/cyclonedx-sbom.py b/elbepack/commands/cyclonedx-sbom.py index 21e5b23ab..496c5d0bd 100644 --- a/elbepack/commands/cyclonedx-sbom.py +++ b/elbepack/commands/cyclonedx-sbom.py @@ -49,20 +49,23 @@ def _remove_empty_fields(dict): def _repository_url(uri): - uri_parts = uri.split('/') - if len(uri_parts) < 6: - raise ValueError('URI needs to be in pool layout') - if uri_parts[-4] == 'pool': - # http://deb.debian.org/debian/pool/a/adduser/adduser_3.134_all.deb - return '/'.join(uri_parts[:-4]) - elif uri_parts[-5] == 'pool': - # http://deb.debian.org/debian/pool/main/a/adduser/adduser_3.134_all.deb - return '/'.join(uri_parts[:-5]) - elif uri_parts[-6] == 'pool': - # http://deb.debian.org/debian-security/pool/updates/main/u/util-linux/bsdutils_2.38.1-5%2bdeb12u1_amd64.deb - return '/'.join(uri_parts[:-6]) - else: - raise ValueError('URI needs to be in pool layout') + parsed = urllib.parse.urlsplit(uri) + path_parts = parsed.path.split('/') + + if path_parts[-1].endswith('.deb'): + # Standard Debian layout: repository root is everything before /pool/. + if 'pool' in path_parts: + repo_path = '/'.join(path_parts[:path_parts.index('pool')]) + else: + # Flat repository: repo URL is everything before the filename. + repo_path = '/'.join(path_parts[:-1]) + + if not repo_path: + repo_path = '/' + + return urllib.parse.urlunsplit((parsed.scheme, parsed.netloc, repo_path, '', '')) + + raise ValueError(f'Unexpected URI format: {uri}') def _purl_from_pkg(pkg): diff --git a/elbepack/main.py b/elbepack/main.py index 972986b55..47163385c 100644 --- a/elbepack/main.py +++ b/elbepack/main.py @@ -18,7 +18,7 @@ def get_cmdlist(): return [x for _, x, _ in pkgutil.iter_modules(elbepack.commands.__path__)] -def _import_cmd_module(cmd): +def import_cmd_module(cmd): return importlib.import_module('.' + cmd, elbepack.commands.__name__) @@ -37,7 +37,7 @@ def main(argv=sys.argv): logging.basicConfig() logging.getLogger('suds').setLevel(logging.WARNING) - cmdmod = _import_cmd_module(args.cmd) + cmdmod = import_cmd_module(args.cmd) try: cmdmod.run_command(cmd_argv) @@ -48,5 +48,5 @@ def main(argv=sys.argv): def run_elbe_subcommand(argv): - cmdmod = _import_cmd_module(argv[0]) + cmdmod = import_cmd_module(argv[0]) return cmdmod.run_command([os.fspath(arg) for arg in argv[1:]]) diff --git a/elbepack/tests/cyclonedx/test_cyclonedx_sbom.py b/elbepack/tests/cyclonedx/test_cyclonedx_sbom.py index b05864f64..228a44114 100644 --- a/elbepack/tests/cyclonedx/test_cyclonedx_sbom.py +++ b/elbepack/tests/cyclonedx/test_cyclonedx_sbom.py @@ -10,6 +10,8 @@ import jsonschema +import pytest + try: import jsonschema._validators @@ -33,7 +35,7 @@ def _extras_msg(extras): from jsonschema.validators import RefResolver -from elbepack.main import run_elbe_subcommand +from elbepack.main import import_cmd_module, run_elbe_subcommand here = pathlib.Path(__file__).parent @@ -76,3 +78,28 @@ def test_reference_data(): reference_errors = here.joinpath('cyclonedx_reference.json.errors').read_text() assert error_report == reference_errors + + +@pytest.mark.parametrize('uri, expected_repository_url', [ + ( + 'http://deb.debian.org/debian/pool/a/adduser/adduser_3.134_all.deb', + 'http://deb.debian.org/debian', + ), + ( + 'http://deb.debian.org/debian/pool/main/a/adduser/adduser_3.134_all.deb', + 'http://deb.debian.org/debian', + ), + ( + 'http://deb.debian.org/debian-security/pool/updates/main/u/util-linux/' + 'bsdutils_2.38.1-5%2bdeb12u1_amd64.deb', + 'http://deb.debian.org/debian-security', + ), + ( + 'https://deb.corporate.com/corp/foo/ethtool_6.14.2-1%7edeb13u1_arm64.deb', + 'https://deb.corporate.com/corp/foo', + ), +]) +def test_repository_url_examples(uri, expected_repository_url): + cyclonedx_sbom = import_cmd_module('cyclonedx-sbom') + + assert cyclonedx_sbom._repository_url(uri) == expected_repository_url diff --git a/newsfragments/+scyclonedx-sbom-flat-repos.rst b/newsfragments/+scyclonedx-sbom-flat-repos.rst new file mode 100644 index 000000000..58252eab6 --- /dev/null +++ b/newsfragments/+scyclonedx-sbom-flat-repos.rst @@ -0,0 +1 @@ +Extend cyclonedx-sbom command to support flat repositories (e.g. minidinst).