Inaky Perez-Gonzalez | 662dde6 | 2017-07-24 10:24:35 -0700 | [diff] [blame] | 1 | #! /usr/bin/python |
| 2 | # |
Anas Nashif | 3ae5262 | 2019-04-06 09:08:09 -0400 | [diff] [blame] | 3 | # SPDX-License-Identifier: Apache-2.0 |
Anas Nashif | 4594370 | 2020-12-11 17:55:15 -0500 | [diff] [blame] | 4 | # Zephyr's Twister library |
Inaky Perez-Gonzalez | 662dde6 | 2017-07-24 10:24:35 -0700 | [diff] [blame] | 5 | # |
Anas Nashif | 5725ed8 | 2020-12-10 09:48:12 -0500 | [diff] [blame] | 6 | # pylint: disable=unused-import |
| 7 | # |
Inaky Perez-Gonzalez | 662dde6 | 2017-07-24 10:24:35 -0700 | [diff] [blame] | 8 | # Set of code that other projects can also import to do things on |
| 9 | # Zephyr's sanity check testcases. |
| 10 | |
| 11 | import logging |
Inaky Perez-Gonzalez | 662dde6 | 2017-07-24 10:24:35 -0700 | [diff] [blame] | 12 | import yaml |
Anas Nashif | ae61b7e | 2020-07-06 11:30:55 -0400 | [diff] [blame] | 13 | try: |
| 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 |
| 19 | except ImportError: |
| 20 | from yaml import Loader, SafeLoader, Dumper |
Inaky Perez-Gonzalez | 662dde6 | 2017-07-24 10:24:35 -0700 | [diff] [blame] | 21 | |
| 22 | log = logging.getLogger("scl") |
| 23 | |
Grzegorz Chwierut | f53a0e9 | 2023-09-15 15:21:06 +0200 | [diff] [blame] | 24 | |
| 25 | class EmptyYamlFileException(Exception): |
| 26 | pass |
| 27 | |
| 28 | |
Inaky Perez-Gonzalez | 662dde6 | 2017-07-24 10:24:35 -0700 | [diff] [blame] | 29 | # |
| 30 | # |
| 31 | def yaml_load(filename): |
| 32 | """ |
| 33 | Safely load a YAML document |
| 34 | |
Nazar Kazakov | f483b1b | 2022-03-16 21:07:43 +0000 | [diff] [blame] | 35 | Follows recommendations from |
Inaky Perez-Gonzalez | 662dde6 | 2017-07-24 10:24:35 -0700 | [diff] [blame] | 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 |
Nazar Kazakov | f483b1b | 2022-03-16 21:07:43 +0000 | [diff] [blame] | 40 | :raises: any other exception on file access errors |
Inaky Perez-Gonzalez | 662dde6 | 2017-07-24 10:24:35 -0700 | [diff] [blame] | 41 | :return: dictionary representing the YAML document |
| 42 | """ |
| 43 | try: |
Pavlo Havrylyuk | fa56366 | 2023-09-12 09:38:52 -0700 | [diff] [blame] | 44 | with open(filename, 'r', encoding='utf-8') as f: |
Anas Nashif | ae61b7e | 2020-07-06 11:30:55 -0400 | [diff] [blame] | 45 | return yaml.load(f, Loader=SafeLoader) |
Inaky Perez-Gonzalez | 662dde6 | 2017-07-24 10:24:35 -0700 | [diff] [blame] | 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 | |
Nazar Kazakov | f483b1b | 2022-03-16 21:07:43 +0000 | [diff] [blame] | 54 | # If pykwalify is installed, then the validate function will work -- |
Inaky Perez-Gonzalez | 662dde6 | 2017-07-24 10:24:35 -0700 | [diff] [blame] | 55 | # otherwise, it is a stub and we'd warn about it. |
| 56 | try: |
| 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 |
Ulf Magnusson | 0d39a10 | 2019-09-06 11:13:19 +0200 | [diff] [blame] | 64 | c = pykwalify.core.Core(source_data=data, schema_data=schema) |
| 65 | c.validate(raise_exception=True) |
Inaky Perez-Gonzalez | 662dde6 | 2017-07-24 10:24:35 -0700 | [diff] [blame] | 66 | |
| 67 | except 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 | |
| 72 | def yaml_load_verify(filename, schema): |
| 73 | """ |
| 74 | Safely load a testcase/sample yaml document and validate it |
Nazar Kazakov | f483b1b | 2022-03-16 21:07:43 +0000 | [diff] [blame] | 75 | against the YAML schema, returning in case of success the YAML data. |
Inaky Perez-Gonzalez | 662dde6 | 2017-07-24 10:24:35 -0700 | [diff] [blame] | 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) |
Grzegorz Chwierut | f53a0e9 | 2023-09-15 15:21:06 +0200 | [diff] [blame] | 86 | if not y: |
| 87 | raise EmptyYamlFileException('No data in YAML file: %s' % filename) |
Inaky Perez-Gonzalez | 662dde6 | 2017-07-24 10:24:35 -0700 | [diff] [blame] | 88 | _yaml_validate(y, schema) |
| 89 | return y |