mirror of
https://github.com/chipsec/chipsec
synced 2026-06-08 13:31:00 +00:00
79f81bbb7e
This commit fixes whitespace errors from checkers W291,W292,W293,W391. They were found by running "flake8 ." from the root directory. These are errors defined by "pycodestyle", and have no functional impact to the source. This is simply fixing whitespace as defined by CHIPSEC's .flake8 configuration. background: https://www.flake8rules.com/rules/W291.html https://www.flake8rules.com/rules/W292.html https://www.flake8rules.com/rules/W293.html https://www.flake8rules.com/rules/W391.html tool versions: flake8 v7.3.0, python v3.13.11 Signed-off-by: William Leara <william.leara@dell.com>
367 lines
14 KiB
Python
367 lines
14 KiB
Python
# CHIPSEC: Platform Security Assessment Framework
|
|
# Copyright (c) 2018-2022, Intel Corporation
|
|
#
|
|
# This program is free software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU General Public License
|
|
# as published by the Free Software Foundation; Version 2.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
#
|
|
# Contact information:
|
|
# chipsec@intel.com
|
|
#
|
|
|
|
import json
|
|
import time
|
|
import os
|
|
from collections import OrderedDict
|
|
import xml.etree.ElementTree as ET
|
|
import xml.dom.minidom
|
|
from chipsec.library.logger import logger
|
|
from typing import Dict, List, Optional
|
|
|
|
|
|
class ExitCode:
|
|
OK = 0
|
|
WARNING = 2
|
|
DEPRECATED = 4
|
|
FAIL = 8
|
|
ERROR = 16
|
|
EXCEPTION = 32
|
|
INFORMATION = 64
|
|
NOTAPPLICABLE = 128
|
|
ARCHIVED = 256
|
|
|
|
help_epilog = """\
|
|
Exit Code
|
|
---------
|
|
CHIPSEC returns an integer exit code:
|
|
- Exit code is 0: all modules ran successfully and passed
|
|
- Exit code is not 0: each bit means the following:
|
|
- Bit 1: WARNING at least one module had a warning
|
|
- Bit 2: DEPRECATED at least one module uses deprecated API
|
|
- Bit 3: FAIL at least one module failed
|
|
- Bit 4: ERROR at least one module wasn't able to run
|
|
- Bit 5: EXCEPTION at least one module threw an unexpected exception
|
|
- Bit 6: INFORMATION at least one module contained information
|
|
- Bit 7: NOT APPLICABLE at least one module was not applicable for the platform
|
|
|
|
"""
|
|
|
|
class TestCase:
|
|
def __init__(self, name: str) -> None:
|
|
self.name = name
|
|
self.result = ''
|
|
self.result_code = 0
|
|
self.output = ''
|
|
self.argv = ''
|
|
self.desc = ''
|
|
self.startTime = 0
|
|
self.endTime = 0
|
|
self.time = None
|
|
|
|
def get_fields(self) -> Dict[str, str]:
|
|
try:
|
|
result_code = f'0x{self.result_code:016X}'
|
|
except ValueError:
|
|
result_code = f'0x{self.result_code.value:016X}'
|
|
return {'name': self.name, 'output': self.output, 'result': self.result, 'code': result_code}
|
|
|
|
def start_module(self) -> None:
|
|
"""Displays a banner for the module name provided."""
|
|
text = f'\n[*] Running module: {self.name}'
|
|
logger().log_heading(text)
|
|
self.startTime = time.time()
|
|
self.desc = self.name
|
|
|
|
def end_module(self, result: str, result_code: int, arg: str) -> None:
|
|
self.result = result
|
|
self.result_code = result_code
|
|
self.argv = arg
|
|
self.endTime = time.time()
|
|
self.time = self.endTime - self.startTime
|
|
|
|
|
|
class ChipsecResults:
|
|
def __init__(self):
|
|
self.test_cases = []
|
|
self.properties = None
|
|
self.summary = False
|
|
self.exceptions = []
|
|
self.time = None
|
|
|
|
def add_properties(self, properties: Dict[str, str]) -> None:
|
|
self.properties = properties
|
|
|
|
def add_testcase(self, test: TestCase) -> None:
|
|
self.test_cases.append(test)
|
|
|
|
def get_current_testcase(self) -> Optional[TestCase]:
|
|
if len(self.test_cases) == 0 or self.summary:
|
|
return None
|
|
return self.test_cases[len(self.test_cases) - 1]
|
|
|
|
def add_exception(self, name):
|
|
self.exceptions.append(str(name))
|
|
|
|
def get_return_code(self):
|
|
pass
|
|
|
|
def order_summary(self):
|
|
return {}
|
|
|
|
def print_summary(self):
|
|
pass
|
|
|
|
|
|
def set_time(self, pTime: Optional[float] = None) -> None:
|
|
"""Sets the time"""
|
|
if pTime is not None:
|
|
self.time = pTime
|
|
else:
|
|
curr_testcase = self.get_current_testcase()
|
|
if curr_testcase:
|
|
self.time = curr_testcase.endTime - self.test_cases[0].startTime
|
|
else:
|
|
self.time = self.test_cases[0].time
|
|
|
|
def get_results(self) -> Dict[str, int]:
|
|
results = {}
|
|
for test in self.test_cases:
|
|
results[test.name] = {'result': test.result}
|
|
return results
|
|
|
|
def xml_summary(self) -> str:
|
|
summary = self.order_summary()
|
|
xml_element = ET.Element("Summary")
|
|
for value in summary.keys():
|
|
temp = {}
|
|
if value == 'total':
|
|
temp['name'] = value
|
|
temp['total'] = f'{summary[value]:d}'
|
|
m_element = ET.SubElement(xml_element, 'result', temp)
|
|
else:
|
|
temp['name'] = value
|
|
temp['total'] = f'{len(summary[value]):d}'
|
|
m_element = ET.SubElement(xml_element, 'result', temp)
|
|
for mod in summary[value]:
|
|
n_element = ET.SubElement(m_element, 'module')
|
|
n_element.text = mod
|
|
return ET.tostring(xml_element, "unicode", None)
|
|
|
|
def json_summary(self) -> str:
|
|
summary = self.order_summary()
|
|
js = json.dumps(summary, sort_keys=False, indent=2, separators=(',', ': '))
|
|
return js
|
|
|
|
def json_full(self) -> str:
|
|
summary = self.get_results()
|
|
js = json.dumps(summary, sort_keys=False, indent=2, separators=(',', ': '))
|
|
return js
|
|
|
|
def xml_full(self, name: str, runtime: Optional[float] = None) -> str:
|
|
xml_element = ET.Element('testsuites')
|
|
summary = self.order_summary()
|
|
summary_dict = {}
|
|
for value in summary.keys():
|
|
if value == 'total':
|
|
summary_dict[value] = f'{summary[value]:d}'
|
|
else:
|
|
summary_dict[value.replace(' ', '')] = f'{len(summary[value]):d}'
|
|
summary_dict["name"] = os.path.basename(os.path.splitext(name)[0])
|
|
if runtime is not None:
|
|
summary_dict["time"] = f'{runtime:5f}'
|
|
ts_element = ET.SubElement(xml_element, "testsuite", summary_dict)
|
|
# add properties
|
|
pr_element = ET.SubElement(ts_element, "properties")
|
|
prop_dict = {}
|
|
if self.properties is not None:
|
|
for value in self.properties:
|
|
prop_dict["name"] = value
|
|
prop_dict["value"] = self.properties[value]
|
|
ET.SubElement(pr_element, "property", prop_dict)
|
|
# add test cases
|
|
for test in self.test_cases:
|
|
ttime = test.time if test.time is not None else 0.0
|
|
tc_element = ET.SubElement(ts_element, "testcase", {'classname': test.name, 'name': test.desc, 'time': f'{ttime:5f}'})
|
|
ET.SubElement(tc_element, "pass", {"type": test.result})
|
|
out_element = ET.SubElement(tc_element, "system-out")
|
|
out_element.text = test.output
|
|
return xml.dom.minidom.parseString(ET.tostring(xml_element, None, None)).toprettyxml()
|
|
|
|
def markdown_full(self, name: str) -> str:
|
|
passed = []
|
|
failed = []
|
|
error = []
|
|
warning = []
|
|
information = []
|
|
notapplicable = []
|
|
deprecated = []
|
|
archived = []
|
|
destination = {'Passed': passed,
|
|
'Failed': failed,
|
|
'Error': error,
|
|
'Warning': warning,
|
|
'Information': information,
|
|
'NotApplicable': notapplicable,
|
|
'Deprecated': deprecated,
|
|
'Archived': archived
|
|
}
|
|
|
|
for test in self.test_cases:
|
|
# Test case as header level 4
|
|
out_string = f'#### {test.name.replace("chipsec.modules.", ""):s}\n'
|
|
for line in test.output.splitlines(True):
|
|
# Format output as code
|
|
out_string += f' {line:s}'
|
|
destination[test.result].append(out_string)
|
|
|
|
ret_string = ''
|
|
for result in destination:
|
|
# Category as header level 1
|
|
ret_string += f'\n# {result:s}:{len(destination[result]):d}\n'
|
|
ret_string += ''.join(destination[result])
|
|
return ret_string
|
|
|
|
class LegacyResults(ChipsecResults):
|
|
def print_summary(self, runtime: Optional[float] = None) -> None:
|
|
summary = self.order_summary()
|
|
filler = '*' * 27
|
|
logger().log(f'\n[CHIPSEC] {filler} SUMMARY {filler}')
|
|
print_dictionary = {'failed to run': logger().log_error,
|
|
'passed': logger().log_passed,
|
|
'information': logger().log_information,
|
|
'archived': logger().log_information,
|
|
'failed': logger().log_failed,
|
|
'not applicable': logger().log_not_applicable}
|
|
if runtime is not None:
|
|
logger().log(f'[CHIPSEC] Time elapsed {runtime:.3f}')
|
|
|
|
for result in summary.keys():
|
|
if result == 'total':
|
|
logger().log(f'[CHIPSEC] Modules {result:16}{summary[result]:d}')
|
|
elif result == 'warnings':
|
|
logger().log(f'[CHIPSEC] Modules with {result:11}{len(summary[result]):d}:')
|
|
for mod in summary[result]:
|
|
logger().log_warning(mod)
|
|
elif result == 'exceptions':
|
|
if len(summary[result]) > 0:
|
|
logger().log(f'[CHIPSEC] Modules with {result:11}{len(summary[result]):d}:')
|
|
for mod in summary[result]:
|
|
logger().log_error(mod)
|
|
elif result == 'archived':
|
|
continue
|
|
else:
|
|
logger().log(f'[CHIPSEC] Modules {result:16}{len(summary[result]):d}:')
|
|
for mod in summary[result]:
|
|
print_dictionary[result](mod)
|
|
logger().log('[CHIPSEC] *****************************************************************')
|
|
|
|
def order_summary(self) -> Dict[str, List[TestCase]]:
|
|
self.summary = True
|
|
ret = OrderedDict()
|
|
ret['failed to run'] = []
|
|
ret['passed'] = []
|
|
ret['information'] = []
|
|
ret['failed'] = []
|
|
ret['warnings'] = []
|
|
ret['not applicable'] = []
|
|
ret['archived'] = []
|
|
destination = {'Passed': 'passed',
|
|
'Failed': 'failed',
|
|
'Error': 'failed to run',
|
|
'Warning': 'warnings',
|
|
'Information': 'information',
|
|
'NotApplicable': 'not applicable',
|
|
'Archived': 'archived'
|
|
}
|
|
executed = 0
|
|
for test in self.test_cases:
|
|
executed += 1
|
|
fields = test.get_fields()
|
|
ret[destination[fields['result']]].append(fields['name'])
|
|
ret['total'] = executed
|
|
ret['exceptions'] = self.exceptions
|
|
return ret
|
|
|
|
def get_return_code(self) -> int:
|
|
summary = self.order_summary()
|
|
destination = {
|
|
'failed to run': ExitCode.ERROR,
|
|
'exceptions': ExitCode.EXCEPTION,
|
|
'failed': ExitCode.FAIL,
|
|
'warnings': ExitCode.WARNING,
|
|
'not applicable': ExitCode.NOTAPPLICABLE,
|
|
'information': ExitCode.INFORMATION,
|
|
'archived': ExitCode.ARCHIVED
|
|
}
|
|
for result in destination.keys():
|
|
if len(summary[result]) != 0:
|
|
return destination[result]
|
|
return ExitCode.OK
|
|
|
|
class ReturnCodeResults(ChipsecResults):
|
|
def print_summary(self, runtime: Optional[float] = None) -> None:
|
|
summary = self.order_summary()
|
|
filler = '*' * 27
|
|
logger().log(f'\n[CHIPSEC] {filler} SUMMARY {filler}')
|
|
if runtime is not None:
|
|
logger().log(f'[CHIPSEC] Time elapsed {runtime:.3f}')
|
|
|
|
for result in summary.keys():
|
|
if result == 'total':
|
|
logger().log(f'[CHIPSEC] Modules {result:16}{summary[result]:d}')
|
|
elif result == 'exceptions':
|
|
if len(summary[result]) > 0:
|
|
logger().log(f'[CHIPSEC] Modules with {result:11}{len(summary[result]):d}:')
|
|
for mod in summary[result]:
|
|
logger().log_error(mod)
|
|
elif result == 'archived':
|
|
continue
|
|
else:
|
|
logger().log(f'[CHIPSEC] Modules {result:16}{len(summary[result]):d}:')
|
|
for mod in summary[result]:
|
|
logger().log(f" {mod}")
|
|
logger().log('[CHIPSEC] *****************************************************************')
|
|
|
|
def order_summary(self):
|
|
if self.time is None:
|
|
self.set_time()
|
|
self.summary = True
|
|
ret = OrderedDict()
|
|
passed = []
|
|
failed = []
|
|
archived = []
|
|
executed = 0
|
|
for test in self.test_cases:
|
|
executed += 1
|
|
fields = test.get_fields()
|
|
if fields['result'] == 'Passed':
|
|
passed.append(fields['name'])
|
|
elif fields['result'] == 'Failed':
|
|
failed.append(fields['name'])
|
|
elif fields['result'] == 'Archived':
|
|
archived.append(fields['name'])
|
|
ret['total'] = executed
|
|
ret['failed'] = failed
|
|
ret['passed'] = passed
|
|
ret['archived'] = archived
|
|
ret['exceptions'] = self.exceptions
|
|
return ret
|
|
|
|
def get_return_code(self):
|
|
summary = self.order_summary()
|
|
if len(self.test_cases) == 1:
|
|
return self.test_cases[0].result_code
|
|
elif len(summary['failed']) != 0:
|
|
return ExitCode.FAIL
|
|
else:
|
|
return ExitCode.OK
|