From cf39406196a2d4d38954c9d036987ad3213a7ae7 Mon Sep 17 00:00:00 2001 From: Andrzej Kurek Date: Wed, 15 Feb 2023 05:42:02 -0500 Subject: [PATCH 1/6] Use config.py as a module in depends.py Signed-off-by: Andrzej Kurek --- tests/scripts/depends.py | 94 ++++++++++++++++++++++++---------------- 1 file changed, 56 insertions(+), 38 deletions(-) diff --git a/tests/scripts/depends.py b/tests/scripts/depends.py index b8bcfd256..4369246f5 100755 --- a/tests/scripts/depends.py +++ b/tests/scripts/depends.py @@ -23,7 +23,7 @@ Test Mbed TLS with a subset of algorithms. This script can be divided into several steps: First, include/mbedtls/config.h or a different config file passed -in the arguments is parsed to extract any configuration options (collect_config_symbols). +in the arguments is parsed to extract any configuration options (using config.py). Then, test domains (groups of jobs, tests) are built based on predefined data collected in the DomainData class. Here, each domain has five major traits: @@ -60,6 +60,9 @@ import subprocess import sys import traceback +import scripts_path # pylint: disable=unused-import +import config + class Colors: # pylint: disable=too-few-public-methods """Minimalistic support for colored output. Each field of an object of this class is either None if colored output @@ -68,6 +71,7 @@ that outputting start switches the text color to the desired color and stop switches the text color back to the default.""" red = None green = None + cyan = None bold_red = None bold_green = None def __init__(self, options=None): @@ -83,6 +87,7 @@ stop switches the text color back to the default.""" normal = '\033[0m' self.red = ('\033[31m', normal) self.green = ('\033[32m', normal) + self.cyan = ('\033[36m', normal) self.bold_red = ('\033[1;31m', normal) self.bold_green = ('\033[1;32m', normal) NO_COLORS = Colors(None) @@ -118,34 +123,39 @@ Remove the backup file if it was saved earlier.""" else: shutil.copy(options.config_backup, options.config) -def run_config_py(options, args): - """Run scripts/config.py with the specified arguments.""" - cmd = ['scripts/config.py'] - if options.config != 'include/mbedtls/config.h': - cmd += ['--file', options.config] - cmd += args - log_command(cmd) - subprocess.check_call(cmd) +def option_exists(conf, option): + if option not in conf.settings: + return False + return True -def set_reference_config(options): +def set_config_option(conf, option, colors, value=None): + """Set configuration option, optionally specifying a value""" + if not option_exists(conf, option): + log_line('Symbol {} was not found in {}'.format(option, conf.filename), color=colors.red) + return False + log_command(['config.py', 'set', option]) + conf.set(option, value) + return True + +def unset_config_option(conf, option, colors): + """Unset configuration option if it exists""" + if not option_exists(conf, option): + log_line('Symbol {} was not found in {}'.format(option, conf.filename), color=colors.red) + return False + log_command(['config.py', 'unset', option]) + conf.unset(option) + return True + +def set_reference_config(conf, options, colors): """Change the library configuration file (config.h) to the reference state. The reference state is the one from which the tested configurations are derived.""" # Turn off options that are not relevant to the tests and slow them down. - run_config_py(options, ['full']) - run_config_py(options, ['unset', 'MBEDTLS_TEST_HOOKS']) + log_command(['config.py', 'full']) + conf.adapt(config.full_adapter) + unset_config_option(conf, 'MBEDTLS_TEST_HOOKS', colors) if options.unset_use_psa: - run_config_py(options, ['unset', 'MBEDTLS_USE_PSA_CRYPTO']) - -def collect_config_symbols(options): - """Read the list of settings from config.h. -Return them in a generator.""" - with open(options.config, encoding="utf-8") as config_file: - rx = re.compile(r'\s*(?://\s*)?#define\s+(\w+)\s*(?:$|/[/*])') - for line in config_file: - m = re.match(rx, line) - if m: - yield m.group(1) + unset_config_option(conf, 'MBEDTLS_USE_PSA_CRYPTO', colors) class Job: """A job builds the library in a specific configuration and runs some tests.""" @@ -173,19 +183,22 @@ If what is False, announce that the job has failed.''' elif what is False: log_line(self.name + ' FAILED', color=colors.red) else: - log_line('starting ' + self.name) + log_line('starting ' + self.name, color=colors.cyan) - def configure(self, options): + def configure(self, conf, options, colors): '''Set library configuration options as required for the job.''' - set_reference_config(options) + set_reference_config(conf, options, colors) for key, value in sorted(self.config_settings.items()): + ret = False if value is True: - args = ['set', key] + ret = set_config_option(conf, key, colors) elif value is False: - args = ['unset', key] + ret = unset_config_option(conf, key, colors) else: - args = ['set', key, value] - run_config_py(options, args) + ret = set_config_option(conf, key, colors, value) + if ret is False: + return False + return True def test(self, options): '''Run the job's build and test commands. @@ -400,11 +413,11 @@ class DomainData: return [symbol for symbol in self.all_config_symbols if re.match(regexp, symbol)] - def __init__(self, options): + def __init__(self, options, conf): """Gather data about the library and establish a list of domains to test.""" build_command = [options.make_command, 'CFLAGS=-Werror'] build_and_test = [build_command, [options.make_command, 'test']] - self.all_config_symbols = set(collect_config_symbols(options)) + self.all_config_symbols = set(conf.settings.keys()) # Find hash modules by name. hash_symbols = self.config_symbols_matching(r'MBEDTLS_(MD|RIPEMD|SHA)[0-9]+_C\Z') hash_symbols.append("MBEDTLS_SHA512_NO_SHA384") @@ -456,16 +469,19 @@ A name can either be the name of a domain or the name of one specific job.""" else: return [self.jobs[name]] -def run(options, job, colors=NO_COLORS): +def run(options, job, conf, colors=NO_COLORS): """Run the specified job (a Job instance).""" subprocess.check_call([options.make_command, 'clean']) job.announce(colors, None) - job.configure(options) + if not job.configure(conf, options, colors): + job.announce(colors, False) + return False + conf.write() success = job.test(options) job.announce(colors, success) return success -def run_tests(options, domain_data): +def run_tests(options, domain_data, conf): """Run the desired jobs. domain_data should be a DomainData instance that describes the available domains and jobs. @@ -481,7 +497,7 @@ Run the jobs listed in options.tasks.""" backup_config(options) try: for job in jobs: - success = run(options, job, colors=colors) + success = run(options, job, conf, colors=colors) if not success: if options.keep_going: failures.append(job.name) @@ -547,7 +563,9 @@ def main(): default=True) options = parser.parse_args() os.chdir(options.directory) - domain_data = DomainData(options) + conf = config.ConfigFile(options.config) + domain_data = DomainData(options, conf) + if options.tasks is True: options.tasks = sorted(domain_data.domains.keys()) if options.list: @@ -556,7 +574,7 @@ def main(): print(domain_name) sys.exit(0) else: - sys.exit(0 if run_tests(options, domain_data) else 1) + sys.exit(0 if run_tests(options, domain_data, conf) else 1) except Exception: # pylint: disable=broad-except traceback.print_exc() sys.exit(3) From 2e1aeb129d620baa632f2c1a9aaea869d9fd7497 Mon Sep 17 00:00:00 2001 From: Andrzej Kurek Date: Mon, 23 Jan 2023 07:19:22 -0500 Subject: [PATCH 2/6] depends.py: merge set/unset config option into one function Signed-off-by: Andrzej Kurek --- tests/scripts/depends.py | 38 ++++++++++++++++---------------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/tests/scripts/depends.py b/tests/scripts/depends.py index 4369246f5..1ab6d70b4 100755 --- a/tests/scripts/depends.py +++ b/tests/scripts/depends.py @@ -59,7 +59,7 @@ import shutil import subprocess import sys import traceback - +# Add the Mbed TLS Python library directory to the module search path import scripts_path # pylint: disable=unused-import import config @@ -128,22 +128,22 @@ def option_exists(conf, option): return False return True -def set_config_option(conf, option, colors, value=None): - """Set configuration option, optionally specifying a value""" +def set_config_option_value(conf, option, colors, value): + """Set/unset a configuration option, optionally specifying a value""" if not option_exists(conf, option): log_line('Symbol {} was not found in {}'.format(option, conf.filename), color=colors.red) return False - log_command(['config.py', 'set', option]) - conf.set(option, value) - return True -def unset_config_option(conf, option, colors): - """Unset configuration option if it exists""" - if not option_exists(conf, option): - log_line('Symbol {} was not found in {}'.format(option, conf.filename), color=colors.red) - return False - log_command(['config.py', 'unset', option]) - conf.unset(option) + if value is False: + log_command(['config.py', 'unset', option]) + conf.unset(option) + else: + if value is True: + log_command(['config.py', 'set', option]) + conf.set(option) + else: + log_command(['config.py', 'set', option, value]) + conf.set(option, value) return True def set_reference_config(conf, options, colors): @@ -153,9 +153,9 @@ derived.""" # Turn off options that are not relevant to the tests and slow them down. log_command(['config.py', 'full']) conf.adapt(config.full_adapter) - unset_config_option(conf, 'MBEDTLS_TEST_HOOKS', colors) + set_config_option_value(conf, 'MBEDTLS_TEST_HOOKS', colors, False) if options.unset_use_psa: - unset_config_option(conf, 'MBEDTLS_USE_PSA_CRYPTO', colors) + set_config_option_value(conf, 'MBEDTLS_USE_PSA_CRYPTO', colors, False) class Job: """A job builds the library in a specific configuration and runs some tests.""" @@ -189,13 +189,7 @@ If what is False, announce that the job has failed.''' '''Set library configuration options as required for the job.''' set_reference_config(conf, options, colors) for key, value in sorted(self.config_settings.items()): - ret = False - if value is True: - ret = set_config_option(conf, key, colors) - elif value is False: - ret = unset_config_option(conf, key, colors) - else: - ret = set_config_option(conf, key, colors, value) + ret = set_config_option_value(conf, key, colors, value) if ret is False: return False return True From 2432dc212e14749a8d2b3abf5689765c4e89c725 Mon Sep 17 00:00:00 2001 From: Andrzej Kurek Date: Tue, 24 Jan 2023 07:40:42 -0500 Subject: [PATCH 3/6] depends.py: improve expected argument type Requested config option can be either boolean or a string. Signed-off-by: Andrzej Kurek --- tests/scripts/depends.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/scripts/depends.py b/tests/scripts/depends.py index 1ab6d70b4..9c3c49a9a 100755 --- a/tests/scripts/depends.py +++ b/tests/scripts/depends.py @@ -59,6 +59,8 @@ import shutil import subprocess import sys import traceback +from typing import Union + # Add the Mbed TLS Python library directory to the module search path import scripts_path # pylint: disable=unused-import import config @@ -128,8 +130,10 @@ def option_exists(conf, option): return False return True -def set_config_option_value(conf, option, colors, value): - """Set/unset a configuration option, optionally specifying a value""" +def set_config_option_value(conf, option, colors, value: Union[bool, str]): + """Set/unset a configuration option, optionally specifying a value. +value can be either True/False (set/unset config option), or a string, +which will make a symbol defined with a certain value.""" if not option_exists(conf, option): log_line('Symbol {} was not found in {}'.format(option, conf.filename), color=colors.red) return False From 3ebe7d62609b58011cb3a011978bc677453b7bb5 Mon Sep 17 00:00:00 2001 From: Andrzej Kurek Date: Mon, 6 Feb 2023 10:48:43 +0100 Subject: [PATCH 4/6] Improve tests/scripts/depends.py code As suggested by gilles-peskine-arm. Co-authored-by: Gilles Peskine Signed-off-by: Andrzej Kurek --- tests/scripts/depends.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/scripts/depends.py b/tests/scripts/depends.py index 9c3c49a9a..e604512d1 100755 --- a/tests/scripts/depends.py +++ b/tests/scripts/depends.py @@ -126,9 +126,7 @@ Remove the backup file if it was saved earlier.""" shutil.copy(options.config_backup, options.config) def option_exists(conf, option): - if option not in conf.settings: - return False - return True + return option in conf.settings def set_config_option_value(conf, option, colors, value: Union[bool, str]): """Set/unset a configuration option, optionally specifying a value. From 3e7666b95defe685dbf8fde999926ea52a501144 Mon Sep 17 00:00:00 2001 From: Andrzej Kurek Date: Mon, 6 Feb 2023 10:49:46 +0100 Subject: [PATCH 5/6] Improve tests/scripts/depends.py code As suggested by gilles-peskine-arm. Co-authored-by: Gilles Peskine Signed-off-by: Andrzej Kurek --- tests/scripts/depends.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/tests/scripts/depends.py b/tests/scripts/depends.py index e604512d1..182471376 100755 --- a/tests/scripts/depends.py +++ b/tests/scripts/depends.py @@ -139,13 +139,12 @@ which will make a symbol defined with a certain value.""" if value is False: log_command(['config.py', 'unset', option]) conf.unset(option) + elif value is True: + log_command(['config.py', 'set', option]) + conf.set(option) else: - if value is True: - log_command(['config.py', 'set', option]) - conf.set(option) - else: - log_command(['config.py', 'set', option, value]) - conf.set(option, value) + log_command(['config.py', 'set', option, value]) + conf.set(option, value) return True def set_reference_config(conf, options, colors): From b790c935e6d48039ec2d49731739fea1b64fef3d Mon Sep 17 00:00:00 2001 From: Andrzej Kurek Date: Wed, 15 Feb 2023 15:19:37 -0500 Subject: [PATCH 6/6] depends.py: remove symbols that are not present in 2.28 Signed-off-by: Andrzej Kurek --- tests/scripts/depends.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tests/scripts/depends.py b/tests/scripts/depends.py index 182471376..f107dd5cf 100755 --- a/tests/scripts/depends.py +++ b/tests/scripts/depends.py @@ -259,11 +259,7 @@ REVERSE_DEPENDENCIES = { 'MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED'], 'MBEDTLS_SHA1_C': SSL_PRE_1_2_DEPENDENCIES, 'MBEDTLS_SHA256_C': ['MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED', - 'MBEDTLS_ENTROPY_FORCE_SHA256', - 'MBEDTLS_SHA256_USE_A64_CRYPTO_IF_PRESENT', - 'MBEDTLS_SHA256_USE_A64_CRYPTO_ONLY'], - 'MBEDTLS_SHA512_C': ['MBEDTLS_SHA512_USE_A64_CRYPTO_IF_PRESENT', - 'MBEDTLS_SHA512_USE_A64_CRYPTO_ONLY'], + 'MBEDTLS_ENTROPY_FORCE_SHA256'], 'MBEDTLS_X509_RSASSA_PSS_SUPPORT': [] }