Skip to content

Commit 8ad7f9b

Browse files
author
Kristinn
authored
Added a decorator to quickly register a function as a feature. (#45)
* Added a decorator to quickly register a function as a feature. * Moved feature additions to the lw object to a separate function. * added marker to the pytest ini file. * Added a bit more resilience into the decode accessor. * Fixed error message for decoding base64.
1 parent 922d526 commit 8ad7f9b

File tree

10 files changed

+54
-23
lines changed

10 files changed

+54
-23
lines changed

jupyter/docker/docker_build/10-functions.py

Lines changed: 0 additions & 4 deletions
This file was deleted.

jupyter/laceworkjupyter/__init__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,15 @@ class LaceworkHelper:
130130

131131
def __init__(self):
132132
self.ctx = LaceworkContext()
133+
self.refresh_features()
133134

135+
def refresh_features(self):
136+
"""
137+
Refresh all the features of the helper.
138+
139+
IF a new feature is added this function can be called to refresh
140+
the features that are registered to the helper object.
141+
"""
134142
for feature, feature_name in manager.LaceworkManager.get_features():
135143
feature_fn = decorators.feature_decorator(feature, self.ctx)
136144
setattr(self, feature_name, feature_fn)

jupyter/laceworkjupyter/accessors.py

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,18 @@
66
"""
77

88
import base64
9+
import binascii
10+
import logging
11+
912
import urllib.parse
1013

1114
import pandas as pd
1215

1316

14-
@pd.api.extensions.register_series_accessor('decode')
17+
logger = logging.getLogger("lacework_sdk.jupyter.accessor")
18+
19+
20+
@pd.api.extensions.register_series_accessor("decode")
1521
class DecodeAccessor:
1622
"""
1723
Accessor class for decoding data.
@@ -26,10 +32,18 @@ def _decode_string_base64(self, string_value):
2632
:param str string_value: The base64 decoded string.
2733
:return: A decoded string.
2834
"""
29-
decoded_string = base64.b64decode(string_value)
3035
try:
31-
return decoded_string.decode('utf8')
36+
decoded_string = base64.b64decode(string_value)
37+
except binascii.Error as exc:
38+
logger.error(
39+
"Unable to decode string: '{0:s}', error: {1!s}".format(
40+
string_value, exc)),
41+
return string_value
42+
43+
try:
44+
return decoded_string.decode("utf8")
3245
except UnicodeDecodeError:
46+
logger.warning("Unable to decode string using UTF-8")
3347
return decoded_string
3448

3549
def base64(self):

jupyter/laceworkjupyter/features/client.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from laceworkjupyter import manager
55

66

7+
@manager.register_feature
78
def get_client(
89
api_key=None, api_secret=None, account=None,
910
subaccount=None, instance=None, base_domain=None,
@@ -21,6 +22,3 @@ def get_client(
2122

2223
ctx.set_client(client)
2324
return client
24-
25-
26-
manager.LaceworkManager.add_feature(get_client, 'get_client')

jupyter/laceworkjupyter/features/date.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from laceworkjupyter import utils
66

77

8+
@manager.register_feature
89
def parse_date_offset(offset_string, ctx=None):
910
"""
1011
Parse date offset string and return a start and end time.
@@ -18,6 +19,3 @@ def parse_date_offset(offset_string, ctx=None):
1819
ctx.add("start_time", start_time)
1920
ctx.add("end_time", end_time)
2021
return start_time, end_time
21-
22-
23-
manager.LaceworkManager.add_feature(parse_date_offset, "parse_date_offset")

jupyter/laceworkjupyter/features/hunt.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,7 @@ def _execute_query(button):
247247
f"'<b><i>lw.ctx.get(\"lql_results\")</i></b>'")
248248

249249

250+
@manager.register_feature
250251
def cloud_hunt(ctx=None):
251252
"""
252253
Displays a UI to build LQL queries to do threat hunting.
@@ -342,6 +343,3 @@ def cloud_hunt(ctx=None):
342343
lw_ctx = ctx
343344

344345
display(grid) # noqa: F821
345-
346-
347-
manager.LaceworkManager.add_feature(cloud_hunt, "cloud_hunt")

jupyter/laceworkjupyter/features/policies.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
logger = logging.getLogger("lacework_sdk.jupyter.feature.policies")
1313

1414

15+
@manager.register_feature
1516
def list_available_queries(ctx=None):
1617
"""
1718
Returns a DataFrame with the available LQL queries.
@@ -21,6 +22,7 @@ def list_available_queries(ctx=None):
2122
return ctx.client.queries.get()
2223

2324

25+
@manager.register_feature
2426
def query_stored_lql(query_id, start_time="", end_time="", ctx=None):
2527
"""
2628
Returns the results from running a LQL query.
@@ -58,8 +60,3 @@ def query_stored_lql(query_id, start_time="", end_time="", ctx=None):
5860

5961
return client.queries.execute_by_id(
6062
query_id=query_id, arguments=arguments)
61-
62-
63-
manager.LaceworkManager.add_feature(
64-
list_available_queries, "list_available_queries")
65-
manager.LaceworkManager.add_feature(query_stored_lql, "query_stored_lql")

jupyter/laceworkjupyter/manager.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,19 @@ def get_features(cls):
3939
"""
4040
for feature_fn, feature_name in cls._features.items():
4141
yield (feature_name, feature_fn)
42+
43+
44+
def register_feature(fn, name=""):
45+
"""
46+
Decorator that can be used to register a feature.
47+
48+
:param function fn: The function to register.
49+
:param str name: Optional string with the name of the function
50+
as it should be registered. If not provided the name of the
51+
function is used.
52+
"""
53+
if not name:
54+
name = fn.__name__
55+
56+
LaceworkManager.add_feature(fn, name)
57+
return fn

jupyter/tests/laceworkjupyter/test_accessors.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,13 @@ def test_decode_accessor():
1111
Tests the decode accessor.
1212
"""
1313
lines = [
14-
{'value': 12, 'some_string': 'VGhpcyBpcyBhIHN0cmluZw==', 'uri': 'http://mbl.is/%3Fstuff=r+1%20af'},
15-
{'value': 114, 'some_string': 'VGhpcyBpcyBhIGEgc2VjcmV0', 'uri': 'http://mbl.is/%3Fsfi=r+1%20af'},
14+
{
15+
'value': 12, 'some_string': 'VGhpcyBpcyBhIHN0cmluZw==',
16+
'uri': 'http://mbl.is/%3Fstuff=r+1%20af'
17+
}, {
18+
'value': 114, 'some_string': 'VGhpcyBpcyBhIGEgc2VjcmV0',
19+
'uri': 'http://mbl.is/%3Fsfi=r+1%20af'
20+
},
1621
]
1722
frame = pd.DataFrame(lines)
1823

pytest.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
[pytest]
22
markers =
33
ci_exempt: mark a test as exempt from CI.
4+
flaky_test: mark a test as potentially flaky.
45

56
addopts =
67
--ignore=tests/api/v2/test_policies.py

0 commit comments

Comments
 (0)