feat(ttp): enable 6 xfail tests — evidence shape + tracing spans
- test_evidence_shape.py: replace broken (command, BehavioralLifter)
pairing with correct (http_fingerprint, HttpFingerprintLifter) case;
expand _LIFTER_CASES to 5-tuples with per-lifter payloads and rule
factories; wire StubRuleStore + _index.install() per lifter; remove
xfail marker — all 4 parametrized cases now pass
- factory.py: add _span() helper gated on _telemetry._ENABLED; wrap
each per-lifter dispatch in _tag_one() that opens a
ttp.lifter.{name} child span per call
- http_fingerprint_lifter.py: add missing name = "http_fingerprint"
- test_tracing.py: replace pytest.fail() stubs in
test_lifter_child_spans_emitted and test_no_pii_canary_in_span_attributes
with real test bodies; remove xfail markers
This commit is contained in:
@@ -21,10 +21,12 @@ from __future__ import annotations
|
||||
import asyncio
|
||||
import logging
|
||||
import os
|
||||
from typing import Final
|
||||
from contextlib import contextmanager
|
||||
from typing import Any, Final
|
||||
|
||||
from collections.abc import Iterator
|
||||
|
||||
from decnet import telemetry as _telemetry
|
||||
from decnet.ttp.base import (
|
||||
KNOWN_SOURCE_KINDS,
|
||||
Tagger,
|
||||
@@ -35,6 +37,22 @@ from decnet.web.db.models.ttp import TTPTag
|
||||
|
||||
_log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@contextmanager
|
||||
def _span(name: str, **attrs: Any) -> Iterator[Any]:
|
||||
"""Tracing helper gated on ``DECNET_DEVELOPER_TRACING``."""
|
||||
if not _telemetry._ENABLED:
|
||||
yield None
|
||||
return
|
||||
tracer = _telemetry.get_tracer("ttp")
|
||||
with tracer.start_as_current_span(name) as span:
|
||||
for key, value in attrs.items():
|
||||
try:
|
||||
span.set_attribute(key, value)
|
||||
except (TypeError, ValueError):
|
||||
continue
|
||||
yield span
|
||||
|
||||
_KNOWN: Final[tuple[str, ...]] = ("composite",)
|
||||
_DEFAULT: Final[str] = "composite"
|
||||
|
||||
@@ -91,12 +109,16 @@ class CompositeTagger(Tagger):
|
||||
if not lifters:
|
||||
self._log_unhandled(event.source_kind)
|
||||
return []
|
||||
results = await asyncio.gather(*(t.tag(event) for t in lifters))
|
||||
results = await asyncio.gather(*(self._tag_one(t, event) for t in lifters))
|
||||
out: list[TTPTag] = []
|
||||
for tags in results:
|
||||
out.extend(tags)
|
||||
return out
|
||||
|
||||
async def _tag_one(self, lifter: Tagger, event: TaggerEvent) -> list[TTPTag]:
|
||||
with _span(f"ttp.lifter.{lifter.name}"):
|
||||
return await lifter.tag(event)
|
||||
|
||||
def _log_unhandled(self, source_kind: str) -> None:
|
||||
if source_kind in KNOWN_SOURCE_KINDS:
|
||||
if source_kind not in self._warned_known:
|
||||
|
||||
@@ -106,6 +106,7 @@ _PREDICATES: Final[dict[str, Predicate]] = {
|
||||
class HttpFingerprintLifter(TolerantTagger):
|
||||
"""Tags HTTP-layer fingerprint events with MITRE ATT&CK techniques."""
|
||||
|
||||
name = "http_fingerprint"
|
||||
HANDLES: frozenset[str] = frozenset({"http_fingerprint"})
|
||||
|
||||
def __init__(self, store: RuleStore) -> None:
|
||||
|
||||
Reference in New Issue
Block a user