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:
47
backend/alembic/versions/b022_add_osint_items.py
Normal file
47
backend/alembic/versions/b022_add_osint_items.py
Normal file
@@ -0,0 +1,47 @@
|
||||
"""add_osint_items
|
||||
|
||||
Revision ID: b022osintitems
|
||||
Revises: b021phasetiming
|
||||
Create Date: 2026-02-17 22:00:00.000000
|
||||
|
||||
Add osint_items table for OSINT enrichment data linked to techniques.
|
||||
"""
|
||||
|
||||
from alembic import op
|
||||
|
||||
revision = "b022osintitems"
|
||||
down_revision = "b021phasetiming"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
op.execute("""
|
||||
CREATE TABLE IF NOT EXISTS osint_items (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
technique_id UUID NOT NULL REFERENCES techniques(id),
|
||||
source_type VARCHAR(50) NOT NULL,
|
||||
source_url TEXT NOT NULL,
|
||||
title VARCHAR(500) NOT NULL,
|
||||
description TEXT,
|
||||
severity VARCHAR(20),
|
||||
discovered_at TIMESTAMP NOT NULL DEFAULT now(),
|
||||
reviewed BOOLEAN NOT NULL DEFAULT false,
|
||||
metadata JSONB DEFAULT '{}'::jsonb
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS ix_osint_items_technique_id
|
||||
ON osint_items (technique_id);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS ix_osint_items_source_type
|
||||
ON osint_items (source_type);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS ix_osint_items_reviewed
|
||||
ON osint_items (reviewed) WHERE NOT reviewed;
|
||||
""")
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.execute("""
|
||||
DROP TABLE IF EXISTS osint_items CASCADE;
|
||||
""")
|
||||
Reference in New Issue
Block a user