diff --git a/greenbone/scap/cve/manager.py b/greenbone/scap/cve/manager.py index 4225bc4..def79e8 100644 --- a/greenbone/scap/cve/manager.py +++ b/greenbone/scap/cve/manager.py @@ -14,6 +14,7 @@ Self, Sequence, ) +from uuid import uuid4 from pontos.nvd.models.cve import CVE from sqlalchemy import ColumnElement, and_, delete, func, select @@ -455,51 +456,68 @@ async def _insert_configurations( await connection.execute(delete_statement) + configuration_statement = self._db.insert(ConfigurationModel) + node_statement = self._db.insert(NodeModel) + match_statement = self._db.insert(CPEMatchModel) + + configurations = [] + matches = [] + nodes = [] + for cve in cves: + if not cve.configurations: + continue + for configuration in cve.configurations: - statement = ( - self._db.insert(ConfigurationModel) # type: ignore[assignment] - .returning(ConfigurationModel.id) - .values( + configuration_id = uuid4() + configurations.append( + dict( + id=configuration_id, cve_id=cve.id, operator=configuration.operator, negate=configuration.negate, ) ) - result = await connection.execute(statement) - configuration_id = result.scalar_one() + if not configuration.nodes: + continue for node in configuration.nodes: - node_statement = ( - self._db.insert(NodeModel) - .returning(NodeModel.id) - .values( + node_id = uuid4() + nodes.append( + dict( + id=node_id, configuration_id=configuration_id, operator=node.operator, negate=node.negate, ) ) - result = await connection.execute(node_statement) - node_id = result.scalar_one() - - statement = self._db.insert(CPEMatchModel) # type: ignore[assignment] - matches = [ - dict( - node_id=node_id, - match_criteria_id=match.match_criteria_id, - vulnerable=match.vulnerable, - criteria=match.criteria, - version_start_excluding=match.version_start_excluding, - version_start_including=match.version_start_including, - version_end_excluding=match.version_end_excluding, - version_end_including=match.version_end_including, - ) - for match in (node.cpe_match or []) - ] + if not node.cpe_match: + continue + + matches.extend( + [ + dict( + node_id=node_id, + match_criteria_id=match.match_criteria_id, + vulnerable=match.vulnerable, + criteria=match.criteria, + version_start_excluding=match.version_start_excluding, + version_start_including=match.version_start_including, + version_end_excluding=match.version_end_excluding, + version_end_including=match.version_end_including, + ) + for match in node.cpe_match + ] + ) - await connection.execute(statement, matches) + if configurations: + await connection.execute(configuration_statement, configurations) + if nodes: + await connection.execute(node_statement, nodes) + if matches: + await connection.execute(match_statement, matches) @asynccontextmanager async def session(self) -> AsyncGenerator[AsyncSession, None]: diff --git a/greenbone/scap/cve/models.py b/greenbone/scap/cve/models.py index 027a875..2cca1bb 100644 --- a/greenbone/scap/cve/models.py +++ b/greenbone/scap/cve/models.py @@ -193,7 +193,7 @@ class VendorCommentModel(Base): class ConfigurationModel(Base): __tablename__ = "cve_configurations" - id: Mapped[int] = mapped_column(primary_key=True) + id: Mapped[Uuid] = mapped_column(Uuid(as_uuid=False), primary_key=True) cve_id: Mapped[cve_fk] operator: Mapped[str | None] negate: Mapped[bool | None] @@ -207,8 +207,9 @@ class ConfigurationModel(Base): class NodeModel(Base): __tablename__ = "cve_nodes" - id: Mapped[int] = mapped_column(primary_key=True) - configuration_id: Mapped[int] = mapped_column( + id: Mapped[Uuid] = mapped_column(Uuid(as_uuid=False), primary_key=True) + configuration_id: Mapped[Uuid] = mapped_column( + Uuid(as_uuid=False), ForeignKey("cve_configurations.id", ondelete="CASCADE"), index=True, ) @@ -229,7 +230,8 @@ class CPEMatchModel(Base): match_criteria_id: Mapped[UUID] = mapped_column( Uuid(as_uuid=False), primary_key=True ) - node_id: Mapped[int] = mapped_column( + node_id: Mapped[UUID] = mapped_column( + Uuid(as_uuid=False), ForeignKey("cve_nodes.id", ondelete="CASCADE"), primary_key=True, index=True,