diff --git a/setup.py b/setup.py
index 034c1b7..052b9b3 100755
--- a/setup.py
+++ b/setup.py
@@ -34,7 +34,7 @@ def read(fname):
setup(
name="sublime-cli",
- version="0.0.31",
+ version="0.0.32",
description="Abstraction to interact with the Sublime API.",
url="https://sublimesecurity.com/",
author="Sublime Security",
@@ -56,6 +56,7 @@ def read(fname):
],
entry_points={"console_scripts": ["sublime = sublime.cli:main"]},
zip_safe=False,
- keywords=["security", "phishing", "analysts", "soc", "threat intelligence", "security-automation", "email security"],
+ keywords=["security", "phishing", "analysts", "soc",
+ "threat intelligence", "security-automation", "email security"],
download_url="https://github.com/sublime-security/sublime-cli",
)
diff --git a/src/sublime/__version__.py b/src/sublime/__version__.py
index b938ac7..8c528c8 100644
--- a/src/sublime/__version__.py
+++ b/src/sublime/__version__.py
@@ -5,4 +5,4 @@
__maintainer__ = "Sublime Security"
__email__ = "hi@sublimesecurity.com"
__status__ = "BETA"
-__version__ = "0.0.30"
+__version__ = "0.0.32"
diff --git a/src/sublime/cli/formatter.py b/src/sublime/cli/formatter.py
index c41e0f6..27ff667 100644
--- a/src/sublime/cli/formatter.py
+++ b/src/sublime/cli/formatter.py
@@ -15,7 +15,7 @@
from jinja2 import Environment, PackageLoader
JINJA2_ENV = Environment(loader=PackageLoader("sublime.cli"),
- extensions=['jinja2.ext.loopcontrols'])
+ extensions=['jinja2.ext.loopcontrols'])
colorama.init()
ANSI_MARKUP = ansimarkup.AnsiMarkup(
@@ -60,14 +60,22 @@ def json_formatter(result, verbose=False, indent=4, offset=0):
return string
+def filter_none_recursive(item):
+ """Recursive Filter Out Values"""
+ if isinstance(item, list):
+ return [filter_none_recursive(sub_item) for sub_item in item if sub_item is not None and (not isinstance(sub_item, list) or any(sub_sub_item is not None for sub_sub_item in sub_item))]
+ return item
+
+
@colored_output
def analyze_formatter(results, verbose):
"""Convert Analyze output into human-readable text."""
mql_offset = 3
json_offset = 2
- template_file = "analyze_multi.txt.j2" if len(results) > 1 else "analyze.txt.j2"
+ template_file = "analyze_multi.txt.j2" if len(
+ results) > 1 else "analyze.txt.j2"
template = JINJA2_ENV.get_template(template_file)
-
+
# calculate total stats
sample_result = next(iter(results.values()))
summary_stats = {
@@ -77,7 +85,7 @@ def analyze_formatter(results, verbose):
}
rules = [rule for rule in sample_result['rule_results']]
queries = [query for query in sample_result['query_results']]
-
+
# separate matched/unmatched messages and distinguish flagged/unflagged rules
flagged_messages = []
unflagged_messages = []
@@ -87,9 +95,17 @@ def analyze_formatter(results, verbose):
falsey_queries = []
failed_queries = []
for query in result['query_results']:
- if query['result']:
+ result_value = query.get('result')
+ if isinstance(result_value, list):
+ # Filter out None values from the result array
+ filtered_result = filter_none_recursive(result_value)
+ if filtered_result and any(item is not None for item in filtered_result):
+ query['result'] = filtered_result
+ normal_queries.append(query)
+ elif result_value:
+ # If the result is not a list and exists (is truthy)
normal_queries.append(query)
- elif query['success']:
+ elif query.get('success'):
falsey_queries.append(query)
else:
failed_queries.append(query)
@@ -101,10 +117,12 @@ def analyze_formatter(results, verbose):
unflagged_rules = []
failed_rules = []
for rule in result['rule_results']:
- if rule['result']:
+ if rule.get('matched'):
flagged_rules.append(rule)
- all_flagged_rules.add(rule['name']+rule['source']) # no unique identifier
- elif rule['success']:
+ # no unique identifier
+ all_flagged_rules.add(
+ rule.get("rule").get('name')+rule.get("rule").get('source'))
+ elif rule.get('success'):
unflagged_rules.append(rule)
else:
failed_rules.append(rule)
@@ -116,30 +134,29 @@ def analyze_formatter(results, verbose):
flagged_messages.append(result)
else:
unflagged_messages.append(result)
-
+
# calculate flagged stats
summary_stats['flagged_rules'] = len(all_flagged_rules)
summary_stats['flagged_messages'] = len(flagged_messages)
# format mql and json outputs
- for msg in flagged_messages + unflagged_messages:
+ for msg in flagged_messages + unflagged_messages:
for result in msg['rule_results'] + msg['query_results']:
if 'result' in result and (isinstance(result['result'], dict) or isinstance(result['result'], list)):
result['result'] = json_formatter(
- result['result'],
- offset=json_offset,
- indent=2)
-
+ result['result'],
+ offset=json_offset,
+ indent=2)
# TO DO: sort each list of messages by extension and file name (or directory?)
return template.render(
- stats=summary_stats,
- flagged_messages=flagged_messages,
- unflagged_messages=unflagged_messages,
- rules=rules,
- queries=queries,
- verbose=verbose)
+ stats=summary_stats,
+ flagged_messages=flagged_messages,
+ unflagged_messages=unflagged_messages,
+ rules=rules,
+ queries=queries,
+ verbose=verbose)
def mdm_formatter(results, verbose):
@@ -153,6 +170,7 @@ def mdm_formatter(results, verbose):
# template = JINJA2_ENV.get_template("message_data_model.txt.j2")
# return template.render(results=results, verbose=verbose)
+
@colored_output
def me_formatter(result, verbose):
"""Convert 'me' output into human-readable text."""
@@ -160,6 +178,7 @@ def me_formatter(result, verbose):
return template.render(result=result, verbose=verbose)
+
@colored_output
def feedback_formatter(result, verbose):
"""Convert 'feedback' output into human-readable text."""
diff --git a/src/sublime/cli/templates/analyze.txt.j2 b/src/sublime/cli/templates/analyze.txt.j2
index 519c5dc..19aa26a 100644
--- a/src/sublime/cli/templates/analyze.txt.j2
+++ b/src/sublime/cli/templates/analyze.txt.j2
@@ -33,7 +33,7 @@
{%- set max_elements = 20 %}
{%- set elements_slice = msg.unflagged_rule_results[:max_elements if verbose < 1 else None] %}
{%- for rule in elements_slice %}
- - {{ rule.name }}
+ - {{ rule.rule.name }}
{%- if verbose %}
Source: {{ rule.source }}
{# new line #}
diff --git a/src/sublime/cli/templates/macros.txt.j2 b/src/sublime/cli/templates/macros.txt.j2
index a6e8265..4bf34ea 100644
--- a/src/sublime/cli/templates/macros.txt.j2
+++ b/src/sublime/cli/templates/macros.txt.j2
@@ -3,7 +3,7 @@
{# new line #}
{%- for rule in msg.flagged_rule_results %}
- - {{ rule.name }}
+ - {{ rule.rule.name}}
{%- if verbose %}
Source: {{ rule.source }}
{# new line #}
@@ -16,7 +16,7 @@
{# new line #}
{%- for rule in msg.failed_rule_results %}
- - {{ rule.name }}
+ - {{ rule.rule.name }}
Error: {{ rule.error }}
{%- if verbose %}
Source: {{ rule.source }}
@@ -34,8 +34,8 @@
{%- if msg.normal_query_results | length > 0 %}
{%- for query in (msg.normal_query_results) %}
-{%- if query.name %}
- - {{ query.name }}
+{%- if query.query.name %}
+ - {{ query.query.name }}
{%- else %}
- Query {{ loop.index }}
{%- endif %}
@@ -49,8 +49,8 @@
{%- if (verbose and (msg.falsey_query_results | length > 0)) or msg.falsey_query_results|length == 1 %}
{%- for query in (msg.falsey_query_results) %}
-{%- if query.name %}
- - {{ query.name }}
+{%- if query.query.name %}
+ - {{ query.query.name }}
{%- else %}
- Query {{ loop.index }}
{%- endif %}
@@ -68,8 +68,8 @@
{# new line #}
{%- for query in msg.failed_query_results %}
-{%- if query.name %}
- - {{ query.name }}
+{%- if query.query.name %}
+ - {{ query.query.name }}
{%- else %}
- Query {{ loop.index }}
{%- endif %}