Empty NotImplementedError bodies; the SQL lands at E.3 implementation. Mixin composed onto SQLModelRepository alongside the existing domain mixins. Dialect-specific INSERT-OR-IGNORE syntax overrides land in the per-backend subclasses at E.3 per the dual-DB-backend convention.
107 lines
3.9 KiB
Python
107 lines
3.9 KiB
Python
"""TTP-tagging repository — `ttp_tag` reads + idempotent inserts.
|
|
|
|
Contract step E.1.10 of `development/TTP_TAGGING.md`. Method bodies
|
|
raise ``NotImplementedError``; the SQL lands at E.3 implementation
|
|
phase. The shape — argument types, return types, idempotency
|
|
semantics on ``insert_tags`` — is the public contract from this
|
|
commit forward.
|
|
|
|
Per the dual-DB-backend project convention, dialect-specific behavior
|
|
(``INSERT OR IGNORE`` on SQLite vs ``INSERT IGNORE`` on MySQL) is
|
|
overridden in the per-dialect subclasses (``decnet.web.db.sqlite``,
|
|
``decnet.web.db.mysql``); the shared base lives here.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from decnet.web.db.models import (
|
|
CampaignTechniqueRow,
|
|
IdentityTechniqueRow,
|
|
TechniqueRollupRow,
|
|
TTPTag,
|
|
)
|
|
from decnet.web.db.sqlmodel_repo._helpers import _MixinBase
|
|
|
|
|
|
class TTPMixin(_MixinBase):
|
|
"""Mixin: TTP-tag query + insert methods composed onto
|
|
:class:`SQLModelRepository`.
|
|
|
|
Expects ``self._session()`` from the base mixin. Adding a new
|
|
``ttp_tag`` query method here requires adding a contract test in
|
|
``tests/web/db/test_ttp_repo.py`` (E.2.13) AND a parametrized run
|
|
against both SQLite and MySQL via the existing ``db_backends``
|
|
fixture.
|
|
"""
|
|
|
|
async def insert_tags(self, rows: list[TTPTag]) -> int:
|
|
"""Bulk-upsert tags with ``INSERT OR IGNORE`` semantics.
|
|
|
|
Returns the number of rows actually inserted (i.e. that were
|
|
not already present at their deterministic
|
|
:func:`compute_tag_uuid` PK). The idempotency property is the
|
|
load-bearing contract: replaying the same source events must
|
|
converge to the same tag set without writing duplicates and
|
|
without raising. See TTP_TAGGING.md §"Idempotency" + §"Bus
|
|
topics — Loop-prevention invariant".
|
|
"""
|
|
raise NotImplementedError(
|
|
"insert_tags lands at E.3 implementation phase",
|
|
)
|
|
|
|
async def list_techniques_by_identity(
|
|
self,
|
|
uuid: str,
|
|
) -> list[IdentityTechniqueRow]:
|
|
"""Per-Identity TTP rollup. Joins ``ttp_tag`` on
|
|
``identity_uuid`` and groups by ``(technique_id,
|
|
sub_technique_id)``. Includes identity-rollup tags (with NULL
|
|
``attacker_uuid``) and per-event tags whose denormalised
|
|
``identity_uuid`` matches.
|
|
"""
|
|
raise NotImplementedError(
|
|
"list_techniques_by_identity lands at E.3",
|
|
)
|
|
|
|
async def list_techniques_by_attacker(
|
|
self,
|
|
uuid: str,
|
|
) -> list[IdentityTechniqueRow]:
|
|
"""Per-Attacker (per-IP) TTP rollup. Reads ``ttp_tag`` filtered
|
|
on ``attacker_uuid``. Identity-rollup tags (NULL attacker
|
|
anchor) are deliberately excluded — those belong to the
|
|
Identity, not any one IP underneath it.
|
|
"""
|
|
raise NotImplementedError(
|
|
"list_techniques_by_attacker lands at E.3",
|
|
)
|
|
|
|
async def list_techniques_by_campaign(
|
|
self,
|
|
uuid: str,
|
|
) -> list[CampaignTechniqueRow]:
|
|
"""Campaign-wide TTP rollup. Joins ``ttp_tag`` -> Identity ->
|
|
``campaign_uuid`` and groups across all member Identities.
|
|
"""
|
|
raise NotImplementedError(
|
|
"list_techniques_by_campaign lands at E.3",
|
|
)
|
|
|
|
async def list_techniques_by_session(
|
|
self,
|
|
sid: str,
|
|
) -> list[IdentityTechniqueRow]:
|
|
"""Session-scoped TTP timeline. Filtered on ``ttp_tag.session_id``.
|
|
Used by the SessionDetail page (post-v0).
|
|
"""
|
|
raise NotImplementedError(
|
|
"list_techniques_by_session lands at E.3",
|
|
)
|
|
|
|
async def list_distinct_techniques(self) -> list[TechniqueRollupRow]:
|
|
"""Fleet-wide distinct-technique rollup with counts +
|
|
most-recent-seen timestamps. Backs ``GET /api/v1/ttp/techniques``.
|
|
"""
|
|
raise NotImplementedError(
|
|
"list_distinct_techniques lands at E.3",
|
|
)
|