| 1 |  |  | """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 2 |  |  |     This file contains a class for creating OVAL graph from ARF XML source | 
            
                                                                                                            
                            
            
                                    
            
            
                | 3 |  |  | """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 4 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 5 | 1 |  | import sys | 
            
                                                                                                            
                            
            
                                    
            
            
                | 6 | 1 |  | from pathlib import Path | 
            
                                                                                                            
                            
            
                                    
            
            
                | 7 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 8 | 1 |  | from lxml import etree as ET | 
            
                                                                                                            
                            
            
                                    
            
            
                | 9 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 10 | 1 |  | from ..exceptions import NotTestedRule | 
            
                                                                                                            
                            
            
                                    
            
            
                | 11 | 1 |  | from ..oval_tree.builder import Builder | 
            
                                                                                                            
                            
            
                                    
            
            
                | 12 | 1 |  | from ._oval_scan_definitions import _OVALScanDefinitions | 
            
                                                                                                            
                            
            
                                    
            
            
                | 13 | 1 |  | from .global_namespaces import namespaces | 
            
                                                                                                            
                            
            
                                    
            
            
                | 14 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 15 | 1 |  | LOCAL_DATA_DIR = Path(__file__).parent.parent / "schemas" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 16 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 17 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 18 | 1 |  | class ARFXMLParser: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 19 | 1 |  |     def __init__(self, src): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 20 | 1 |  |         self.src = src | 
            
                                                                                                            
                            
            
                                    
            
            
                | 21 | 1 |  |         self.tree = ET.parse(self.src) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 22 | 1 |  |         self.root = self.tree.getroot() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 23 | 1 |  |         self.arf_schemas_path = 'arf/1.1/asset-reporting-format_1.1.0.xsd' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 24 | 1 |  |         if not self.validate(self.arf_schemas_path): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 25 | 1 |  |             start_red_color = '\033[91m' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 26 | 1 |  |             end_red_color = '\033[0m' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 27 | 1 |  |             message = "{}Warning: This file is not valid arf report.{}".format( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 28 |  |  |                 start_red_color, end_red_color) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 29 | 1 |  |             print(message, file=sys.stderr) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 30 | 1 |  |         try: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 31 | 1 |  |             self.used_rules, self.not_tested_rules = self._get_rules_in_profile() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 32 | 1 |  |             self.report_data_href = list(self.used_rules.values())[0]['href'] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 33 | 1 |  |             self.report_data = self._get_report_data(self.report_data_href) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 34 | 1 |  |             self.definitions = self._get_definitions() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 35 | 1 |  |             self.oval_definitions = self._get_oval_definitions() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 36 | 1 |  |             self.scan_definitions = _OVALScanDefinitions( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 37 |  |  |                 self.definitions, self.oval_definitions, self.report_data).get_scan() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 38 | 1 |  |         except BaseException as error: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 39 | 1 |  |             raise ValueError( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 40 |  |  |                 'This file "{}" is not arf report file or there are no results'.format( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 41 |  |  |                     self.src)) from error | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 42 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 43 | 1 |  |     def validate(self, xsd_path): | 
            
                                                                        
                            
            
                                    
            
            
                | 44 | 1 |  |         xsd_path = str(LOCAL_DATA_DIR / xsd_path) | 
            
                                                                        
                            
            
                                    
            
            
                | 45 | 1 |  |         xmlschema_doc = ET.parse(xsd_path) | 
            
                                                                        
                            
            
                                    
            
            
                | 46 | 1 |  |         xmlschema = ET.XMLSchema(xmlschema_doc) | 
            
                                                                        
                            
            
                                    
            
            
                | 47 | 1 |  |         return xmlschema.validate(self.tree) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 48 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 49 | 1 |  |     @staticmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 50 |  |  |     def _get_rule_dict(rule_result, result, id_def, check_content_ref): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 51 | 1 |  |         message = rule_result.find('.//xccdf:message', namespaces) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 52 | 1 |  |         rule_dict = {} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 53 | 1 |  |         rule_dict['id_def'] = id_def | 
            
                                                                                                            
                            
            
                                    
            
            
                | 54 | 1 |  |         rule_dict['href'] = check_content_ref.attrib.get('href') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 55 | 1 |  |         rule_dict['result'] = result.text | 
            
                                                                                                            
                            
            
                                    
            
            
                | 56 | 1 |  |         if message is not None: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 57 |  |  |             rule_dict['message'] = message.text | 
            
                                                                                                            
                            
            
                                    
            
            
                | 58 | 1 |  |         return rule_dict | 
            
                                                                                                            
                            
            
                                    
            
            
                | 59 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 60 | 1 |  |     def _get_rules_in_profile(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 61 | 1 |  |         rules_results = self.root.findall( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 62 |  |  |             './/xccdf:TestResult/xccdf:rule-result', namespaces) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 63 | 1 |  |         rules = {} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 64 | 1 |  |         not_tested_rules = {} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 65 | 1 |  |         for rule_result in rules_results: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 66 | 1 |  |             result = rule_result.find('.//xccdf:result', namespaces) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 67 | 1 |  |             check_content_ref = rule_result.find( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 68 |  |  |                 './/xccdf:check/xccdf:check-content-ref', namespaces) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 69 | 1 |  |             if check_content_ref is not None: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 70 | 1 |  |                 id_ = rule_result.get('idref') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 71 | 1 |  |                 id_def = check_content_ref.attrib.get('name') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 72 | 1 |  |                 if id_def is not None: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 73 | 1 |  |                     rules[id_] = self._get_rule_dict( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 74 |  |  |                         rule_result, result, id_def, check_content_ref) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 75 | 1 |  |                     continue | 
            
                                                                                                            
                            
            
                                    
            
            
                | 76 | 1 |  |             not_tested_rules[rule_result.get('idref')] = result.text | 
            
                                                                                                            
                            
            
                                    
            
            
                | 77 | 1 |  |         return (rules, not_tested_rules) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 78 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 79 | 1 |  |     def _get_report_data(self, href): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 80 | 1 |  |         report_data = None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 81 | 1 |  |         reports = self.root.find('.//arf:reports', namespaces) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 82 | 1 |  |         for report in reports: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 83 | 1 |  |             if "#" + str(report.get("id")) == href: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 84 | 1 |  |                 report_data = report | 
            
                                                                                                            
                            
            
                                    
            
            
                | 85 | 1 |  |         return report_data | 
            
                                                                                                            
                            
            
                                    
            
            
                | 86 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 87 | 1 |  |     def _get_definitions(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 88 | 1 |  |         return self.report_data.find( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 89 |  |  |             ('.//XMLSchema:oval_results/XMLSchema:results/' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 90 |  |  |              'XMLSchema:system/XMLSchema:definitions'), namespaces) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 91 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 92 | 1 |  |     def _get_oval_definitions(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 93 | 1 |  |         return self.root.find( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 94 |  |  |             './/arf:report-requests/arf:report-request/' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 95 |  |  |             'arf:content/scap:data-stream-collection/' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 96 |  |  |             'scap:component/oval-definitions:oval_definitions/' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 97 |  |  |             'oval-definitions:definitions', namespaces) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 98 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 99 | 1 |  |     def _get_definition_of_rule(self, rule_id): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 100 | 1 |  |         if rule_id in self.used_rules: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 101 | 1 |  |             rule_info = self.used_rules[rule_id] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 102 | 1 |  |             return dict(rule_id=rule_id, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 103 |  |  |                         definition_id=rule_info['id_def'], | 
            
                                                                                                            
                            
            
                                    
            
            
                | 104 |  |  |                         definition=self.scan_definitions[rule_info['id_def']]) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 105 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 106 | 1 |  |         if rule_id in self.not_tested_rules: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 107 | 1 |  |             raise NotTestedRule( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 108 |  |  |                 'Rule "{}" is {}, so there are no results.' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 109 |  |  |                 .format(rule_id, self.not_tested_rules[rule_id])) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 110 | 1 |  |         raise ValueError('404 rule "{}" not found!'.format(rule_id)) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 111 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 112 | 1 |  |     def get_oval_tree(self, rule_id): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 113 | 1 |  |         return Builder.dict_of_rule_to_oval_tree( | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 114 |  |  |             self._get_definition_of_rule(rule_id)) | 
            
                                                        
            
                                    
            
            
                | 115 |  |  |  |