Skip to content

Commit

Permalink
feat: add support for poetry lock format v2.0 (#469)
Browse files Browse the repository at this point in the history

Signed-off-by: tewfik-ghariani <tewfik.ghariani@1und1.de>
Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
Co-authored-by: tewfik-ghariani <tewfik.ghariani@1und1.de>
  • Loading branch information
jkowalleck and tewfik-ghariani authored Dec 13, 2022
1 parent 895f597 commit 0b1e07f
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 27 deletions.
15 changes: 13 additions & 2 deletions cyclonedx_py/parser/poetry.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,13 @@ def __init__(
debug_message('loading poetry_lock_contents')
poetry_lock = load_toml(poetry_lock_contents)

poetry_lock_metadata = poetry_lock['metadata']
try:
poetry_lock_version = tuple(int(p) for p in str(poetry_lock_metadata['lock-version']).split('.'))
except Exception:
poetry_lock_version = (0,)
debug_message('detected poetry_lock_version: {!r}', poetry_lock_version)

debug_message('processing poetry_lock')
for package in poetry_lock['package']:
debug_message('processing package: {!r}', package)
Expand All @@ -51,7 +58,12 @@ def __init__(
name=package['name'], bom_ref=bom_ref, version=package['version'],
purl=purl
)
for file_metadata in poetry_lock['metadata']['files'][package['name']]:
debug_message('detecting package_files')
package_files = package['files'] \
if poetry_lock_version >= (2,) \
else poetry_lock_metadata['files'][package['name']]
debug_message('processing package_files: {!r}', package_files)
for file_metadata in package_files:
debug_message('processing file_metadata: {!r}', file_metadata)
try:
component.external_references.add(ExternalReference(
Expand All @@ -64,7 +76,6 @@ def __init__(
# @todo traceback and details to the output?
debug_message('Warning: suppressed {!r}', error)
del error

self._components.append(component)


Expand Down
46 changes: 29 additions & 17 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ toml = "^0.10.0"
[tool.poetry.dev-dependencies]
autopep8 = "^1.6.0"
isort = { version = "^5.10.0", python = ">= 3.6.1" }
ddt = "^1.6.0"
tox = "^3.25.1"
coverage = [
{ python = ">=3.6,<3.7", version = "^6.2", extras = ["toml"] },
Expand Down
File renamed without changes.
18 changes: 18 additions & 0 deletions tests/fixtures/poetry-lock20-simple.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# This file is automatically @generated by Poetry and should not be changed by hand.

[[package]]
name = "toml"
version = "0.10.2"
description = "Python Library for Tom's Obvious, Minimal Language"
category = "main"
optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
files = [
{file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"},
{file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
]

[metadata]
lock-version = "2.0"
python-versions = "^3.9"
content-hash = "b97d7a3bc03286e93fd688187cbdcd469fe0e5108cdc7936c432995f983f478c"
21 changes: 13 additions & 8 deletions tests/test_parser_poetry.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,19 @@
import os
from unittest import TestCase

from ddt import data, ddt

from cyclonedx_py.parser.poetry import PoetryFileParser


@ddt
class TestPoetryParser(TestCase):

def test_simple(self) -> None:
tests_poetry_lock_file = os.path.join(os.path.dirname(__file__), 'fixtures/poetry-lock-simple.txt')

parser = PoetryFileParser(poetry_lock_filename=tests_poetry_lock_file)
@data('poetry-lock11-simple.txt',
'poetry-lock20-simple.txt')
def test_simple(self, lock_file_name: str) -> None:
poetry_lock_filename = os.path.join(os.path.dirname(__file__), 'fixtures', lock_file_name)
parser = PoetryFileParser(poetry_lock_filename=poetry_lock_filename)
self.assertEqual(1, parser.component_count())
component = next(filter(lambda c: c.name == 'toml', parser.get_components()), None)
self.assertIsNotNone(component)
Expand All @@ -37,10 +41,11 @@ def test_simple(self) -> None:
self.assertEqual('0.10.2', component.version)
self.assertEqual(2, len(component.external_references), f'{component.external_references}')

def test_simple_purl_bom_ref(self) -> None:
tests_poetry_lock_file = os.path.join(os.path.dirname(__file__), 'fixtures/poetry-lock-simple.txt')

parser = PoetryFileParser(poetry_lock_filename=tests_poetry_lock_file, use_purl_bom_ref=True)
@data('poetry-lock11-simple.txt',
'poetry-lock20-simple.txt')
def test_simple_purl_bom_ref(self, lock_file_name: str) -> None:
poetry_lock_filename = os.path.join(os.path.dirname(__file__), 'fixtures', lock_file_name)
parser = PoetryFileParser(poetry_lock_filename=poetry_lock_filename, use_purl_bom_ref=True)
self.assertEqual(1, parser.component_count())
component = next(filter(lambda c: c.name == 'toml', parser.get_components()), None)
self.assertIsNotNone(component)
Expand Down

0 comments on commit 0b1e07f

Please sign in to comment.