soc_ai/detection/analytic_models.py
Rama main · réplica de lectura del repositorio original.
"""A drafted analytic: a catalog spec the model wrote from a confirmed finding."""
from __future__ import annotations
from pydantic import BaseModel, ConfigDict, Field
from soc_ai.detection.models import DryRunResult
class AnalyticDraft(BaseModel):
"""The model's output. Validated by parse_spec before anything stores it."""
model_config = ConfigDict(extra="forbid")
spec_yaml: str = Field(
description=(
"One catalog analytic as YAML: id, title, description, level, "
"scope_field, scope_kind, precondition, detection, false_positives."
),
max_length=12000,
)
rationale: str = Field(
description="2 to 4 sentences. What it fires on and which evidence justifies it.",
max_length=2000,
)
class Generalization(BaseModel):
"""What the generalization check found on the draft the route returns.
``pinned`` holds one sentence per pin. Empty means the analytic describes a
behaviour. ``retried`` says the model rewrote the draft once.
"""
pinned: list[str] = []
retried: bool = False
class DraftReview(BaseModel):
"""The draft in words, for the confirm box (soc_ai.hunting.draft_review).
The box showed the id and one dry-run line, and the definition was
readable only after the save.
"""
title: str
# The detection as one sentence.
logic: str
false_positives: list[str] = []
# "Source finding: 0 of 3 documents match. They are older than the 30-day
# dry run." None when the check did not run.
source: str | None = None
# "This analytic repeats 2 Suricata rules. They raise alerts already."
# None when a clause tests a behaviour of its own.
repeats_alerts: str | None = None
class AnalyticDraftOut(BaseModel):
"""What the route returns: the stored candidate and its dry run."""
analytic_id: str
spec_yaml: str
rationale: str
dry_run: DryRunResult
# ``candidate`` once stored. ``preview`` for a draft the route did not store.
status: str = "candidate"
# What the draft could not read, in the analyst's words. A slow grid
# leaves the draft to the stored finding, and the note says so.
notes: list[str] = []
# None when the check found nothing on the first draft.
generalization: Generalization | None = None
# The draft in words. Set on a preview.
review: DraftReview | None = None