Skip to content

Commit e5a4f61

Browse files
authored
Updates for msticpy compatibility (#46)
* Updates for msticpy compatibility Fixing data_providers to check for required parameter before creating class ip_summary - handle either dataclass or tuple representation of whois result ti.py - TI call using ioc_col instead of deprecated obs_col minor updates to unit tests. * Updating version to 1.2.2 * Fixing call to data providers and pandas compat
1 parent c7b5b91 commit e5a4f61

File tree

8 files changed

+109
-40
lines changed

8 files changed

+109
-40
lines changed

msticnb/_version.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
"""Version file."""
2-
VERSION = "1.2.1"
2+
3+
VERSION = "1.2.2"

msticnb/data_providers.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
# --------------------------------------------------------------------------
66
"""Data Providers class and init function."""
77
import inspect
8+
import logging
89
import sys
910
from collections import namedtuple
1011
from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple, Union
@@ -351,7 +352,16 @@ def _query_prov(self, provider: str, provider_defn: ProviderDefn, **kwargs) -> A
351352
prov_kwargs_args = self._get_provider_kwargs(provider, **kwargs)
352353

353354
# instantiate the provider class (sending all kwargs)
354-
created_provider = provider_defn.prov_class(provider, **prov_kwargs_args)
355+
provider_class = provider_defn.prov_class
356+
if (
357+
"data_environment"
358+
in inspect.signature(provider_class.__init__).parameters
359+
):
360+
prov_kwargs_args = {"data_environment": provider, **prov_kwargs_args}
361+
logging.info(
362+
"Creating provider %s with args %s", provider, prov_kwargs_args
363+
)
364+
created_provider = provider_defn.prov_class(**prov_kwargs_args)
355365
if created_provider.connected:
356366
return created_provider
357367
# get the args required by connect function

msticnb/nb/azsent/host/win_host_events.py

Lines changed: 64 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -281,17 +281,39 @@ def _get_win_security_events(qry_prov, host_name, timespan):
281281

282282
@set_text(docs=_CELL_DOCS, key="display_event_pivot")
283283
def _display_event_pivot(event_pivot):
284-
display(
285-
event_pivot.style.map(lambda x: "color: white" if x == 0 else "")
286-
.map(
287-
lambda x: "background-color: lightblue"
288-
if not isinstance(x, str) and x > 0
289-
else ""
284+
if pd.__version__ < "2.1.0":
285+
styled_data = (
286+
event_pivot.style.applymap(lambda x: "color: white" if x == 0 else "")
287+
.applymap(
288+
lambda x: (
289+
"background-color: lightblue"
290+
if not isinstance(x, str) and x > 0
291+
else ""
292+
)
293+
)
294+
.set_properties(
295+
subset=["Activity"], **{"width": "400px", "text-align": "left"}
296+
)
297+
.highlight_max(axis=1)
298+
.hide(axis="index")
290299
)
291-
.set_properties(subset=["Activity"], **{"width": "400px", "text-align": "left"})
292-
.highlight_max(axis=1)
293-
.hide(axis="index")
294-
)
300+
else:
301+
styled_data = (
302+
event_pivot.style.map(lambda x: "color: white" if x == 0 else "")
303+
.map(
304+
lambda x: (
305+
"background-color: lightblue"
306+
if not isinstance(x, str) and x > 0
307+
else ""
308+
)
309+
)
310+
.set_properties(
311+
subset=["Activity"], **{"width": "400px", "text-align": "left"}
312+
)
313+
.highlight_max(axis=1)
314+
.hide(axis="index")
315+
)
316+
display(styled_data)
295317

296318

297319
# %%
@@ -408,17 +430,39 @@ def _create_acct_event_pivot(account_event_data):
408430

409431
@set_text(docs=_CELL_DOCS, key="display_acct_event_pivot")
410432
def _display_acct_event_pivot(event_pivot_df):
411-
display(
412-
event_pivot_df.style.map(lambda x: "color: white" if x == 0 else "")
413-
.map(
414-
lambda x: "background-color: lightblue"
415-
if not isinstance(x, str) and x > 0
416-
else ""
433+
if pd.__version__ < "2.1.0":
434+
styled_data = (
435+
event_pivot_df.style.applymap(lambda x: "color: white" if x == 0 else "")
436+
.applymap(
437+
lambda x: (
438+
"background-color: lightblue"
439+
if not isinstance(x, str) and x > 0
440+
else ""
441+
)
442+
)
443+
.set_properties(
444+
subset=["Activity"], **{"width": "400px", "text-align": "left"}
445+
)
446+
.highlight_max(axis=1)
447+
.hide(axis="index")
417448
)
418-
.set_properties(subset=["Activity"], **{"width": "400px", "text-align": "left"})
419-
.highlight_max(axis=1)
420-
.hide(axis="index")
421-
)
449+
else:
450+
styled_data = (
451+
event_pivot_df.style.map(lambda x: "color: white" if x == 0 else "")
452+
.map(
453+
lambda x: (
454+
"background-color: lightblue"
455+
if not isinstance(x, str) and x > 0
456+
else ""
457+
)
458+
)
459+
.set_properties(
460+
subset=["Activity"], **{"width": "400px", "text-align": "left"}
461+
)
462+
.highlight_max(axis=1)
463+
.hide(axis="index")
464+
)
465+
display(styled_data)
422466

423467

424468
@set_text(docs=_CELL_DOCS, key="display_acct_mgmt_timeline")

msticnb/nb/azsent/network/ip_summary.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -963,7 +963,11 @@ def _populate_host_entity(result, geo_lookup=None):
963963
# Public IP functions
964964
def _get_whois(src_ip, result):
965965
"""Get WhoIs data and split out networks."""
966-
_, whois_dict = get_whois_info(src_ip)
966+
whois_result = get_whois_info(src_ip)
967+
if hasattr(whois_result, "properties"):
968+
whois_dict = whois_result.properties
969+
else:
970+
whois_dict = whois_result[1]
967971
result.whois = pd.DataFrame(whois_dict)
968972
result.whois_nets = pd.DataFrame(whois_dict.get("nets", []))
969973
if df_has_data(result.whois):

msticnb/nblib/ti.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def get_ti_results(
4242
ti_merged_df = None
4343
iocs = data[col].dropna().unique()
4444
nb_markdown(f"Querying TI for {len(iocs)} indicators...")
45-
ti_results = ti_lookup.lookup_iocs(data=data, obs_col=col)
45+
ti_results = ti_lookup.lookup_iocs(data=data, ioc_col=col)
4646
if isinstance(ti_results, pd.DataFrame) and not ti_results.empty:
4747
ti_results = ti_results[ti_results["Severity"].isin(["warning", "high"])]
4848
ti_merged_df = data.merge(ti_results, how="inner", left_on=col, right_on="Ioc")

tests/nb/azsent/network/test_ip_summary.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ def test_ip_summary_notebooklet(
130130
respx.get(re.compile(r"http://rdap\.arin\.net/.*")).respond(200, json=rdap_response)
131131
respx.get(
132132
re.compile(r"https://otx\.alienvault.*|https://www\.virustotal.*")
133-
).respond(200, json=_OTX_RESP)
133+
).respond(200, json=OTX_RESP)
134134
respx.get(re.compile(r"https://check\.torproject\.org.*")).respond(404)
135135
respx.get(re.compile(r"https://api\.greynoise\.io.*")).respond(404)
136136
respx.get(re.compile(r".*SecOps-Institute/Tor-IP-Addresses.*")).respond(
@@ -230,7 +230,7 @@ def test_ip_summary_notebooklet_all(
230230
respx.get(re.compile(r"http://rdap\.arin\.net/.*")).respond(200, json=rdap_response)
231231
respx.get(
232232
re.compile(r"https://otx\.alienvault.*|https://www\.virustotal.*")
233-
).respond(200, json=_OTX_RESP)
233+
).respond(200, json=OTX_RESP)
234234
respx.get(re.compile(r"https://check\.torproject\.org.*")).respond(404)
235235
respx.get(re.compile(r"https://api\.greynoise\.io.*")).respond(404)
236236
respx.get(re.compile(r".*SecOps-Institute/Tor-IP-Addresses.*")).respond(
@@ -296,7 +296,7 @@ def test_ip_summary_mde_data(
296296
respx.get(re.compile(r"http://rdap\.arin\.net/.*")).respond(200, json=rdap_response)
297297
respx.get(
298298
re.compile(r"https://otx\.alienvault.*|https://www\.virustotal.*")
299-
).respond(200, json=_OTX_RESP)
299+
).respond(200, json=OTX_RESP)
300300
respx.get(re.compile(r"https://check\.torproject\.org.*")).respond(404)
301301
respx.get(re.compile(r"https://api\.greynoise\.io.*")).respond(404)
302302
respx.get(re.compile(r".*SecOps-Institute/Tor-IP-Addresses.*")).respond(
@@ -331,7 +331,7 @@ def test_ip_summary_mde_data(
331331
check.is_instance(result.ti_results, pd.DataFrame)
332332

333333

334-
_OTX_RESP = {
334+
OTX_RESP = {
335335
"ioc_param": "url",
336336
"response": {
337337
"response": "Found stuff",

tests/nb/azsent/network/test_network_flow_summary.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
TILookupMock,
2828
get_test_data_path,
2929
)
30+
from .test_ip_summary import OTX_RESP
3031

3132
# pylint: disable=no-member
3233

@@ -89,6 +90,15 @@ def test_network_flow_summary_notebooklet(
8990
# LocalData_query_paths=[test_data],
9091
# )
9192
respx.get(re.compile(r"http://rdap\.arin\.net/.*")).respond(200, json=rdap_response)
93+
respx.get(
94+
re.compile(r"https://otx\.alienvault.*|https://www\.virustotal.*")
95+
).respond(200, json=OTX_RESP)
96+
respx.get(re.compile(r"https://check\.torproject\.org.*")).respond(404)
97+
respx.get(re.compile(r"https://api\.greynoise\.io.*")).respond(404)
98+
respx.get(re.compile(r".*SecOps-Institute/Tor-IP-Addresses.*")).respond(
99+
200, content=b"12.34.56.78\n12.34.56.78\n12.34.56.78"
100+
)
101+
respx.get(re.compile(r"https://api\.greynoise\.io/.*")).respond(404)
92102

93103
test_nb = nblts.azsent.network.NetworkFlowSummary()
94104
tspan = TimeSpan(period="1D")

tests/unit_test_lib.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -141,24 +141,24 @@ def lookup_ioc(
141141
for i in range(3):
142142
hit = random.randint(1, 10) > 5
143143

144-
result_args = dict(
145-
Provider=f"TIProv-{i}",
146-
Ioc=observable,
147-
IocType=ioc_type,
148-
QuerySubtype="mock",
149-
Result=True,
150-
Severity=2 if hit else 0,
151-
Details=f"Details for {observable}",
152-
RawResult=f"Raw details for {observable}",
153-
)
144+
result_args = {
145+
"Provider": f"TIProv-{i}",
146+
"Ioc": observable,
147+
"IocType": ioc_type,
148+
"QuerySubtype": "mock",
149+
"Result": True,
150+
"Severity": 2 if hit else 0,
151+
"Details": f"Details for {observable}",
152+
"RawResult": f"Raw details for {observable}",
153+
}
154154
if check_mp_version("2.0"):
155155
result_args["sanitized_value"] = observable
156156
else:
157157
result_args["SafeIoC"] = observable
158158
result_list.append(result_args)
159159
return pd.DataFrame(result_list)
160160

161-
def lookup_iocs(self, data, obs_col: Optional[str] = None, **kwargs):
161+
def lookup_iocs(self, data, ioc_col: Optional[str] = None, **kwargs):
162162
"""Lookup fake TI."""
163163
del kwargs
164164
item_result: List[pd.DataFrame] = []
@@ -169,7 +169,7 @@ def lookup_iocs(self, data, obs_col: Optional[str] = None, **kwargs):
169169
)
170170
elif isinstance(data, pd.DataFrame):
171171
item_result.extend(
172-
self.lookup_ioc(observable=row[obs_col]) for row in data.itertuples()
172+
self.lookup_ioc(observable=row[ioc_col]) for row in data.itertuples()
173173
)
174174
elif isinstance(data, list):
175175
item_result.extend(self.lookup_ioc(observable=obs) for obs in data)

0 commit comments

Comments
 (0)