feat(phase-38): automatic intelligence — OSINT enrichment + stale coverage detection

Tarea 4.1 — OSINT Enrichment:
- Add OsintItem model with source_type, severity, CVSS metadata, review flag
- Add Alembic migration b022 with osint_items table and optimized indexes
- Add osint_enrichment_service with NVD API integration, deduplication, rate limiting
- Add OSINT router: GET /osint/items, /osint/summary, /osint/technique/{id}
- Add POST /osint/items/{id}/review to mark items as reviewed
- Add POST /osint/enrich/{technique_id} for manual single-technique enrichment
- Techniques with new CVEs are automatically flagged review_required=True
- Register weekly enrichment job in APScheduler
- Add NVD_API_KEY config setting for optional increased rate limits

Tarea 4.2 — Stale Coverage Detection:
- Add stale_detection_service that flags techniques with no validated test
  in the last N days, or never-validated but with a coverage status
- Configurable threshold via STALE_THRESHOLD_DAYS setting (default 365)
- Register daily stale detection job in APScheduler
- Only flags techniques not already marked review_required
This commit is contained in:
2026-02-17 17:47:47 +01:00
parent 31e116b4ba
commit 222979574a
9 changed files with 607 additions and 2 deletions

View File

@@ -18,6 +18,7 @@ from app.models.compliance import ComplianceFramework, ComplianceControl, Compli
from app.models.coverage_snapshot import CoverageSnapshot, SnapshotTechniqueState
from app.models.jira_link import JiraLink, JiraLinkEntityType, JiraSyncDirection
from app.models.worklog import Worklog
from app.models.osint_item import OsintItem
from app.models.enums import TechniqueStatus, TestState, TestResult, TeamSide
__all__ = [
@@ -30,6 +31,6 @@ __all__ = [
"ComplianceFramework", "ComplianceControl", "ComplianceControlMapping",
"CoverageSnapshot", "SnapshotTechniqueState",
"JiraLink", "JiraLinkEntityType", "JiraSyncDirection",
"Worklog",
"Worklog", "OsintItem",
"TechniqueStatus", "TestState", "TestResult", "TeamSide",
]

View File

@@ -0,0 +1,40 @@
"""OSINT enrichment items — CVEs, blogs, PoCs, and advisories linked to techniques."""
import uuid
from datetime import datetime
from sqlalchemy import Column, String, Text, Boolean, DateTime, ForeignKey
from sqlalchemy.dialects.postgresql import UUID, JSONB
from sqlalchemy.orm import relationship
from app.database import Base
class OsintItem(Base):
"""Represents an OSINT data point (CVE, blog, PoC, advisory) associated
with a MITRE ATT&CK technique.
Used by the enrichment pipeline to surface relevant threat intelligence
for each technique, flagging those that need review.
"""
__tablename__ = "osint_items"
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
technique_id = Column(
UUID(as_uuid=True),
ForeignKey("techniques.id"),
nullable=False,
index=True,
)
source_type = Column(String(50), nullable=False) # "cve", "blog", "poc", "advisory"
source_url = Column(Text, nullable=False)
title = Column(String(500), nullable=False)
description = Column(Text, nullable=True)
severity = Column(String(20), nullable=True) # CRITICAL, HIGH, MEDIUM, LOW, UNKNOWN
discovered_at = Column(DateTime, default=datetime.utcnow, nullable=False)
reviewed = Column(Boolean, default=False)
metadata_ = Column("metadata", JSONB, default={})
# ── Relationships ─────────────────────────────────────────────────
technique = relationship("Technique", backref="osint_items")