We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Cron.py unicode decode error
It looks like input evidence caused a unicode error for cron. I think this would only be raised when receiving unreadable input but filing this if we want to catch this exception differently/look into it further

```
 Traceback (most recent call last):
  File "/usr/local/lib/python3.8/dist-packages/turbinia-20220216-py3.8.egg/turbinia/workers/__init__.py", line 1005, in run_wrapper
    self.result = self.run(evidence, self.result)
  File "/usr/local/lib/python3.8/dist-packages/turbinia-20220216-py3.8.egg/turbinia/workers/cron.py", line 54, in run
    crontab = input_file.read()
  File "/usr/lib/python3.8/codecs.py", line 322, in decode
    (result, consumed) = self._buffer_decode(data, self.errors, final)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xdc in position 0: invalid continuation byte
```

--- 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/cron.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 # Copyright 2021 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 cron 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 CronAnalysisTask(TurbiniaTask):
30   """Task to analyze crontabs."""
31 
32   REQUIRED_STATES = [
33       state.ATTACHED, state.CONTAINER_MOUNTED, state.DECOMPRESSED
34   ]
35 
36   def run(self, evidence, result):
37     """Run the cron analysis worker.
38 
39     Args:
40         evidence (Evidence object):  The evidence we will process.
41         result (TurbiniaTaskResult): The object to place task results into.
42 
43     Returns:
44         TurbiniaTaskResult object.
45     """
46     # Where to store the resulting output file.
47     output_file_name = 'cron_analysis.txt'
48     output_file_path = os.path.join(self.output_dir, output_file_name)
49     # Set the output file as the data source for the output evidence.
50     output_evidence = ReportText(source_path=output_file_path)
51 
52     # Read the input file
53     with open(evidence.local_path, 'r') as input_file:
54       crontab = input_file.read()
55 
56     (report, priority, summary) = self.analyse_crontab(crontab)
57     output_evidence.text_data = report
58     result.report_priority = priority
59     result.report_data = report
60 
61     # Write the report to the output file.
62     with open(output_file_path, 'wb') as fh:
63       fh.write(output_evidence.text_data.encode('utf-8'))
64 
65     # Add the resulting evidence to the result object.
66     result.add_evidence(output_evidence, evidence.config)
67     result.close(self, success=True, status=summary)
68     return result
69 
70   def analyse_crontab(self, crontab):
71     """Analyses a Cron file.
72 
73     Args:
74       crontab (str): file content.
75 
76     Returns:
77       Tuple(
78         report_text(str): The report data
79         report_priority(int): The priority of the report (0 - 100)
80         summary(str): A summary of the report (used for task status)
81       )
82     """
83     findings = []
84     wget_or_curl = re.compile(r'(wget|curl)', re.IGNORECASE | re.MULTILINE)
85     pipe_to_sh = re.compile(r'\|(.*)sh ', re.IGNORECASE | re.MULTILINE)
86     get_piped_to_sh = re.compile(
87         r'((wget|curl).*\|)+(.*sh)', re.IGNORECASE | re.MULTILINE)
88 
89     if re.search(get_piped_to_sh, crontab):
90       findings.append(fmt.bullet('Remote file retrieval piped to a shell.'))
91     elif re.search(wget_or_curl, crontab):
92       findings.append(fmt.bullet('Remote file retrieval'))
93     elif re.search(pipe_to_sh, crontab):
94       findings.append(fmt.bullet('File piped to shell'))
95 
96     if findings:
97       summary = 'Potentially backdoored crontab found.'
98       findings.insert(0, fmt.heading4(fmt.bold(summary)))
99       report = '\n'.join(findings)
100       return (report, Priority.HIGH, summary)
101 
102     report = 'No issues found in crontabs'
103     return (report, Priority.LOW, report)
104
```
--- 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/cron.py b/turbinia/workers/cron.py
--- a/turbinia/workers/cron.py
+++ b/turbinia/workers/cron.py
@@ -51,7 +51,14 @@
 
     # Read the input file
     with open(evidence.local_path, 'r') as input_file:
-      crontab = input_file.read()
+      try:
+        crontab = input_file.read()
+      except UnicodeDecodeError as exception:
+        message = 'Error parsing cron file {0:s}: {1!s}'.format(
+            evidence.local_path, exception)
+        result.log(message)
+        result.close(self, success=False, status=message)
+        return result
 
     (report, priority, summary) = self.analyse_crontab(crontab)
     output_evidence.text_data = report

{"golden_diff": "diff --git a/turbinia/workers/cron.py b/turbinia/workers/cron.py\n--- a/turbinia/workers/cron.py\n+++ b/turbinia/workers/cron.py\n@@ -51,7 +51,14 @@\n \n     # Read the input file\n     with open(evidence.local_path, 'r') as input_file:\n-      crontab = input_file.read()\n+      try:\n+        crontab = input_file.read()\n+      except UnicodeDecodeError as exception:\n+        message = 'Error parsing cron file {0:s}: {1!s}'.format(\n+            evidence.local_path, exception)\n+        result.log(message)\n+        result.close(self, success=False, status=message)\n+        return result\n \n     (report, priority, summary) = self.analyse_crontab(crontab)\n     output_evidence.text_data = report\n", "issue": "Cron.py unicode decode error\nIt looks like input evidence caused a unicode error for cron. I think this would only be raised when receiving unreadable input but filing this if we want to catch this exception differently/look into it further\r\n\r\n```\r\n Traceback (most recent call last):\r\n  File \"/usr/local/lib/python3.8/dist-packages/turbinia-20220216-py3.8.egg/turbinia/workers/__init__.py\", line 1005, in run_wrapper\r\n    self.result = self.run(evidence, self.result)\r\n  File \"/usr/local/lib/python3.8/dist-packages/turbinia-20220216-py3.8.egg/turbinia/workers/cron.py\", line 54, in run\r\n    crontab = input_file.read()\r\n  File \"/usr/lib/python3.8/codecs.py\", line 322, in decode\r\n    (result, consumed) = self._buffer_decode(data, self.errors, final)\r\nUnicodeDecodeError: 'utf-8' codec can't decode byte 0xdc in position 0: invalid continuation byte\r\n```\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n# Copyright 2021 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 cron 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 CronAnalysisTask(TurbiniaTask):\n  \"\"\"Task to analyze crontabs.\"\"\"\n\n  REQUIRED_STATES = [\n      state.ATTACHED, state.CONTAINER_MOUNTED, state.DECOMPRESSED\n  ]\n\n  def run(self, evidence, result):\n    \"\"\"Run the cron 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 = 'cron_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      crontab = input_file.read()\n\n    (report, priority, summary) = self.analyse_crontab(crontab)\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_crontab(self, crontab):\n    \"\"\"Analyses a Cron file.\n\n    Args:\n      crontab (str): 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    wget_or_curl = re.compile(r'(wget|curl)', re.IGNORECASE | re.MULTILINE)\n    pipe_to_sh = re.compile(r'\\|(.*)sh ', re.IGNORECASE | re.MULTILINE)\n    get_piped_to_sh = re.compile(\n        r'((wget|curl).*\\|)+(.*sh)', re.IGNORECASE | re.MULTILINE)\n\n    if re.search(get_piped_to_sh, crontab):\n      findings.append(fmt.bullet('Remote file retrieval piped to a shell.'))\n    elif re.search(wget_or_curl, crontab):\n      findings.append(fmt.bullet('Remote file retrieval'))\n    elif re.search(pipe_to_sh, crontab):\n      findings.append(fmt.bullet('File piped to shell'))\n\n    if findings:\n      summary = 'Potentially backdoored crontab 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 crontabs'\n    return (report, Priority.LOW, report)\n", "path": "turbinia/workers/cron.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n# Copyright 2021 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 cron 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 CronAnalysisTask(TurbiniaTask):\n  \"\"\"Task to analyze crontabs.\"\"\"\n\n  REQUIRED_STATES = [\n      state.ATTACHED, state.CONTAINER_MOUNTED, state.DECOMPRESSED\n  ]\n\n  def run(self, evidence, result):\n    \"\"\"Run the cron 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 = 'cron_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      try:\n        crontab = input_file.read()\n      except UnicodeDecodeError as exception:\n        message = 'Error parsing cron file {0:s}: {1!s}'.format(\n            evidence.local_path, exception)\n        result.log(message)\n        result.close(self, success=False, status=message)\n        return result\n\n    (report, priority, summary) = self.analyse_crontab(crontab)\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_crontab(self, crontab):\n    \"\"\"Analyses a Cron file.\n\n    Args:\n      crontab (str): 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    wget_or_curl = re.compile(r'(wget|curl)', re.IGNORECASE | re.MULTILINE)\n    pipe_to_sh = re.compile(r'\\|(.*)sh ', re.IGNORECASE | re.MULTILINE)\n    get_piped_to_sh = re.compile(\n        r'((wget|curl).*\\|)+(.*sh)', re.IGNORECASE | re.MULTILINE)\n\n    if re.search(get_piped_to_sh, crontab):\n      findings.append(fmt.bullet('Remote file retrieval piped to a shell.'))\n    elif re.search(wget_or_curl, crontab):\n      findings.append(fmt.bullet('Remote file retrieval'))\n    elif re.search(pipe_to_sh, crontab):\n      findings.append(fmt.bullet('File piped to shell'))\n\n    if findings:\n      summary = 'Potentially backdoored crontab 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 crontabs'\n    return (report, Priority.LOW, report)\n", "path": "turbinia/workers/cron.py"}]}