import enum import uuid from datetime import datetime from sqlalchemy import Boolean, DateTime, Enum, ForeignKey, String from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.orm import Mapped, mapped_column, relationship from api.models.base import Base, new_uuid class Ecosystem(str, enum.Enum): python = "python" node = "node" rust = "rust" go = "go" java = "java" terraform = "terraform" ansible = "ansible" tool = "tool" other = "other" class SBOMEntry(Base): """Snapshot-based SBOM entry — no updated_at; new ingest replaces old rows.""" __tablename__ = "sbom_entries" id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), primary_key=True, default=new_uuid ) repo_id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), ForeignKey("managed_repos.id", ondelete="RESTRICT"), nullable=False, index=True, ) package_name: Mapped[str] = mapped_column(String(300), nullable=False) package_version: Mapped[str | None] = mapped_column(String(100), nullable=True) ecosystem: Mapped[Ecosystem] = mapped_column( Enum(Ecosystem, name="ecosystem"), nullable=False ) license_spdx: Mapped[str | None] = mapped_column(String(100), nullable=True) is_direct: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True) is_dev: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False) snapshot_id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), ForeignKey("sbom_snapshots.id", ondelete="RESTRICT"), nullable=False, index=True, ) snapshot_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), nullable=False ) created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), nullable=False ) repo: Mapped["ManagedRepo"] = relationship("ManagedRepo", lazy="selectin") # noqa: F821 snapshot: Mapped["SBOMSnapshot"] = relationship( # noqa: F821 "SBOMSnapshot", lazy="selectin", back_populates="entries" )