Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,19 @@
from collections.abc import Mapping, Sequence
from typing import Any

from stix2 import Identity # type: ignore
from stix2 import (
AttackPattern,
Bundle,
ExternalReference,
IntrusionSet,
Location,
Malware,
MarkingDefinition,
Relationship,
)
from stix2.v21 import _DomainObject

from crowdstrike_feeds_services.utils import (
create_authored_by_relationships,
create_external_reference,
Expand All @@ -17,18 +30,6 @@
remove_html_tags,
timestamp_to_datetime,
)
from stix2 import Identity # type: ignore
from stix2 import (
AttackPattern,
Bundle,
ExternalReference,
IntrusionSet,
Location,
Malware,
MarkingDefinition,
Relationship,
)
from stix2.v21 import _DomainObject

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -107,6 +108,7 @@ def _create_intrusion_set(self) -> IntrusionSet:
aliases = self._get_aliases()
primary_motivation, secondary_motivations = self._get_motivations()
external_references = self._create_external_references()
labels = self._get_labels()

return create_intrusion_set(
self.actor["name"],
Expand All @@ -117,11 +119,35 @@ def _create_intrusion_set(self) -> IntrusionSet:
last_seen=self.last_seen,
primary_motivation=primary_motivation,
secondary_motivations=secondary_motivations,
labels=labels,
confidence=self.confidence_level,
external_references=external_references,
object_markings=self.object_markings,
)

def _get_labels(self) -> list[str] | None:
labels: list[str] = []

actor_motivations = self.actor.get("motivations")
if isinstance(actor_motivations, list):
for motivation in actor_motivations:
if isinstance(motivation, Mapping):
value = str(
motivation.get("value") or motivation.get("slug") or ""
).strip()
else:
value = str(motivation).strip()
if value:
labels.append(value)

actor_type = self.actor.get("actor_type")
if actor_type:
actor_type_str = str(actor_type).strip()
if actor_type_str:
labels.append(actor_type_str)

return labels or None

def _get_description(self) -> str | None:
actor = self.actor

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
from datetime import datetime
from typing import TYPE_CHECKING, Any, Dict, Generator, List, Optional

from stix2 import Bundle, Identity, MarkingDefinition

from crowdstrike_feeds_connector.related_actors.importer import (
RelatedActorImporter,
)
Expand All @@ -14,15 +16,15 @@
paginate,
timestamp_to_datetime,
)
from stix2 import Bundle, Identity, MarkingDefinition

from ..importer import BaseImporter
from .builder import ActorBundleBuilder

if TYPE_CHECKING:
from crowdstrike_feeds_connector import ConnectorSettings
from pycti import OpenCTIConnectorHelper

from crowdstrike_feeds_connector import ConnectorSettings


class ActorImporter(BaseImporter):
"""CrowdStrike actor importer."""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import stix2
import yaml

from crowdstrike_feeds_services.client.base_api import BaseCrowdstrikeClient
from crowdstrike_feeds_services.utils import (
create_organization,
Expand All @@ -30,9 +31,10 @@
from .vulnerability.importer import VulnerabilityImporter

if TYPE_CHECKING:
from crowdstrike_feeds_connector.settings import ConnectorSettings
from pycti import OpenCTIConnectorHelper

from crowdstrike_feeds_connector.settings import ConnectorSettings


class CrowdStrike:
"""CrowdStrike connector."""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@
import stix2

if TYPE_CHECKING:
from crowdstrike_feeds_connector import ConnectorSettings
from pycti import OpenCTIConnectorHelper

from crowdstrike_feeds_connector import ConnectorSettings


class BaseImporter(ABC):
"""CrowdStrike importer module."""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,24 @@
from collections.abc import Mapping
from typing import Any, Dict, List, NamedTuple, Optional, Sequence, Set, cast

from pycti import OpenCTIConnectorHelper
from stix2 import Bundle
from stix2.v21 import (
AttackPattern,
Identity,
)
from stix2.v21 import Indicator as STIXIndicator
from stix2.v21 import (
KillChainPhase,
Malware,
MarkingDefinition,
Relationship,
Vulnerability,
_DomainObject,
_Observable,
_RelationshipObject,
)

from crowdstrike_feeds_connector.related_actors.builder import RelatedActorBundleBuilder
from crowdstrike_feeds_services.utils import (
OBSERVATION_FACTORY_CRYPTOCURRENCY_WALLET,
Expand Down Expand Up @@ -37,23 +55,6 @@
CS_KILL_CHAIN_TO_LOCKHEED_MARTIN_CYBER_KILL_CHAIN,
)
from crowdstrike_feeds_services.utils.labels import extract_label_names
from pycti import OpenCTIConnectorHelper
from stix2 import Bundle
from stix2.v21 import (
AttackPattern,
Identity,
)
from stix2.v21 import Indicator as STIXIndicator
from stix2.v21 import (
KillChainPhase,
Malware,
MarkingDefinition,
Relationship,
Vulnerability,
_DomainObject,
_Observable,
_RelationshipObject,
)


class Observation(NamedTuple):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
from datetime import datetime
from typing import TYPE_CHECKING, Any, Dict, List, NamedTuple, Optional, Set

from stix2 import Bundle, Identity, MarkingDefinition

from crowdstrike_feeds_connector.related_actors.importer import RelatedActorImporter
from crowdstrike_feeds_services.client.indicators import IndicatorsAPI
from crowdstrike_feeds_services.utils import (
Expand All @@ -12,15 +14,15 @@
from crowdstrike_feeds_services.utils.attack_lookup import AttackTechniqueLookup
from crowdstrike_feeds_services.utils.labels import parse_crowdstrike_labels
from crowdstrike_feeds_services.utils.report_fetcher import FetchedReport, ReportFetcher
from stix2 import Bundle, Identity, MarkingDefinition

from ..importer import BaseImporter
from .builder import IndicatorBundleBuilder, IndicatorBundleBuilderConfig

if TYPE_CHECKING:
from crowdstrike_feeds_connector import ConnectorSettings
from pycti import OpenCTIConnectorHelper

from crowdstrike_feeds_connector import ConnectorSettings


class IndicatorImporterConfig(NamedTuple):
"""CrowdStrike indicator importer configuration."""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,18 @@

from typing import Any, List, Optional

from stix2 import Identity # type: ignore
from stix2 import (
AttackPattern,
Bundle,
ExternalReference,
KillChainPhase,
Malware,
MarkingDefinition,
Relationship,
)
from stix2.v21 import _DomainObject # type: ignore

from crowdstrike_feeds_services.utils import (
create_external_reference,
create_kill_chain_phase,
Expand All @@ -17,17 +29,6 @@
CS_CAPABILITY_TO_MALWARE_TYPE,
CS_KILL_CHAIN_TO_LOCKHEED_MARTIN_CYBER_KILL_CHAIN,
)
from stix2 import Identity # type: ignore
from stix2 import (
AttackPattern,
Bundle,
ExternalReference,
KillChainPhase,
Malware,
MarkingDefinition,
Relationship,
)
from stix2.v21 import _DomainObject # type: ignore


class MalwareBundleBuilder:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
from datetime import datetime
from typing import TYPE_CHECKING, Any, Dict, Generator, List, Optional

from stix2 import Bundle, Identity, MarkingDefinition # type: ignore

from crowdstrike_feeds_services.client.malware import MalwareAPI
from crowdstrike_feeds_services.utils import (
create_attack_pattern,
Expand All @@ -11,15 +13,15 @@
paginate,
timestamp_to_datetime,
)
from stix2 import Bundle, Identity, MarkingDefinition # type: ignore

from ..importer import BaseImporter
from .builder import MalwareBundleBuilder

if TYPE_CHECKING:
from crowdstrike_feeds_connector import ConnectorSettings
from pycti import OpenCTIConnectorHelper

from crowdstrike_feeds_connector import ConnectorSettings


class MalwareImporter(BaseImporter):
"""CrowdStrike malware importer."""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,6 @@
from collections.abc import Mapping
from typing import Any, cast

from crowdstrike_feeds_services.utils import (
create_external_reference,
create_intrusion_set,
normalize_start_time_and_stop_time,
timestamp_to_datetime,
)
from stix2 import (
AttackPattern,
ExternalReference,
Expand All @@ -18,6 +12,13 @@
MarkingDefinition,
)

from crowdstrike_feeds_services.utils import (
create_external_reference,
create_intrusion_set,
normalize_start_time_and_stop_time,
timestamp_to_datetime,
)

logger = logging.getLogger(__name__)


Expand Down Expand Up @@ -253,6 +254,21 @@ def _create_intrusion_set_from_actor_entity(
)
)

# Labels: raw CrowdStrike motivation values and actor_type
labels: list[str] = []
for mot in motivations_raw:
if isinstance(mot, Mapping):
val = str(mot.get("value") or mot.get("slug") or "").strip()
else:
val = str(mot).strip()
if val:
labels.append(val)
actor_type = actor.get("actor_type")
if actor_type:
actor_type_str = str(actor_type).strip()
if actor_type_str:
labels.append(actor_type_str)

Comment on lines +256 to +271
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The label-extraction logic here duplicates the new _get_labels() logic in actor/builder.py (motivation value/slug normalization + actor_type). Consider centralizing this into a shared helper (e.g., in crowdstrike_feeds_services.utils) to avoid diverging behavior between the two builders over time.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need Product/Integration input on how the team wants to handle this.
@Kakudou
@Ninoxe
@helene-nguyen

return create_intrusion_set(
name,
created_by=created_by,
Expand All @@ -263,6 +279,7 @@ def _create_intrusion_set_from_actor_entity(
goals=goals or None,
primary_motivation=primary_motivation,
secondary_motivations=secondary_motivations or None,
labels=labels or None,
confidence=confidence,
external_references=external_references or None,
object_markings=object_markings,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
from crowdstrike_feeds_services.client.actors import ActorsAPI

if TYPE_CHECKING:
from crowdstrike_feeds_connector import ConnectorSettings
from pycti import OpenCTIConnectorHelper

from crowdstrike_feeds_connector import ConnectorSettings


class RelatedActorImporter:
"""CrowdStrike actor importer."""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,19 @@
from collections.abc import Sequence
from typing import Any, Iterable, Mapping, cast

from stix2 import (
Bundle,
ExternalReference,
Identity,
IntrusionSet,
Location,
Malware,
MarkingDefinition,
Relationship,
)
from stix2 import Report as STIXReport
from stix2.v21 import _DomainObject, _RelationshipObject

from crowdstrike_feeds_connector.related_actors.builder import RelatedActorBundleBuilder
from crowdstrike_feeds_services.utils import (
create_external_reference,
Expand All @@ -18,18 +31,6 @@
normalize_start_time_and_stop_time,
timestamp_to_datetime,
)
from stix2 import (
Bundle,
ExternalReference,
Identity,
IntrusionSet,
Location,
Malware,
MarkingDefinition,
Relationship,
)
from stix2 import Report as STIXReport
from stix2.v21 import _DomainObject, _RelationshipObject

logger = logging.getLogger(__name__)

Expand Down
Loading
Loading