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#
25#
26def yaml_load(filename):
27    """
28    Safely load a YAML document
29
30    Follows recomendations from
31    https://security.openstack.org/guidelines/dg_avoid-dangerous-input-parsing-libraries.html.
32
33    :param str filename: filename to load
34    :raises yaml.scanner: On YAML scan issues
35    :raises: any other exception on file access erors
36    :return: dictionary representing the YAML document
37    """
38    try:
39        with open(filename, 'r') as f:
40            return yaml.load(f, Loader=SafeLoader)
41    except yaml.scanner.ScannerError as e:	# For errors parsing schema.yaml
42        mark = e.problem_mark
43        cmark = e.context_mark
44        log.error("%s:%d:%d: error: %s (note %s context @%s:%d:%d %s)",
45                  mark.name, mark.line, mark.column, e.problem,
46                  e.note, cmark.name, cmark.line, cmark.column, e.context)
47        raise
48
49# If pykwalify is installed, then the validate functionw ill work --
50# otherwise, it is a stub and we'd warn about it.
51try:
52    import pykwalify.core
53    # Don't print error messages yourself, let us do it
54    logging.getLogger("pykwalify.core").setLevel(50)
55
56    def _yaml_validate(data, schema):
57        if not schema:
58            return
59        c = pykwalify.core.Core(source_data=data, schema_data=schema)
60        c.validate(raise_exception=True)
61
62except ImportError as e:
63    log.warning("can't import pykwalify; won't validate YAML (%s)", e)
64    def _yaml_validate(data, schema):
65        pass
66
67def yaml_load_verify(filename, schema):
68    """
69    Safely load a testcase/sample yaml document and validate it
70    against the YAML schema, returing in case of success the YAML data.
71
72    :param str filename: name of the file to load and process
73    :param dict schema: loaded YAML schema (can load with :func:`yaml_load`)
74
75    # 'document.yaml' contains a single YAML document.
76    :raises yaml.scanner.ScannerError: on YAML parsing error
77    :raises pykwalify.errors.SchemaError: on Schema violation error
78    """
79    # 'document.yaml' contains a single YAML document.
80    y = yaml_load(filename)
81    _yaml_validate(y, schema)
82    return y
83