"""Technique query service — framework-agnostic queries for technique details.""" from __future__ import annotations from sqlalchemy.orm import Session, joinedload from app.domain.errors import EntityNotFoundError from app.models.technique import Technique from app.services.d3fend_import_service import get_defenses_for_technique def get_technique_detail(db: Session, mitre_id: str) -> dict: """Fetch full technique details including tests and D3FEND defenses.""" technique = ( db.query(Technique) .options(joinedload(Technique.tests)) .filter(Technique.mitre_id == mitre_id) .first() ) if technique is None: raise EntityNotFoundError("Technique", mitre_id) defenses = get_defenses_for_technique(db, technique.id) return { "id": str(technique.id), "mitre_id": technique.mitre_id, "name": technique.name, "description": technique.description, "tactic": technique.tactic, "platforms": technique.platforms or [], "mitre_version": technique.mitre_version, "mitre_last_modified": technique.mitre_last_modified, "is_subtechnique": technique.is_subtechnique, "parent_mitre_id": technique.parent_mitre_id, "status_global": technique.status_global.value if technique.status_global else "not_evaluated", "review_required": technique.review_required, "last_review_date": technique.last_review_date, "tests": [ { "id": str(t.id), "name": t.name, "state": t.state.value if t.state else None, "result": t.result.value if t.result else None, "platform": t.platform, "created_at": t.created_at.isoformat() if t.created_at else None, } for t in technique.tests ], "d3fend_defenses": defenses, }