Source code for soar_sdk.models.finding

from typing import Any

import pydantic
from pydantic import BaseModel, ConfigDict, field_validator


[docs] class DrilldownSearch(BaseModel): """Represents a drilldown search in a finding.""" name: str search: str earliest: str latest: str
[docs] class DrilldownDashboardToken(BaseModel): """Represents a token for a drilldown dashboard.""" name: str value: str
[docs] class DrilldownDashboard(BaseModel): """Represents a drilldown dashboard in a finding.""" app: str dashboard_id: str name: str tokens: list[DrilldownDashboardToken] | None = None
[docs] class FindingAttachment(BaseModel): """Represents a file attachment to upload to the SOAR vault during on_es_poll. The SDK uploads these to the container vault before creating the finding, then populates the finding's email.attachments and email.raw_email_link with the resulting vault links. """ file_name: str data: bytes is_raw_email: bool = False
[docs] class FindingEmailAttachment(BaseModel): """Represents an email attachment metadata object in a finding.""" filename: str filesize: int | None = None url: str | None = None
[docs] class FindingEmailReporter(BaseModel): """Information about the person who reported the phishing email.""" model_config = ConfigDict(extra="forbid", populate_by_name=True) from_: str = pydantic.Field(alias="from", serialization_alias="from") to: str | list[str] | None = None cc: str | list[str] | None = None bcc: str | list[str] | None = None subject: str | None = None message_id: str | None = None id: str | None = None body: str | None = None date: str | None = None @field_validator("body", mode="before") @classmethod def _truncate_body(cls, v: str | None) -> str | None: if isinstance(v, str) and len(v) > 500: return v[:500] return v
[docs] class FindingEmail(BaseModel): """Email object containing all email-related fields for phishing findings.""" model_config = ConfigDict(extra="forbid") headers: dict[str, Any] | None = None body: str | None = None urls: list[str] | None = None attachments: list[FindingEmailAttachment] | None = None raw_email_link: str | None = None reporter: FindingEmailReporter | None = None
[docs] class Finding(BaseModel): """Represents a finding to be created during on_es_poll. Findings are stored in ES and can be associated with SOAR containers/artifacts for investigation workflow. Only rule_title is required. All other fields are optional and will use ES defaults or asset ingest configuration if not provided. """ model_config = ConfigDict(extra="forbid") rule_title: str security_domain: str | None = None rule_description: str | None = None risk_object: str | None = None risk_object_type: str | None = None risk_score: float | None = None status: str | None = None urgency: str | None = None owner: str | None = None disposition: str | None = None drilldown_searches: list[DrilldownSearch] | None = None drilldown_dashboards: list[DrilldownDashboard] | None = None annotations: dict[str, list[str]] | None = None risk_event_count: int | None = None all_risk_objects: list[str] | None = None source: list[str] | None = None exclude_map_fields: list[str] | None = None queue_id: str | None = None email: FindingEmail | None = None run_threat_analysis: bool = False launch_automation: bool = False investigation_type: str | None = None automation_rule: str | None = None finding_source: str | None = None additional_fields: dict[str, Any] | None = None attachments: list[FindingAttachment] | None = None
[docs] def to_dict(self) -> dict[str, Any]: """Convert the finding to a dictionary (excludes attachments).""" return self.model_dump( exclude_none=True, exclude={"attachments"}, by_alias=True )