Skip to content

Commit

Permalink
Merge branch 'releases/0.8.9'
Browse files Browse the repository at this point in the history
  • Loading branch information
t0mz06 committed Oct 25, 2024
2 parents 39b6438 + 6e1ccc0 commit 0cf8416
Show file tree
Hide file tree
Showing 10 changed files with 151 additions and 47 deletions.
2 changes: 1 addition & 1 deletion src/pytmv1/__about__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.8.8"
__version__ = "0.8.9"
10 changes: 8 additions & 2 deletions src/pytmv1/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,24 +33,27 @@
SaeIndicator,
SandboxSuspiciousObject,
SuspiciousObject,
TaskError,
TiAlert,
TiIndicator,
Value,
ValueList,
)
from .model.enum import (
AlertStatus,
ApiExpInMonths,
ApiStatus,
DetectionType,
EntityType,
EventID,
EventSubID,
Iam,
IntegrityLevel,
InvestigationResult,
InvestigationStatus,
OatDataSource,
OatEntityType,
OatRiskLevel,
OatType,
ObjectType,
OperatingSystem,
ProductCode,
Expand Down Expand Up @@ -131,6 +134,7 @@
"AddCustomScriptResp",
"Alert",
"AlertNote",
"AlertStatus",
"ApiExpInMonths",
"ApiKey",
"ApiKeyRequest",
Expand Down Expand Up @@ -172,6 +176,7 @@
"ImpactScope",
"Indicator",
"IntegrityLevel",
"InvestigationResult",
"InvestigationStatus",
"ListAlertsResp",
"ListAlertNoteResp",
Expand Down Expand Up @@ -204,7 +209,7 @@
"OatFilter",
"OatObject",
"OatRiskLevel",
"OatType",
"DetectionType",
"ObjectRequest",
"ObjectType",
"OperatingSystem",
Expand All @@ -230,6 +235,7 @@
"SuspiciousObject",
"SuspiciousObjectRequest",
"TaskAction",
"TaskError",
"TerminateProcessRequest",
"TerminateProcessTaskResp",
"TextResp",
Expand Down
39 changes: 28 additions & 11 deletions src/pytmv1/api/alert.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,14 @@
from .. import utils
from ..core import Core
from ..model.common import SaeAlert, TiAlert
from ..model.enum import Api, HttpMethod, InvestigationStatus, QueryOp
from ..model.enum import (
AlertStatus,
Api,
HttpMethod,
InvestigationResult,
InvestigationStatus,
QueryOp,
)
from ..model.response import (
ConsumeLinkableResp,
GetAlertResp,
Expand All @@ -22,30 +29,40 @@ def __init__(self, core: Core):
def update_status(
self,
alert_id: str,
status: InvestigationStatus,
if_match: str,
etag: str,
status: Optional[AlertStatus] = None,
inv_result: Optional[InvestigationResult] = None,
inv_status: Optional[InvestigationStatus] = None,
) -> Result[NoContentResp]:
"""Edit the status of an alert or investigation triggered in Workbench.
:param alert_id: Workbench alert id.
:type alert_id: str
:param status: Status to be updated.
:type status: InvestigationStatus
:param if_match: Target resource will be updated only if
:param status: Status of a case or investigation.
:type status: Optional[AlertStatus]
:param inv_result: Findings of a case or investigation.
:type inv_result: Optional[InvestigationResult]
:param inv_status: (deprecated) Status of an investigation.
:type inv_status: Optional[InvestigationStatus]
:param etag: Target resource will be updated only if
it matches ETag of the target one.
:type if_match: str
:type etag: str
:rtype: Result[NoContentResp]:
"""
return self._core.send(
NoContentResp,
Api.UPDATE_ALERT_STATUS.value.format(alert_id),
HttpMethod.PATCH,
json={"investigationStatus": status},
json=utils.filter_none(
{
"status": status,
"investigationResult": inv_result,
"investigationStatus": inv_status,
}
),
headers={
"If-Match": (
if_match
if if_match.startswith('"')
else '"' + if_match + '"'
etag if etag.startswith('"') else '"' + etag + '"'
)
},
)
Expand Down
26 changes: 20 additions & 6 deletions src/pytmv1/mapper.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
from typing import Dict, List
from typing import Dict, List, Union

from pydantic.alias_generators import to_camel

from .model.common import Alert, Entity, HostInfo, Indicator, SaeAlert, TiAlert
from .model.common import (
Alert,
Entity,
HostInfo,
SaeAlert,
SaeIndicator,
TiAlert,
TiIndicator,
)

INDICATOR_CEF_MAP: Dict[str, str] = {
"command_line": "dproc",
Expand All @@ -29,7 +37,6 @@
def map_cef(alert: Alert) -> Dict[str, str]:
data: Dict[str, str] = _map_common(alert)
_map_entities(data, alert.impact_scope.entities)
_map_indicators(data, alert.indicators)
if isinstance(alert, SaeAlert):
_map_sae(data, alert)
if isinstance(alert, TiAlert):
Expand All @@ -55,8 +62,6 @@ def _map_common(alert: Alert) -> Dict[str, str]:
cn3Label="Account Count",
cn4=str(alert.impact_scope.email_address_count),
cn4Label="Email Address Count",
cs1=", ".join(alert.indicators[0].provenance),
cs1Label="Provenance",
)


Expand All @@ -69,7 +74,10 @@ def _map_entities(data: Dict[str, str], entities: List[Entity]) -> None:
data["duser"] = entity.entity_value


def _map_indicators(data: Dict[str, str], indicators: List[Indicator]) -> None:
def _map_indicators(
data: Dict[str, str],
indicators: Union[List[TiIndicator], List[SaeIndicator]],
) -> None:
for indicator in indicators:
if isinstance(indicator.value, HostInfo):
data["shost"] = indicator.value.name
Expand All @@ -81,6 +89,8 @@ def _map_indicators(data: Dict[str, str], indicators: List[Indicator]) -> None:


def _map_sae(data: Dict[str, str], alert: SaeAlert) -> None:
data["cs1"] = ", ".join(alert.indicators[0].provenance)
data["cs1Label"] = "Provenance"
data["cs2"] = alert.matched_rules[0].matched_filters[0].name
data["cs2Label"] = "Matched Filter"
data["cs3"] = ", ".join(
Expand All @@ -89,9 +99,12 @@ def _map_sae(data: Dict[str, str], alert: SaeAlert) -> None:
data["cs3Label"] = "Matched Techniques"
data["reason"] = alert.matched_rules[0].name
data["msg"] = data.get("msg", "") + f"\nDescription: {alert.description}"
_map_indicators(data, alert.indicators)


def _map_ti(data: Dict[str, str], alert: TiAlert) -> None:
data["cs1"] = ", ".join(alert.indicators[0].provenance)
data["cs1Label"] = "Provenance"
data["cs2"] = ", ".join(alert.matched_indicator_patterns[0].tags)
data["cs2Label"] = "Matched Pattern Tags"
data["cs3"] = alert.matched_indicator_patterns[0].pattern
Expand All @@ -104,3 +117,4 @@ def _map_ti(data: Dict[str, str], alert: TiAlert) -> None:
data["industry"] = alert.industry
if alert.region_and_country:
data["regionAndCountry"] = alert.region_and_country
_map_indicators(data, alert.indicators)
59 changes: 44 additions & 15 deletions src/pytmv1/model/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@
from pydantic.alias_generators import to_camel

from .enum import (
AlertStatus,
ApiStatus,
DetectionType,
EntityType,
EventID,
EventSubID,
Iam,
IntegrityLevel,
InvestigationResult,
InvestigationStatus,
OatDataSource,
OatEntityType,
Expand Down Expand Up @@ -54,16 +57,24 @@ class Account(BaseModel):
class Alert(BaseConsumable):
id: str
schema_version: str
status: AlertStatus
# Deprecated
investigation_status: InvestigationStatus
investigation_result: InvestigationResult
workbench_link: str
alert_provider: Provider
model: str
model_type: DetectionType
score: int
severity: Severity
impact_scope: ImpactScope
created_date_time: str
updated_date_time: str
indicators: List[Indicator]
first_investigated_date_time: Optional[str] = None
incident_id: Optional[str] = None
case_id: Optional[str] = None
owner_ids: List[str] = Field(default=[])
model_id: str


class AlertNote(BaseConsumable):
Expand Down Expand Up @@ -123,6 +134,11 @@ class Endpoint(BaseConsumable):
os_description: str
product_code: ProductCode
installed_product_codes: List[ProductCode]
componentUpdatePolicy: Optional[str] = None
componentUpdateStatus: Optional[str] = None
componentVersion: Optional[str] = None
policyName: Optional[str] = None
protectionManager: Optional[str] = None


class EmailActivity(BaseConsumable):
Expand Down Expand Up @@ -199,9 +215,12 @@ class Entity(BaseModel):
entity_id: str
entity_type: EntityType
entity_value: Union[str, HostInfo]
related_entities: List[str]
related_entities: Union[List[str], List[List[str]]]
related_indicator_ids: List[int]
provenance: List[str]
management_scope_group_id: Optional[str] = None
management_scope_instance_id: Optional[str] = None
management_scope_partition_key: Optional[str] = None


class Error(BaseModel):
Expand Down Expand Up @@ -231,14 +250,16 @@ class ImpactScope(BaseModel):
server_count: int
account_count: int
email_address_count: int
container_count: int
cloud_identity_count: int
entities: List[Entity]


class Indicator(BaseModel):
id: int
type: str
value: Union[str, HostInfo]
related_entities: List[str]
related_entities: Union[List[str], List[List[str]]]
provenance: List[str]


Expand Down Expand Up @@ -362,16 +383,17 @@ class OatEvent(BaseConsumable):
detail: Union[EndpointActivity, EmailActivity]


class SaeAlert(Alert):
description: str
matched_rules: List[MatchedRule]


class SaeIndicator(Indicator):
field: str
filter_ids: List[str]


class SaeAlert(Alert):
description: str
matched_rules: List[MatchedRule]
indicators: List[SaeIndicator]


class SandboxSuspiciousObject(BaseModel):
risk_level: RiskLevel
analysis_completion_date_time: str
Expand Down Expand Up @@ -404,6 +426,19 @@ class SuspiciousObject(ExceptionObject):
expired_date_time: str


class TaskError(BaseModel):
code: str
message: str
number: int


class TiIndicator(Indicator):
fields: List[List[str]]
matched_indicator_pattern_ids: List[str]
first_seen_date_times: List[str]
last_seen_date_times: List[str]


class TiAlert(Alert):
campaign: Optional[str] = None
industry: Optional[str] = None
Expand All @@ -413,13 +448,7 @@ class TiAlert(Alert):
matched_indicator_count: int
report_link: str
matched_indicator_patterns: List[MatchedIndicatorPattern]


class TiIndicator(Indicator):
fields: List[List[str]]
matched_indicator_pattern_ids: List[str]
first_seen_date_times: List[str]
last_seen_date_times: List[str]
indicators: List[TiIndicator]


def _get_task_id(data: Dict[str, Any]) -> Optional[str]:
Expand Down
Loading

0 comments on commit 0cf8416

Please sign in to comment.