diff --git a/Scripts/generate_test_report.py b/Scripts/generate_test_report.py index effc165..5fff6ef 100644 --- a/Scripts/generate_test_report.py +++ b/Scripts/generate_test_report.py @@ -35,13 +35,9 @@ def __init__(self, trx_path, coverage_path=None): self.file_coverage = [] def parse_trx(self): - # Create a secure XML parser that disables external entity processing - parser = ET.XMLParser() - parser.parser.DefaultHandler = lambda data: None - parser.parser.ExternalEntityRefHandler = lambda context, base, uri, notationName: False - parser.parser.EntityDeclHandler = lambda entityName, is_parameter_entity, value, base, systemId, notationName, publicId: False - - tree = ET.parse(self.trx_path, parser) + # Use defusedxml for secure XML parsing + from defusedxml.ElementTree import parse + tree = parse(self.trx_path) root = tree.getroot() ns = {'t': 'http://microsoft.com/schemas/VisualStudio/TeamTest/2010'} @@ -121,13 +117,9 @@ def parse_coverage(self): if not self.coverage_path or not os.path.exists(self.coverage_path): return try: - # Create a secure XML parser that disables external entity processing - parser = ET.XMLParser() - parser.parser.DefaultHandler = lambda data: None - parser.parser.ExternalEntityRefHandler = lambda context, base, uri, notationName: False - parser.parser.EntityDeclHandler = lambda entityName, is_parameter_entity, value, base, systemId, notationName, publicId: False - - tree = ET.parse(self.coverage_path, parser) + # Use defusedxml for secure XML parsing + from defusedxml.ElementTree import parse + tree = parse(self.coverage_path) root = tree.getroot() self.coverage['lines_pct'] = float(root.get('line-rate', 0)) * 100 self.coverage['branches_pct'] = float(root.get('branch-rate', 0)) * 100 @@ -221,6 +213,18 @@ def _parse_condition_coverage(cond_str): return int(m.group(2)), int(m.group(3)) return 0, 0 + @staticmethod + def _esc(text): + if text is None: + return "" + text = str(text) + return (text + .replace('&', '&') + .replace('<', '<') + .replace('>', '>') + .replace('"', '"') + .replace("'", ''')) + @staticmethod def _sanitize_xml_attribute_value(value): """Sanitize XML attribute value to prevent XPath injection.""" @@ -259,18 +263,6 @@ def _validate_output_path(output_path): return normalized_path - @staticmethod - def _esc(text): - if text is None: - return "" - text = str(text) - return (text - .replace('&', '&') - .replace('<', '<') - .replace('>', '>') - .replace('"', '"') - .replace("'", ''')) - def _format_duration_display(self, seconds): if seconds < 60: return f"{seconds:.1f}s"