Skip to content

Commit 8eeb54a

Browse files
committed
Updated init files and created legacy mapping
1 parent 23aabf3 commit 8eeb54a

4 files changed

Lines changed: 125 additions & 8 deletions

File tree

src/attackcti/__init__.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"""attackcti package.
22
33
This package exposes a small, stable public surface:
4-
- `AttackClient`: main client class
4+
- `MitreAttackClient`: main client class
55
- `attack_client`: backwards-compatible alias
66
"""
77

@@ -18,13 +18,13 @@
1818
__version__ = "0.0.0"
1919

2020
if TYPE_CHECKING: # pragma: no cover
21-
from .client import AttackClient as AttackClient
21+
from .client import MitreAttackClient as AttackClient
2222

2323

2424
def __getattr__(name: str) -> Any: # PEP 562
2525
"""Lazily expose selected public symbols."""
26-
if name in {"AttackClient", "attack_client"}:
27-
from .client import AttackClient
26+
if name in {"MitreAttackClient", "attack_client"}:
27+
from .client import MitreAttackClient
2828

29-
return AttackClient
29+
return MitreAttackClient
3030
raise AttributeError(name)

src/attackcti/__main__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1+
"""`python -m attackcti` entrypoint."""
2+
13
from .cli import main
24

35
if __name__ == "__main__":
46
raise SystemExit(main())
5-

src/attackcti/attack_api.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"""Backwards-compatible module."""
22

3-
from .client import AttackClient, AttackClient as attack_client # noqa: F401
3+
from .client import MitreAttackClient
4+
from .client import MitreAttackClient as attack_client
45

5-
__all__ = ["AttackClient", "attack_client"]
6+
__all__ = ["MitreAttackClient", "attack_client"]

src/attackcti/legacy.py

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
"""Attach legacy `MitreAttackClient.get_*` methods.
2+
3+
The modern API is exposed via sub-clients (composition), e.g.:
4+
- `client.enterprise.get_techniques()`
5+
- `client.relationships.get_software_used_by_group()`
6+
7+
For backwards compatibility, this module installs `MitreAttackClient.get_*` methods which delegate to
8+
the appropriate sub-client methods.
9+
"""
10+
11+
from __future__ import annotations
12+
13+
from typing import Any, Callable, Dict, Tuple
14+
15+
LegacyTarget = Tuple[str, str]
16+
17+
18+
LEGACY_METHODS: Dict[str, LegacyTarget] = {
19+
# Query (cross-domain)
20+
"get_attack": ("query", "get_attack"),
21+
"get_campaigns": ("query.campaigns", "get_campaigns"),
22+
"get_techniques": ("query.techniques", "get_techniques"),
23+
"get_groups": ("query.groups", "get_groups"),
24+
"get_mitigations": ("query.mitigations", "get_mitigations"),
25+
"get_data_components": ("query.data_sources", "get_data_components"),
26+
"get_software": ("query.software", "get_software"),
27+
"get_relationships": ("query.relationships", "get_relationships"),
28+
"get_tactics": ("query.tactics", "get_tactics"),
29+
"get_data_sources": ("query.data_sources", "get_data_sources"),
30+
"get_technique_by_name": ("query.techniques", "get_technique_by_name"),
31+
"get_techniques_by_content": ("query.techniques", "get_techniques_by_content"),
32+
"get_techniques_by_platform": ("query.techniques", "get_techniques_by_platform"),
33+
"get_techniques_by_tactic": ("query.techniques", "get_techniques_by_tactic"),
34+
"get_object_by_attack_id": ("query", "get_object_by_attack_id"),
35+
"get_campaign_by_alias": ("query.campaigns", "get_campaign_by_alias"),
36+
"get_group_by_alias": ("query.groups", "get_group_by_alias"),
37+
"get_campaigns_since_time": ("query.campaigns", "get_campaigns_since_time"),
38+
"get_techniques_since_time": ("query.techniques", "get_techniques_since_time"),
39+
# Enterprise domain
40+
"get_enterprise": ("enterprise", "get"),
41+
"get_enterprise_campaigns": ("enterprise", "get_campaigns"),
42+
"get_enterprise_techniques": ("enterprise", "get_techniques"),
43+
"get_enterprise_data_components": ("enterprise", "get_data_components"),
44+
"get_enterprise_mitigations": ("enterprise", "get_mitigations"),
45+
"get_enterprise_groups": ("enterprise", "get_groups"),
46+
"get_enterprise_malware": ("enterprise", "get_malware"),
47+
"get_enterprise_tools": ("enterprise", "get_tools"),
48+
"get_enterprise_relationships": ("enterprise", "get_relationships"),
49+
"get_enterprise_tactics": ("enterprise", "get_tactics"),
50+
"get_enterprise_data_sources": ("enterprise", "get_data_sources"),
51+
# Mobile domain
52+
"get_mobile": ("mobile", "get"),
53+
"get_mobile_campaigns": ("mobile", "get_campaigns"),
54+
"get_mobile_techniques": ("mobile", "get_techniques"),
55+
"get_mobile_data_components": ("mobile", "get_data_components"),
56+
"get_mobile_mitigations": ("mobile", "get_mitigations"),
57+
"get_mobile_groups": ("mobile", "get_groups"),
58+
"get_mobile_malware": ("mobile", "get_malware"),
59+
"get_mobile_tools": ("mobile", "get_tools"),
60+
"get_mobile_relationships": ("mobile", "get_relationships"),
61+
"get_mobile_tactics": ("mobile", "get_tactics"),
62+
"get_mobile_data_sources": ("mobile", "get_data_sources"),
63+
# ICS domain
64+
"get_ics": ("ics", "get"),
65+
"get_ics_campaigns": ("ics", "get_campaigns"),
66+
"get_ics_techniques": ("ics", "get_techniques"),
67+
"get_ics_data_components": ("ics", "get_data_components"),
68+
"get_ics_mitigations": ("ics", "get_mitigations"),
69+
"get_ics_groups": ("ics", "get_groups"),
70+
"get_ics_malware": ("ics", "get_malware"),
71+
"get_ics_tools": ("ics", "get_tools"),
72+
"get_ics_relationships": ("ics", "get_relationships"),
73+
"get_ics_tactics": ("ics", "get_tactics"),
74+
"get_ics_data_sources": ("ics", "get_data_sources"),
75+
# Detections
76+
"get_detection_strategies": ("query.detections", "get_detection_strategies"),
77+
"get_analytics": ("query.detections", "get_analytics"),
78+
"get_detection_strategies_by_technique": ("query.detections", "get_detection_strategies_by_technique"),
79+
"get_analytics_by_technique": ("query.detections", "get_analytics_by_technique"),
80+
"get_log_source_references_by_technique": ("query.detections", "get_log_source_references_by_technique"),
81+
"get_data_components_by_technique_via_analytics": ("query.detections", "get_data_components_by_technique_via_analytics"),
82+
# Relationships
83+
"get_relationships_by_object": ("query.relationships", "get_relationships_by_object"),
84+
"get_techniques_by_relationship": ("query.relationships", "get_techniques_by_relationship"),
85+
"get_techniques_used_by_group": ("query.relationships", "get_techniques_used_by_group"),
86+
"get_techniques_used_by_all_groups": ("query.relationships", "get_techniques_used_by_all_groups"),
87+
"get_software_used_by_group": ("query.relationships", "get_software_used_by_group"),
88+
"get_techniques_used_by_software": ("query.relationships", "get_techniques_used_by_software"),
89+
"get_techniques_used_by_group_software": ("query.relationships", "get_techniques_used_by_group_software"),
90+
"get_techniques_mitigated_by_mitigations": ("query.relationships", "get_techniques_mitigated_by_mitigations"),
91+
"get_data_components_by_technique": ("query.detections", "get_data_components_by_technique_via_analytics"),
92+
"export_groups_navigator_layers": ("query.relationships", "export_groups_navigator_layers"),
93+
}
94+
95+
96+
def _make_delegator(property_name: str, method_name: str, legacy_name: str) -> Callable[..., Any]:
97+
def delegator(self: Any, *args: Any, **kwargs: Any) -> Any:
98+
target = self
99+
for attr in property_name.split("."):
100+
target = getattr(target, attr)
101+
method = getattr(target, method_name)
102+
return method(*args, **kwargs)
103+
104+
delegator.__name__ = legacy_name
105+
delegator.__qualname__ = legacy_name
106+
delegator.__doc__ = f"Legacy alias for `{property_name}.{method_name}()`."
107+
return delegator
108+
109+
110+
def attach_legacy_methods(client_cls: type) -> None:
111+
"""Attach legacy methods to the given MitreAttackClient class."""
112+
for legacy_name, (property_name, method_name) in LEGACY_METHODS.items():
113+
if hasattr(client_cls, legacy_name):
114+
continue
115+
setattr(client_cls, legacy_name, _make_delegator(property_name, method_name, legacy_name))

0 commit comments

Comments
 (0)