1#! /usr/bin/python 2# 3# SPDX-License-Identifier: Apache-2.0 4# Zephyr's Twister library 5# 6# pylint: disable=unused-import 7# 8# Set of code that other projects can also import to do things on 9# Zephyr's sanity check testcases. 10 11import logging 12import yaml 13try: 14 # Use the C LibYAML parser if available, rather than the Python parser. 15 # It's much faster. 16 from yaml import CLoader as Loader 17 from yaml import CSafeLoader as SafeLoader 18 from yaml import CDumper as Dumper 19except ImportError: 20 from yaml import Loader, SafeLoader, Dumper 21 22log = logging.getLogger("scl") 23 24 25class EmptyYamlFileException(Exception): 26 pass 27 28 29# 30# 31def yaml_load(filename): 32 """ 33 Safely load a YAML document 34 35 Follows recommendations from 36 https://security.openstack.org/guidelines/dg_avoid-dangerous-input-parsing-libraries.html. 37 38 :param str filename: filename to load 39 :raises yaml.scanner: On YAML scan issues 40 :raises: any other exception on file access errors 41 :return: dictionary representing the YAML document 42 """ 43 try: 44 with open(filename, 'r', encoding='utf-8') as f: 45 return yaml.load(f, Loader=SafeLoader) 46 except yaml.scanner.ScannerError as e: # For errors parsing schema.yaml 47 mark = e.problem_mark 48 cmark = e.context_mark 49 log.error("%s:%d:%d: error: %s (note %s context @%s:%d:%d %s)", 50 mark.name, mark.line, mark.column, e.problem, 51 e.note, cmark.name, cmark.line, cmark.column, e.context) 52 raise 53 54# If pykwalify is installed, then the validate function will work -- 55# otherwise, it is a stub and we'd warn about it. 56try: 57 import pykwalify.core 58 # Don't print error messages yourself, let us do it 59 logging.getLogger("pykwalify.core").setLevel(50) 60 61 def _yaml_validate(data, schema): 62 if not schema: 63 return 64 c = pykwalify.core.Core(source_data=data, schema_data=schema) 65 c.validate(raise_exception=True) 66 67except ImportError as e: 68 log.warning("can't import pykwalify; won't validate YAML (%s)", e) 69 def _yaml_validate(data, schema): 70 pass 71 72def yaml_load_verify(filename, schema): 73 """ 74 Safely load a testcase/sample yaml document and validate it 75 against the YAML schema, returning in case of success the YAML data. 76 77 :param str filename: name of the file to load and process 78 :param dict schema: loaded YAML schema (can load with :func:`yaml_load`) 79 80 # 'document.yaml' contains a single YAML document. 81 :raises yaml.scanner.ScannerError: on YAML parsing error 82 :raises pykwalify.errors.SchemaError: on Schema violation error 83 """ 84 # 'document.yaml' contains a single YAML document. 85 y = yaml_load(filename) 86 if not y: 87 raise EmptyYamlFileException('No data in YAML file: %s' % filename) 88 _yaml_validate(y, schema) 89 return y 90