Skip to content
Closed
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
"""Add manual_verification table

Revision ID: a9befc7a716c
Revises: j2k3l4m5n678
Create Date: 2026-04-04

"""
from typing import Sequence, Union

from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision: str = "a9befc7a716c"
down_revision: Union[str, Sequence[str], None] = "j1k2l3m4n567"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:
"""Upgrade schema."""
op.create_table(
"manual_verification",
sa.Column("id", sa.Integer(), nullable=False),
sa.Column("scan_id", sa.Integer(), nullable=False),
sa.Column("control_id", sa.String(length=50), nullable=False),
sa.Column("user_id", sa.Integer(), nullable=False),
sa.Column("status", sa.String(length=20), nullable=False),
sa.Column("comment", sa.Text(), nullable=True),
sa.Column(
"created_at", sa.DateTime(), server_default=sa.text("now()"), nullable=False
),
sa.Column(
"updated_at",
sa.DateTime(),
server_default=sa.text("now()"),
nullable=False,
),
sa.ForeignKeyConstraint(["scan_id"], ["scan.id"], ondelete="CASCADE"),
sa.ForeignKeyConstraint(["user_id"], ["user.id"], ondelete="CASCADE"),
sa.PrimaryKeyConstraint("id"),
)


def downgrade() -> None:
"""Downgrade schema."""
op.drop_table("manual_verification")
2 changes: 2 additions & 0 deletions backend-api/app/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from app.models.aws_connection import AWSConnection
from app.models.platform import Platform
from app.models.scan_result import ScanResult
from app.models.manual_verification import ManualVerification
from app.models.compliance import Scan
from app.models.evidence_validation import EvidenceValidation
from app.models.contact import ContactSubmission, SubmissionNote, SubmissionHistory
Expand All @@ -23,6 +24,7 @@
"AWSConnection",
"Platform",
"ScanResult",
"ManualVerification",
"Scan",
"EvidenceValidation",
"ContactSubmission",
Expand Down
34 changes: 34 additions & 0 deletions backend-api/app/models/manual_verification.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
"""manualVerification Model for user-submitted control verifications."""

from datetime import datetime
from typing import TYPE_CHECKING, Optional

from sqlalchemy import ForeignKey, String, Text
from sqlalchemy.orm import Mapped, mapped_column, relationship
from sqlalchemy.sql import func

from app.db.base import Base

if TYPE_CHECKING:
from app.models.compliance import Scan # prevent version conflict with circular import
from app.models.user import User # prevent version conflict with circular import

class ManualVerification(Base):
"""Model for manual verification of controls by users."""

__tablename__ = "manual_verification"

id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
scan_id: Mapped[int] = mapped_column(ForeignKey("scan.id"), nullable=False)
control_id: Mapped[str] = mapped_column(String(50), nullable=False)
user_id: Mapped[int] = mapped_column(ForeignKey("user.id"), nullable=False)
# Status: passed or failed
status: Mapped[str] = mapped_column(String(20), nullable=False)
comment: Mapped[Optional[str]] = mapped_column(Text, nullable=True)

created_at: Mapped[datetime] = mapped_column(server_default=func.now(), nullable=False)
updated_at: Mapped[datetime] = mapped_column(server_default=func.now(), onupdate=func.now(), nullable=False)

# Relationships
scan: Mapped["Scan"] = relationship()
user: Mapped["User"] = relationship()
Loading