Skip to content

Commit c2f2903

Browse files
authored
Misc build and linter fixes (#44)
* Replaced reference to pywhois with msticpy whois - i url_summary.py Fixed creation of process tree - ensuring Rarity column remains numeric in logon_session_rarity.py Fixes in ti.py for potentially unitialized variables. Fixed missing respx mocked URLs in test_ip_summary.py * Updating requirements.txt to align with msticpy * Mypy and pylint fixes
1 parent a1bb25a commit c2f2903

17 files changed

+99
-67
lines changed

.pre-commit-config.yaml

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,33 +7,24 @@ repos:
77
- id: trailing-whitespace
88
args: [--markdown-linebreak-ext=md]
99
- repo: https://github.com/ambv/black
10-
rev: 22.1.0
10+
rev: 24.4.2
1111
hooks:
1212
- id: black
1313
language: python
1414
args:
1515
- -t
1616
- py36
17-
- repo: https://github.com/PyCQA/pylint
18-
rev: v2.12.2
19-
hooks:
20-
- id: pylint
21-
args:
22-
- --disable=E0401,W0511,duplicate-code
23-
- --ignore-patterns=test_
24-
- repo: https://gitlab.com/pycqa/flake8
25-
rev: 3.9.2
26-
hooks:
27-
- id: flake8
28-
args:
29-
- --extend-ignore=E0401,E501,W503
30-
- --max-line-length=90
31-
- --exclude=tests,test*.py
3217
- repo: https://github.com/pycqa/isort
33-
rev: 5.10.1
18+
rev: 5.12.0
3419
hooks:
3520
- id: isort
3621
name: isort (python)
3722
args:
3823
- --profile
39-
- black
24+
- black
25+
- repo: https://github.com/astral-sh/ruff-pre-commit
26+
# Ruff version.
27+
rev: v0.4.5
28+
hooks:
29+
# Run the linter.
30+
- id: ruff

msticnb/nb/azsent/account/account_summary.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -142,17 +142,17 @@ def __init__(
142142
self.description: str = "Account Activity Summary"
143143
self.account_entity: entities.Account = None
144144
self.account_activity: Optional[pd.DataFrame] = None
145-
self.account_selector: nbwidgets.SelectItem = None
145+
self.account_selector: Optional[nbwidgets.SelectItem] = None
146146
self.related_alerts: Optional[pd.DataFrame] = None
147-
self.alert_timeline: LayoutDOM = None
147+
self.alert_timeline: Optional[LayoutDOM] = None
148148
self.related_bookmarks: Optional[pd.DataFrame] = None
149149
self.host_logons: Optional[pd.DataFrame] = None
150150
self.host_logon_summary: Optional[pd.DataFrame] = None
151151
self.azure_activity: Optional[pd.DataFrame] = None
152152
self.azure_activity_summary: Optional[pd.DataFrame] = None
153-
self.azure_timeline_by_provider: LayoutDOM = None
154-
self.account_timeline_by_ip: LayoutDOM = None
155-
self.azure_timeline_by_operation: LayoutDOM = None
153+
self.azure_timeline_by_provider: Optional[LayoutDOM] = None
154+
self.account_timeline_by_ip: Optional[LayoutDOM] = None
155+
self.azure_timeline_by_operation: Optional[LayoutDOM] = None
156156
self.ip_summary: Optional[pd.DataFrame] = None
157157
self.ip_all_data: Optional[pd.DataFrame] = None
158158

msticnb/nb/azsent/host/host_logons_summary.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -107,9 +107,9 @@ class HostLogonsSummary(Notebooklet): # pylint: disable=too-few-public-methods
107107

108108
metadata = _CLS_METADATA
109109

110-
@set_text(docs=_CELL_DOCS, key="run") # noqa: MC0001
110+
@set_text(docs=_CELL_DOCS, key="run") # noqa: MC0001, C901
111111
# pylint: disable=too-many-locals, too-many-branches, too-many-statements
112-
def run( # noqa:MC0001
112+
def run( # noqa:MC0001, C901
113113
self,
114114
value: Any = None,
115115
data: Optional[pd.DataFrame] = None,
@@ -380,13 +380,13 @@ def _process_stack_bar(data: pd.DataFrame, silent: bool) -> figure:
380380
legend_label=results,
381381
)
382382

383-
viz.y_range.start = 0
383+
viz.y_range.start = 0 # type: ignore[attr-defined]
384384
viz.x_range.range_padding = 0.1 # type: ignore[attr-defined]
385385
viz.xgrid.grid_line_color = None # type: ignore[attr-defined]
386386
viz.axis.minor_tick_line_color = None
387387
viz.yaxis.axis_label = "% of logons"
388388
viz.xaxis.axis_label = "Process name" # type: ignore[assignment]
389-
viz.outline_line_color = None
389+
viz.outline_line_color = None # type: ignore[assignment]
390390
viz.legend.location = "top_left"
391391
viz.legend.orientation = "horizontal"
392392

msticnb/nb/azsent/host/host_network_summary.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ def __init__(self, *args, **kwargs):
8686

8787
# pylint: disable=too-many-branches
8888
@set_text(docs=_CELL_DOCS, key="run") # noqa: MC0001
89-
def run( # noqa:MC0001
89+
def run( # noqa:MC0001, C901
9090
self,
9191
value: Any = None,
9292
data: Optional[pd.DataFrame] = None,
@@ -163,6 +163,10 @@ def run( # noqa:MC0001
163163
qry_prov=self.query_provider,
164164
timespan=self.timespan,
165165
)
166+
if result.flows is None:
167+
nb_markdown("No network flow data found.")
168+
self._last_result = result
169+
return self._last_result
166170

167171
remote_ip_col = "RemoteIP"
168172
local_ip_col = "LocalIP"
@@ -239,7 +243,7 @@ def _display_results(self):
239243

240244

241245
@lru_cache()
242-
def _get_host_flows(host_name, ip_addr, qry_prov, timespan) -> pd.DataFrame:
246+
def _get_host_flows(host_name, ip_addr, qry_prov, timespan) -> Optional[pd.DataFrame]:
243247
if host_name:
244248
nb_data_wait("Host flow events")
245249
host_flows = qry_prov.MDE.host_connections(timespan, host_name=host_name)
@@ -254,6 +258,8 @@ def _get_host_flows(host_name, ip_addr, qry_prov, timespan) -> pd.DataFrame:
254258
host_flows_csl = qry_prov.Network.ip_network_connections_csl(
255259
timespan, ip=ip_addr
256260
)
261+
else:
262+
return None
257263
return pd.concat([host_flows, host_flows_csl], sort=False)
258264

259265

msticnb/nb/azsent/host/host_summary.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ def __init__(self, *args, **kwargs):
124124
super().__init__(*args, **kwargs)
125125

126126
# pylint: disable=too-many-branches, too-many-statements
127-
def run( # noqa:MC0001
127+
def run( # noqa:MC0001, C901
128128
self,
129129
value: Any = None,
130130
data: Optional[pd.DataFrame] = None,

msticnb/nb/azsent/host/logon_session_rarity.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
from msticpy.analysis.eventcluster import char_ord_score, dbcluster_events, delim_count
1111
from msticpy.common.timespan import TimeSpan
1212

13+
# pylint: disable=unused-import
14+
from msticpy.init import mp_pandas_accessors # noqa: F401
15+
1316
try:
1417
from msticpy import nbwidgets
1518

@@ -252,13 +255,21 @@ def process_tree(
252255
acct_col = self.column_map.get(COL_ACCT)
253256
data = self._last_result.processes_with_cluster
254257
data = data[data[acct_col] == account]
255-
data.mp_plot.process_tree(legend_col="Rarity")
258+
proc_tree_data = data.mp.build_process_tree()
259+
proc_tree_data["Rarity"] = pd.to_numeric(
260+
proc_tree_data["Rarity"], errors="coerce"
261+
).fillna(0)
262+
proc_tree_data.mp_plot.process_tree(legend_col="Rarity")
256263
return
257264
session = session or self._event_browser.value
258265
sess_col = self.column_map.get(COL_SESS)
259266
data = self._last_result.processes_with_cluster
260267
data = data[data[sess_col] == session]
261-
data.mp_plot.process_tree(legend_col="Rarity")
268+
proc_tree_data = data.mp.build_process_tree()
269+
proc_tree_data["Rarity"] = pd.to_numeric(
270+
proc_tree_data["Rarity"], errors="coerce"
271+
).fillna(0)
272+
proc_tree_data.mp_plot.process_tree(legend_col="Rarity")
262273

263274
def browse_events(self):
264275
"""Browse the events by logon session."""

msticnb/nb/azsent/network/ip_summary.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ class IpAddressSummary(Notebooklet):
209209

210210
# pylint: disable=too-many-branches, too-many-statements
211211
@set_text(docs=_CELL_DOCS, key="run") # noqa: MC0001
212-
def run( # noqa: MC0001
212+
def run( # noqa: MC0001,C901
213213
self,
214214
value: Any = None,
215215
data: Optional[pd.DataFrame] = None,

msticnb/nb/azsent/network/network_flow_summary.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ def __init__(self, data_providers: Optional[DataProviders] = None, **kwargs):
166166

167167
# pylint: disable=too-many-branches
168168
@set_text(docs=_CELL_DOCS, key="run") # noqa: MC0001
169-
def run( # noqa: MC0001
169+
def run( # noqa: MC0001, C901
170170
self,
171171
value: Any = None,
172172
data: Optional[pd.DataFrame] = None,

msticnb/nb/azsent/url/url_summary.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,16 @@
1313
import pandas as pd
1414
import tldextract
1515
from IPython.display import Image, display
16-
from whois import whois # type: ignore
1716

1817
# pylint: disable=ungrouped-imports
1918
try:
2019
from msticpy import nbwidgets
2120
from msticpy.context.domain_utils import DomainValidator, screenshot
21+
from msticpy.context.ip_utils import ip_whois as whois
2222
from msticpy.vis.timeline import display_timeline, display_timeline_values
2323
except ImportError:
2424
# Fall back to msticpy locations prior to v2.0.0
25+
from whois import whois # type: ignore
2526
from msticpy.sectools.domain_utils import DomainValidator, screenshot
2627
from msticpy.nbtools import nbwidgets
2728
from msticpy.nbtools.nbdisplay import display_timeline, display_timeline_values
@@ -95,7 +96,7 @@ class URLSummary(Notebooklet):
9596

9697
# pylint: disable=too-many-branches, too-many-locals, too-many-statements
9798
@set_text(docs=_CELL_DOCS, key="run") # noqa: MC0001
98-
def run( # noqa:MC0001
99+
def run( # noqa:MC0001, C901
99100
self,
100101
value: Any = None,
101102
data: Optional[pd.DataFrame] = None,
@@ -161,6 +162,7 @@ def run( # noqa:MC0001
161162
self._last_result = result
162163

163164
self.url = value.strip().lower()
165+
164166
_, domain, tld = cast(Tuple[Any, str, str], tldextract.extract(self.url)) # type: ignore
165167
domain = f"{domain.lower()}.{tld.lower()}"
166168
domain_validator = DomainValidator()

msticnb/nblib/azsent/host.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ def get_aznet_topology(
102102

103103

104104
@lru_cache() # noqa:MC0001
105-
def verify_host_name( # noqa: MC0001
105+
def verify_host_name( # noqa: MC0001, C901
106106
qry_prov: QueryProvider, host_name: str, timespan: TimeSpan = None, **kwargs
107107
) -> HostNameVerif:
108108
"""

msticnb/nblib/ti.py

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
# license information.
55
# --------------------------------------------------------------------------
66
"""Threat Intelligence notebooklet feature support."""
7-
from typing import Any, Tuple, Optional
7+
from typing import Any, Optional, Tuple
88

99
import numpy as np
1010
import pandas as pd
@@ -81,36 +81,36 @@ def extract_iocs(
8181
)
8282
b64_iocs = b64_extracted.mp_ioc.extract(columns=["decoded_string"])
8383
b64_iocs["SourceIndex"] = pd.to_numeric(b64_iocs["SourceIndex"])
84-
data_b64_iocs = pd.merge(
84+
data = pd.merge(
8585
left=data,
8686
right=b64_iocs,
8787
how="outer",
8888
left_index=True,
8989
right_on="SourceIndex",
9090
)
91-
else:
92-
data_b64_iocs = data
93-
other_iocs = data_b64_iocs.mp_ioc.extract(columns=[col])
94-
all_data_w_iocs = pd.merge(
95-
left=data_b64_iocs,
96-
right=other_iocs,
91+
92+
iocs = data.mp_ioc.extract(columns=[col])
93+
data = pd.merge(
94+
left=data,
95+
right=iocs,
9796
how="outer",
9897
left_index=True,
9998
right_on="SourceIndex",
10099
)
101-
if "Observable_x" in all_data_w_iocs.columns:
102-
all_data_w_iocs["IoC"] = np.where(
103-
all_data_w_iocs["Observable_x"].isna(),
104-
all_data_w_iocs["Observable_y"],
105-
all_data_w_iocs["Observable_x"],
100+
101+
if "Observable_x" in data.columns:
102+
data["IoC"] = np.where(
103+
data["Observable_x"].isna(),
104+
data["Observable_y"],
105+
data["Observable_x"],
106106
)
107-
all_data_w_iocs["IoCType"] = np.where(
108-
all_data_w_iocs["IoCType_x"].isna(),
109-
all_data_w_iocs["IoCType_y"],
110-
all_data_w_iocs["IoCType_x"],
107+
data["IoCType"] = np.where(
108+
data["IoCType_x"].isna(),
109+
data["IoCType_y"],
110+
data["IoCType_x"],
111111
)
112-
all_data_w_iocs["IoC"] = all_data_w_iocs["IoC"].astype("str")
112+
data["IoC"] = data["IoC"].astype("str")
113113
else:
114-
all_data_w_iocs["IoC"] = all_data_w_iocs["Observable"].astype("str")
115-
all_data_w_iocs["IoCType"] = all_data_w_iocs["IoCType"].astype("str")
116-
return all_data_w_iocs
114+
data["IoC"] = data["Observable"].astype("str")
115+
data["IoCType"] = data["IoCType"].astype("str")
116+
return data

msticnb/notebooklet.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
import warnings
1010
from abc import ABC, abstractmethod
1111
from functools import wraps
12-
from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple
12+
from pathlib import Path
13+
from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple, Union
1314

1415
import pandas as pd
1516
from IPython.core.getipython import get_ipython
@@ -35,7 +36,7 @@ class Notebooklet(ABC):
3536
metadata: NBMetadata = NBMetadata(
3637
name="Notebooklet", description="Base class", default_options=[]
3738
)
38-
module_path = ""
39+
module_path: Union[str, Path] = ""
3940

4041
def __init__(self, data_providers: Optional[DataProviders] = None, **kwargs):
4142
"""

msticnb/read_modules.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from functools import partial
1212
from operator import itemgetter
1313
from pathlib import Path
14-
from typing import Dict, Iterable, List, Tuple, Union
14+
from typing import Dict, Iterable, List, Tuple, Type, Union
1515
from warnings import warn
1616

1717
from . import nb
@@ -24,8 +24,7 @@
2424
__author__ = "Ian Hellen"
2525

2626
nblts: NBContainer = NBContainer()
27-
# index of notebooklets classes by full path
28-
nb_index: Dict[str, type] = {}
27+
nb_index: Dict[str, Type[Notebooklet]] = {}
2928

3029

3130
def discover_modules(nb_path: Union[str, Iterable[str], None] = None) -> NBContainer:
@@ -97,7 +96,7 @@ def _import_from_folder(nb_folder: Path, pkg_folder: Path):
9796
nb_index[cls_index] = nb_class
9897

9998

100-
def _find_cls_modules(folder: Path, pkg_folder: Path) -> Dict[str, type]:
99+
def _find_cls_modules(folder: Path, pkg_folder: Path) -> Dict[str, Type[Notebooklet]]:
101100
"""
102101
Import .py files in `folder` and return any Notebooklet classes found.
103102

pyproject.toml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
[build-system]
2+
requires = [
3+
"setuptools>=42",
4+
"wheel"
5+
]
6+
build-backend = "setuptools.build_meta"
7+
8+
[tool.isort]
9+
profile = "black"
10+
src_paths = ["msticnb", "tests"]
11+
12+
[tool.pydocstyle]
13+
convention = "numpy"
14+
15+
[tool.ruff.lint]
16+
# Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`) codes by default.
17+
# Unlike Flake8, Ruff doesn't enable pycodestyle warnings (`W`) or
18+
# McCabe complexity (`C901`) by default.
19+
select = ["E4", "E7", "E9", "F", "W", "D", "C"]
20+
ignore = ["D212", "D417", "D203"]

requirements.txt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
bokeh<3.0.0
1+
bokeh>=1.4.0, <3.4.0
22
defusedxml>=0.6.0
33
ipython>=7.23.1
44
ipywidgets>=7.5.1
@@ -9,5 +9,4 @@ numpy>=1.17.3
99
pandas>=0.25.3
1010
python-dateutil>=2.8.1
1111
tqdm>=4.41.1
12-
python-whois>=0.7.3
1312
tldextract>=3.3.0

tests/nb/azsent/host/test_hostlogonsummary.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
from msticpy.vis.foliummap import FoliumMap
1919
except ImportError:
2020
# Fall back to msticpy locations prior to v2.0.0
21-
from msticpy.nbtools.foliummap import FoliumMap
21+
from msticpy.nbtools.foliummap import FoliumMap # noqa: F401
2222

2323
from msticnb import data_providers, discover_modules, nblts
2424

0 commit comments

Comments
 (0)