diff --git a/contentctl/objects/abstract_security_content_objects/detection_abstract.py b/contentctl/objects/abstract_security_content_objects/detection_abstract.py index 81e8f737..0f11321b 100644 --- a/contentctl/objects/abstract_security_content_objects/detection_abstract.py +++ b/contentctl/objects/abstract_security_content_objects/detection_abstract.py @@ -5,16 +5,8 @@ from enum import StrEnum from typing import TYPE_CHECKING, Annotated, Any, List, Optional, Union -from pydantic import ( - Field, - FilePath, - HttpUrl, - ValidationInfo, - computed_field, - field_validator, - model_serializer, - model_validator, -) +from pydantic import (Field, FilePath, HttpUrl, ValidationInfo, computed_field, + field_validator, model_serializer, model_validator) from contentctl.objects.lookup import FileBackedLookup, KVStoreLookup, Lookup from contentctl.objects.macro import Macro @@ -31,22 +23,16 @@ from contentctl.objects.base_test_result import TestResultStatus from contentctl.objects.constants import ( CONTENTCTL_DETECTION_STANZA_NAME_FORMAT_TEMPLATE, - CONTENTCTL_MAX_SEARCH_NAME_LENGTH, - ES_MAX_STANZA_LENGTH, - ES_SEARCH_STANZA_NAME_FORMAT_AFTER_CLONING_IN_PRODUCT_TEMPLATE, -) + CONTENTCTL_MAX_SEARCH_NAME_LENGTH, ES_MAX_STANZA_LENGTH, + ES_SEARCH_STANZA_NAME_FORMAT_AFTER_CLONING_IN_PRODUCT_TEMPLATE) from contentctl.objects.data_source import DataSource from contentctl.objects.deployment import Deployment from contentctl.objects.detection_tags import DetectionTags -from contentctl.objects.drilldown import DRILLDOWN_SEARCH_PLACEHOLDER, Drilldown -from contentctl.objects.enums import ( - AnalyticsType, - ContentStatus, - DataModel, - NistCategory, - ProvidingTechnology, - RiskSeverity, -) +from contentctl.objects.drilldown import (DRILLDOWN_SEARCH_PLACEHOLDER, + Drilldown) +from contentctl.objects.enums import (AnalyticsType, ContentStatus, DataModel, + NistCategory, ProvidingTechnology, + RiskSeverity) from contentctl.objects.integration_test import IntegrationTest from contentctl.objects.manual_test import ManualTest from contentctl.objects.rba import RBAObject, RiskScoreValue_Type @@ -381,6 +367,21 @@ def annotations(self) -> dict[str, Union[List[str], int, str]]: # So start with the mapping object. annotations_dict.update(self.mappings) + ##### Adding other tags in detection ##### + # They should be referenced as a list in the yaml under tags>others + ### Example: + ## others: + ## - tag1: + ## - value1 + ## - tag2: + ## - value21 + ## - value22 + for temp_annotation in self.tags: + if temp_annotation[0] == "others": + other_tags = temp_annotation[1] + for other_tag in other_tags: + annotations_dict.update(other_tag) + # Make sure that the results are sorted for readability/easier diffs return dict(sorted(annotations_dict.items(), key=lambda item: item[0])) diff --git a/contentctl/objects/detection_tags.py b/contentctl/objects/detection_tags.py index c723e5c8..91b551c6 100644 --- a/contentctl/objects/detection_tags.py +++ b/contentctl/objects/detection_tags.py @@ -3,18 +3,9 @@ import uuid from typing import TYPE_CHECKING, List, Optional, Union -from pydantic import ( - UUID4, - BaseModel, - ConfigDict, - Field, - HttpUrl, - ValidationInfo, - computed_field, - field_validator, - model_serializer, - model_validator, -) +from pydantic import (UUID4, BaseModel, ConfigDict, Field, HttpUrl, + ValidationInfo, computed_field, field_validator, + model_serializer, model_validator) from contentctl.objects.story import Story from contentctl.objects.throttling import Throttling @@ -25,24 +16,17 @@ from contentctl.objects.annotated_types import CVE_TYPE, MITRE_ATTACK_ID_TYPE from contentctl.objects.atomic import AtomicEnrichment, AtomicTest from contentctl.objects.constants import ATTACK_TACTICS_KILLCHAIN_MAPPING -from contentctl.objects.enums import ( - AssetType, - Cis18Value, - KillChainPhase, - NistCategory, - SecurityContentProductName, - SecurityDomain, -) -from contentctl.objects.mitre_attack_enrichment import ( - MitreAttackEnrichment, - MitreAttackGroup, -) +from contentctl.objects.enums import (AssetType, Cis18Value, KillChainPhase, + NistCategory, SecurityContentProductName, + SecurityDomain) +from contentctl.objects.mitre_attack_enrichment import (MitreAttackEnrichment, + MitreAttackGroup) class DetectionTags(BaseModel): # detection spec - model_config = ConfigDict(validate_default=False, extra="forbid") + model_config = ConfigDict(validate_default=False, extra="allow") analytic_story: list[Story] = Field(...) asset_type: AssetType = Field(...) group: list[str] = []