From 58822b18df395213c2b7af961a470e1ecee7ed8e Mon Sep 17 00:00:00 2001 From: Jack Lloyd Date: Fri, 24 Jul 2026 11:08:28 -0400 Subject: [PATCH] Fix various lint warnings from ruff 0.16 --- configure.py | 130 ++++++++---------- src/configs/ruff.toml | 11 ++ src/configs/sphinx/conf.py | 15 +- src/ct_selftest/ct_selftest.py | 8 +- src/editors/vscode/scripts/bogo.py | 6 +- src/editors/vscode/scripts/common.py | 7 +- src/editors/vscode/scripts/test.py | 6 +- src/python/botan3.py | 62 +++++---- src/scripts/acvp_tests.py | 6 +- src/scripts/bench.py | 32 ++--- src/scripts/build_docs.py | 15 +- src/scripts/check.py | 3 +- src/scripts/ci/download_ci_dep.py | 1 + src/scripts/ci/gh_clang_tidy_fixes_in_pr.py | 6 +- src/scripts/ci/gha_linux_packages.py | 1 + src/scripts/ci/setup_gh_actions.sh | 2 +- src/scripts/ci_build.py | 28 ++-- src/scripts/ci_check_generated_files.py | 1 - src/scripts/ci_check_headers.py | 6 +- src/scripts/ci_check_install.py | 10 +- src/scripts/ci_report_sizes.py | 4 +- src/scripts/cleanup.py | 20 +-- src/scripts/compare_perf.py | 5 +- src/scripts/config_for_oss_fuzz.py | 4 +- src/scripts/create_corpus_zip.py | 5 +- src/scripts/dev_tools/addchain.py | 9 +- .../dev_tools/analyze_timing_results.py | 4 +- src/scripts/dev_tools/file_size_check.py | 5 +- .../dev_tools/format_wycheproof_ecdsa.py | 3 +- src/scripts/dev_tools/gen_dilithium_kat.py | 5 +- src/scripts/dev_tools/gen_ec_groups.py | 9 +- src/scripts/dev_tools/gen_ffi_decls.py | 1 + src/scripts/dev_tools/gen_frodo_kat.py | 9 +- src/scripts/dev_tools/gen_kyber_kat.py | 11 +- src/scripts/dev_tools/gen_mlkem_acvp_kat.py | 13 +- src/scripts/dev_tools/gen_mp_comba.py | 12 +- src/scripts/dev_tools/gen_mp_monty.py | 9 +- src/scripts/dev_tools/gen_oids.py | 4 +- src/scripts/dev_tools/gen_os_features.py | 14 +- src/scripts/dev_tools/gen_pqc_dsa_kats.py | 13 +- src/scripts/dev_tools/gen_sphincsplus_kat.py | 9 +- src/scripts/dev_tools/gen_tls_suite_info.py | 13 +- src/scripts/dev_tools/macro_checks.py | 5 +- src/scripts/dev_tools/run_clang_format.py | 17 ++- src/scripts/dev_tools/run_clang_tidy.py | 16 +-- src/scripts/dev_tools/show_dependencies.py | 29 ++-- .../xmss_test_vector_from_reference.py | 35 +++-- src/scripts/dist.py | 4 +- src/scripts/gdb/strubtest.py | 1 + src/scripts/install.py | 7 +- src/scripts/python_unittests.py | 57 ++++---- src/scripts/python_unittests_unix.py | 6 +- src/scripts/repo_config.py | 2 +- src/scripts/rewrite_lcov.py | 5 +- src/scripts/run_limbo_tests.py | 15 +- src/scripts/run_tests_under_valgrind.py | 8 +- src/scripts/run_tls_attacker.py | 9 +- src/scripts/run_tls_fuzzer.py | 10 +- src/scripts/test_all_configs.py | 5 +- src/scripts/test_cli.py | 28 ++-- src/scripts/test_cli_crypt.py | 22 ++- src/scripts/test_fuzzers.py | 27 ++-- src/scripts/test_python.py | 17 +-- src/scripts/test_strubbed_symbols.py | 9 +- .../tls_anvil/analyze_tls_anvil_report.py | 15 +- src/scripts/tls_anvil/run_tls_anvil_tests.py | 4 +- .../tls_anvil/tls_anvil_trigger_server.py | 7 +- src/scripts/tls_scanner/tls_scanner.py | 27 ++-- src/scripts/website.py | 11 +- src/scripts/wycheproof.py | 37 +++-- 70 files changed, 494 insertions(+), 478 deletions(-) create mode 100644 src/configs/ruff.toml mode change 100755 => 100644 src/python/botan3.py mode change 100644 => 100755 src/scripts/dev_tools/gen_frodo_kat.py mode change 100644 => 100755 src/scripts/dev_tools/gen_mlkem_acvp_kat.py mode change 100644 => 100755 src/scripts/repo_config.py mode change 100644 => 100755 src/scripts/test_python.py diff --git a/configure.py b/configure.py index bc836f51365..87b692a5371 100755 --- a/configure.py +++ b/configure.py @@ -15,8 +15,10 @@ import collections import copy +import errno import json -import sys +import logging +import optparse # pylint: disable=deprecated-module import os import os.path import platform @@ -24,11 +26,10 @@ import shlex import shutil import subprocess -import traceback -import logging +import sys import time -import errno -import optparse # pylint: disable=deprecated-module +import traceback + # An error caused by and to be fixed by the user, e.g. invalid command line argument class UserError(Exception): @@ -42,7 +43,7 @@ class InternalError(Exception): def flatten(lst): - return sum(lst, []) + return [elem for sub in lst for elem in sub] def normalize_source_path(source): """ @@ -73,7 +74,7 @@ def parse_version_file(version_path): key_and_val = re.compile(r"([a-z_]+) = ([a-zA-Z0-9:\-\']+)") results = {} - for line in version_file.readlines(): + for line in version_file: if not line or line[0] == '#': continue match = key_and_val.match(line) @@ -95,7 +96,7 @@ class Version: """ Version information are all static members """ - data = {} + data = {} # noqa: RUF012 @staticmethod def get_data(): @@ -769,7 +770,7 @@ def parse_lex_dict(as_list, map_name, infofile): raise InternalError("Lex dictionary has invalid format (input not divisible by 3): %s" % as_list) result = {} - for key, sep, value in [as_list[3*i:3*i+3] for i in range(0, len(as_list)//3)]: + for key, sep, value in [as_list[3*i:3*i+3] for i in range(len(as_list)//3)]: if sep != '->': raise InternalError("Map %s in %s has invalid format" % (map_name, infofile)) if key in result: @@ -825,7 +826,7 @@ def lexed_tokens(): # Convert to an iterator raise LexerError('Group "%s" not terminated' % (group), infofile, lexer.lineno) - elif token in name_val_pairs.keys(): + elif token in name_val_pairs: if isinstance(out.__dict__[token], list): out.__dict__[token].append(lexer.get_token()) else: @@ -1020,9 +1021,7 @@ def known_isa(isa): return True compound_isa = isa.split(':') - if len(compound_isa) == 2 and compound_isa[0] in arch_info and compound_isa[1] in all_isa_extn: - return True - return False + return len(compound_isa) == 2 and compound_isa[0] in arch_info and compound_isa[1] in all_isa_extn for isa in self.isa: if not known_isa(isa): @@ -1074,11 +1073,7 @@ def compatible_cpu(self, archinfo, options): if isa not in archinfo.isa_extensions: return False - if self.arch != []: - if arch_name not in self.arch and cpu_name not in self.arch: - return False - - return True + return self.arch == [] or arch_name in self.arch or cpu_name in self.arch def compatible_os(self, os_data, options): if not self.os_features: @@ -1186,10 +1181,7 @@ def is_dependency_on_virtual(this_module, dependency): if not dependency.is_virtual(): return False - if this_module.parent_module == dependency.basename: - return False - - return True + return this_module.parent_module != dependency.basename missing = [s for s in self.dependencies(None, None) if s not in modules or is_dependency_on_virtual(self, modules[s])] @@ -1273,9 +1265,9 @@ def supported_isa_extensions(self, cc, options): isas = [] for isa in self.isa_extensions: - if (isa, self.basename) not in options.disable_intrinsics: - if cc.isa_flags_for(isa, self.basename) is not None: - isas.append(isa) + if (isa, self.basename) not in options.disable_intrinsics and \ + cc.isa_flags_for(isa, self.basename) is not None: + isas.append(isa) return sorted(isas) @@ -1477,7 +1469,7 @@ def mach_abi_groups(): else: yield 'rt' - for all_except in [s for s in self.mach_abi_linking.keys() if s.startswith('all!')]: + for all_except in [s for s in self.mach_abi_linking if s.startswith('all!')]: exceptions = all_except[4:].split(',') if options.os not in exceptions and options.arch not in exceptions: yield all_except @@ -1582,10 +1574,9 @@ def cc_compile_flags(self, options): if options.arch in self.cpu_flags: yield self.cpu_flags[options.arch] - if options.arch in self.cpu_flags_no_debug: - # Only enable these if no debug/sanitizer options enabled - if not (options.debug_mode or sanitizers_enabled): - yield self.cpu_flags_no_debug[options.arch] + # Only enable these if no debug/sanitizer options enabled + if options.arch in self.cpu_flags_no_debug and not (options.debug_mode or sanitizers_enabled): + yield self.cpu_flags_no_debug[options.arch] yield from options.extra_cxxflags @@ -1737,12 +1728,12 @@ def enabled_features(self, options): return sorted(feats) def enabled_features_public(self, options): - public_feat = set(['threads', 'filesystem']) - return sorted(list(set(self.enabled_features(options)) & public_feat)) + public_feat = {'threads', 'filesystem'} + return sorted(set(self.enabled_features(options)) & public_feat) def enabled_features_internal(self, options): - public_feat = set(['threads', 'filesystem']) - return sorted(list(set(self.enabled_features(options)) - public_feat)) + public_feat = {'threads', 'filesystem'} + return sorted(set(self.enabled_features(options)) - public_feat) def macros(self, cc): value = [cc.add_compile_definition_option + define @@ -1872,12 +1863,10 @@ def insert_join(match): cond_type = cond_match.group(1) cond_var = cond_match.group(2) - include_cond = False - - if cond_type == 'if' and cond_var in self.vals and self.vals.get(cond_var): - include_cond = True - elif cond_type == 'unless' and (cond_var not in self.vals or (not self.vals.get(cond_var))): - include_cond = True + if cond_type == 'if': + include_cond = bool(self.vals.get(cond_var)) + else: # unless + include_cond = not self.vals.get(cond_var) idx += 1 while idx < len(lines): @@ -1949,6 +1938,16 @@ def process_template(template_file, variables): def yield_objectfile_list(sources, obj_dir, obj_suffix, options): obj_suffix = '.' + obj_suffix + def fixup_obj_name(name): + def remove_dups(parts): + last = None + for part in parts: + if last is None or part != last: + last = part + yield part + + return '_'.join(remove_dups(name.split('_'))) + for src in sources: (directory, filename) = os.path.split(os.path.normpath(src)) parts_in_src = directory.split('src' + os.sep) @@ -1966,16 +1965,6 @@ def yield_objectfile_list(sources, obj_dir, obj_suffix, options): else: name = '_'.join(parts) + '_' + filename - def fixup_obj_name(name): - def remove_dups(parts): - last = None - for part in parts: - if last is None or part != last: - last = part - yield part - - return '_'.join(remove_dups(name.split('_'))) - name = fixup_obj_name(name) else: name = filename @@ -2643,7 +2632,7 @@ def resolve_dependencies(available_modules, dependency_table, module, loaded_mod - loaded_modules: modules already loaded. Defensive copy in order to not change value for caller. """ if loaded_modules is None: - loaded_modules = set([]) + loaded_modules = set() else: loaded_modules = copy.copy(loaded_modules) @@ -2740,13 +2729,12 @@ def choose(self): else: self._handle_by_load_on(module) - if 'compression' in self._to_load: - # Confirm that we have at least one compression library enabled - # Otherwise we leave a lot of useless support code compiled in, plus a - # make_compressor call that always fails - if 'zlib' not in self._to_load and 'bzip2' not in self._to_load and 'lzma' not in self._to_load: - self._to_load.remove('compression') - self._not_using_because['no enabled compression schemes'].add('compression') + # Confirm that we have at least one compression library enabled + # Otherwise we leave a lot of useless support code compiled in, plus a + # make_compressor call that always fails + if 'compression' in self._to_load and not self._to_load & {'zlib', 'bzip2', 'lzma'}: + self._to_load.remove('compression') + self._not_using_because['no enabled compression schemes'].add('compression') # The AVX2 implementation of Argon2 fails when compiled by GCC in # amalgamation mode. @@ -2882,7 +2870,7 @@ def __init__(self, input_filepaths): try: contents = AmalgamationGenerator.read_header(filepath) self.file_contents[os.path.basename(filepath)] = contents - except IOError as ex: + except OSError as ex: logging.error('Error processing file %s for amalgamation: %s', filepath, ex) self.contents = '' @@ -2982,10 +2970,7 @@ def generate(self): logging.info('Writing amalgamation header to %s', amalgamation_header_fsname) pub_header_amalag.write_to_file(amalgamation_header_fsname, "BOTAN_AMALGAMATION_H_") - internal_headers_list = [] - - for hdr in self._build_paths.internal_headers: - internal_headers_list.append(hdr) + internal_headers_list = list(self._build_paths.internal_headers) # file descriptors for all `amalgamation_sources` amalgamation_fsname = '%s.cpp' % (self._filename_prefix) @@ -3000,7 +2985,7 @@ def generate(self): amalgamation_file.write(internal_headers.header_includes) amalgamation_file.write(internal_headers.contents) - unconditional_headers = set([]) + unconditional_headers = set() for mod in sorted(self._modules, key=lambda module: module.basename): for src in sorted(mod.source): @@ -3298,9 +3283,8 @@ def canonicalize_build_targets(options): if options.os == 'windows' and options.build_shared_lib is None and options.build_static_lib is None: options.build_shared_lib = True - if options.with_stack_protector is None: - if options.os in info_os: - options.with_stack_protector = info_os[options.os].use_stack_protector + if options.with_stack_protector is None and options.os in info_os: + options.with_stack_protector = info_os[options.os].use_stack_protector if options.build_shared_lib is None: if options.os == 'windows' and options.build_static_lib: @@ -3408,9 +3392,8 @@ def validate_options(options, info_os, info_cc, available_module_policies): if options.with_texinfo and not options.with_sphinx: raise UserError('Option --with-texinfo requires --with-sphinx') - if options.ct_value_barrier_type: - if options.ct_value_barrier_type not in ['asm', 'volatile', 'none']: - raise UserError('Unknown setting "%s" for --ct-value-barrier-type' % (options.ct_value_barrier_type)) + if options.ct_value_barrier_type and options.ct_value_barrier_type not in ['asm', 'volatile', 'none']: + raise UserError('Unknown setting "%s" for --ct-value-barrier-type' % (options.ct_value_barrier_type)) # Warnings if options.os == 'windows' and options.compiler not in ('msvc', 'clangcl'): @@ -3662,8 +3645,7 @@ def escape_build_lines(contents): with open(rst2man_file, 'w', encoding='utf8') as f: f.write(rst2man_header) f.write("\n") - for line in cli_doc_contents: - f.write(line) + f.writelines(cli_doc_contents) date = 'dated %d' % (Version.datestamp()) if Version.datestamp() != 0 else 'undated' @@ -3682,8 +3664,8 @@ def escape_build_lines(contents): def list_os_features(all_os_features, info_os): for feat in all_os_features: - os_with_feat = [o for o in info_os.keys() if feat in info_os[o].target_features] - os_without_feat = [o for o in info_os.keys() if feat not in info_os[o].target_features] + os_with_feat = [o for o in info_os if feat in info_os[o].target_features] + os_without_feat = [o for o in info_os if feat not in info_os[o].target_features] if len(os_with_feat) < len(os_without_feat): print("%s: %s" % (feat, ' '.join(sorted(os_with_feat)))) diff --git a/src/configs/ruff.toml b/src/configs/ruff.toml new file mode 100644 index 00000000000..59c981686d5 --- /dev/null +++ b/src/configs/ruff.toml @@ -0,0 +1,11 @@ +target-version = "py38" + +[lint] +ignore = [ + "BLE001", # catching Exception in a script's top level error handler is fine + "DTZ", # datetimes are fine in build/dev scripts + "LOG015", # standalone scripts use the root logger on purpose + "SIM115", # not worth rewriting every open() into a with block + "TRY002", # raising plain Exception is fine for standalone scripts + "UP031", # printf-style formatting is fine +] diff --git a/src/configs/sphinx/conf.py b/src/configs/sphinx/conf.py index db06544ed69..b42e6a6afee 100644 --- a/src/configs/sphinx/conf.py +++ b/src/configs/sphinx/conf.py @@ -1,8 +1,7 @@ -# -* coding: utf-8 -*- # Sphinx configuration file -import sys import re +import sys #import sphinx @@ -21,7 +20,7 @@ def parse_version_file(version_path): key_and_val = re.compile(r"([a-z_]+) = ([a-zA-Z0-9:\-\']+)") results = {} - for line in version_file.readlines(): + for line in version_file: if not line or line[0] == '#': continue match = key_and_val.match(line) @@ -58,8 +57,8 @@ def parse_version_file(version_path): master_doc = 'contents' -project = u'botan' -copyright = u'2000-2023, The Botan Authors' +project = 'botan' +copyright = '2000-2023, The Botan Authors' version = '%d.%d' % (version_major, version_minor) release = '%d.%d.%d%s' % (version_major, version_minor, version_patch, version_suffix) @@ -101,7 +100,7 @@ def parse_version_file(version_path): try: # On Arch this is python-sphinx-furo - import furo # noqa: F401 + import furo # noqa: F401 html_theme = "furo" # Add a small edit button to each document to allow visitors to easily @@ -195,9 +194,9 @@ def parse_version_file(version_path): # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). -authors = u'The Botan Authors' +authors = 'The Botan Authors' latex_documents = [ - ('contents', 'botan.tex', u'Botan Reference Guide', authors, 'manual'), + ('contents', 'botan.tex', 'Botan Reference Guide', authors, 'manual'), ] # The name of an image file (relative to this directory) to place at the top of diff --git a/src/ct_selftest/ct_selftest.py b/src/ct_selftest/ct_selftest.py index 436be820909..0aed437232a 100755 --- a/src/ct_selftest/ct_selftest.py +++ b/src/ct_selftest/ct_selftest.py @@ -8,14 +8,16 @@ Botan is released under the Simplified BSD License (see license.txt) """ +from __future__ import annotations -import subprocess import argparse +import json import os +import subprocess import sys -from typing import Self from enum import StrEnum, auto -import json +from typing import Self + def run_command(cmd: list[str], is_text = True): """ Run the command . """ diff --git a/src/editors/vscode/scripts/bogo.py b/src/editors/vscode/scripts/bogo.py index c88084e48d0..9601c393844 100755 --- a/src/editors/vscode/scripts/bogo.py +++ b/src/editors/vscode/scripts/bogo.py @@ -3,7 +3,9 @@ import argparse import os import sys -from common import run_cmd, get_concurrency + +from common import get_concurrency, run_cmd + def find_repo_root(): current_dir = os.path.dirname(os.path.abspath(__file__)) @@ -17,7 +19,7 @@ def find_repo_root(): REPO_ROOT = find_repo_root() sys.path.insert(0, os.path.join(REPO_ROOT, 'src', 'scripts')) -from repo_config import RepoConfig # noqa: E402 pylint: disable=wrong-import-position +from repo_config import RepoConfig # pylint: disable=wrong-import-position BORING_PATH = os.path.join(REPO_ROOT, "build_deps", "boringssl") BOGO_PATH = os.path.join(BORING_PATH, "ssl", "test", "runner") diff --git a/src/editors/vscode/scripts/common.py b/src/editors/vscode/scripts/common.py index 55fbf44941c..7879c6730c3 100644 --- a/src/editors/vscode/scripts/common.py +++ b/src/editors/vscode/scripts/common.py @@ -1,8 +1,9 @@ +import multiprocessing import os -import sys -import subprocess import re -import multiprocessing +import subprocess +import sys + class BuildError(Exception): pass diff --git a/src/editors/vscode/scripts/test.py b/src/editors/vscode/scripts/test.py index ef69059928b..2b90be0cf99 100755 --- a/src/editors/vscode/scripts/test.py +++ b/src/editors/vscode/scripts/test.py @@ -1,9 +1,9 @@ #!/usr/bin/env python3 -import os -import re import argparse import glob +import os +import re import common @@ -11,7 +11,7 @@ def discover_tests_in_file(test_file): - if not os.path.dirname(test_file) == TESTS_DIR: + if os.path.dirname(test_file) != TESTS_DIR: return [] with open(test_file, 'r', encoding='utf-8') as f: diff --git a/src/python/botan3.py b/src/python/botan3.py old mode 100755 new mode 100644 index 47432105178..b03df0166f7 --- a/src/python/botan3.py +++ b/src/python/botan3.py @@ -17,17 +17,37 @@ """ from __future__ import annotations -from ctypes import CDLL, CFUNCTYPE, POINTER, byref, create_string_buffer, \ - c_void_p, c_size_t, c_uint8, c_uint32, c_uint64, c_int, c_uint, c_char, c_char_p, addressof, Array, \ - cast, memmove, py_object, string_at -from typing import Callable, Any, Union -from sys import platform -from time import strptime, mktime, time as system_time from binascii import hexlify -from datetime import datetime from collections.abc import Iterable +from ctypes import ( + CDLL, + CFUNCTYPE, + POINTER, + Array, + addressof, + byref, + c_char, + c_char_p, + c_int, + c_size_t, + c_uint, + c_uint8, + c_uint32, + c_uint64, + c_void_p, + cast, + create_string_buffer, + memmove, + py_object, + string_at, +) +from datetime import datetime from enum import IntEnum +from sys import platform +from time import mktime, strptime +from time import time as system_time +from typing import Any, Callable, Union # This Python module requires the FFI API version introduced in Botan 3.11.0 # @@ -737,7 +757,7 @@ def _ctype_bits(s: str | bytes) -> bytes: elif isinstance(s, str): return s.encode('utf-8') else: - raise Exception("Internal error - unexpected type %s provided to _ctype_bits" % (type(s).__name__)) + raise TypeError("Internal error - unexpected type %s provided to _ctype_bits" % (type(s).__name__)) def _ctype_bufout(buf): return buf.raw @@ -2031,9 +2051,7 @@ def stateful_operation(self) -> bool: """Return whether the key is stateful or not.""" r = c_int(0) _DLL.botan_privkey_stateful_operation(self.__obj, byref(r)) - if r.value == 0: - return False - return True + return r.value != 0 def remaining_operations(self) -> int: """If the key is stateful, return the number of remaining operations. @@ -2133,9 +2151,7 @@ def update(self, msg: str | bytes): def check_signature(self, signature: str | bytes) -> bool: bits = _ctype_bits(signature) rc = _DLL.botan_pk_op_verify_finish(self.__obj, bits, len(bits)) - if rc == 0: - return True - return False + return rc == 0 class PKKeyAgreement: """Previously ``pk_op_key_agreement``""" @@ -2950,18 +2966,14 @@ def supports_application_specific_group(cls) -> bool: to register an application specific elliptic curve""" r = c_int(0) _DLL.botan_ec_group_supports_application_specific_group(byref(r)) - if r.value == 0: - return False - return True + return r.value != 0 @classmethod def supports_named_group(cls, name: str) -> bool: """Returns true if in this build configuration `ECGroup.from_name(name)` will succeed""" r = c_int(0) _DLL.botan_ec_group_supports_named_group(_ctype_str(name), byref(r)) - if r.value == 0: - return False - return True + return r.value != 0 @classmethod def from_params(cls, oid: OID, p: MPI, a: MPI, b: MPI, base_x: MPI, base_y: MPI, order: MPI) -> ECGroup: @@ -3011,9 +3023,7 @@ def from_name(cls, name: str) -> ECGroup: def unregister(cls, oid: OID) -> bool: """Unregister a previously registered group""" rc = _DLL.botan_ec_group_unregister(oid.handle_()) - if rc == 1: - return True - return False + return rc == 1 def to_der(self) -> bytes: """Export the group in DER encoding""" @@ -3279,9 +3289,7 @@ def check(self, code: int, timestamp: int | None = None, acceptable_drift: int = if timestamp is None: timestamp = int(system_time()) rc = _DLL.botan_totp_check(self.__obj, code, timestamp, acceptable_drift) - if rc == 0: - return True - return False + return rc == 0 def nist_key_wrap(kek: bytes, key: bytes, cipher: str | None = None) -> bytes: cipher_algo = "AES-%d" % (8*len(kek)) if cipher is None else cipher @@ -3464,7 +3472,7 @@ def zfec_decode(k: int, n: int, indexes: list[int], inputs: list[bytes]) -> list for i in inputs: if len(i) != share_size: raise ValueError( - "Share size mismatch: {} != {}".format(len(i), share_size) + f"Share size mismatch: {len(i)} != {share_size}" ) # allocate memory for our outputs (create_string_buffer creates diff --git a/src/scripts/acvp_tests.py b/src/scripts/acvp_tests.py index 9dbc911bf6a..613230cf7e4 100755 --- a/src/scripts/acvp_tests.py +++ b/src/scripts/acvp_tests.py @@ -10,6 +10,7 @@ Botan is released under the Simplified BSD License (see license.txt) """ +from __future__ import annotations import argparse import binascii @@ -27,7 +28,6 @@ import botan3 as botan - # ---- Infra ---- @@ -1981,7 +1981,7 @@ def _kda_party_info(party: dict) -> bytes: # uPartyInfo / vPartyInfo: concatenation of the party's fields in the # order they appear (partyId, ephemeralData). out = _from_hex(party["partyId"]) - if "ephemeralData" in party and party["ephemeralData"]: + if party.get("ephemeralData"): out += _from_hex(party["ephemeralData"]) return out @@ -2100,7 +2100,7 @@ def _kda_resolve(group: dict, test: dict) -> tuple[str, bytes]: algo = _KDA_ONESTEP_AUX_MAP.get(aux) if algo is None: raise TestSkip(f"Unsupported auxFunction: {aux}") - uses_salt = aux.startswith("HMAC-") or aux.startswith("KMAC-") + uses_salt = aux.startswith(("HMAC-", "KMAC-")) salt = _from_hex(kp.get("salt", "")) if uses_salt else b"" return algo, salt diff --git a/src/scripts/bench.py b/src/scripts/bench.py index c461b6a8244..55f35dfd5df 100755 --- a/src/scripts/bench.py +++ b/src/scripts/bench.py @@ -10,19 +10,21 @@ Botan is released under the Simplified BSD License (see license.txt) """ -import logging -import os -import sys -import optparse # pylint: disable=deprecated-module -import subprocess -import re import json +import logging import math +import optparse # pylint: disable=deprecated-module +import os import platform -from datetime import datetime +import re import shutil -import numpy as np +import subprocess +import sys +from datetime import datetime + import matplotlib.pyplot as plt +import numpy as np + def setup_logging(options): if options.verbose: @@ -283,11 +285,9 @@ def graphs(self): buf_sizes = self.results.keys() x = np.arange(len(buf_sizes)) width = 0.4 - multiplier = 0 - fig, ax = plt.subplots(layout='constrained') - for lib in ['Botan', 'OpenSSL']: + for multiplier, lib in enumerate(['Botan', 'OpenSSL']): offset = width * multiplier results = [math.ceil(x[lib.lower()]/(1024*1024)) for x in self.results.values()] rects = ax.bar(x + offset, results, width, label=lib) @@ -328,7 +328,7 @@ def result_string(self): openssl = v['openssl'] botan = v['botan'] - for op in openssl.keys(): + for op in openssl: if openssl[op] > botan[op]: winner = 'openssl' ratio = float(openssl[op]) / botan[op] @@ -350,9 +350,7 @@ def graphs(self): for op in ['sign', 'verify']: fig, ax = plt.subplots(layout='constrained') - multiplier = 0 - - for lib in ['Botan', 'OpenSSL']: + for multiplier, lib in enumerate(['Botan', 'OpenSSL']): offset = width * multiplier results = [x[lib.lower()][op] for x in self.results.values()] rects = ax.bar(x + offset, results, width, label=lib) @@ -408,11 +406,9 @@ def graphs(self): key_sizes = self.results.keys() x = np.arange(len(key_sizes)) width = 0.4 - multiplier = 0 - fig, ax = plt.subplots(layout='constrained') - for lib in ['Botan', 'OpenSSL']: + for multiplier, lib in enumerate(['Botan', 'OpenSSL']): offset = width * multiplier results = [x[lib.lower()] for x in self.results.values()] rects = ax.bar(x + offset, results, width, label=lib) diff --git a/src/scripts/build_docs.py b/src/scripts/build_docs.py index 6495cde3dc7..4d411832d79 100755 --- a/src/scripts/build_docs.py +++ b/src/scripts/build_docs.py @@ -8,16 +8,17 @@ Botan is released under the Simplified BSD License (see license.txt) """ -import sys -import optparse # pylint: disable=deprecated-module -import subprocess -import shutil -import logging import json -import tempfile +import logging +import multiprocessing +import optparse # pylint: disable=deprecated-module import os +import shutil import stat -import multiprocessing +import subprocess +import sys +import tempfile + def get_concurrency(): """ diff --git a/src/scripts/check.py b/src/scripts/check.py index cc75f3a2357..7073c5c4cab 100755 --- a/src/scripts/check.py +++ b/src/scripts/check.py @@ -10,11 +10,12 @@ import json import logging -import optparse # pylint: disable=deprecated-module +import optparse # pylint: disable=deprecated-module import os import subprocess import sys + def run_and_check(cmd_line, env=None, cwd=None): logging.info("Starting %s", ' '.join(cmd_line)) diff --git a/src/scripts/ci/download_ci_dep.py b/src/scripts/ci/download_ci_dep.py index da375398012..401a1b30611 100755 --- a/src/scripts/ci/download_ci_dep.py +++ b/src/scripts/ci/download_ci_dep.py @@ -15,6 +15,7 @@ import tempfile import urllib.request + def load_config(dep_name): config_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', '..', 'configs', 'ci_deps.conf') diff --git a/src/scripts/ci/gh_clang_tidy_fixes_in_pr.py b/src/scripts/ci/gh_clang_tidy_fixes_in_pr.py index ad756546dc9..2ca2022d70e 100755 --- a/src/scripts/ci/gh_clang_tidy_fixes_in_pr.py +++ b/src/scripts/ci/gh_clang_tidy_fixes_in_pr.py @@ -6,6 +6,7 @@ Botan is released under the Simplified BSD License (see license.txt) """ +from __future__ import annotations import argparse import glob @@ -14,6 +15,7 @@ import yaml + class FileLocation: def __init__(self, line : int, column : int, endline : int | None = None, endcolumn : int | None = None): self.line = line @@ -47,10 +49,8 @@ def __map_file_offset(self, offset : int) -> tuple[int, int]: """ For self.file determine the (line, column) given a byte offset """ with open(self.file, encoding="utf-8") as srcfile: readoffset = 0 - lineoffset = 0 - for line in srcfile.readlines(): + for lineoffset, line in enumerate(srcfile, start=1): readoffset += len(line) - lineoffset += 1 if readoffset >= offset: coloffset = offset - readoffset + len(line) return (lineoffset, coloffset) diff --git a/src/scripts/ci/gha_linux_packages.py b/src/scripts/ci/gha_linux_packages.py index a35bf6d6901..a9a6f03a71c 100755 --- a/src/scripts/ci/gha_linux_packages.py +++ b/src/scripts/ci/gha_linux_packages.py @@ -8,6 +8,7 @@ import sys + def gha_linux_packages(target, compiler): packages = [ 'ccache', diff --git a/src/scripts/ci/setup_gh_actions.sh b/src/scripts/ci/setup_gh_actions.sh index 8b572165594..334b1d9bc1b 100755 --- a/src/scripts/ci/setup_gh_actions.sh +++ b/src/scripts/ci/setup_gh_actions.sh @@ -56,7 +56,7 @@ if type -p "apt-get"; then "${SCRIPT_LOCATION}"/download_ci_dep.py limbo "${SCRIPT_LOCATION}/../../../limbo.json" elif [ "$TARGET" = "lint" ]; then - pip install "ruff~=0.15.0" + pip install "ruff~=0.16.0" elif [ "$TARGET" = "typos" ]; then cargo install typos-cli@1.48.0 diff --git a/src/scripts/ci_build.py b/src/scripts/ci_build.py index 4a2cacdc283..d8836bb2951 100755 --- a/src/scripts/ci_build.py +++ b/src/scripts/ci_build.py @@ -9,14 +9,15 @@ Botan is released under the Simplified BSD License (see license.txt) """ +import multiprocessing +import optparse # pylint: disable=deprecated-module import os import platform import subprocess import sys -import time import tempfile -import optparse # pylint: disable=deprecated-module -import multiprocessing +import time + def get_concurrency(): def_concurrency = 2 @@ -459,10 +460,7 @@ def add_boost_support(target, target_os): if target == 'sanitizer' and target_os == 'linux': return True - if target == 'shared' and target_os != 'windows': - return True - - return False + return target == 'shared' and target_os != 'windows' if add_boost_support(target, target_os): flags += ['--with-boost'] @@ -509,9 +507,8 @@ def add_boost_support(target, target_os): flags += ['--with-tpm'] test_cmd += ['--run-online-tests'] - if target in ['coverage', 'pkcs11']: - if pkcs11_lib and os.access(pkcs11_lib, os.R_OK): - test_cmd += ['--pkcs11-lib=%s' % (pkcs11_lib)] + if target in ['coverage', 'pkcs11'] and pkcs11_lib and os.access(pkcs11_lib, os.R_OK): + test_cmd += ['--pkcs11-lib=%s' % (pkcs11_lib)] if target in ['coverage', 'sanitizer']: test_cmd += ['--run-long-tests'] @@ -700,10 +697,7 @@ def skip_tls_proxy_tests_for_this_target(ci_image): # The tls_proxy test seems to consistently fail on certain macOS images # See GH #5160 - if ci_image in ['macos-15-intel', 'macos-26']: - return True - - return False + return ci_image in ['macos-15-intel', 'macos-26'] def main(args=None): """ @@ -737,9 +731,7 @@ def main(args=None): elif options.cc == 'gcc-14': options.cc = 'gcc' # Hack: 'gcc-14' is not a valid compiler identifier for ``./configure.py --cc`` options.cc_bin = 'g++-14' - elif options.cc == 'clang': - options.cc_bin = 'clang++' - elif options.cc == 'xcode': + elif options.cc in ['clang', 'xcode']: options.cc_bin = 'clang++' elif options.cc == 'msvc': options.cc_bin = 'cl' @@ -825,7 +817,7 @@ def main(args=None): # be able to annotate the correct files. cmds.append(["indir:%s" % root_dir, py_interp, '-m', 'pylint'] + pylint_flags + py_scripts) - ruff_flags = [] + ruff_flags = ["--config", "%s/src/configs/ruff.toml" % (root_dir)] if is_running_in_github_actions(): ruff_flags += ["--output-format=github"] diff --git a/src/scripts/ci_check_generated_files.py b/src/scripts/ci_check_generated_files.py index 6b03cdd4e39..d9f579142cf 100755 --- a/src/scripts/ci_check_generated_files.py +++ b/src/scripts/ci_check_generated_files.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -# coding=utf8 """ (C) 2026 Jack Lloyd diff --git a/src/scripts/ci_check_headers.py b/src/scripts/ci_check_headers.py index 70cdb7acc6a..15e2ca0b2f6 100755 --- a/src/scripts/ci_check_headers.py +++ b/src/scripts/ci_check_headers.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -# coding=utf8 """ Botan CI check headers script @@ -9,10 +8,11 @@ Botan is released under the Simplified BSD License (see license.txt) """ -import sys -import os import json +import os import re +import sys + def main(args=None): if args is None: diff --git a/src/scripts/ci_check_install.py b/src/scripts/ci_check_install.py index f6a69511522..f0d6dd19c76 100755 --- a/src/scripts/ci_check_install.py +++ b/src/scripts/ci_check_install.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -# coding=utf8 """ Botan CI check installation script @@ -11,11 +10,12 @@ Botan is released under the Simplified BSD License (see license.txt) """ -import os -import sys import json +import os import re import subprocess +import sys + def verify_library(build_config): lib_dir = build_config['libdir'] @@ -23,7 +23,7 @@ def verify_library(build_config): print('Error: libdir "%s" is not a directory' % lib_dir) return False - found_libs = set([]) + found_libs = set() major_version = int(build_config["version_major"]) @@ -58,7 +58,7 @@ def verify_includes(build_config): return False expected_headers = set(build_config['public_headers'] + build_config['external_headers']) - found_headers = set([]) + found_headers = set() for (_, _, filenames) in os.walk(include_dir): for filename in filenames: diff --git a/src/scripts/ci_report_sizes.py b/src/scripts/ci_report_sizes.py index 54e85f4e5e8..95c694d6ba1 100755 --- a/src/scripts/ci_report_sizes.py +++ b/src/scripts/ci_report_sizes.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -# coding=utf8 """ This script reports the sizes of various binary artifacts in CI @@ -9,9 +8,10 @@ Botan is released under the Simplified BSD License (see license.txt) """ +import json import os import sys -import json + def format_size(bytes): kB = 1024 diff --git a/src/scripts/cleanup.py b/src/scripts/cleanup.py index d020576a4f3..744d4d113aa 100755 --- a/src/scripts/cleanup.py +++ b/src/scripts/cleanup.py @@ -8,15 +8,16 @@ Botan is released under the Simplified BSD License (see license.txt) """ +import errno +import json +import logging +import optparse # pylint: disable=deprecated-module import os -import sys -import stat import re -import optparse # pylint: disable=deprecated-module -import logging -import json import shutil -import errno +import stat +import sys + def remove_dir(d): try: @@ -122,10 +123,9 @@ def main(args=None): if match and match.group(1) in known_suffix: remove_file(os.path.join(build_config['out_dir'], f)) - if options.distclean: - if 'generated_files' in build_config: - for f in build_config['generated_files'].split(' '): - remove_file(f) + if options.distclean and 'generated_files' in build_config: + for f in build_config['generated_files'].split(' '): + remove_file(f) return 0 diff --git a/src/scripts/compare_perf.py b/src/scripts/compare_perf.py index 086aaa50b0a..430ebbce4e7 100755 --- a/src/scripts/compare_perf.py +++ b/src/scripts/compare_perf.py @@ -9,9 +9,10 @@ """ import json -import optparse # pylint: disable=deprecated-module -import sys +import optparse # pylint: disable=deprecated-module import re +import sys + def ops_per_second(events, nanos): return (events * 1000000000) / nanos diff --git a/src/scripts/config_for_oss_fuzz.py b/src/scripts/config_for_oss_fuzz.py index e9967a166df..81d83b61feb 100755 --- a/src/scripts/config_for_oss_fuzz.py +++ b/src/scripts/config_for_oss_fuzz.py @@ -9,8 +9,8 @@ """ import os -import sys import subprocess +import sys if len(sys.argv) != 3: print("Expected args: %s " % (sys.argv[0])) @@ -38,4 +38,4 @@ configure = os.path.realpath(os.path.join(os.path.realpath(__file__), '..', '..', '..', 'configure.py')) -subprocess.run([configure] + args) +subprocess.run([configure] + args, check=True) diff --git a/src/scripts/create_corpus_zip.py b/src/scripts/create_corpus_zip.py index 96971d31613..f2e976b76f9 100755 --- a/src/scripts/create_corpus_zip.py +++ b/src/scripts/create_corpus_zip.py @@ -8,10 +8,11 @@ # This is primarily used by OSS-Fuzz but might be useful if you were # deploying the binaries in a custom fuzzer deployment system. -import sys import os -import zipfile import stat +import sys +import zipfile + def main(args=None): if args is None: diff --git a/src/scripts/dev_tools/addchain.py b/src/scripts/dev_tools/addchain.py index 885c980d874..f3077273544 100755 --- a/src/scripts/dev_tools/addchain.py +++ b/src/scripts/dev_tools/addchain.py @@ -9,15 +9,16 @@ the code suitable for pcurves """ -import sys import subprocess +import sys + def addchain_gen(n): search = subprocess.Popen(['addchain', 'search', str(n)], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - (stdout, stderr) = search.communicate() + (stdout, _stderr) = search.communicate() gen = subprocess.Popen(['addchain', 'gen'], stdin=subprocess.PIPE, @@ -26,12 +27,12 @@ def addchain_gen(n): gen.stdin.write(stdout) - (stdout, stderr) = gen.communicate() + (stdout, _stderr) = gen.communicate() return stdout.decode('utf8').split('\n') def addchain_code(n, indent=3): - vars = set([]) + vars = set() output = [] diff --git a/src/scripts/dev_tools/analyze_timing_results.py b/src/scripts/dev_tools/analyze_timing_results.py index ef3b9972578..332496c90d3 100755 --- a/src/scripts/dev_tools/analyze_timing_results.py +++ b/src/scripts/dev_tools/analyze_timing_results.py @@ -8,8 +8,10 @@ import re import sys + import numpy + def compute_stats_for(nm, results): return { 'name': nm, @@ -33,7 +35,7 @@ def main(args = None): timing_line = re.compile('([0-9]+);([0-9]+);([0-9]+)') - key_ids = set([]) + key_ids = set() results = {} for line in open(args[1]): diff --git a/src/scripts/dev_tools/file_size_check.py b/src/scripts/dev_tools/file_size_check.py index e1a118aadac..0f2741ab6e7 100755 --- a/src/scripts/dev_tools/file_size_check.py +++ b/src/scripts/dev_tools/file_size_check.py @@ -1,11 +1,12 @@ #!/usr/bin/python import json -import subprocess import re +import subprocess import sys from multiprocessing.pool import ThreadPool + def lines_in(f): lines = 0 for line in f.decode('utf8').splitlines(): @@ -18,7 +19,7 @@ def lines_in(f): return lines def run_cc(cmd): - preproc = subprocess.run(cmd.split(' '), stdout=subprocess.PIPE) + preproc = subprocess.run(cmd.split(' '), stdout=subprocess.PIPE, check=True) return lines_in(preproc.stdout) diff --git a/src/scripts/dev_tools/format_wycheproof_ecdsa.py b/src/scripts/dev_tools/format_wycheproof_ecdsa.py index 7bf2af8f4de..3b36f64f24d 100755 --- a/src/scripts/dev_tools/format_wycheproof_ecdsa.py +++ b/src/scripts/dev_tools/format_wycheproof_ecdsa.py @@ -6,9 +6,10 @@ Botan is released under the Simplified BSD License (see license.txt) """ -import sys import json import re +import sys + def map_group_name(group): if group.startswith('brainpoolP'): diff --git a/src/scripts/dev_tools/gen_dilithium_kat.py b/src/scripts/dev_tools/gen_dilithium_kat.py index 6c4e830ca77..cc36b4f618c 100755 --- a/src/scripts/dev_tools/gen_dilithium_kat.py +++ b/src/scripts/dev_tools/gen_dilithium_kat.py @@ -12,9 +12,10 @@ # Botan is released under the Simplified BSD License (see license.txt) # -import sys -import hashlib import binascii +import hashlib +import sys + class KatReader: def __init__(self, file): diff --git a/src/scripts/dev_tools/gen_ec_groups.py b/src/scripts/dev_tools/gen_ec_groups.py index d64a7522b16..6170232de64 100755 --- a/src/scripts/dev_tools/gen_ec_groups.py +++ b/src/scripts/dev_tools/gen_ec_groups.py @@ -6,14 +6,15 @@ Botan is released under the Simplified BSD License (see license.txt) """ -import sys -import re import datetime -import os import errno +import os +import re +import sys from textwrap import dedent, indent -from jinja2 import Environment, FileSystemLoader + from addchain import addchain_code +from jinja2 import Environment, FileSystemLoader """ NOTE: This script requires the Jinja templating library to be installed. diff --git a/src/scripts/dev_tools/gen_ffi_decls.py b/src/scripts/dev_tools/gen_ffi_decls.py index 6cf189b2648..cb30a295212 100755 --- a/src/scripts/dev_tools/gen_ffi_decls.py +++ b/src/scripts/dev_tools/gen_ffi_decls.py @@ -9,6 +9,7 @@ """ import traceback + from pycparser import c_ast, parse_file ffi_header = 'src/lib/ffi/ffi.h' diff --git a/src/scripts/dev_tools/gen_frodo_kat.py b/src/scripts/dev_tools/gen_frodo_kat.py old mode 100644 new mode 100755 index 5e7a3d4862a..d07e0c288cd --- a/src/scripts/dev_tools/gen_frodo_kat.py +++ b/src/scripts/dev_tools/gen_frodo_kat.py @@ -14,10 +14,11 @@ # Botan is released under the Simplified BSD License (see license.txt) # -import sys -import hashlib import binascii +import hashlib import os +import sys + class KatReader: def __init__(self, file): @@ -122,9 +123,9 @@ def main(args = None): for kat in list(reader.read_kats())[:25]: kat = compress_kat(kat) - for key in kat.keys(): + for key in kat: print(key, '=', kat[key], file=output) - print("", file=output) + print(file=output) if __name__ == '__main__': sys.exit(main()) diff --git a/src/scripts/dev_tools/gen_kyber_kat.py b/src/scripts/dev_tools/gen_kyber_kat.py index eed0592ec40..af0a3f2187d 100755 --- a/src/scripts/dev_tools/gen_kyber_kat.py +++ b/src/scripts/dev_tools/gen_kyber_kat.py @@ -27,11 +27,12 @@ # Botan is released under the Simplified BSD License (see license.txt) # -import sys -import hashlib +import argparse import binascii +import hashlib import os -import argparse +import sys + class KatReader: def __init__(self, file): @@ -212,9 +213,9 @@ def main(args = None): for kat in list(reader.read_kats())[:args.kats_per_mode]: kat = compress_kat(kat, mode) - for key in kat.keys(): + for key in kat: print(key, '=', kat[key], file=output) - print("", file=output) + print(file=output) if __name__ == '__main__': args = parse_arguments() diff --git a/src/scripts/dev_tools/gen_mlkem_acvp_kat.py b/src/scripts/dev_tools/gen_mlkem_acvp_kat.py old mode 100644 new mode 100755 index 903d83c965c..0b4bca2cb4d --- a/src/scripts/dev_tools/gen_mlkem_acvp_kat.py +++ b/src/scripts/dev_tools/gen_mlkem_acvp_kat.py @@ -10,12 +10,13 @@ # Botan is released under the Simplified BSD License (see license.txt) # +import argparse import binascii import hashlib import json -import argparse import sys + def shake_256_16(v): # v is assumed to be hex h = hashlib.shake_256() @@ -135,12 +136,12 @@ def main(args = None): for kat in kat_by_paramset: kat = compress_kat_keygen(kat) - for key in kat.keys(): + for key in kat: if key in ["Z", "D", "EK", "DK"]: print(key, '=', kat[key], file=output) - print("", file=output) + print(file=output) if args.encapdecap_directory is not None: - encaps_kat, decaps_kat = mlkem_load_encdec( + encaps_kat, _decaps_kat = mlkem_load_encdec( args.encapdecap_directory + '/prompt.json', args.encapdecap_directory + '/expectedResults.json') @@ -153,10 +154,10 @@ def main(args = None): for kat in kat_by_paramset: kat = compress_kat_encaps(kat) - for key in kat.keys(): + for key in kat: if key in ["M", "EK", "K", "C"]: print(key, '=', kat[key], file=output) - print("", file=output) + print(file=output) with open("src/tests/data/pubkey/ml_kem_acvp_decap.vec", 'w') as output: print("# This file was auto-generated from the ACVP KATs", file=output) diff --git a/src/scripts/dev_tools/gen_mp_comba.py b/src/scripts/dev_tools/gen_mp_comba.py index 6beefb838b2..20cbd96fbd1 100755 --- a/src/scripts/dev_tools/gen_mp_comba.py +++ b/src/scripts/dev_tools/gen_mp_comba.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 -import sys import datetime +import sys # (C) 2011,2014,2015,2016 Jack Lloyd # Botan is released under the Simplified BSD License (see license.txt) @@ -12,7 +12,7 @@ def comba_indexes(N): indexes = [] - for i in range(0, 2*N): + for i in range(2*N): x = [] for j in range(max(0, i-N+1), min(N, i+1)): @@ -25,7 +25,7 @@ def comba_sqr_indexes(N): indexes = [] - for i in range(0, 2*N): + for i in range(2*N): x = [] for j in range(max(0, i-N+1), min(N, i+1)): @@ -40,7 +40,7 @@ def comba_sqr_indexes(N): def comba_multiply_code(N): indexes = comba_indexes(N) - for (i,idx) in zip(range(0, len(indexes)), indexes): + for (i,idx) in zip(range(len(indexes)), indexes): for pair in idx: print(" accum.mul(x[%d], y[%d]);" % (pair[0], pair[1])) @@ -49,8 +49,8 @@ def comba_multiply_code(N): def comba_square_code(N): indexes = comba_sqr_indexes(N) - for (rnd,idx) in zip(range(0, len(indexes)), indexes): - for (i,pair) in zip(range(0, len(idx)), idx): + for (rnd,idx) in zip(range(len(indexes)), indexes): + for (i,pair) in zip(range(len(idx)), idx): if pair[0] == pair[1]: print(" accum.mul(x[%d], x[%d]);" % (pair[0], pair[1])) elif i % 2 == 0: diff --git a/src/scripts/dev_tools/gen_mp_monty.py b/src/scripts/dev_tools/gen_mp_monty.py index d19bea733b6..b9652b741a2 100755 --- a/src/scripts/dev_tools/gen_mp_monty.py +++ b/src/scripts/dev_tools/gen_mp_monty.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 -import sys import datetime +import sys # (C) 2018,2023,2025 Jack Lloyd # Botan is released under the Simplified BSD License (see license.txt) @@ -29,7 +29,7 @@ def monty_redc_code(n, p_dash1=False): lines.append("ws[0] = accum.monty_step(p[0], p_dash);") for i in range(1, n): - for j in range(0, i): + for j in range(i): lines.append("accum.mul(ws[%d], p[%d]);" % (j, i-j)) lines.append("accum.add(z[%d]);" % (i)) @@ -38,7 +38,7 @@ def monty_redc_code(n, p_dash1=False): else: lines.append("ws[%d] = accum.monty_step(p[0], p_dash);" % (i)) - for i in range(0, n - 1): + for i in range(n - 1): for j in range(i + 1, n): lines.append("accum.mul(ws[%d], p[%d]);" % (j, n + i-j)) @@ -81,8 +81,7 @@ def main(args = None): with open('./src/lib/math/mp/mp_monty_n.cpp', encoding='utf8', mode='w') as monty_n: monty_n.write(header) - for n in sizes: - monty_n.write(monty_redc_code(n)) + monty_n.writelines(monty_redc_code(n) for n in sizes) monty_n.write(footer) diff --git a/src/scripts/dev_tools/gen_oids.py b/src/scripts/dev_tools/gen_oids.py index 8eba522708e..d087286a00b 100755 --- a/src/scripts/dev_tools/gen_oids.py +++ b/src/scripts/dev_tools/gen_oids.py @@ -9,11 +9,13 @@ NOTE: This script requires the Jinja templating library to be installed. """ -import sys import datetime import re +import sys + from jinja2 import Environment, FileSystemLoader + # This must match OID::hash_code def hash_oid(oid): word_size = 2 ** 64 diff --git a/src/scripts/dev_tools/gen_os_features.py b/src/scripts/dev_tools/gen_os_features.py index 83448dcdb03..75430ed9470 100755 --- a/src/scripts/dev_tools/gen_os_features.py +++ b/src/scripts/dev_tools/gen_os_features.py @@ -23,7 +23,7 @@ # locale sys.path.append(botan_root) -from configure import OsInfo # noqa: E402 +from configure import OsInfo parser = argparse.ArgumentParser(description="") parser.add_argument('--verbose', dest='verbose', action='store_const', @@ -67,23 +67,23 @@ def update_os(): print(".. This file was automatically generated by src/scripts/dev_tools/%s on %s" % (os.path.basename(sys.argv[0]), today), file=f1) print(".. All manual changes will be lost. Edit the script instead.", file=f1) - print("", file=f1) + print(file=f1) print(TABLE_TITLE, file=f1) print("========================================", file=f1) - print("", file=f1) + print(file=f1) print("A summary of OS features as defined in ``src/build-data/os``.", file=f1) - print("", file=f1) + print(file=f1) print("::", file=f1) - print("", file=f1) + print(file=f1) for o in oslist: print(" %s: %s" % (o[0:1], o), file=f1) - print("", file=f1) + print(file=f1) print('.. csv-table::', file=f1) print(' :header: "Feature", "' + '", "'.join([o[0:1] for o in oslist]) + '"', file=f1) - print('', file=f1) + print(file=f1) for f in featurelist: line = ' "' + f + '"' diff --git a/src/scripts/dev_tools/gen_pqc_dsa_kats.py b/src/scripts/dev_tools/gen_pqc_dsa_kats.py index 498e8789106..4ada02a359b 100644 --- a/src/scripts/dev_tools/gen_pqc_dsa_kats.py +++ b/src/scripts/dev_tools/gen_pqc_dsa_kats.py @@ -12,6 +12,7 @@ import os import re import sys + from dilithium_py.drbg.aes256_ctr_drbg import AES256_CTR_DRBG from fips204 import ML_DSA, ML_DSA_PARAM from fips205 import SLH_DSA_PARAMS @@ -97,20 +98,20 @@ def main(args = None): print("SigDet = %s" % binascii.hexlify(signature_det).decode("utf-8").upper(), file=output) print("HashSigDet = %s" % binascii.hexlify(hash_fn(signature_det)).decode("utf-8").upper(), file=output) print("HashSigRand = %s" % binascii.hexlify(hash_fn(signature_rand)).decode("utf-8").upper(), file=output) - print("", file=output) + print(file=output) elif algo == "ml_dsa": - for param in ML_DSA_PARAM.keys(): + for param in ML_DSA_PARAM: for det_str, deterministic in [("Deterministic", True), ("Randomized", False)]: alg = ML_DSA(param) output = open('src/tests/data/pubkey/%s_%s.vec' % (transform_mldsa_string(param), det_str), 'w') print("# See src/scripts/dev_tools/gen_pqc_dsa_kats.py", file=output) - print("", file=output) + print(file=output) print(create_mldsa_ini_label(param, det_str), file=output) - print("", file=output) + print(file=output) hash_fn = sha3_256 - def mldsa_sign_internal(m, sk, rnd): + def mldsa_sign_internal(m, sk, rnd, alg=alg): # For some reason the interfaces vary between FIPS 204 and FIPS 205... if rnd is None: rnd = bytes([0]*32) @@ -134,7 +135,7 @@ def mldsa_sign_internal(m, sk, rnd): print("HashPk = %s" % binascii.hexlify(hash_fn(pk)).decode("utf-8").upper(), file=output) print("HashSk = %s" % binascii.hexlify(hash_fn(keygen_rand)).decode("utf-8").upper(), file=output) print("HashSig = %s" % binascii.hexlify(hash_fn(signature)).decode("utf-8").upper(), file=output) - print("", file=output) + print(file=output) else: print("Usage: gen_pqc_dsa_kats.py ") return 1 diff --git a/src/scripts/dev_tools/gen_sphincsplus_kat.py b/src/scripts/dev_tools/gen_sphincsplus_kat.py index 116043fa197..775f839df99 100755 --- a/src/scripts/dev_tools/gen_sphincsplus_kat.py +++ b/src/scripts/dev_tools/gen_sphincsplus_kat.py @@ -12,9 +12,10 @@ # Botan is released under the Simplified BSD License (see license.txt) # -import sys -import hashlib import binascii +import hashlib +import sys + class KatReader: def __init__(self, file): @@ -85,11 +86,9 @@ def main(args = None): hash_fn = sha256 if "sha2" in param.lower() else sha3_256 - cnt = 0 - for kat in reader.read_kats(): + for cnt, kat in enumerate(reader.read_kats()): if cnt >= limit: break - cnt += 1 # Remove the input message from the end of the 'sm' field signature = binascii.unhexlify(kat["sm"][:-kat["mlen"]*2]) diff --git a/src/scripts/dev_tools/gen_tls_suite_info.py b/src/scripts/dev_tools/gen_tls_suite_info.py index 135bbccc7e0..d8a62f74a3a 100755 --- a/src/scripts/dev_tools/gen_tls_suite_info.py +++ b/src/scripts/dev_tools/gen_tls_suite_info.py @@ -9,13 +9,15 @@ Botan is released under the Simplified BSD License (see license.txt) """ -import sys -import re import datetime import hashlib import optparse +import re +import sys + from jinja2 import Environment, FileSystemLoader + def to_ciphersuite_info(code, name): sig_and_kex = '' @@ -56,10 +58,7 @@ def to_ciphersuite_info(code, name): cipher = cipher_and_mac[:-1] - if mac_algo == '8' and cipher[-1] == 'CCM': - cipher = cipher[:-1] - mac_algo = 'CCM_8' - elif len(cipher) >= 2 and cipher[-2] == 'CCM' and cipher[-1] == '8': + if (mac_algo == '8' and cipher[-1] == 'CCM') or (len(cipher) >= 2 and cipher[-2] == 'CCM' and cipher[-1] == '8'): cipher = cipher[:-1] mac_algo = 'CCM_8' @@ -174,9 +173,9 @@ def open_input(args): except OSError: pass - import urllib.request import urllib.error import urllib.parse + import urllib.request return urllib.request.urlopen(iana_url) else: return open(args[1]) diff --git a/src/scripts/dev_tools/macro_checks.py b/src/scripts/dev_tools/macro_checks.py index 51a4faac100..04a0ed3ea58 100755 --- a/src/scripts/dev_tools/macro_checks.py +++ b/src/scripts/dev_tools/macro_checks.py @@ -6,10 +6,11 @@ # Scans all source and test files and makes sure we are not using a # BOTAN_HAS_xxx macro which is not actually defined anywhere. -from configure import ModuleInfo, load_info_files import os import re +from configure import ModuleInfo, load_info_files + src_dir = 'src' lib_dir = os.path.join(src_dir, 'lib') @@ -34,7 +35,7 @@ for dirname, subdirs, files in os.walk(src_dir): for fname in files: - if fname.endswith('.h') or fname.endswith('.cpp'): + if fname.endswith(('.h', '.cpp')): contents = open(os.path.join(dirname, fname)).read() for m in re.finditer(macro, contents): diff --git a/src/scripts/dev_tools/run_clang_format.py b/src/scripts/dev_tools/run_clang_format.py index 671df109ca7..c748376457c 100755 --- a/src/scripts/dev_tools/run_clang_format.py +++ b/src/scripts/dev_tools/run_clang_format.py @@ -6,17 +6,18 @@ Botan is released under the Simplified BSD License (see license.txt) """ -import subprocess -import sys -import optparse # pylint: disable=deprecated-module -import multiprocessing import difflib -import time +import multiprocessing +import optparse # pylint: disable=deprecated-module import os import re import shutil +import subprocess +import sys +import time from multiprocessing.pool import ThreadPool + def clang_format_style_path(): script_location = os.path.dirname(os.path.abspath(__file__)) relative_style_path = "../../configs/clang-format" @@ -76,10 +77,8 @@ def list_source_files_in(directory): for (dirpath, _, filenames) in os.walk(directory): for filename in filenames: - if filename.endswith('.cpp') or filename.endswith('.h'): - - if filename not in excluded: - yield os.path.join(dirpath, filename) + if filename.endswith(('.cpp', '.h')) and filename not in excluded: + yield os.path.join(dirpath, filename) def filter_files(files, filters): if len(filters) == 0: diff --git a/src/scripts/dev_tools/run_clang_tidy.py b/src/scripts/dev_tools/run_clang_tidy.py index 7ae5fe10a5a..e8d7c2a1847 100755 --- a/src/scripts/dev_tools/run_clang_tidy.py +++ b/src/scripts/dev_tools/run_clang_tidy.py @@ -10,8 +10,7 @@ import hashlib import json import multiprocessing -from multiprocessing.pool import ThreadPool -import optparse # pylint: disable=deprecated-module +import optparse # pylint: disable=deprecated-module import os import random import re @@ -21,6 +20,7 @@ import sys import time import uuid +from multiprocessing.pool import ThreadPool enabled_checks = [ 'bugprone-*', @@ -189,7 +189,7 @@ def preproc_file(compile_commands): cmd, check=True, stdout=subprocess.PIPE, - universal_newlines=True) + text=True) return hashlib.sha256(result.stdout.encode('utf-8')).hexdigest() @@ -308,7 +308,7 @@ def main(args = None): # pylint: disable=too-many-return-statements files_to_check = [] for file in changes.split(): - if file.endswith('.cpp') or file.endswith('.h'): + if file.endswith(('.cpp', '.h')): files_to_check.append(os.path.basename(file)) if len(files_to_check) == 0: @@ -319,7 +319,7 @@ def main(args = None): # pylint: disable=too-many-return-statements for line in sys.stdin: file = os.path.basename(line.strip()) - if file.endswith('.cpp') or file.endswith('.h'): + if file.endswith(('.cpp', '.h')): files_to_check.append(file) elif file in ['run_clang_tidy.py']: scan_all = True @@ -388,9 +388,9 @@ def main(args = None): # pylint: disable=too-many-return-statements continue cache_hit = False - if cache is not None: - if cache.hit(config=check_config, source_file=info['preproc'], clang_tidy=clang_tidy_version): - cache_hit = True + if cache is not None and \ + cache.hit(config=check_config, source_file=info['preproc'], clang_tidy=clang_tidy_version): + cache_hit = True if cache_hit and not options.quiet: print("Checked", info["file"], " (cached)") diff --git a/src/scripts/dev_tools/show_dependencies.py b/src/scripts/dev_tools/show_dependencies.py index 28d3ed60ec9..7144cf6b76e 100755 --- a/src/scripts/dev_tools/show_dependencies.py +++ b/src/scripts/dev_tools/show_dependencies.py @@ -14,18 +14,18 @@ # global import argparse import copy -import sys -import subprocess -from collections import OrderedDict import glob import os +import subprocess +import sys +from collections import OrderedDict # Assume this script is in botan/src/scripts botan_root = os.path.join(os.path.dirname(sys.argv[0]), "..", "..") # locale sys.path.append(botan_root) -from configure import ModuleInfo # noqa: E402 +from configure import ModuleInfo parser = argparse.ArgumentParser(description= 'Show Botan module dependencies. ' @@ -71,7 +71,9 @@ def dicts(t): return {k: dicts(t[k]) for k in t} -def paths(t, path = [], level=0): +def paths(t, path=None, level=0): + if path is None: + path = [] ret = [] for key in t: ret.append(path + [key]) @@ -95,7 +97,7 @@ def paths(t, path = [], level=0): names=[m.basename for m in modules] names.sort() print(names) - print("") + print() if args.verbose: print("resolving dependencies ...") @@ -103,13 +105,13 @@ def paths(t, path = [], level=0): def cartinality(depdict): return sum([len(depdict[k]) for k in depdict]) -registered_dependencies = dict() -all_dependencies = dict() -direct_dependencies = dict() +registered_dependencies = {} +all_dependencies = {} +direct_dependencies = {} for module in modules: lst = module.dependencies(None) - registered_dependencies[module.basename] = set(lst) - set([module.basename]) + registered_dependencies[module.basename] = set(lst) - {module.basename} # Get all_dependencies from registered_dependencies def add_dependency(): @@ -118,7 +120,7 @@ def add_dependency(): new_modules_for_key = None for currently_in in all_dependencies[key]: if currently_in in all_dependencies: - potentially_new_modules_for_key = all_dependencies[currently_in] - set([key]) + potentially_new_modules_for_key = all_dependencies[currently_in] - {key} if not potentially_new_modules_for_key <= all_dependencies[key]: new_modules_for_key = potentially_new_modules_for_key.copy() break @@ -156,7 +158,7 @@ def depends_on(a, b): def remove_indirect_dependencies(): for mod in direct_dependencies: for one in direct_dependencies[mod]: - others = direct_dependencies[mod] - set([one]) + others = direct_dependencies[mod] - {one} for other in others: if depends_on(other, one): direct_dependencies[mod].remove(one) @@ -192,9 +194,10 @@ def openfile(f): print(key.ljust(17) + " : " + ", ".join(sorted(direct_dependencies[key]))) if args.mode == "draw": - import graphviz as gv import tempfile + import graphviz as gv + tmpdir = tempfile.mkdtemp(prefix="botan-") g2 = gv.Digraph(format=args.format, engine=args.engine) diff --git a/src/scripts/dev_tools/xmss_test_vector_from_reference.py b/src/scripts/dev_tools/xmss_test_vector_from_reference.py index 1548b86c76c..88cc13c3054 100755 --- a/src/scripts/dev_tools/xmss_test_vector_from_reference.py +++ b/src/scripts/dev_tools/xmss_test_vector_from_reference.py @@ -13,9 +13,9 @@ """ import asyncio -import tempfile -import sys import binascii +import sys +import tempfile async def run(cmd, args): @@ -95,11 +95,11 @@ async def join(strings): async def make_xmss_sig_vec_entry(xmss_param): async def entry(msg): kp = await Keypair.generate(xmss_param) - out = "Params = {}\n".format(kp.params_name) - out += "Msg = {}\n".format(tohex(msg)) - out += "PrivateKey = {}\n".format(tohex(kp.secret_key)) + out = f"Params = {kp.params_name}\n" + out += f"Msg = {tohex(msg)}\n" + out += f"PrivateKey = {tohex(kp.secret_key)}\n" sig = await kp.sign(msg) - out += "Signature = {}\n".format(tohex(sig)) + out += f"Signature = {tohex(sig)}\n" return out return await join([entry(msg) for msg in TEST_MESSAGES]) @@ -108,11 +108,11 @@ async def entry(msg): async def make_xmss_verify_vec_entry(xmss_param): async def entry(msg): kp = await Keypair.generate(xmss_param) - out = "Params = {}\n".format(kp.params_name) - out += "Msg = {}\n".format(tohex(msg)) - out += "PublicKey = {}\n".format(tohex(kp.public_key)) + out = f"Params = {kp.params_name}\n" + out += f"Msg = {tohex(msg)}\n" + out += f"PublicKey = {tohex(kp.public_key)}\n" sig = await kp.sign(msg) - out += "Signature = {}\n".format(tohex(sig)) + out += f"Signature = {tohex(sig)}\n" return out return await join([entry(msg) for msg in TEST_MESSAGES]) @@ -120,18 +120,17 @@ async def entry(msg): async def make_xmss_keygen_vec_entry(xmss_param): kp = await Keypair.generate(xmss_param) - out = "Params = {}\n".format(xmss_param) - out += "SecretSeed = {}\n".format(tohex(kp.secret_seed)) - out += "PublicSeed = {}\n".format(tohex(kp.public_seed)) - out += "SecretPrf = {}\n".format(tohex(kp.secret_prf)) - out += "PublicKey = {}\n".format(tohex(kp.public_key)) - out += "PrivateKey = {}\n".format(tohex(kp.secret_key)) + out = f"Params = {xmss_param}\n" + out += f"SecretSeed = {tohex(kp.secret_seed)}\n" + out += f"PublicSeed = {tohex(kp.public_seed)}\n" + out += f"SecretPrf = {tohex(kp.secret_prf)}\n" + out += f"PublicKey = {tohex(kp.public_key)}\n" + out += f"PrivateKey = {tohex(kp.secret_key)}\n" return out if len(sys.argv) < 3: - print("Usage: {} ".format( - sys.argv[0])) + print(f"Usage: {sys.argv[0]} ") sys.exit(1) funs = { diff --git a/src/scripts/dist.py b/src/scripts/dist.py index b0c7e5b191d..a94b01c8134 100755 --- a/src/scripts/dist.py +++ b/src/scripts/dist.py @@ -15,7 +15,7 @@ import hashlib import io import logging -import optparse # pylint: disable=deprecated-module +import optparse # pylint: disable=deprecated-module import os import re import shutil @@ -94,7 +94,7 @@ def extract_revision(revision, to): tar_val = run_git(['archive', '--format=tar', '--prefix=%s/' % (to), revision]) tar_f = tarfile.open(fileobj=io.BytesIO(tar_val)) - if sys.version_info.major == 3 and sys.version_info.minor >= 12: + if sys.version_info >= (3, 12): tar_f.extractall(filter='fully_trusted') else: tar_f.extractall() diff --git a/src/scripts/gdb/strubtest.py b/src/scripts/gdb/strubtest.py index a48552cc205..63c3f099e93 100644 --- a/src/scripts/gdb/strubtest.py +++ b/src/scripts/gdb/strubtest.py @@ -20,6 +20,7 @@ import gdb + def stack_pointer(frame): return frame.read_register('sp') diff --git a/src/scripts/install.py b/src/scripts/install.py index 85f4d31c1c9..1e241e2bf9b 100755 --- a/src/scripts/install.py +++ b/src/scripts/install.py @@ -11,12 +11,13 @@ import errno import json import logging -import optparse # pylint: disable=deprecated-module +import optparse # pylint: disable=deprecated-module import os import shutil import sys import traceback + def parse_command_line(args): parser = optparse.OptionParser() @@ -92,7 +93,7 @@ def makedirs(dirname, exist_ok=True): os.makedirs(dirname) except OSError as ex: if ex.errno != errno.EEXIST or not exist_ok: - raise ex + raise # Clear link and create new one def force_symlink(target, linkname): @@ -100,7 +101,7 @@ def force_symlink(target, linkname): os.unlink(linkname) except OSError as ex: if ex.errno != errno.ENOENT: - raise ex + raise os.symlink(target, linkname) def calculate_exec_mode(options): diff --git a/src/scripts/python_unittests.py b/src/scripts/python_unittests.py index a6a22f3f0b5..6e325fe4a7e 100755 --- a/src/scripts/python_unittests.py +++ b/src/scripts/python_unittests.py @@ -14,8 +14,11 @@ import unittest sys.path.append("../..") # Botan repo root -from configure import AmalgamationHelper # pylint: disable=wrong-import-position -from configure import ModulesChooser # pylint: disable=wrong-import-position +from configure import ( # pylint: disable=wrong-import-position + AmalgamationHelper, + ModulesChooser, +) + class AmalgamationHelperTests(unittest.TestCase): def test_matcher_std_includes(self): @@ -63,23 +66,23 @@ def test_matcher_any_includes(self): class ModulesChooserResolveDependencies(unittest.TestCase): def test_base(self): - available_modules = set(["A", "B"]) + available_modules = {"A", "B"} table = { "A": [], } ok, modules = ModulesChooser.resolve_dependencies(available_modules, table, "A") self.assertTrue(ok) - self.assertEqual(modules, set(["A"])) + self.assertEqual(modules, {"A"}) def test_no_dependencies_defined(self): - available_modules = set(["A", "B"]) + available_modules = {"A", "B"} table = { "A": [], } with self.assertRaises(KeyError): ModulesChooser.resolve_dependencies(available_modules, table, "B") - available_modules = set(["A", "B"]) + available_modules = {"A", "B"} table = { "A": ["B"], } @@ -87,17 +90,17 @@ def test_no_dependencies_defined(self): ModulesChooser.resolve_dependencies(available_modules, table, "A") def test_add_dependency(self): - available_modules = set(["A", "B"]) + available_modules = {"A", "B"} table = { "A": ["B"], "B": [] } ok, modules = ModulesChooser.resolve_dependencies(available_modules, table, "A") self.assertTrue(ok) - self.assertEqual(modules, set(["A", "B"])) + self.assertEqual(modules, {"A", "B"}) def test_add_dependencies_two_levels(self): - available_modules = set(["A", "B", "C"]) + available_modules = {"A", "B", "C"} table = { "A": ["B"], "B": ["C"], @@ -105,10 +108,10 @@ def test_add_dependencies_two_levels(self): } ok, modules = ModulesChooser.resolve_dependencies(available_modules, table, "A") self.assertTrue(ok) - self.assertEqual(modules, set(["A", "B", "C"])) + self.assertEqual(modules, {"A", "B", "C"}) def test_circular(self): - available_modules = set(["A", "B", "C"]) + available_modules = {"A", "B", "C"} table = { "A": ["B"], "B": ["C"], @@ -116,10 +119,10 @@ def test_circular(self): } ok, modules = ModulesChooser.resolve_dependencies(available_modules, table, "A") self.assertTrue(ok) - self.assertEqual(modules, set(["A", "B", "C"])) + self.assertEqual(modules, {"A", "B", "C"}) def test_not_available(self): - available_modules = set(["A", "C"]) + available_modules = {"A", "C"} table = { "A": ["B"], "B": ["C"], @@ -129,7 +132,7 @@ def test_not_available(self): self.assertFalse(ok) def test_dependency_not_available(self): - available_modules = set(["A", "C"]) + available_modules = {"A", "C"} table = { "A": ["B"], "B": ["C"], @@ -139,7 +142,7 @@ def test_dependency_not_available(self): self.assertFalse(ok) def test_dependency2_not_available(self): - available_modules = set(["A", "B"]) + available_modules = {"A", "B"} table = { "A": ["B"], "B": ["C"], @@ -149,7 +152,7 @@ def test_dependency2_not_available(self): self.assertFalse(ok) def test_dependency_choices(self): - available_modules = set(["A", "B", "C"]) + available_modules = {"A", "B", "C"} table = { "A": ["B|C"], "B": [], @@ -157,10 +160,10 @@ def test_dependency_choices(self): } ok, modules = ModulesChooser.resolve_dependencies(available_modules, table, "A") self.assertTrue(ok) - self.assertTrue(modules == set(["A", "B"]) or modules == set(["A", "C"])) + self.assertTrue(modules in ({"A", "B"}, {"A", "C"})) def test_dependency_prefer_existing(self): - available_modules = set(["A", "B", "C"]) + available_modules = {"A", "B", "C"} table = { "A": ["C", "B|C"], "B": [], @@ -168,10 +171,10 @@ def test_dependency_prefer_existing(self): } ok, modules = ModulesChooser.resolve_dependencies(available_modules, table, "A") self.assertTrue(ok) - self.assertEqual(modules, set(["A", "C"])) + self.assertEqual(modules, {"A", "C"}) def test_dependency_prefer_existing2(self): - available_modules = set(["A", "B", "C"]) + available_modules = {"A", "B", "C"} table = { "A": ["B", "B|C"], "B": [], @@ -179,10 +182,10 @@ def test_dependency_prefer_existing2(self): } ok, modules = ModulesChooser.resolve_dependencies(available_modules, table, "A") self.assertTrue(ok) - self.assertEqual(modules, set(["A", "B"])) + self.assertEqual(modules, {"A", "B"}) def test_dependency_choices_impossible(self): - available_modules = set(["A", "C"]) + available_modules = {"A", "C"} table = { "A": ["B|C"], "B": [], @@ -190,10 +193,10 @@ def test_dependency_choices_impossible(self): } ok, modules = ModulesChooser.resolve_dependencies(available_modules, table, "A") self.assertTrue(ok) - self.assertEqual(modules, set(["A", "C"])) + self.assertEqual(modules, {"A", "C"}) def test_dependency_choices_impossible2(self): - available_modules = set(["A", "B"]) + available_modules = {"A", "B"} table = { "A": ["B|C"], "B": [], @@ -201,10 +204,10 @@ def test_dependency_choices_impossible2(self): } ok, modules = ModulesChooser.resolve_dependencies(available_modules, table, "A") self.assertTrue(ok) - self.assertEqual(modules, set(["A", "B"])) + self.assertEqual(modules, {"A", "B"}) def test_deep(self): - available_modules = set(["A", "B", "C", "E", "G"]) + available_modules = {"A", "B", "C", "E", "G"} table = { "A": ["B|C"], "B": ["D"], @@ -216,7 +219,7 @@ def test_deep(self): } ok, modules = ModulesChooser.resolve_dependencies(available_modules, table, "G") self.assertTrue(ok) - self.assertEqual(modules, set(["G", "A", "C", "E"])) + self.assertEqual(modules, {"G", "A", "C", "E"}) if __name__ == '__main__': diff --git a/src/scripts/python_unittests_unix.py b/src/scripts/python_unittests_unix.py index fe9f06a62a8..fd49473039f 100755 --- a/src/scripts/python_unittests_unix.py +++ b/src/scripts/python_unittests_unix.py @@ -16,8 +16,10 @@ import unittest sys.path.append("../..") # Botan repo root -from install import prepend_destdir # pylint: disable=wrong-import-position -from install import PrependDestdirError # pylint: disable=wrong-import-position +from install import ( # pylint: disable=wrong-import-position + PrependDestdirError, + prepend_destdir, +) class PrependDestdir(unittest.TestCase): diff --git a/src/scripts/repo_config.py b/src/scripts/repo_config.py old mode 100644 new mode 100755 index a4cfdcc13f5..cb7113e5bf9 --- a/src/scripts/repo_config.py +++ b/src/scripts/repo_config.py @@ -30,7 +30,7 @@ def __init__(self, env_file: str = _DEFAULT_REPO_CONFIG_LOCATION): self._file_path = env_file parser = re.compile(r'^(?P\w+)\s*=\s*((?P[^\"]\S+)|\"(?P\S+)\")\s*$') with open(self._file_path, 'r', encoding='utf-8') as f: - for line in f.readlines(): + for line in f: if m := parser.match(line): var = m.group('var') val = m.group('val') or m.group('quoted_val') diff --git a/src/scripts/rewrite_lcov.py b/src/scripts/rewrite_lcov.py index c0c12f5faa1..b88055b7be7 100755 --- a/src/scripts/rewrite_lcov.py +++ b/src/scripts/rewrite_lcov.py @@ -6,9 +6,10 @@ Botan is released under the Simplified BSD License (see license.txt) """ -import sys -import re import os +import re +import sys + def main(args = None): if args is None: diff --git a/src/scripts/run_limbo_tests.py b/src/scripts/run_limbo_tests.py index bc1da7b4fc1..9266bec4841 100755 --- a/src/scripts/run_limbo_tests.py +++ b/src/scripts/run_limbo_tests.py @@ -4,14 +4,15 @@ Runs the tests from https://github.com/C2SP/x509-limbo """ -from botan3 import X509Cert -from dateutil import parser import json -import optparse # pylint: disable=deprecated-module +import optparse # pylint: disable=deprecated-module import re import subprocess import sys +from botan3 import X509Cert +from dateutil import parser + ignored_tests = {} tests_that_succeed_unexpectedly = { @@ -137,7 +138,8 @@ def dump_x509(who, cert): dump_cmd = ['openssl', 'x509', '-text', '-noout'] proc = subprocess.run(dump_cmd, input=bytes(cert, 'utf8'), - capture_output=True) + capture_output=True, + check=False) print(proc.stdout.decode('utf8')) @@ -189,9 +191,8 @@ def main(args = None): modified = 0 for test in limbo_json['testcases']: - if run_only is not None: - if run_only.match(test['id']) is None: - continue + if run_only is not None and run_only.match(test['id']) is None: + continue if test['extended_key_usage'] != [] or test['max_chain_depth'] is not None: # we have no way of expressing this here diff --git a/src/scripts/run_tests_under_valgrind.py b/src/scripts/run_tests_under_valgrind.py index 199abcf71ba..b6d8030f54b 100755 --- a/src/scripts/run_tests_under_valgrind.py +++ b/src/scripts/run_tests_under_valgrind.py @@ -9,13 +9,13 @@ """ import multiprocessing -import optparse # pylint: disable=deprecated-module +import optparse # pylint: disable=deprecated-module import subprocess import sys import time - from multiprocessing.pool import ThreadPool + def get_concurrency(): def_concurrency = 2 max_concurrency = 16 @@ -44,7 +44,7 @@ def run_valgrind(options, test): cmd = valgrind_cmd + [options.test_binary] + botan_test_options + test start = time.time() - proc = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + proc = subprocess.run(cmd, capture_output=True, check=False) duration = time.time() - start if options.verbose: @@ -60,7 +60,7 @@ def run_valgrind(options, test): return False def filter_tests(available, cmdline, options): - skip_tests = sum([x.split(',') for x in options.skip_tests], []) + skip_tests = [t for x in options.skip_tests for t in x.split(',')] to_run = [] diff --git a/src/scripts/run_tls_attacker.py b/src/scripts/run_tls_attacker.py index 4d69749f7cc..ac2f0aff014 100755 --- a/src/scripts/run_tls_attacker.py +++ b/src/scripts/run_tls_attacker.py @@ -3,14 +3,15 @@ # (C) 2017 Jack Lloyd # Botan is released under the Simplified BSD License (see license.txt) +import optparse import os -import sys +import random +import string import subprocess +import sys import tempfile import time -import random -import optparse -import string + def run_subprocess(cmd): print("Running '%s'" % (' '.join(cmd))) diff --git a/src/scripts/run_tls_fuzzer.py b/src/scripts/run_tls_fuzzer.py index a5ca0535a52..f2721dd71ed 100755 --- a/src/scripts/run_tls_fuzzer.py +++ b/src/scripts/run_tls_fuzzer.py @@ -4,12 +4,13 @@ # Botan is released under the Simplified BSD License (see license.txt) import argparse -import subprocess import logging -import sys import os +import subprocess +import sys import time + def script_is_disabled(script_name): if script_name.find('tls13') >= 0: return True @@ -36,10 +37,7 @@ def script_is_disabled(script_name): 'test-invalid-client-hello.py', 'test-large-hello.py', } - if script_name in slow: - return True - - return False + return script_name in slow def main(args = None): if args is None: diff --git a/src/scripts/test_all_configs.py b/src/scripts/test_all_configs.py index 012e287f1d6..9911e12e62c 100755 --- a/src/scripts/test_all_configs.py +++ b/src/scripts/test_all_configs.py @@ -11,9 +11,10 @@ Botan is released under the Simplified BSD License (see license.txt) """ -import optparse # pylint: disable=deprecated-module -import sys +import optparse # pylint: disable=deprecated-module import subprocess +import sys + def get_module_list(configure_py): configure = subprocess.Popen([configure_py, '--list-modules'], stdout=subprocess.PIPE) diff --git a/src/scripts/test_cli.py b/src/scripts/test_cli.py index b3e5266661f..2d26dc7d27b 100755 --- a/src/scripts/test_cli.py +++ b/src/scripts/test_cli.py @@ -12,7 +12,7 @@ import json import logging import multiprocessing -import optparse # pylint: disable=deprecated-module +import optparse # pylint: disable=deprecated-module import os import platform import random @@ -26,9 +26,9 @@ import threading import time import traceback -from multiprocessing.pool import ThreadPool from http.client import HTTPSConnection -from http.server import HTTPServer, BaseHTTPRequestHandler +from http.server import BaseHTTPRequestHandler, HTTPServer +from multiprocessing.pool import ThreadPool # pylint: disable=global-statement,unused-argument @@ -280,13 +280,12 @@ def test_cli(cmd, cmd_options, if expected_stderr is not None: logging.error('Expected output on stderr but got nothing', stack_info=True) - if expected_output is not None: - if stdout != expected_output: - logging.error("Got unexpected output running cmd %s %s", cmd, cmd_options, stack_info=True) - if len(stdout) != len(expected_output): - logging.info("Output lengths %d vs expected %d", len(stdout), len(expected_output)) - logging.info("Got %s", stdout) - logging.info("Exp %s", expected_output) + if expected_output is not None and stdout != expected_output: + logging.error("Got unexpected output running cmd %s %s", cmd, cmd_options, stack_info=True) + if len(stdout) != len(expected_output): + logging.info("Output lengths %d vs expected %d", len(stdout), len(expected_output)) + logging.info("Got %s", stdout) + logging.info("Exp %s", expected_output) return stdout @@ -306,12 +305,12 @@ def cli_config_tests(_tmp_dir): if platform.system() == 'Windows': if len(prefix) < 4 or prefix[1] != ':' or prefix[2] != '\\': logging.error("Bad prefix %s", prefix) - if not ldflags.endswith(("-L%s\\lib" % (prefix))): + if not ldflags.endswith("-L%s\\lib" % (prefix)): logging.error("Bad ldflags %s", ldflags) else: if len(prefix) < 4 or prefix[0] != '/': logging.error("Bad prefix %s", prefix) - if not ldflags.endswith(("-L%s/lib" % (prefix))): + if not ldflags.endswith("-L%s/lib" % (prefix)): logging.error("Bad ldflags %s", ldflags) if ("-I%s/include/botan-3" % (prefix)) not in cflags and ("-I%s/include" % (prefix)) not in cflags: logging.error("Bad cflags %s", cflags) @@ -1775,9 +1774,8 @@ def cli_speed_tests(_tmp_dir): format_re_ks = re.compile(r'^AES-128/GCM\(16\).* [0-9]+ key schedule/sec; [0-9]+\.[0-9]+ ms/op .*\([0-9]+ (op|ops) in [0-9\.]+ ms\)') format_re_cipher = re.compile(r'^AES-128/GCM\(16\) .* buffer size [0-9]+ bytes: [0-9]+\.[0-9]+ MiB\/sec .*\([0-9]+\.[0-9]+ MiB in [0-9]+\.[0-9]+ ms\)') for line in output: - if format_re_ks.match(line) is None: - if format_re_cipher.match(line) is None: - logging.error('Unexpected line %s', line) + if format_re_ks.match(line) is None and format_re_cipher.match(line) is None: + logging.error('Unexpected line %s', line) output = test_cli("speed", ["--msec=%d" % (msec), "scrypt"], None).split('\n') diff --git a/src/scripts/test_cli_crypt.py b/src/scripts/test_cli_crypt.py index 325fca68f67..092c87a86ba 100755 --- a/src/scripts/test_cli_crypt.py +++ b/src/scripts/test_cli_crypt.py @@ -7,18 +7,19 @@ Botan is released under the Simplified BSD License (see license.txt) """ -import binascii import argparse +import binascii +import logging +import multiprocessing +import os.path import re import subprocess import sys -import os.path -import logging import time from collections import OrderedDict -import multiprocessing from multiprocessing.pool import ThreadPool + class VecDocument: def __init__(self, filepath): self.data = OrderedDict() @@ -70,10 +71,10 @@ def get_data(self): TESTS_RUN = 0 TESTS_FAILED = 0 -class TestLogHandler(logging.StreamHandler, object): +class TestLogHandler(logging.StreamHandler): def emit(self, record): # Do the default stuff first - super(TestLogHandler, self).emit(record) + super().emit(record) if record.levelno >= logging.ERROR: global TESTS_FAILED TESTS_FAILED += 1 @@ -92,7 +93,7 @@ def setup_logging(options): logging.getLogger().setLevel(log_level) def test_cipher_kat(cli_binary, data): - iv = data['Nonce'] if 'Nonce' in data else '' + iv = data.get('Nonce', '') key = data['Key'] plaintext = data['In'].lower() ciphertext = data['Out'].lower() @@ -133,12 +134,9 @@ def test_cipher_kat(cli_binary, data): def get_testdata(document, max_tests): out = [] for algorithm in document: - testcase_number = 0 - for testcase in document[algorithm]: - testcase_number += 1 + for testcase_number, testcase in enumerate(document[algorithm], start=1): for direction in ['encrypt', 'decrypt']: - testname = "{} no {:0>3} ({})".format( - algorithm.lower(), testcase_number, direction) + testname = f"{algorithm.lower()} no {testcase_number:0>3} ({direction})" testname = re.sub("[^a-z0-9-]", "_", testname) testname = re.sub("_+", "_", testname) testname = testname.strip("_") diff --git a/src/scripts/test_fuzzers.py b/src/scripts/test_fuzzers.py index b1f32bec487..dca9c0705e4 100755 --- a/src/scripts/test_fuzzers.py +++ b/src/scripts/test_fuzzers.py @@ -3,14 +3,15 @@ # (C) 2017,2018 Jack Lloyd # Botan is released under the Simplified BSD License (see license.txt) -import sys +import multiprocessing +import optparse # pylint: disable=deprecated-module import os -import subprocess -import optparse # pylint: disable=deprecated-module import stat -import multiprocessing -import time +import subprocess +import sys import tempfile +import time + def run_fuzzer_gdb(args): (fuzzer_bin, corpus_file) = args @@ -80,13 +81,13 @@ def main(args=None): print("Error could not access fuzzers directory '%s'" % (fuzzer_dir)) return 1 - fuzzers = set([]) + fuzzers = set() for fuzzer in os.listdir(fuzzer_dir): if fuzzer.endswith('.zip'): continue fuzzers.add(fuzzer) - corpii = set([]) + corpii = set() for corpus in os.listdir(corpus_dir): # Ignore regular files in toplevel dir if not stat.S_ISDIR(os.stat(os.path.join(corpus_dir, corpus)).st_mode): @@ -100,9 +101,9 @@ def main(args=None): fuzzers_without_corpus = fuzzers - corpii corpus_without_fuzzers = corpii - fuzzers - for f in sorted(list(fuzzers_without_corpus)): + for f in sorted(fuzzers_without_corpus): print("Warning: Fuzzer %s has no corpus" % (f)) - for c in sorted(list(corpus_without_fuzzers)): + for c in sorted(corpus_without_fuzzers): print("Warning: Corpus %s has no fuzzer" % (c)) fuzzers_with_corpus = fuzzers & corpii @@ -117,10 +118,10 @@ def main(args=None): run_fuzzer_func = run_fuzzer_gdb if options.gdb else run_fuzzer - for fuzzer in sorted(list(fuzzers_with_corpus)): + for fuzzer in sorted(fuzzers_with_corpus): fuzzer_bin = os.path.join(fuzzer_dir, fuzzer) corpus_subdir = os.path.join(corpus_dir, fuzzer) - corpus_files = [os.path.join(corpus_subdir, fsname) for fsname in sorted(list(os.listdir(corpus_subdir)))] + corpus_files = [os.path.join(corpus_subdir, fsname) for fsname in sorted(os.listdir(corpus_subdir))] # We have to do this hack because multiprocessing's Pool.map doesn't support # passing any initial arguments, just the single iterable @@ -162,7 +163,7 @@ def main(args=None): fd.write(random_input) fd.close() - for fuzzer in sorted(list(fuzzers)): + for fuzzer in sorted(fuzzers): fuzzer_bin = os.path.join(fuzzer_dir, fuzzer) if fuzzer in fuzzers_with_corpus: @@ -170,7 +171,7 @@ def main(args=None): else: corpus_subdir = random_corpus_dir - corpus_files = [os.path.join(corpus_subdir, fsname) for fsname in sorted(list(os.listdir(corpus_subdir)))] + corpus_files = [os.path.join(corpus_subdir, fsname) for fsname in sorted(os.listdir(corpus_subdir))] if fuzzer in slow_fuzzers: corpus_files = corpus_files[:random_corpus_size_for_slow_fuzzers] diff --git a/src/scripts/test_python.py b/src/scripts/test_python.py old mode 100644 new mode 100755 index 7e85cdb087b..62d67578bfe --- a/src/scripts/test_python.py +++ b/src/scripts/test_python.py @@ -6,14 +6,14 @@ Botan is released under the Simplified BSD License (see license.txt) """ -import unittest +import argparse import binascii import hashlib import os import platform -import argparse import sys import time +import unittest from itertools import permutations # Starting with Python 3.8 DLL search locations are more restricted on Windows. @@ -23,7 +23,8 @@ if platform.system() == "Windows" and hasattr(os, "add_dll_directory"): os.add_dll_directory(os.getcwd()) -import botan3 as botan # pylint: disable=wrong-import-position +import botan3 as botan # pylint: disable=wrong-import-position + def hex_encode(buf): return binascii.hexlify(buf).decode('ascii') @@ -331,7 +332,7 @@ def test_esdm_rng(self): if ex.error_code() == -40: # Not Implemented self.skipTest("No ESDM support in this build") else: - raise ex + raise output1 = esdm_rng.get(32) output2 = esdm_rng.get(32) @@ -359,7 +360,7 @@ def test_tpm2_rng(self): if ex.error_code() == -40: # Not Implemented self.skipTest("No TPM2 support in this build") else: - raise ex + raise if tpm2_ctx.supports_botan_crypto_backend(): user_rng = botan.RandomNumberGenerator("user") @@ -374,7 +375,7 @@ def test_tpm2_rng(self): # invalid session object provided with self.assertRaisesRegex(botan.BotanException, r".*0 to 3 TPM2Session objects.*"): botan.RandomNumberGenerator("tpm2", tpm2_context=tpm2_ctx, - tpm2_sessions=int(0)) + tpm2_sessions=0) # too many "sessions" provided with self.assertRaisesRegex(botan.BotanException, r".*0 to 3 TPM2Session objects.*"): @@ -945,7 +946,7 @@ def test_rfc7748_kex(self): a_pubv = a_op.public_value() b_pubv = b_op.public_value() - salt = bytes() + salt = b"" a_key = a_op.agree(b_pubv, 0, salt) b_key = b_op.agree(a_pubv, 0, salt) @@ -1473,7 +1474,7 @@ def test_ec_points(self): self.assertTrue(xy_bytes == x_bytes + y_bytes) self.assertTrue(uncompressed_bytes == "04" + xy_bytes) - self.assertTrue(compressed_bytes.startswith("02") or compressed_bytes.startswith("03")) + self.assertTrue(compressed_bytes.startswith(("02", "03"))) self.assertTrue(compressed_bytes[2::] == x_bytes) self.assertTrue(result == botan.ECPoint.from_xy(group, botan.MPI(x_bytes, 16), botan.MPI(y_bytes, 16))) diff --git a/src/scripts/test_strubbed_symbols.py b/src/scripts/test_strubbed_symbols.py index 294c7ac986b..af6c4d177b4 100755 --- a/src/scripts/test_strubbed_symbols.py +++ b/src/scripts/test_strubbed_symbols.py @@ -6,15 +6,14 @@ # Botan is released under the Simplified BSD License (see license.txt) # -import subprocess +import argparse import os +import platform +import subprocess import sys -import argparse import tempfile -import platform - -from textwrap import indent from enum import Enum +from textwrap import indent SCRIPT_LOCATION = os.path.dirname(os.path.abspath(__file__)) GDB_EXTENSION = os.path.join(SCRIPT_LOCATION, "gdb", "strubtest.py") diff --git a/src/scripts/tls_anvil/analyze_tls_anvil_report.py b/src/scripts/tls_anvil/analyze_tls_anvil_report.py index 21ade4857f8..6ad3334a7e6 100755 --- a/src/scripts/tls_anvil/analyze_tls_anvil_report.py +++ b/src/scripts/tls_anvil/analyze_tls_anvil_report.py @@ -6,12 +6,11 @@ # (C) 2023 Fabian Albert, Rohde & Schwarz Cybersecurity # # Botan is released under the Simplified BSD License (see license.txt) -import sys import argparse -import os import json import logging - +import os +import sys result_level = { "STRICTLY_SUCCEEDED": 0, @@ -61,13 +60,13 @@ def xfail_list(side): xfails = {} for test in conceptually_succeeded: - if test.startswith('both.') or test.startswith(side): + if test.startswith(('both.', side)): xfails[test] = result_level["CONCEPTUALLY_SUCCEEDED"] for test in partially_failed: - if test.startswith('both.') or test.startswith(side): + if test.startswith(('both.', side)): xfails[test] = result_level["PARTIALLY_FAILED"] for test in fully_failed: - if test.startswith('both.') or test.startswith(side): + if test.startswith(('both.', side)): xfails[test] = result_level["FULLY_FAILED"] return xfails @@ -148,7 +147,7 @@ def process_test_result(result_path: str, xfails: dict, seen_xfails: set): if method_id in xfails: expected_level = xfails[method_id] seen_xfails.add(method_id) - expected_label = [k for k, v in result_level.items() if v == expected_level][0] + expected_label = next(k for k, v in result_level.items() if v == expected_level) if actual_level != expected_level: # Test is doing other than expected -> error @@ -226,7 +225,7 @@ def main(args=None): # Check that every xfail entry was actually seen in the results missing_xfails = set(xfails.keys()) - seen_xfails for method_id in sorted(missing_xfails): - expected_label = [k for k, v in result_level.items() if v == xfails[method_id]][0] + expected_label = next(k for k, v in result_level.items() if v == xfails[method_id]) logging.warning( "xfailed test '%s' (expected %s) was not found in results.", method_id, expected_label) diff --git a/src/scripts/tls_anvil/run_tls_anvil_tests.py b/src/scripts/tls_anvil/run_tls_anvil_tests.py index b538db9bb65..7bcd37f26a6 100755 --- a/src/scripts/tls_anvil/run_tls_anvil_tests.py +++ b/src/scripts/tls_anvil/run_tls_anvil_tests.py @@ -7,13 +7,13 @@ # (C) 2023 Fabian Albert, Rohde & Schwarz Cybersecurity # # Botan is released under the Simplified BSD License (see license.txt) -import sys import argparse import os import subprocess +import sys sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), '..')) -from repo_config import RepoConfig # noqa: E402 +from repo_config import RepoConfig _repo_config = RepoConfig() diff --git a/src/scripts/tls_anvil/tls_anvil_trigger_server.py b/src/scripts/tls_anvil/tls_anvil_trigger_server.py index 544fd8d5185..d30310318b0 100644 --- a/src/scripts/tls_anvil/tls_anvil_trigger_server.py +++ b/src/scripts/tls_anvil/tls_anvil_trigger_server.py @@ -7,14 +7,13 @@ # # Botan is released under the Simplified BSD License (see license.txt) -import sys +import argparse import os import signal import subprocess -import argparse +import sys import threading -from http.server import HTTPServer, BaseHTTPRequestHandler - +from http.server import BaseHTTPRequestHandler, HTTPServer # Populated from command-line arguments in main() botan_cli = None diff --git a/src/scripts/tls_scanner/tls_scanner.py b/src/scripts/tls_scanner/tls_scanner.py index 1004ffeec28..e9e7b3d64c0 100755 --- a/src/scripts/tls_scanner/tls_scanner.py +++ b/src/scripts/tls_scanner/tls_scanner.py @@ -3,13 +3,14 @@ # (C) 2017 Jack Lloyd # Botan is released under the Simplified BSD License (see license.txt) +import re +import subprocess import sys import time -import subprocess -import re + def format_report(client_output): - version_re = re.compile('TLS (v1\.[0-3]) using ([A-Z0-9_]+)') + version_re = re.compile(r'TLS (v1\.[0-3]) using ([A-Z0-9_]+)') version_match = version_re.search(client_output) @@ -30,32 +31,32 @@ def scanner(args = None): scanners = {} - for url in [s.strip() for s in open(args[1]).readlines()]: + for url in [s.strip() for s in open(args[1])]: scanners[url] = subprocess.Popen(['../../../botan', 'tls_client', '--policy=policy.txt', url], stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE) - for url in scanners.keys(): - scanners[url].stdin.close() + for scan_proc in scanners.values(): + scan_proc.stdin.close() report = {} timeout = 10 - for url in scanners.keys(): + for url, scan_proc in scanners.items(): print("waiting for", url) for i in range(timeout): - scanners[url].poll() - if scanners[url].returncode is not None: + scan_proc.poll() + if scan_proc.returncode is not None: break #print("Waiting %d more seconds for %s" % (timeout-i, url)) time.sleep(1) - if scanners[url].returncode is not None: - output = scanners[url].stdout.read() + scanners[url].stderr.read() + if scan_proc.returncode is not None: + output = scan_proc.stdout.read() + scan_proc.stderr.read() report[url] = format_report(output.decode("utf-8")) - for url in report.keys(): - print(url, ":", report[url]) + for url, result in report.items(): + print(url, ":", result) return 0 diff --git a/src/scripts/website.py b/src/scripts/website.py index ec30b8e3f78..ae383851656 100755 --- a/src/scripts/website.py +++ b/src/scripts/website.py @@ -8,13 +8,14 @@ Botan is released under the Simplified BSD License (see license.txt) """ -import optparse # pylint: disable=deprecated-module -import subprocess -import sys import errno +import optparse # pylint: disable=deprecated-module +import os import shutil +import subprocess +import sys import tempfile -import os + def run_and_check(cmd_line, cwd=None): print("Executing %s ..." % (' '.join(cmd_line))) @@ -137,7 +138,7 @@ def main(args): if e.errno == errno.EEXIST: pass else: - raise e + raise for subdir in ['_static', '_sources', 'doxygen', 'handbook']: try: diff --git a/src/scripts/wycheproof.py b/src/scripts/wycheproof.py index 90d2085d4bb..a60fb462718 100755 --- a/src/scripts/wycheproof.py +++ b/src/scripts/wycheproof.py @@ -10,6 +10,7 @@ Botan is released under the Simplified BSD License (see license.txt) """ +from __future__ import annotations import argparse import base64 @@ -1596,16 +1597,15 @@ def handle_rsa_oaep(_data: dict, group: dict, test: dict) -> None: "ComputedMsg": plaintext.hex(), } ) - elif test["result"] == "invalid": - if plaintext == expected: - raise TestFailure( - { - "Ctext": test["ct"], - "Ptext": test["msg"], - "Padding": padding, - "Note": "Invalid test decrypted successfully", - } - ) + elif test["result"] == "invalid" and plaintext == expected: + raise TestFailure( + { + "Ctext": test["ct"], + "Ptext": test["msg"], + "Padding": padding, + "Note": "Invalid test decrypted successfully", + } + ) @register("RSAES-PKCS1-v1_5") @@ -1635,15 +1635,14 @@ def handle_rsa_pkcs1_enc(_data: dict, group: dict, test: dict) -> None: "ComputedMsg": plaintext.hex(), } ) - elif test["result"] == "invalid": - if plaintext == expected: - raise TestFailure( - { - "Ctext": test["ct"], - "Ptext": test["msg"], - "Note": "Invalid test decrypted successfully", - } - ) + elif test["result"] == "invalid" and plaintext == expected: + raise TestFailure( + { + "Ctext": test["ct"], + "Ptext": test["msg"], + "Note": "Invalid test decrypted successfully", + } + ) # ---- XDH handler (X25519, X448) ----