Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion docs/source/design-decisions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ The following table shows how fields in a Debian binary package are mapped to fi
``Conffiles``, \-, \-
``Depends``, [#depends]_, [#depends]_
``Recommends``, \-, \-
``Pre-Depends``, \-, \-
``Pre-Depends``, [#pre_depends]_, [#pre_depends]_
``Suggests``, \-, \-
``Description``, ``summary`` and ``description`` [#description]_, ``description``
``Built-Using``, [#built_using_spdx]_, [#built_using_cdx]_
Expand All @@ -71,6 +71,7 @@ The following table shows how fields in a Debian binary package are mapped to fi
.. [#architecture] The architecture is only part of the PURL
.. [#source] When a ``Source`` is specified it gets a separate entry in the SBOM and the dependency is added
.. [#depends] When a ``Dependency`` is specified a dependency is created for the related packages
.. [#pre_depends] ``Pre-Depends`` dependencies are treated exactly the same as ``Depends`` dependencies, i.e. simply appended to them
.. [#description] The synopsis (first line) is the ``summary``, the rest goes into the ``description``
.. [#built_using_spdx] Any ``Built-Using`` dependency gets a separate entry and the ``GENERATED_FROM`` relationship is used
.. [#built_using_cdx] Any ``Built-Using`` dependency gets a separate entry and the dependency is added
Expand Down
18 changes: 17 additions & 1 deletion src/debsbom/dpkg/package.py
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,7 @@ class BinaryPackage(Package):
architecture: str | None
source: Dependency | None
depends: list[Dependency]
pre_depends: list[Dependency]
provides: list[VirtualPackage]
built_using: list[Dependency]
description: str | None
Expand All @@ -582,6 +583,7 @@ def __init__(
architecture: str | None = None,
source: Dependency | None = None,
depends: list[Dependency] = [],
pre_depends: list[Dependency] = [],
provides: list[VirtualPackage] = [],
built_using: list[Dependency] = [],
description: str | None = None,
Expand All @@ -597,6 +599,7 @@ def __init__(
self.source = source
self.version = Version(version)
self.depends = depends
self.pre_depends = pre_depends
self.provides = provides
self.built_using = built_using
self.description = description
Expand Down Expand Up @@ -627,6 +630,11 @@ def source_package(self) -> SourcePackage | None:
else:
return None

@property
def all_depends(self) -> Iterable[Dependency]:
"""Returns an iterator containing both "Depends" and "Pre-Depends."""
return itertools.chain(self.depends, self.pre_depends)

@property
def unique_depends(self):
"""
Expand All @@ -636,7 +644,7 @@ def unique_depends(self):
"""
seen = set()
unique = []
for dep in self.depends:
for dep in self.all_depends:
key = (dep.name, dep.arch)
if key not in seen:
seen.add(key)
Expand Down Expand Up @@ -667,6 +675,10 @@ def merge_with(self, other: "BinaryPackage"):
depends.extend(x for x in other.depends if x not in depends)
self.depends = depends

pre_depends = list(self.pre_depends)
pre_depends.extend(x for x in other.pre_depends if x not in pre_depends)
self.pre_depends = pre_depends

built_using = list(self.built_using)
built_using.extend(x for x in other.built_using if x not in built_using)
self.built_using = built_using
Expand Down Expand Up @@ -735,6 +747,9 @@ def from_deb822(cls, package) -> "BinaryPackage":
pdepends = package.relations["depends"] or []
dependencies = Dependency.from_pkg_relations(pdepends)

pre_pdepends = package.relations["pre-depends"] or []
pre_dependencies = Dependency.from_pkg_relations(pre_pdepends)

provides = VirtualPackage.from_pkg_relations(package.relations["provides"] or [])

# static dependencies
Expand All @@ -756,6 +771,7 @@ def from_deb822(cls, package) -> "BinaryPackage":
source=srcdep,
version=package.get("Version"),
depends=dependencies,
pre_depends=pre_dependencies,
provides=provides,
built_using=sdepends,
description=cls._cleanup_description(package.get("Description")),
Expand Down
1 change: 1 addition & 0 deletions tests/data/dpkg-status-minimal
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Maintainer: Matthias Klose <doko@debian.org>
Architecture: amd64
Version: 2.40-2
Provides: binutils-gold, elf-binutils
Pre-Depends: init-system-helpers (>= 1.54~)
Depends: binutils-common (= 2.40-2), libbinutils (= 2.40-2), binutils-x86-64-linux-gnu (= 2.40-2)
Suggests: binutils-doc (>= 2.40-2)
Conflicts: binutils-mingw-w64-i686 (<< 2.23.52.20130612-1+3), binutils-mingw-w64-x86-64 (<< 2.23.52.20130612-1+3), binutils-multiarch (<< 2.27-8), modutils (<< 2.4.19-1)
Expand Down
28 changes: 28 additions & 0 deletions tests/root/pre-depends/var/lib/dpkg/status
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
Package: test-pre-depends
Status: install ok installed
Priority: optional
Installed-Size: 1234
Maintainer: Siemens <siemens@example.com>
Architecture: amd64
Version: 1.0.0-1
Depends: depends (>= 1.2.3)
Pre-Depends: pre-depends (>= 2.3.4)
Description: Test Package for Pre-Depends

Package: pre-depends
Status: install ok installed
Priority: optional
Installed-Size: 1234
Maintainer: Siemens <siemens@example.com>
Architecture: amd64
Version: 2.3.4
Description: Pre-Depends Package

Package: depends
Status: install ok installed
Priority: optional
Installed-Size: 1234
Maintainer: Siemens <siemens@example.com>
Architecture: amd64
Version: 1.2.3
Description: Depends Package
3 changes: 3 additions & 0 deletions tests/test_dpkg.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ def test_parse_minimal_status_file(mode):
assert bpkg.maintainer == "Matthias Klose <doko@debian.org>"
assert bpkg.source == Dependency(bpkg.name, None, ("=", bpkg.version), arch="source")
assert bpkg.version == "2.40-2"
assert bpkg.pre_depends == [
Dependency("init-system-helpers", None, (">=", "1.54~")),
]
assert bpkg.depends == [
Dependency("binutils-common", None, ("=", bpkg.version)),
Dependency("libbinutils", None, ("=", bpkg.version)),
Expand Down
34 changes: 34 additions & 0 deletions tests/test_generation.py
Original file line number Diff line number Diff line change
Expand Up @@ -497,3 +497,37 @@ def test_virtual_package(tmpdir, sbom_generator):
found = True
break
assert found


def test_pre_depends(tmpdir, sbom_generator):
_spdx_tools = pytest.importorskip("spdx_tools")
_cyclonedx = pytest.importorskip("cyclonedx")

dbom = sbom_generator("tests/root/pre-depends")
outdir = Path(tmpdir)
dbom.generate(str(outdir / "sbom"), validate=True)
with open(outdir / "sbom.spdx.json") as file:
spdx_json = json.loads(file.read())
relationships = spdx_json["relationships"]
assert {
"spdxElementId": "SPDXRef-test-pre-depends-amd64",
"relatedSpdxElement": "SPDXRef-pre-depends-amd64",
"relationshipType": "DEPENDS_ON",
} in relationships
assert {
"spdxElementId": "SPDXRef-test-pre-depends-amd64",
"relatedSpdxElement": "SPDXRef-depends-amd64",
"relationshipType": "DEPENDS_ON",
} in relationships

with open(outdir / "sbom.cdx.json") as file:
spdx_json = json.loads(file.read())
dependencies = spdx_json["dependencies"]
assert {
"dependsOn": [
"pkg:deb/debian/depends@1.2.3?arch=amd64",
"pkg:deb/debian/pre-depends@2.3.4?arch=amd64",
"pkg:deb/debian/test-pre-depends@1.0.0-1?arch=source",
],
"ref": "pkg:deb/debian/test-pre-depends@1.0.0-1?arch=amd64",
} in dependencies