feat(phase-21): add V3 demo seed, DataSource and DetectionRule models (T-200, T-201, T-202)

This commit is contained in:
2026-02-09 16:06:44 +01:00
parent 29eab4ef77
commit 022c4f2886
7 changed files with 796 additions and 1 deletions

View File

@@ -7,10 +7,13 @@ from app.models.evidence import Evidence
from app.models.intel import IntelItem
from app.models.audit import AuditLog
from app.models.notification import Notification
from app.models.data_source import DataSource
from app.models.detection_rule import DetectionRule
from app.models.enums import TechniqueStatus, TestState, TestResult, TeamSide
__all__ = [
"User", "Technique", "Test", "TestTemplate", "Evidence",
"IntelItem", "AuditLog", "Notification",
"IntelItem", "AuditLog", "Notification", "DataSource",
"DetectionRule",
"TechniqueStatus", "TestState", "TestResult", "TeamSide",
]

View File

@@ -0,0 +1,39 @@
"""DataSource model — registry of external data sources for import."""
import uuid
from datetime import datetime
from sqlalchemy import Column, String, Text, Boolean, DateTime, Index
from sqlalchemy.dialects.postgresql import UUID, JSONB
from app.database import Base
class DataSource(Base):
"""
Unified registry of all external data sources (attack procedures,
detection rules, threat intel, defensive techniques).
Each source can be independently enabled/disabled and tracks its own
synchronisation state.
"""
__tablename__ = "data_sources"
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
name = Column(String, unique=True, nullable=False) # e.g. "atomic_red_team"
display_name = Column(String, nullable=False) # e.g. "Atomic Red Team"
type = Column(String, nullable=False) # attack_procedure / detection_rule / threat_intel / defensive_technique
url = Column(String, nullable=True) # URL base of repo/API
description = Column(Text, nullable=True)
is_enabled = Column(Boolean, default=True)
last_sync_at = Column(DateTime, nullable=True)
last_sync_status = Column(String, nullable=True) # success / error / in_progress
last_sync_stats = Column(JSONB, nullable=True) # {"imported": X, "updated": Y, ...}
sync_frequency = Column(String, nullable=True) # daily / weekly / monthly / manual
config = Column(JSONB, nullable=True) # source-specific configuration
created_at = Column(DateTime, default=datetime.utcnow)
__table_args__ = (
Index('ix_data_sources_type', 'type'),
Index('ix_data_sources_is_enabled', 'is_enabled'),
)

View File

@@ -0,0 +1,42 @@
"""DetectionRule model — detection rules from multiple sources."""
import uuid
from datetime import datetime
from sqlalchemy import Column, String, Text, Boolean, DateTime, Index
from sqlalchemy.dialects.postgresql import UUID, JSONB
from app.database import Base
class DetectionRule(Base):
"""
Detection rule from an external source (Sigma, Elastic, Splunk, custom).
Each rule is mapped to one MITRE ATT&CK technique via
``mitre_technique_id`` and stores the complete rule content in
``rule_content``.
"""
__tablename__ = "detection_rules"
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
mitre_technique_id = Column(String, nullable=False) # e.g. "T1059.001"
title = Column(String, nullable=False)
description = Column(Text, nullable=True)
source = Column(String, nullable=False) # sigma / elastic / splunk / custom
source_id = Column(String, nullable=True) # ID in the source repo (for dedup)
source_url = Column(String, nullable=True)
rule_content = Column(Text, nullable=False) # YAML / KQL / SPL content
rule_format = Column(String, nullable=False) # sigma_yaml / kql / spl / custom
severity = Column(String, nullable=True) # informational / low / medium / high / critical
platforms = Column(JSONB, nullable=True, default=[])
log_sources = Column(JSONB, nullable=True) # e.g. {"product": "windows", "service": "sysmon"}
false_positive_rate = Column(String, nullable=True) # low / medium / high
is_active = Column(Boolean, default=True)
created_at = Column(DateTime, default=datetime.utcnow)
__table_args__ = (
Index('ix_detection_rules_mitre_technique_id', 'mitre_technique_id'),
Index('ix_detection_rules_source', 'source'),
Index('ix_detection_rules_severity', 'severity'),
)