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
7 changes: 7 additions & 0 deletions src/debsbom/bomreader/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Copyright (C) 2025 Siemens
#
# SPDX-License-Identifier: MIT

from .bomreader import BomReader
from .spdxbomreader import SpdxBomReader
from .cdxbomreader import CdxBomReader
23 changes: 23 additions & 0 deletions src/debsbom/bomreader/bomreader.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Copyright (C) 2025 Siemens
#
# SPDX-License-Identifier: MIT

from abc import abstractmethod
from pathlib import Path
from typing import IO


class BomReader:
"""Base class for SBOM importers"""

@classmethod
@abstractmethod
def read_file(cls, filename: Path):
"""Parse and return a BOM instance from the file"""
raise NotImplementedError()

@classmethod
@abstractmethod
def read_stream(cls, stream: IO[str]):
"""Parse and return a BOM instance from the stream"""
raise NotImplementedError()
25 changes: 25 additions & 0 deletions src/debsbom/bomreader/cdxbomreader.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Copyright (C) 2025 Siemens
#
# SPDX-License-Identifier: MIT

from typing import IO

from .bomreader import BomReader
from ..sbom import CDXType

import json
from pathlib import Path
from cyclonedx.model.bom import Bom


class CdxBomReader(BomReader, CDXType):
"""Import an CycloneDX SBOM"""

@classmethod
def read_file(cls, filename: Path) -> Bom:
with open(filename, "r") as f:
return cls.read_stream(f)

@classmethod
def read_stream(cls, stream: IO[str]) -> Bom:
return Bom.from_json(json.load(stream))
27 changes: 27 additions & 0 deletions src/debsbom/bomreader/spdxbomreader.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Copyright (C) 2025 Siemens
#
# SPDX-License-Identifier: MIT

import json
from pathlib import Path
from typing import IO

from pathlib import Path
from spdx_tools.spdx.parser.parse_anything import parse_file as spdx_parse_file
from spdx_tools.spdx.parser.jsonlikedict.json_like_dict_parser import JsonLikeDictParser
from spdx_tools.spdx.model.document import Document

from .bomreader import BomReader
from ..sbom import SPDXType


class SpdxBomReader(BomReader, SPDXType):
"""Import an SPDX SBOM"""

@classmethod
def read_file(cls, filename: Path) -> Document:
return spdx_parse_file(str(filename))

@classmethod
def read_stream(cls, stream: IO[str]) -> Document:
return JsonLikeDictParser().parse(json.load(stream))
9 changes: 0 additions & 9 deletions src/debsbom/download/cdx.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,3 @@ def create_package(cls, c: Component) -> Package:
continue
pkg.checksums[CHKSUM_TO_INTERNAL[cks.alg]] = cks.content
return pkg

@classmethod
def from_file(cls, filename: Path) -> "CdxPackageResolver":
with open(filename, "r") as f:
return cls.from_stream(f)

@classmethod
def from_stream(cls, stream: IO[str]) -> "CdxPackageResolver":
return cls(Bom.from_json(json.load(stream)))
12 changes: 8 additions & 4 deletions src/debsbom/download/resolver.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,12 +140,14 @@ def create(filename: Path) -> "PackageResolver":
"""
if filename.name.endswith("spdx.json"):
from .spdx import SpdxPackageResolver
from ..bomreader import SpdxBomReader

return SpdxPackageResolver.from_file(filename)
return SpdxPackageResolver(SpdxBomReader.read_file(filename))
elif filename.name.endswith("cdx.json"):
from .cdx import CdxPackageResolver
from ..bomreader import CdxBomReader

return CdxPackageResolver.from_file(filename)
return CdxPackageResolver(CdxBomReader.read_file(filename))
else:
raise RuntimeError("Cannot determine file format")

Expand All @@ -156,12 +158,14 @@ def from_stream(stream: IO, bomtype=SBOMType) -> "PackageResolver":
"""
if bomtype == SBOMType.SPDX:
from .spdx import SpdxPackageResolver
from ..bomreader import SpdxBomReader

return SpdxPackageResolver.from_stream(stream)
return SpdxPackageResolver(SpdxBomReader.read_stream(stream))
else:
from .cdx import CdxPackageResolver
from ..bomreader import CdxBomReader

return CdxPackageResolver.from_stream(stream)
return CdxPackageResolver(CdxBomReader.read_stream(stream))


class PackageStreamResolver(PackageResolver):
Expand Down
14 changes: 0 additions & 14 deletions src/debsbom/download/spdx.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,11 @@
#
# SPDX-License-Identifier: MIT

import json
from typing import IO
from ..dpkg.package import ChecksumAlgo, Package
from ..sbom import SPDXType
from .resolver import PackageResolver

import logging
from collections.abc import Iterable
from pathlib import Path
from spdx_tools.spdx.parser.parse_anything import parse_file
from spdx_tools.spdx.parser.jsonlikedict.json_like_dict_parser import JsonLikeDictParser
import spdx_tools.spdx.model.package as spdx_package
import spdx_tools.spdx.model.document as spdx_document
from spdx_tools.spdx.model.checksum import ChecksumAlgorithm
Expand Down Expand Up @@ -68,11 +62,3 @@ def create_package(cls, p: spdx_package.Package) -> Package:
continue
pkg.checksums[CHKSUM_TO_INTERNAL[cks.algorithm]] = cks.value
return pkg

@classmethod
def from_file(cls, filename: Path) -> "SpdxPackageResolver":
return cls(parse_file(str(filename)))

@classmethod
def from_stream(cls, stream: IO[str]) -> "SpdxPackageResolver":
return cls(JsonLikeDictParser().parse(json.load(stream)))