We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
docker explorer task failing with debug_tasks enabled
In turbinia config ```DEBUG_TASKS = True```

```
2021-02-24 14:32:11 [INFO] Running sudo /usr/local/bin/de.py -r /tmp/turbinia-mounts/turbinia6k7f8uxc/var/lib/docker list all_containers -d
usage: de.py [-h] [-d] [-r DOCKER_DIRECTORY] [-V]
             {download,mount,list,history} ...
de.py: error: unrecognized arguments: -d
```

https://github.com/hacktobeer/turbinia/blob/master/turbinia/workers/docker.py#L71

^ appends '-d' to the end of the de.py command. This is incorrect and will fail the docker explorer command. It should not be appended but come right after 'de.py' -> 'de.py -d'

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `turbinia/workers/docker.py`
Content:
```
1 # Copyright 2015 Google Inc.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #      http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 """Task for running docker-explorer."""
15 
16 from __future__ import unicode_literals
17 
18 import json
19 import logging
20 import subprocess
21 
22 from turbinia import TurbiniaException
23 from turbinia.evidence import DockerContainer
24 from turbinia.evidence import EvidenceState as state
25 from turbinia.lib import utils
26 from turbinia.workers import Priority
27 from turbinia.workers import TurbiniaTask
28 from turbinia.lib.docker_manager import GetDockerPath
29 from turbinia import config
30 
31 log = logging.getLogger('turbinia')
32 
33 
34 class DockerContainersEnumerationTask(TurbiniaTask):
35   """Enumerates Docker containers on Linux"""
36 
37   REQUIRED_STATES = [state.ATTACHED, state.MOUNTED]
38 
39   def GetContainers(self, evidence):
40     """Lists the containers from an input Evidence.
41 
42     We use subprocess to run the DockerExplorer script, instead of using the
43     Python module, because we need to make sure all DockerExplorer code runs
44     as root.
45 
46     Args:
47       evidence (Evidence): the input Evidence.
48 
49     Returns:
50       a list(dict) containing information about the containers found.
51 
52     Raises:
53       TurbiniaException: when the docker-explorer tool cannot be found or failed
54           to run.
55     """
56     config.LoadConfig()
57     docker_dir = GetDockerPath(evidence.mount_path)
58 
59     containers_info = None
60 
61     # TODO(rgayon): use docker-explorer exposed constant when
62     # https://github.com/google/docker-explorer/issues/80 is in.
63     de_binary = utils.get_exe_path('de.py')
64     if not de_binary:
65       raise TurbiniaException('Cannot find de.py in path')
66 
67     docker_explorer_command = [
68         'sudo', de_binary, '-r', docker_dir, 'list', 'all_containers'
69     ]
70     if config.DEBUG_TASKS or evidence.config.get('debug_tasks'):
71       docker_explorer_command.append('-d')
72     log.info('Running {0:s}'.format(' '.join(docker_explorer_command)))
73     try:
74       json_string = subprocess.check_output(docker_explorer_command).decode(
75           'utf-8')
76     except json.JSONDecodeError as e:
77       raise TurbiniaException(
78           'Error decoding JSON output from de.py: {0!s}'.format(e))
79     except subprocess.CalledProcessError as e:
80       raise TurbiniaException('de.py returned an error: {0!s}'.format(e))
81 
82     containers_info = json.loads(json_string)
83 
84     return containers_info
85 
86   def run(self, evidence, result):
87     """Run the docker-explorer tool to list containerss.
88 
89     Args:
90        evidence (Evidence object):  The evidence to process
91        result (TurbiniaTaskResult): The object to place task results into.
92 
93     Returns:
94       TurbiniaTaskResult object.
95     """
96 
97     status_report = ''
98     success = False
99 
100     status_report = (
101         'Error enumerating Docker containers, evidence has no mounted '
102         'filesystem')
103     found_containers = []
104     try:
105       containers_info = self.GetContainers(evidence)
106       for container_info in containers_info:
107         container_id = container_info.get('container_id')
108         found_containers.append(container_id)
109         container_evidence = DockerContainer(container_id=container_id)
110         result.add_evidence(container_evidence, evidence.config)
111       success = True
112       status_report = 'Found {0!s} containers: {1:s}'.format(
113           len(found_containers), ' '.join(found_containers))
114     except TurbiniaException as e:
115       status_report = 'Error enumerating Docker containers: {0!s}'.format(e)
116 
117     result.report_priority = Priority.LOW
118     result.report_data = status_report
119     result.close(self, success=success, status=status_report)
120     return result
121
```

Path: `turbinia/workers/redis.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 # Copyright 2018 Google Inc.
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 #      http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 """Task for analysing redis_config files."""
16 
17 from __future__ import unicode_literals
18 
19 import os
20 import re
21 
22 from turbinia.evidence import EvidenceState as state
23 from turbinia.evidence import ReportText
24 from turbinia.lib import text_formatter as fmt
25 from turbinia.workers import TurbiniaTask
26 from turbinia.workers import Priority
27 
28 
29 class RedisAnalysisTask(TurbiniaTask):
30   """Task to analyze a Redis configuration file."""
31 
32   REQUIRED_STATES = [state.ATTACHED, state.MOUNTED]
33 
34   def run(self, evidence, result):
35     """Run the Redis configuration analysis worker.
36 
37     Args:
38         evidence (Evidence object):  The evidence we will process.
39         result (TurbiniaTaskResult): The object to place task results into.
40 
41     Returns:
42         TurbiniaTaskResult object.
43     """
44     # Where to store the resulting output file.
45     output_file_name = 'redis_config_analysis.txt'
46     output_file_path = os.path.join(self.output_dir, output_file_name)
47     # Set the output file as the data source for the output evidence.
48     output_evidence = ReportText(source_path=output_file_path)
49 
50     # Read the input file
51     with open(evidence.local_path, 'r') as input_file:
52       redis_config = input_file.read()
53 
54     (report, priority, summary) = self.analyse_redis_config(redis_config)
55     output_evidence.text_data = report
56     result.report_priority = priority
57     result.report_data = report
58 
59     # Write the report to the output file.
60     with open(output_file_path, 'w') as fh:
61       fh.write(output_evidence.text_data.encode('utf-8'))
62 
63     # Add the resulting evidence to the result object.
64     result.add_evidence(output_evidence, evidence.config)
65     result.close(self, success=True, status=summary)
66     return result
67 
68   def analyse_redis_config(self, config):
69     """Analyses a Redis configuration.
70 
71     Args:
72       config (str): configuration file content.
73 
74     Returns:
75       Tuple(
76         report_text(str): The report data
77         report_priority(int): The priority of the report (0 - 100)
78         summary(str): A summary of the report (used for task status)
79       )
80     """
81     findings = []
82     bind_everywhere_re = re.compile(
83         r'^\s*bind[\s"]*0\.0\.0\.0', re.IGNORECASE | re.MULTILINE)
84 
85     if re.search(bind_everywhere_re, config):
86       findings.append(fmt.bullet('Redis listening on every IP'))
87 
88     if findings:
89       summary = 'Insecure Redis configuration found.'
90       findings.insert(0, fmt.heading4(fmt.bold(summary)))
91       report = '\n'.join(findings)
92       return (report, Priority.HIGH, summary)
93 
94     report = 'No issues found in Redis configuration'
95     return (report, Priority.LOW, report)
96
```
--- 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()

```

diff --git a/turbinia/workers/docker.py b/turbinia/workers/docker.py
--- a/turbinia/workers/docker.py
+++ b/turbinia/workers/docker.py
@@ -64,11 +64,13 @@
     if not de_binary:
       raise TurbiniaException('Cannot find de.py in path')
 
-    docker_explorer_command = [
-        'sudo', de_binary, '-r', docker_dir, 'list', 'all_containers'
-    ]
+    docker_explorer_command = ['sudo', de_binary]
+
     if config.DEBUG_TASKS or evidence.config.get('debug_tasks'):
       docker_explorer_command.append('-d')
+
+    docker_explorer_command.extend(['-r', docker_dir, 'list', 'all_containers'])
+
     log.info('Running {0:s}'.format(' '.join(docker_explorer_command)))
     try:
       json_string = subprocess.check_output(docker_explorer_command).decode(
diff --git a/turbinia/workers/redis.py b/turbinia/workers/redis.py
--- a/turbinia/workers/redis.py
+++ b/turbinia/workers/redis.py
@@ -57,7 +57,7 @@
     result.report_data = report
 
     # Write the report to the output file.
-    with open(output_file_path, 'w') as fh:
+    with open(output_file_path, 'wb') as fh:
       fh.write(output_evidence.text_data.encode('utf-8'))
 
     # Add the resulting evidence to the result object.

{"golden_diff": "diff --git a/turbinia/workers/docker.py b/turbinia/workers/docker.py\n--- a/turbinia/workers/docker.py\n+++ b/turbinia/workers/docker.py\n@@ -64,11 +64,13 @@\n     if not de_binary:\n       raise TurbiniaException('Cannot find de.py in path')\n \n-    docker_explorer_command = [\n-        'sudo', de_binary, '-r', docker_dir, 'list', 'all_containers'\n-    ]\n+    docker_explorer_command = ['sudo', de_binary]\n+\n     if config.DEBUG_TASKS or evidence.config.get('debug_tasks'):\n       docker_explorer_command.append('-d')\n+\n+    docker_explorer_command.extend(['-r', docker_dir, 'list', 'all_containers'])\n+\n     log.info('Running {0:s}'.format(' '.join(docker_explorer_command)))\n     try:\n       json_string = subprocess.check_output(docker_explorer_command).decode(\ndiff --git a/turbinia/workers/redis.py b/turbinia/workers/redis.py\n--- a/turbinia/workers/redis.py\n+++ b/turbinia/workers/redis.py\n@@ -57,7 +57,7 @@\n     result.report_data = report\n \n     # Write the report to the output file.\n-    with open(output_file_path, 'w') as fh:\n+    with open(output_file_path, 'wb') as fh:\n       fh.write(output_evidence.text_data.encode('utf-8'))\n \n     # Add the resulting evidence to the result object.\n", "issue": "docker explorer task failing with debug_tasks enabled\nIn turbinia config ```DEBUG_TASKS = True```\r\n\r\n```\r\n2021-02-24 14:32:11 [INFO] Running sudo /usr/local/bin/de.py -r /tmp/turbinia-mounts/turbinia6k7f8uxc/var/lib/docker list all_containers -d\r\nusage: de.py [-h] [-d] [-r DOCKER_DIRECTORY] [-V]\r\n             {download,mount,list,history} ...\r\nde.py: error: unrecognized arguments: -d\r\n```\r\n\r\nhttps://github.com/hacktobeer/turbinia/blob/master/turbinia/workers/docker.py#L71\r\n\r\n^ appends '-d' to the end of the de.py command. This is incorrect and will fail the docker explorer command. It should not be appended but come right after 'de.py' -> 'de.py -d'\n", "before_files": [{"content": "# Copyright 2015 Google Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\"\"\"Task for running docker-explorer.\"\"\"\n\nfrom __future__ import unicode_literals\n\nimport json\nimport logging\nimport subprocess\n\nfrom turbinia import TurbiniaException\nfrom turbinia.evidence import DockerContainer\nfrom turbinia.evidence import EvidenceState as state\nfrom turbinia.lib import utils\nfrom turbinia.workers import Priority\nfrom turbinia.workers import TurbiniaTask\nfrom turbinia.lib.docker_manager import GetDockerPath\nfrom turbinia import config\n\nlog = logging.getLogger('turbinia')\n\n\nclass DockerContainersEnumerationTask(TurbiniaTask):\n  \"\"\"Enumerates Docker containers on Linux\"\"\"\n\n  REQUIRED_STATES = [state.ATTACHED, state.MOUNTED]\n\n  def GetContainers(self, evidence):\n    \"\"\"Lists the containers from an input Evidence.\n\n    We use subprocess to run the DockerExplorer script, instead of using the\n    Python module, because we need to make sure all DockerExplorer code runs\n    as root.\n\n    Args:\n      evidence (Evidence): the input Evidence.\n\n    Returns:\n      a list(dict) containing information about the containers found.\n\n    Raises:\n      TurbiniaException: when the docker-explorer tool cannot be found or failed\n          to run.\n    \"\"\"\n    config.LoadConfig()\n    docker_dir = GetDockerPath(evidence.mount_path)\n\n    containers_info = None\n\n    # TODO(rgayon): use docker-explorer exposed constant when\n    # https://github.com/google/docker-explorer/issues/80 is in.\n    de_binary = utils.get_exe_path('de.py')\n    if not de_binary:\n      raise TurbiniaException('Cannot find de.py in path')\n\n    docker_explorer_command = [\n        'sudo', de_binary, '-r', docker_dir, 'list', 'all_containers'\n    ]\n    if config.DEBUG_TASKS or evidence.config.get('debug_tasks'):\n      docker_explorer_command.append('-d')\n    log.info('Running {0:s}'.format(' '.join(docker_explorer_command)))\n    try:\n      json_string = subprocess.check_output(docker_explorer_command).decode(\n          'utf-8')\n    except json.JSONDecodeError as e:\n      raise TurbiniaException(\n          'Error decoding JSON output from de.py: {0!s}'.format(e))\n    except subprocess.CalledProcessError as e:\n      raise TurbiniaException('de.py returned an error: {0!s}'.format(e))\n\n    containers_info = json.loads(json_string)\n\n    return containers_info\n\n  def run(self, evidence, result):\n    \"\"\"Run the docker-explorer tool to list containerss.\n\n    Args:\n       evidence (Evidence object):  The evidence to process\n       result (TurbiniaTaskResult): The object to place task results into.\n\n    Returns:\n      TurbiniaTaskResult object.\n    \"\"\"\n\n    status_report = ''\n    success = False\n\n    status_report = (\n        'Error enumerating Docker containers, evidence has no mounted '\n        'filesystem')\n    found_containers = []\n    try:\n      containers_info = self.GetContainers(evidence)\n      for container_info in containers_info:\n        container_id = container_info.get('container_id')\n        found_containers.append(container_id)\n        container_evidence = DockerContainer(container_id=container_id)\n        result.add_evidence(container_evidence, evidence.config)\n      success = True\n      status_report = 'Found {0!s} containers: {1:s}'.format(\n          len(found_containers), ' '.join(found_containers))\n    except TurbiniaException as e:\n      status_report = 'Error enumerating Docker containers: {0!s}'.format(e)\n\n    result.report_priority = Priority.LOW\n    result.report_data = status_report\n    result.close(self, success=success, status=status_report)\n    return result\n", "path": "turbinia/workers/docker.py"}, {"content": "# -*- coding: utf-8 -*-\n# Copyright 2018 Google Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\"\"\"Task for analysing redis_config files.\"\"\"\n\nfrom __future__ import unicode_literals\n\nimport os\nimport re\n\nfrom turbinia.evidence import EvidenceState as state\nfrom turbinia.evidence import ReportText\nfrom turbinia.lib import text_formatter as fmt\nfrom turbinia.workers import TurbiniaTask\nfrom turbinia.workers import Priority\n\n\nclass RedisAnalysisTask(TurbiniaTask):\n  \"\"\"Task to analyze a Redis configuration file.\"\"\"\n\n  REQUIRED_STATES = [state.ATTACHED, state.MOUNTED]\n\n  def run(self, evidence, result):\n    \"\"\"Run the Redis configuration analysis worker.\n\n    Args:\n        evidence (Evidence object):  The evidence we will process.\n        result (TurbiniaTaskResult): The object to place task results into.\n\n    Returns:\n        TurbiniaTaskResult object.\n    \"\"\"\n    # Where to store the resulting output file.\n    output_file_name = 'redis_config_analysis.txt'\n    output_file_path = os.path.join(self.output_dir, output_file_name)\n    # Set the output file as the data source for the output evidence.\n    output_evidence = ReportText(source_path=output_file_path)\n\n    # Read the input file\n    with open(evidence.local_path, 'r') as input_file:\n      redis_config = input_file.read()\n\n    (report, priority, summary) = self.analyse_redis_config(redis_config)\n    output_evidence.text_data = report\n    result.report_priority = priority\n    result.report_data = report\n\n    # Write the report to the output file.\n    with open(output_file_path, 'w') as fh:\n      fh.write(output_evidence.text_data.encode('utf-8'))\n\n    # Add the resulting evidence to the result object.\n    result.add_evidence(output_evidence, evidence.config)\n    result.close(self, success=True, status=summary)\n    return result\n\n  def analyse_redis_config(self, config):\n    \"\"\"Analyses a Redis configuration.\n\n    Args:\n      config (str): configuration file content.\n\n    Returns:\n      Tuple(\n        report_text(str): The report data\n        report_priority(int): The priority of the report (0 - 100)\n        summary(str): A summary of the report (used for task status)\n      )\n    \"\"\"\n    findings = []\n    bind_everywhere_re = re.compile(\n        r'^\\s*bind[\\s\"]*0\\.0\\.0\\.0', re.IGNORECASE | re.MULTILINE)\n\n    if re.search(bind_everywhere_re, config):\n      findings.append(fmt.bullet('Redis listening on every IP'))\n\n    if findings:\n      summary = 'Insecure Redis configuration found.'\n      findings.insert(0, fmt.heading4(fmt.bold(summary)))\n      report = '\\n'.join(findings)\n      return (report, Priority.HIGH, summary)\n\n    report = 'No issues found in Redis configuration'\n    return (report, Priority.LOW, report)\n", "path": "turbinia/workers/redis.py"}], "after_files": [{"content": "# Copyright 2015 Google Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\"\"\"Task for running docker-explorer.\"\"\"\n\nfrom __future__ import unicode_literals\n\nimport json\nimport logging\nimport subprocess\n\nfrom turbinia import TurbiniaException\nfrom turbinia.evidence import DockerContainer\nfrom turbinia.evidence import EvidenceState as state\nfrom turbinia.lib import utils\nfrom turbinia.workers import Priority\nfrom turbinia.workers import TurbiniaTask\nfrom turbinia.lib.docker_manager import GetDockerPath\nfrom turbinia import config\n\nlog = logging.getLogger('turbinia')\n\n\nclass DockerContainersEnumerationTask(TurbiniaTask):\n  \"\"\"Enumerates Docker containers on Linux\"\"\"\n\n  REQUIRED_STATES = [state.ATTACHED, state.MOUNTED]\n\n  def GetContainers(self, evidence):\n    \"\"\"Lists the containers from an input Evidence.\n\n    We use subprocess to run the DockerExplorer script, instead of using the\n    Python module, because we need to make sure all DockerExplorer code runs\n    as root.\n\n    Args:\n      evidence (Evidence): the input Evidence.\n\n    Returns:\n      a list(dict) containing information about the containers found.\n\n    Raises:\n      TurbiniaException: when the docker-explorer tool cannot be found or failed\n          to run.\n    \"\"\"\n    config.LoadConfig()\n    docker_dir = GetDockerPath(evidence.mount_path)\n\n    containers_info = None\n\n    # TODO(rgayon): use docker-explorer exposed constant when\n    # https://github.com/google/docker-explorer/issues/80 is in.\n    de_binary = utils.get_exe_path('de.py')\n    if not de_binary:\n      raise TurbiniaException('Cannot find de.py in path')\n\n    docker_explorer_command = ['sudo', de_binary]\n\n    if config.DEBUG_TASKS or evidence.config.get('debug_tasks'):\n      docker_explorer_command.append('-d')\n\n    docker_explorer_command.extend(['-r', docker_dir, 'list', 'all_containers'])\n\n    log.info('Running {0:s}'.format(' '.join(docker_explorer_command)))\n    try:\n      json_string = subprocess.check_output(docker_explorer_command).decode(\n          'utf-8')\n    except json.JSONDecodeError as e:\n      raise TurbiniaException(\n          'Error decoding JSON output from de.py: {0!s}'.format(e))\n    except subprocess.CalledProcessError as e:\n      raise TurbiniaException('de.py returned an error: {0!s}'.format(e))\n\n    containers_info = json.loads(json_string)\n\n    return containers_info\n\n  def run(self, evidence, result):\n    \"\"\"Run the docker-explorer tool to list containerss.\n\n    Args:\n       evidence (Evidence object):  The evidence to process\n       result (TurbiniaTaskResult): The object to place task results into.\n\n    Returns:\n      TurbiniaTaskResult object.\n    \"\"\"\n\n    status_report = ''\n    success = False\n\n    status_report = (\n        'Error enumerating Docker containers, evidence has no mounted '\n        'filesystem')\n    found_containers = []\n    try:\n      containers_info = self.GetContainers(evidence)\n      for container_info in containers_info:\n        container_id = container_info.get('container_id')\n        found_containers.append(container_id)\n        container_evidence = DockerContainer(container_id=container_id)\n        result.add_evidence(container_evidence, evidence.config)\n      success = True\n      status_report = 'Found {0!s} containers: {1:s}'.format(\n          len(found_containers), ' '.join(found_containers))\n    except TurbiniaException as e:\n      status_report = 'Error enumerating Docker containers: {0!s}'.format(e)\n\n    result.report_priority = Priority.LOW\n    result.report_data = status_report\n    result.close(self, success=success, status=status_report)\n    return result\n", "path": "turbinia/workers/docker.py"}, {"content": "# -*- coding: utf-8 -*-\n# Copyright 2018 Google Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\"\"\"Task for analysing redis_config files.\"\"\"\n\nfrom __future__ import unicode_literals\n\nimport os\nimport re\n\nfrom turbinia.evidence import EvidenceState as state\nfrom turbinia.evidence import ReportText\nfrom turbinia.lib import text_formatter as fmt\nfrom turbinia.workers import TurbiniaTask\nfrom turbinia.workers import Priority\n\n\nclass RedisAnalysisTask(TurbiniaTask):\n  \"\"\"Task to analyze a Redis configuration file.\"\"\"\n\n  REQUIRED_STATES = [state.ATTACHED, state.MOUNTED]\n\n  def run(self, evidence, result):\n    \"\"\"Run the Redis configuration analysis worker.\n\n    Args:\n        evidence (Evidence object):  The evidence we will process.\n        result (TurbiniaTaskResult): The object to place task results into.\n\n    Returns:\n        TurbiniaTaskResult object.\n    \"\"\"\n    # Where to store the resulting output file.\n    output_file_name = 'redis_config_analysis.txt'\n    output_file_path = os.path.join(self.output_dir, output_file_name)\n    # Set the output file as the data source for the output evidence.\n    output_evidence = ReportText(source_path=output_file_path)\n\n    # Read the input file\n    with open(evidence.local_path, 'r') as input_file:\n      redis_config = input_file.read()\n\n    (report, priority, summary) = self.analyse_redis_config(redis_config)\n    output_evidence.text_data = report\n    result.report_priority = priority\n    result.report_data = report\n\n    # Write the report to the output file.\n    with open(output_file_path, 'wb') as fh:\n      fh.write(output_evidence.text_data.encode('utf-8'))\n\n    # Add the resulting evidence to the result object.\n    result.add_evidence(output_evidence, evidence.config)\n    result.close(self, success=True, status=summary)\n    return result\n\n  def analyse_redis_config(self, config):\n    \"\"\"Analyses a Redis configuration.\n\n    Args:\n      config (str): configuration file content.\n\n    Returns:\n      Tuple(\n        report_text(str): The report data\n        report_priority(int): The priority of the report (0 - 100)\n        summary(str): A summary of the report (used for task status)\n      )\n    \"\"\"\n    findings = []\n    bind_everywhere_re = re.compile(\n        r'^\\s*bind[\\s\"]*0\\.0\\.0\\.0', re.IGNORECASE | re.MULTILINE)\n\n    if re.search(bind_everywhere_re, config):\n      findings.append(fmt.bullet('Redis listening on every IP'))\n\n    if findings:\n      summary = 'Insecure Redis configuration found.'\n      findings.insert(0, fmt.heading4(fmt.bold(summary)))\n      report = '\\n'.join(findings)\n      return (report, Priority.HIGH, summary)\n\n    report = 'No issues found in Redis configuration'\n    return (report, Priority.LOW, report)\n", "path": "turbinia/workers/redis.py"}]}