Files
Aegis/backend/app/models/template_suggestion.py
T
kitos c753797019
Aegis CI / lint-and-test (push) Has been cancelled
Snyk Security Scan / Python vulnerabilities (backend) (push) Has been cancelled
Snyk Security Scan / npm vulnerabilities (frontend) (push) Has been cancelled
Snyk Security Scan / Docker image vulnerabilities (backend) (push) Has been cancelled
feat(test-catalog): add template creation and lead-approval workflow
Leads get a Create Template button that adds directly to the catalog
(existing POST /test-templates). Operators (red_tech/blue_tech) get the
same button, but their proposal now lands in a new template_suggestions
review queue instead — a lead on their team can approve it as-is, edit
fields before approving, or discard it. Modeled on the existing
ProcedureSuggestion review workflow.
2026-07-16 12:08:23 +02:00

54 lines
2.4 KiB
Python

"""SQLAlchemy model for operator-proposed test templates, pending lead review.
Leads create templates directly (see TestTemplateCreate router). An
operator (red_tech/blue_tech) gets the same "create template" action, but
their submission lands here instead of the live catalog — a lead on their
team reviews it, optionally edits any field, and either approves it (which
creates the real TestTemplate) or discards it.
"""
import uuid
from sqlalchemy import Column, DateTime, ForeignKey, String, Text, func
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import relationship
from app.database import Base
class TemplateSuggestion(Base):
"""A proposed new TestTemplate submitted by an operator, pending lead review."""
__tablename__ = "template_suggestions"
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
# Proposed TestTemplate fields — mirrors TestTemplateCreate.
mitre_technique_id = Column(String, nullable=False)
name = Column(String, nullable=False)
description = Column(Text, nullable=True)
source = Column(String, nullable=False, default="custom", server_default="custom")
source_url = Column(String, nullable=True)
attack_procedure = Column(Text, nullable=True)
expected_detection = Column(Text, nullable=True)
platform = Column(String, nullable=True)
tool_suggested = Column(String, nullable=True)
severity = Column(String, nullable=True)
atomic_test_id = Column(String, nullable=True)
suggested_remediation = Column(Text, nullable=True)
# "red" or "blue" — derived from the submitter's role, determines which
# lead reviews it (admins can review both).
team = Column(String(10), nullable=False)
submitted_by = Column(UUID(as_uuid=True), ForeignKey("users.id"), nullable=True)
status = Column(String(10), nullable=False, default="pending", server_default="pending") # pending/approved/rejected
reviewed_by = Column(UUID(as_uuid=True), ForeignKey("users.id"), nullable=True)
reviewed_at = Column(DateTime, nullable=True)
created_template_id = Column(UUID(as_uuid=True), ForeignKey("test_templates.id"), nullable=True)
created_at = Column(DateTime(timezone=True), server_default=func.now())
submitter = relationship("User", foreign_keys=[submitted_by])
reviewer = relationship("User", foreign_keys=[reviewed_by])
created_template = relationship("TestTemplate", foreign_keys=[created_template_id])