feat(ttp): implement E.3.14b intel catch-up via attacker.session.ended
On every attacker.session.ended event, the TTP worker now reads the persisted AttackerIntel row (if any) and synthesizes an intel-source TaggerEvent so intel-derived tags emit even when attacker.intel.enriched was dropped or arrived before the worker started. Key changes: - AttackerIntel.to_intel_event_payload() — single source of truth for the intel-row → lifter payload projection; shared by future callers without importing decnet.intel.* (no-SPOF contract preserved). - BaseRepository.get_attacker_intel_row_by_uuid() — returns the live SQLModel instance so the catch-up path can call to_intel_event_payload(). - _build_intel_catchup_event() in ttp/worker.py — looks up the intel row, builds the TaggerEvent, returns None on absent row (silence, not error). - _process_event() extended: appends the catch-up event to tagger_events when topic contains "session.ended". Deterministic source_id keeps compute_tag_uuid idempotent across replays; INSERT OR IGNORE deduplicates against any prior attacker.intel.enriched path. DummyRepo stub + coverage call added per feedback_run_base_repo_test.md.
This commit is contained in:
@@ -3,6 +3,7 @@ from collections.abc import AsyncIterator
|
||||
from datetime import datetime
|
||||
from typing import Any, Optional
|
||||
|
||||
from decnet.web.db.models.attacker_intel import AttackerIntel
|
||||
from decnet.web.db.models.topology import DeckyRow, EdgeRow, LANRow, TopologySummary
|
||||
from decnet.web.db.models import (
|
||||
CampaignTechniqueRow,
|
||||
@@ -452,6 +453,19 @@ class BaseRepository(ABC):
|
||||
"""Return the threat-intel row for ``uuid`` or ``None`` if missing."""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def get_attacker_intel_row_by_uuid(
|
||||
self, uuid: str,
|
||||
) -> Optional[AttackerIntel]:
|
||||
"""Return the live :class:`AttackerIntel` SQLModel instance for
|
||||
``uuid``, or ``None`` if no row exists.
|
||||
|
||||
Prefer this over :meth:`get_attacker_intel_by_uuid` when the
|
||||
caller needs to call :meth:`~AttackerIntel.to_intel_event_payload`
|
||||
(e.g. the TTP worker's intel catch-up path on session.ended).
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def get_unenriched_attackers(
|
||||
self, limit: int = 100,
|
||||
|
||||
Reference in New Issue
Block a user