Files
Aegis/backend/app/models/test.py
Kitos bdeeed54e1
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
feat(compliance): data classification fields and retention policies job [FASE-3.5]
2026-05-18 14:17:29 +02:00

84 lines
4.8 KiB
Python

import uuid
from sqlalchemy import Column, String, Text, Boolean, Integer, DateTime, ForeignKey, Enum, Index, func
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import relationship
from app.database import Base
from app.models.enums import TestState, TestResult
class Test(Base):
"""
Test model representing a security test for a MITRE ATT&CK technique.
Each test documents an attempt to validate coverage of a specific technique,
including the procedure, tools used, and outcome. V2 introduces dual
validation: Red Lead and Blue Lead must each approve independently.
"""
__tablename__ = "tests"
# ── Core fields ─────────────────────────────────────────────────
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
technique_id = Column(UUID(as_uuid=True), ForeignKey("techniques.id"), nullable=False)
name = Column(String, nullable=False)
description = Column(Text, nullable=True)
platform = Column(String, nullable=True)
procedure_text = Column(Text, nullable=True)
tool_used = Column(String, nullable=True)
execution_date = Column(DateTime, nullable=True)
created_by = Column(UUID(as_uuid=True), ForeignKey("users.id"), nullable=True)
result = Column(Enum(TestResult, name="testresult"), nullable=True)
state = Column(Enum(TestState, name="teststate"), default=TestState.draft)
created_at = Column(DateTime(timezone=True), server_default=func.now())
# ── Red Team fields ─────────────────────────────────────────────
red_summary = Column(Text, nullable=True)
attack_success = Column(Boolean, nullable=True)
red_validated_by = Column(UUID(as_uuid=True), ForeignKey("users.id"), nullable=True)
red_validated_at = Column(DateTime, nullable=True)
red_validation_status = Column(String, nullable=True) # pending / approved / rejected
red_validation_notes = Column(Text, nullable=True)
# ── Blue Team fields ────────────────────────────────────────────
blue_summary = Column(Text, nullable=True)
detection_result = Column(Enum(TestResult, name="testresult"), nullable=True)
blue_validated_by = Column(UUID(as_uuid=True), ForeignKey("users.id"), nullable=True)
blue_validated_at = Column(DateTime, nullable=True)
blue_validation_status = Column(String, nullable=True) # pending / approved / rejected
blue_validation_notes = Column(Text, nullable=True)
# ── Phase timing fields (for automatic Tempo worklogs) ──────────
red_started_at = Column(DateTime, nullable=True)
blue_started_at = Column(DateTime, nullable=True)
paused_at = Column(DateTime, nullable=True)
red_paused_seconds = Column(Integer, default=0)
blue_paused_seconds = Column(Integer, default=0)
# ── Remediation fields ───────────────────────────────────────────
remediation_steps = Column(Text, nullable=True)
remediation_status = Column(String, nullable=True) # pending / in_progress / completed / not_applicable
remediation_assignee = Column(UUID(as_uuid=True), ForeignKey("users.id"), nullable=True)
# ── Re-test fields ────────────────────────────────────────────
retest_of = Column(UUID(as_uuid=True), ForeignKey("tests.id"), nullable=True)
retest_count = Column(Integer, default=0)
data_classification = Column(String(20), nullable=False, server_default="internal")
# ── Relationships ───────────────────────────────────────────────
technique = relationship("Technique", back_populates="tests")
evidences = relationship("Evidence", back_populates="test")
creator = relationship("User", foreign_keys=[created_by])
red_validator = relationship("User", foreign_keys=[red_validated_by])
blue_validator = relationship("User", foreign_keys=[blue_validated_by])
remediation_user = relationship("User", foreign_keys=[remediation_assignee])
original_test = relationship("Test", remote_side="Test.id", foreign_keys=[retest_of])
retests = relationship("Test", foreign_keys=[retest_of], back_populates="original_test")
__table_args__ = (
Index("ix_tests_technique_id", "technique_id"),
Index("ix_tests_state", "state"),
Index("ix_tests_created_at", "created_at"),
Index("ix_tests_technique_state", "technique_id", "state"),
Index("ix_tests_state_created_at", "state", "created_at"),
)