prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Sigma analyzer creates saved search and story even with 0 results
  The Sigma analyzer will create a story and saved search even if there are no results from the analyzer.
  
  Fix: Only create saved search and story if there was any events tagged.
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `timesketch/lib/analyzers/sigma_tagger.py`
  Content:
  ```
  1 """Index analyzer plugin for sigma."""
  2 from __future__ import unicode_literals
  3 
  4 import logging
  5 import time
  6 import elasticsearch
  7 
  8 from flask import current_app
  9 
  10 from timesketch.lib.analyzers import utils
  11 
  12 from timesketch.lib.analyzers import interface
  13 from timesketch.lib.analyzers import manager
  14 import timesketch.lib.sigma_util as ts_sigma_lib
  15 
  16 
  17 logger = logging.getLogger('timesketch.analyzers.sigma_tagger')
  18 
  19 
  20 class SigmaPlugin(interface.BaseAnalyzer):
  21     """Analyzer for Sigma."""
  22 
  23     NAME = 'sigma'
  24     DISPLAY_NAME = 'Sigma'
  25     DESCRIPTION = 'Run pre-defined Sigma rules and tag matching events'
  26 
  27     def run_sigma_rule(self, query, rule_name, tag_list = None):
  28         """Runs a sigma rule and applies the appropriate tags.
  29 
  30         Args:
  31             query: elastic search query for events to tag.
  32             rule_name: rule_name to apply to matching events.
  33             tag_list: a list of additional tags to be added to the event(s)
  34 
  35         Returns:
  36             int: number of events tagged.
  37         """
  38         return_fields = []
  39         tagged_events_counter = 0
  40         events = self.event_stream(
  41             query_string=query, return_fields=return_fields)
  42         for event in events:
  43             ts_sigma_rules = event.source.get('ts_sigma_rule', [])
  44             ts_sigma_rules.append(rule_name)
  45             event.add_attributes({'ts_sigma_rule': list(set(ts_sigma_rules))})
  46             ts_ttp = event.source.get('ts_ttp', [])
  47             for tag in tag_list:
  48                 # special handling for sigma tags that TS considers TTPS
  49                 # https://car.mitre.org and https://attack.mitre.org
  50                 if tag.startswith(('attack.', 'car.')):
  51                     ts_ttp.append(tag)
  52                     tag_list.remove(tag)
  53             event.add_tags(tag_list)
  54             if len(ts_ttp) > 0:
  55                 event.add_attributes({'ts_ttp': list(set(ts_ttp))})
  56             event.commit()
  57             tagged_events_counter += 1
  58         return tagged_events_counter
  59 
  60     def run(self):
  61         """Entry point for the analyzer.
  62 
  63         Returns:
  64             String with summary of the analyzer result.
  65         """
  66 
  67         tags_applied = {}
  68         sigma_rule_counter = 0
  69         sigma_rules = ts_sigma_lib.get_all_sigma_rules()
  70         if sigma_rules is None:
  71             logger.error('No  Sigma rules found. Check SIGMA_RULES_FOLDERS')
  72         problem_strings = []
  73         output_strings = []
  74 
  75         for rule in sigma_rules:
  76             tags_applied[rule.get('file_name')] = 0
  77             try:
  78                 sigma_rule_counter += 1
  79                 tagged_events_counter = self.run_sigma_rule(
  80                     rule.get('es_query'), rule.get('file_name'),
  81                     tag_list=rule.get('tags'))
  82                 tags_applied[rule.get('file_name')] += tagged_events_counter
  83                 if sigma_rule_counter % 10 == 0:
  84                     logger.debug('Rule {0:d}/{1:d}'.format(
  85                         sigma_rule_counter, len(sigma_rules)))
  86             except elasticsearch.TransportError as e:
  87                 logger.error(
  88                     'Timeout executing search for {0:s}: '
  89                     '{1!s} waiting for 10 seconds'.format(
  90                         rule.get('file_name'), e), exc_info=True)
  91                 # this is caused by too many ES queries in short time range
  92                 # TODO: https://github.com/google/timesketch/issues/1782
  93                 sleep_time = current_app.config.get(
  94                     'SIGMA_TAG_DELAY', 15)
  95                 time.sleep(sleep_time)
  96                 tagged_events_counter = self.run_sigma_rule(
  97                     rule.get('es_query'), rule.get('file_name'),
  98                     tag_list=rule.get('tags'))
  99                 tags_applied[rule.get('file_name')] += tagged_events_counter
  100             # Wide exception handling since there are multiple exceptions that
  101             # can be raised by the underlying sigma library.
  102             except: # pylint: disable=bare-except
  103                 logger.error(
  104                     'Problem with rule in file {0:s}: '.format(
  105                         rule.get('file_name')), exc_info=True)
  106                 problem_strings.append('* {0:s}'.format(
  107                     rule.get('file_name')))
  108                 continue
  109 
  110         total_tagged_events = sum(tags_applied.values())
  111         output_strings.append('Applied {0:d} tags'.format(total_tagged_events))
  112 
  113         if sigma_rule_counter > 0:
  114             self.add_sigma_match_view(sigma_rule_counter)
  115 
  116         if len(problem_strings) > 0:
  117             output_strings.append('Problematic rules:')
  118             output_strings.extend(problem_strings)
  119 
  120         return '\n'.join(output_strings)
  121 
  122     def add_sigma_match_view(self, sigma_rule_counter):
  123         """Adds a view with the top 20 matching rules.
  124 
  125         Args:
  126             sigma_rule_counter number of matching rules
  127 
  128         """
  129         view = self.sketch.add_view(
  130             view_name='Sigma Rule matches', analyzer_name=self.NAME,
  131             query_string='tag:"sigma*"')
  132         agg_params = {
  133             'field': 'tag',
  134             'limit': 20,
  135             'index': [self.timeline_id],
  136         }
  137         agg_obj = self.sketch.add_aggregation(
  138             name='Top 20 Sigma tags', agg_name='field_bucket',
  139             agg_params=agg_params, view_id=view.id, chart_type='hbarchart',
  140             description='Created by the Sigma analyzer')
  141 
  142         story = self.sketch.add_story('Sigma Rule hits')
  143         story.add_text(
  144             utils.SIGMA_STORY_HEADER, skip_if_exists=True)
  145 
  146         story.add_text(
  147             '## Sigma Analyzer.\n\nThe Sigma '
  148             'analyzer takes Events and matches them with Sigma rules.'
  149             'In this timeline the analyzer discovered {0:d} '
  150             'Sigma tags.\n\nThis is a summary of '
  151             'it\'s findings.'.format(sigma_rule_counter))
  152         story.add_text(
  153             'The top 20 most commonly discovered tags were:')
  154         story.add_aggregation(agg_obj)
  155         story.add_text(
  156             'And an overview of all the discovered search terms:')
  157         story.add_view(view)
  158 
  159 
  160 class RulesSigmaPlugin(SigmaPlugin):
  161     """Sigma plugin to run rules."""
  162 
  163     NAME = 'sigma'
  164 
  165 manager.AnalysisManager.register_analyzer(RulesSigmaPlugin)
  166
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/timesketch/lib/analyzers/sigma_tagger.py b/timesketch/lib/analyzers/sigma_tagger.py
  --- a/timesketch/lib/analyzers/sigma_tagger.py
  +++ b/timesketch/lib/analyzers/sigma_tagger.py
  @@ -110,7 +110,7 @@
           total_tagged_events = sum(tags_applied.values())
           output_strings.append('Applied {0:d} tags'.format(total_tagged_events))
   
  -        if sigma_rule_counter > 0:
  +        if total_tagged_events > 0:
               self.add_sigma_match_view(sigma_rule_counter)
   
           if len(problem_strings) > 0:
  
verification_info: {"golden_diff": "diff --git a/timesketch/lib/analyzers/sigma_tagger.py b/timesketch/lib/analyzers/sigma_tagger.py\n--- a/timesketch/lib/analyzers/sigma_tagger.py\n+++ b/timesketch/lib/analyzers/sigma_tagger.py\n@@ -110,7 +110,7 @@\n         total_tagged_events = sum(tags_applied.values())\n         output_strings.append('Applied {0:d} tags'.format(total_tagged_events))\n \n-        if sigma_rule_counter > 0:\n+        if total_tagged_events > 0:\n             self.add_sigma_match_view(sigma_rule_counter)\n \n         if len(problem_strings) > 0:\n", "issue": "Sigma analyzer creates saved search and story even with 0 results\nThe Sigma analyzer will create a story and saved search even if there are no results from the analyzer.\r\n\r\nFix: Only create saved search and story if there was any events tagged.\n", "before_files": [{"content": "\"\"\"Index analyzer plugin for sigma.\"\"\"\nfrom __future__ import unicode_literals\n\nimport logging\nimport time\nimport elasticsearch\n\nfrom flask import current_app\n\nfrom timesketch.lib.analyzers import utils\n\nfrom timesketch.lib.analyzers import interface\nfrom timesketch.lib.analyzers import manager\nimport timesketch.lib.sigma_util as ts_sigma_lib\n\n\nlogger = logging.getLogger('timesketch.analyzers.sigma_tagger')\n\n\nclass SigmaPlugin(interface.BaseAnalyzer):\n    \"\"\"Analyzer for Sigma.\"\"\"\n\n    NAME = 'sigma'\n    DISPLAY_NAME = 'Sigma'\n    DESCRIPTION = 'Run pre-defined Sigma rules and tag matching events'\n\n    def run_sigma_rule(self, query, rule_name, tag_list = None):\n        \"\"\"Runs a sigma rule and applies the appropriate tags.\n\n        Args:\n            query: elastic search query for events to tag.\n            rule_name: rule_name to apply to matching events.\n            tag_list: a list of additional tags to be added to the event(s)\n\n        Returns:\n            int: number of events tagged.\n        \"\"\"\n        return_fields = []\n        tagged_events_counter = 0\n        events = self.event_stream(\n            query_string=query, return_fields=return_fields)\n        for event in events:\n            ts_sigma_rules = event.source.get('ts_sigma_rule', [])\n            ts_sigma_rules.append(rule_name)\n            event.add_attributes({'ts_sigma_rule': list(set(ts_sigma_rules))})\n            ts_ttp = event.source.get('ts_ttp', [])\n            for tag in tag_list:\n                # special handling for sigma tags that TS considers TTPS\n                # https://car.mitre.org and https://attack.mitre.org\n                if tag.startswith(('attack.', 'car.')):\n                    ts_ttp.append(tag)\n                    tag_list.remove(tag)\n            event.add_tags(tag_list)\n            if len(ts_ttp) > 0:\n                event.add_attributes({'ts_ttp': list(set(ts_ttp))})\n            event.commit()\n            tagged_events_counter += 1\n        return tagged_events_counter\n\n    def run(self):\n        \"\"\"Entry point for the analyzer.\n\n        Returns:\n            String with summary of the analyzer result.\n        \"\"\"\n\n        tags_applied = {}\n        sigma_rule_counter = 0\n        sigma_rules = ts_sigma_lib.get_all_sigma_rules()\n        if sigma_rules is None:\n            logger.error('No  Sigma rules found. Check SIGMA_RULES_FOLDERS')\n        problem_strings = []\n        output_strings = []\n\n        for rule in sigma_rules:\n            tags_applied[rule.get('file_name')] = 0\n            try:\n                sigma_rule_counter += 1\n                tagged_events_counter = self.run_sigma_rule(\n                    rule.get('es_query'), rule.get('file_name'),\n                    tag_list=rule.get('tags'))\n                tags_applied[rule.get('file_name')] += tagged_events_counter\n                if sigma_rule_counter % 10 == 0:\n                    logger.debug('Rule {0:d}/{1:d}'.format(\n                        sigma_rule_counter, len(sigma_rules)))\n            except elasticsearch.TransportError as e:\n                logger.error(\n                    'Timeout executing search for {0:s}: '\n                    '{1!s} waiting for 10 seconds'.format(\n                        rule.get('file_name'), e), exc_info=True)\n                # this is caused by too many ES queries in short time range\n                # TODO: https://github.com/google/timesketch/issues/1782\n                sleep_time = current_app.config.get(\n                    'SIGMA_TAG_DELAY', 15)\n                time.sleep(sleep_time)\n                tagged_events_counter = self.run_sigma_rule(\n                    rule.get('es_query'), rule.get('file_name'),\n                    tag_list=rule.get('tags'))\n                tags_applied[rule.get('file_name')] += tagged_events_counter\n            # Wide exception handling since there are multiple exceptions that\n            # can be raised by the underlying sigma library.\n            except: # pylint: disable=bare-except\n                logger.error(\n                    'Problem with rule in file {0:s}: '.format(\n                        rule.get('file_name')), exc_info=True)\n                problem_strings.append('* {0:s}'.format(\n                    rule.get('file_name')))\n                continue\n\n        total_tagged_events = sum(tags_applied.values())\n        output_strings.append('Applied {0:d} tags'.format(total_tagged_events))\n\n        if sigma_rule_counter > 0:\n            self.add_sigma_match_view(sigma_rule_counter)\n\n        if len(problem_strings) > 0:\n            output_strings.append('Problematic rules:')\n            output_strings.extend(problem_strings)\n\n        return '\\n'.join(output_strings)\n\n    def add_sigma_match_view(self, sigma_rule_counter):\n        \"\"\"Adds a view with the top 20 matching rules.\n\n        Args:\n            sigma_rule_counter number of matching rules\n\n        \"\"\"\n        view = self.sketch.add_view(\n            view_name='Sigma Rule matches', analyzer_name=self.NAME,\n            query_string='tag:\"sigma*\"')\n        agg_params = {\n            'field': 'tag',\n            'limit': 20,\n            'index': [self.timeline_id],\n        }\n        agg_obj = self.sketch.add_aggregation(\n            name='Top 20 Sigma tags', agg_name='field_bucket',\n            agg_params=agg_params, view_id=view.id, chart_type='hbarchart',\n            description='Created by the Sigma analyzer')\n\n        story = self.sketch.add_story('Sigma Rule hits')\n        story.add_text(\n            utils.SIGMA_STORY_HEADER, skip_if_exists=True)\n\n        story.add_text(\n            '## Sigma Analyzer.\\n\\nThe Sigma '\n            'analyzer takes Events and matches them with Sigma rules.'\n            'In this timeline the analyzer discovered {0:d} '\n            'Sigma tags.\\n\\nThis is a summary of '\n            'it\\'s findings.'.format(sigma_rule_counter))\n        story.add_text(\n            'The top 20 most commonly discovered tags were:')\n        story.add_aggregation(agg_obj)\n        story.add_text(\n            'And an overview of all the discovered search terms:')\n        story.add_view(view)\n\n\nclass RulesSigmaPlugin(SigmaPlugin):\n    \"\"\"Sigma plugin to run rules.\"\"\"\n\n    NAME = 'sigma'\n\nmanager.AnalysisManager.register_analyzer(RulesSigmaPlugin)\n", "path": "timesketch/lib/analyzers/sigma_tagger.py"}], "after_files": [{"content": "\"\"\"Index analyzer plugin for sigma.\"\"\"\nfrom __future__ import unicode_literals\n\nimport logging\nimport time\nimport elasticsearch\n\nfrom flask import current_app\n\nfrom timesketch.lib.analyzers import utils\n\nfrom timesketch.lib.analyzers import interface\nfrom timesketch.lib.analyzers import manager\nimport timesketch.lib.sigma_util as ts_sigma_lib\n\n\nlogger = logging.getLogger('timesketch.analyzers.sigma_tagger')\n\n\nclass SigmaPlugin(interface.BaseAnalyzer):\n    \"\"\"Analyzer for Sigma.\"\"\"\n\n    NAME = 'sigma'\n    DISPLAY_NAME = 'Sigma'\n    DESCRIPTION = 'Run pre-defined Sigma rules and tag matching events'\n\n    def run_sigma_rule(self, query, rule_name, tag_list = None):\n        \"\"\"Runs a sigma rule and applies the appropriate tags.\n\n        Args:\n            query: elastic search query for events to tag.\n            rule_name: rule_name to apply to matching events.\n            tag_list: a list of additional tags to be added to the event(s)\n\n        Returns:\n            int: number of events tagged.\n        \"\"\"\n        return_fields = []\n        tagged_events_counter = 0\n        events = self.event_stream(\n            query_string=query, return_fields=return_fields)\n        for event in events:\n            ts_sigma_rules = event.source.get('ts_sigma_rule', [])\n            ts_sigma_rules.append(rule_name)\n            event.add_attributes({'ts_sigma_rule': list(set(ts_sigma_rules))})\n            ts_ttp = event.source.get('ts_ttp', [])\n            for tag in tag_list:\n                # special handling for sigma tags that TS considers TTPS\n                # https://car.mitre.org and https://attack.mitre.org\n                if tag.startswith(('attack.', 'car.')):\n                    ts_ttp.append(tag)\n                    tag_list.remove(tag)\n            event.add_tags(tag_list)\n            if len(ts_ttp) > 0:\n                event.add_attributes({'ts_ttp': list(set(ts_ttp))})\n            event.commit()\n            tagged_events_counter += 1\n        return tagged_events_counter\n\n    def run(self):\n        \"\"\"Entry point for the analyzer.\n\n        Returns:\n            String with summary of the analyzer result.\n        \"\"\"\n\n        tags_applied = {}\n        sigma_rule_counter = 0\n        sigma_rules = ts_sigma_lib.get_all_sigma_rules()\n        if sigma_rules is None:\n            logger.error('No  Sigma rules found. Check SIGMA_RULES_FOLDERS')\n        problem_strings = []\n        output_strings = []\n\n        for rule in sigma_rules:\n            tags_applied[rule.get('file_name')] = 0\n            try:\n                sigma_rule_counter += 1\n                tagged_events_counter = self.run_sigma_rule(\n                    rule.get('es_query'), rule.get('file_name'),\n                    tag_list=rule.get('tags'))\n                tags_applied[rule.get('file_name')] += tagged_events_counter\n                if sigma_rule_counter % 10 == 0:\n                    logger.debug('Rule {0:d}/{1:d}'.format(\n                        sigma_rule_counter, len(sigma_rules)))\n            except elasticsearch.TransportError as e:\n                logger.error(\n                    'Timeout executing search for {0:s}: '\n                    '{1!s} waiting for 10 seconds'.format(\n                        rule.get('file_name'), e), exc_info=True)\n                # this is caused by too many ES queries in short time range\n                # TODO: https://github.com/google/timesketch/issues/1782\n                sleep_time = current_app.config.get(\n                    'SIGMA_TAG_DELAY', 15)\n                time.sleep(sleep_time)\n                tagged_events_counter = self.run_sigma_rule(\n                    rule.get('es_query'), rule.get('file_name'),\n                    tag_list=rule.get('tags'))\n                tags_applied[rule.get('file_name')] += tagged_events_counter\n            # Wide exception handling since there are multiple exceptions that\n            # can be raised by the underlying sigma library.\n            except: # pylint: disable=bare-except\n                logger.error(\n                    'Problem with rule in file {0:s}: '.format(\n                        rule.get('file_name')), exc_info=True)\n                problem_strings.append('* {0:s}'.format(\n                    rule.get('file_name')))\n                continue\n\n        total_tagged_events = sum(tags_applied.values())\n        output_strings.append('Applied {0:d} tags'.format(total_tagged_events))\n\n        if total_tagged_events > 0:\n            self.add_sigma_match_view(sigma_rule_counter)\n\n        if len(problem_strings) > 0:\n            output_strings.append('Problematic rules:')\n            output_strings.extend(problem_strings)\n\n        return '\\n'.join(output_strings)\n\n    def add_sigma_match_view(self, sigma_rule_counter):\n        \"\"\"Adds a view with the top 20 matching rules.\n\n        Args:\n            sigma_rule_counter number of matching rules\n\n        \"\"\"\n        view = self.sketch.add_view(\n            view_name='Sigma Rule matches', analyzer_name=self.NAME,\n            query_string='tag:\"sigma*\"')\n        agg_params = {\n            'field': 'tag',\n            'limit': 20,\n            'index': [self.timeline_id],\n        }\n        agg_obj = self.sketch.add_aggregation(\n            name='Top 20 Sigma tags', agg_name='field_bucket',\n            agg_params=agg_params, view_id=view.id, chart_type='hbarchart',\n            description='Created by the Sigma analyzer')\n\n        story = self.sketch.add_story('Sigma Rule hits')\n        story.add_text(\n            utils.SIGMA_STORY_HEADER, skip_if_exists=True)\n\n        story.add_text(\n            '## Sigma Analyzer.\\n\\nThe Sigma '\n            'analyzer takes Events and matches them with Sigma rules.'\n            'In this timeline the analyzer discovered {0:d} '\n            'Sigma tags.\\n\\nThis is a summary of '\n            'it\\'s findings.'.format(sigma_rule_counter))\n        story.add_text(\n            'The top 20 most commonly discovered tags were:')\n        story.add_aggregation(agg_obj)\n        story.add_text(\n            'And an overview of all the discovered search terms:')\n        story.add_view(view)\n\n\nclass RulesSigmaPlugin(SigmaPlugin):\n    \"\"\"Sigma plugin to run rules.\"\"\"\n\n    NAME = 'sigma'\n\nmanager.AnalysisManager.register_analyzer(RulesSigmaPlugin)\n", "path": "timesketch/lib/analyzers/sigma_tagger.py"}]}