From 70ebe74d1781f509b8407deac8229369bee461ac Mon Sep 17 00:00:00 2001 From: Kunal Mehta Date: Tue, 10 Jan 2023 12:59:52 -0500 Subject: [PATCH] Apply pyupgrade to Python files Generated with `pyupgrade --py38-plus **.py`, with manual adjustments for unused imports and then running black+isort. Mostly covers: * migration to f-strings * removal of coding: utf-8 comments * io.open() -> open() Fixes #6699. --- admin/bootstrap.py | 26 ++++------ admin/securedrop_admin/__init__.py | 52 +++++++++---------- admin/tests/test_integration.py | 41 +++++++-------- admin/tests/test_securedrop-admin-setup.py | 5 +- admin/tests/test_securedrop-admin.py | 12 ++--- .../callback_plugins/ansible_version_check.py | 3 -- .../build-ossec-deb-pkg/library/ossec_urls.py | 6 +-- .../roles/restore/files/compare_torrc.py | 3 +- .../tails-config/files/securedrop_init.py | 23 ++++---- .../journalist_gui/SecureDropUpdater.py | 2 +- journalist_gui/journalist_gui/resources_rc.py | 2 - journalist_gui/journalist_gui/updaterUI.py | 4 +- journalist_gui/test_gui.py | 2 +- .../tests/test_play_configuration.py | 7 ++- .../tests/test_build_dependencies.py | 6 +-- .../tests/test_securedrop_deb_package.py | 26 +++++----- .../tests/test_security_updates.py | 2 +- .../app-code/test_securedrop_app_code.py | 12 ++--- .../app-code/test_securedrop_rqrequeue.py | 6 +-- .../app-code/test_securedrop_rqworker.py | 8 +-- .../test_securedrop_shredder_configuration.py | 6 +-- ...securedrop_source_deleter_configuration.py | 6 +-- .../test_apache_journalist_interface.py | 12 ++--- .../app/apache/test_apache_service.py | 10 ++-- .../apache/test_apache_source_interface.py | 14 ++--- .../app/apache/test_apache_system_config.py | 10 ++-- molecule/testinfra/app/test_app_network.py | 3 +- molecule/testinfra/app/test_apparmor.py | 6 +-- molecule/testinfra/app/test_appenv.py | 4 +- molecule/testinfra/app/test_ossec_agent.py | 2 +- molecule/testinfra/app/test_tor_config.py | 2 +- .../testinfra/app/test_tor_hidden_services.py | 8 +-- .../common/test_automatic_updates.py | 10 ++-- molecule/testinfra/common/test_grsecurity.py | 15 +++--- .../testinfra/common/test_release_upgrades.py | 2 +- .../testinfra/common/test_system_hardening.py | 4 +- molecule/testinfra/common/test_tor_mirror.py | 6 +-- molecule/testinfra/common/test_user_config.py | 2 +- molecule/testinfra/conftest.py | 7 ++- molecule/testinfra/mon/test_mon_network.py | 3 +- molecule/testinfra/mon/test_ossec_server.py | 2 +- molecule/testinfra/mon/test_postfix.py | 2 +- .../testinfra/ossec/test_journalist_mail.py | 32 +++++------- securedrop/alembic/env.py | 2 - securedrop/db.py | 2 - .../ossec-common/var/ossec/checksdconfig.py | 3 +- securedrop/encryption.py | 2 +- securedrop/i18n_tool.py | 24 ++++----- securedrop/journalist.py | 1 - securedrop/journalist_app/__init__.py | 2 +- securedrop/journalist_app/account.py | 1 - securedrop/journalist_app/admin.py | 8 +-- securedrop/journalist_app/api.py | 6 +-- securedrop/journalist_app/col.py | 6 +-- securedrop/journalist_app/decorators.py | 1 - securedrop/journalist_app/forms.py | 4 +- securedrop/journalist_app/main.py | 3 +- securedrop/journalist_app/utils.py | 9 ++-- securedrop/loaddata.py | 7 ++- securedrop/manage.py | 15 +++--- securedrop/management/run.py | 4 +- securedrop/management/submissions.py | 10 ++-- securedrop/models.py | 14 ++--- securedrop/passphrases.py | 2 +- securedrop/rm.py | 5 +- securedrop/secure_tempfile.py | 12 ++--- securedrop/server_os.py | 2 +- securedrop/source_app/info.py | 1 - securedrop/source_app/main.py | 5 +- securedrop/source_app/utils.py | 4 +- securedrop/source_user.py | 2 +- securedrop/specialstrings.py | 2 +- securedrop/store.py | 45 +++++++--------- securedrop/template_filters.py | 1 - securedrop/tests/config_from_2014.py | 2 +- securedrop/tests/conftest.py | 2 +- securedrop/tests/i18n/code.py | 1 - securedrop/tests/migrations/helpers.py | 2 - .../migrations/migration_15ac9509fc68.py | 2 - .../migrations/migration_1ddb81fb88c2.py | 2 - .../migrations/migration_2d0ce3ee5bdc.py | 2 - .../migrations/migration_35513370ba0d.py | 2 - .../migrations/migration_3d91d6948753.py | 2 - .../migrations/migration_3da3fcab826a.py | 2 - .../migrations/migration_48a75abc0121.py | 2 - .../migrations/migration_60f41bb14d98.py | 2 - .../migrations/migration_6db892e17271.py | 2 - .../migrations/migration_92fba0be98e9.py | 2 - .../migrations/migration_a9fe328b053a.py | 1 - .../migrations/migration_b060f38c0c31.py | 2 - .../migrations/migration_b58139cfdc8c.py | 8 ++- .../migrations/migration_c5a02eb52f2d.py | 1 - .../migrations/migration_d9d36b6f4d1e.py | 1 - .../migrations/migration_de00920916bf.py | 1 - .../migrations/migration_e0a525cbab83.py | 2 - .../migrations/migration_f2833ac34bb6.py | 2 - .../migrations/migration_faac8092c123.py | 3 -- .../migrations/migration_fccf57ceef02.py | 2 - securedrop/tests/test_alembic.py | 6 +-- securedrop/tests/test_db.py | 4 +- securedrop/tests/test_i18n.py | 3 +- securedrop/tests/test_i18n_tool.py | 21 ++++---- securedrop/tests/test_integration.py | 9 ++-- securedrop/tests/test_journalist.py | 20 +++---- securedrop/tests/test_journalist_api.py | 7 ++- securedrop/tests/test_manage.py | 11 ++-- securedrop/tests/test_rm.py | 2 +- securedrop/tests/test_secure_tempfile.py | 4 +- securedrop/tests/test_source.py | 3 +- securedrop/tests/test_source_utils.py | 3 +- securedrop/tests/test_store.py | 17 +++--- securedrop/tests/test_worker.py | 6 +-- securedrop/tests/utils/api_helper.py | 2 +- securedrop/tests/utils/asynchronous.py | 1 - securedrop/tests/utils/db_helper.py | 5 +- securedrop/tests/utils/i18n.py | 6 +-- securedrop/tests/utils/instrument.py | 7 +-- securedrop/upload-screenshots.py | 14 +++-- securedrop/worker.py | 6 +-- 119 files changed, 345 insertions(+), 483 deletions(-) diff --git a/admin/bootstrap.py b/admin/bootstrap.py index 49367bc3e2..25974d9493 100755 --- a/admin/bootstrap.py +++ b/admin/bootstrap.py @@ -1,4 +1,3 @@ -# -*- mode: python; coding: utf-8 -*- # # Copyright (C) 2013-2018 Freedom of the Press Foundation & al # Copyright (C) 2018 Loic Dachary @@ -53,9 +52,8 @@ def run_command(command: List[str]) -> Iterator[bytes]: """ popen = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) if popen.stdout is None: - raise EnvironmentError("Could not run command: None stdout") - for stdout_line in iter(popen.stdout.readline, b""): - yield stdout_line + raise OSError("Could not run command: None stdout") + yield from iter(popen.stdout.readline, b"") popen.stdout.close() return_code = popen.wait() if return_code: @@ -111,10 +109,8 @@ def install_apt_dependencies(args: argparse.Namespace) -> None: """ sdlog.info("Installing SecureDrop Admin dependencies") sdlog.info( - ( - "You'll be prompted for the temporary Tails admin password," - " which was set on Tails login screen" - ) + "You'll be prompted for the temporary Tails admin password," + " which was set on Tails login screen" ) apt_command = [ @@ -142,7 +138,7 @@ def install_apt_dependencies(args: argparse.Namespace) -> None: # under Tails 2.x. If updates are being applied, don't try to pile # on with more apt requests. sdlog.error( - ("Failed to install apt dependencies. Check network" " connection and try again.") + "Failed to install apt dependencies. Check network" " connection and try again." ) raise @@ -181,7 +177,7 @@ def envsetup(args: argparse.Namespace, virtualenv_dir: str = VENV_DIR) -> None: ) except subprocess.CalledProcessError as e: sdlog.debug(e.output) - sdlog.error(("Unable to create virtualenv. Check network settings" " and try again.")) + sdlog.error("Unable to create virtualenv. Check network settings" " and try again.") sdlog.debug("Cleaning up virtualenv") if os.path.exists(virtualenv_dir): shutil.rmtree(virtualenv_dir) @@ -234,23 +230,21 @@ def install_pip_dependencies( "only-if-needed", ] - sdlog.info("Checking {} for securedrop-admin".format(desc)) + sdlog.info(f"Checking {desc} for securedrop-admin") try: pip_output = subprocess.check_output( maybe_torify() + pip_install_cmd, stderr=subprocess.STDOUT ) except subprocess.CalledProcessError as e: sdlog.debug(e.output) - sdlog.error( - ("Failed to install {}. Check network" " connection and try again.".format(desc)) - ) + sdlog.error("Failed to install {}. Check network" " connection and try again.".format(desc)) raise sdlog.debug(pip_output) if "Successfully installed" in str(pip_output): - sdlog.info("{} for securedrop-admin upgraded".format(desc)) + sdlog.info(f"{desc} for securedrop-admin upgraded") else: - sdlog.info("{} for securedrop-admin are up-to-date".format(desc)) + sdlog.info(f"{desc} for securedrop-admin are up-to-date") def parse_argv(argv: List[str]) -> argparse.Namespace: diff --git a/admin/securedrop_admin/__init__.py b/admin/securedrop_admin/__init__.py index 2e1888188f..f956a15425 100755 --- a/admin/securedrop_admin/__init__.py +++ b/admin/securedrop_admin/__init__.py @@ -1,4 +1,3 @@ -# -*- mode: python; coding: utf-8 -*- # # Copyright (C) 2013-2018 Freedom of the Press Foundation & al # Copyright (C) 2018 Loic Dachary @@ -26,7 +25,6 @@ import argparse import base64 import functools -import io import ipaddress import json import logging @@ -154,7 +152,7 @@ def split_list(text: str) -> List[str]: class ValidatePath(Validator): def __init__(self, basedir: str) -> None: self.basedir = basedir - super(SiteConfig.ValidatePath, self).__init__() + super().__init__() def validate(self, document: Document) -> bool: if document.text == "": @@ -168,7 +166,7 @@ class ValidateOptionalPath(ValidatePath): def validate(self, document: Document) -> bool: if document.text == "": return True - return super(SiteConfig.ValidateOptionalPath, self).validate(document) + return super().validate(document) class ValidateYesNo(Validator): def validate(self, document: Document) -> bool: @@ -192,7 +190,7 @@ class ValidateOptionalFingerprint(ValidateFingerprint): def validate(self, document: Document) -> bool: if document.text == "": return True - return super(SiteConfig.ValidateOptionalFingerprint, self).validate(document) + return super().validate(document) class ValidateInt(Validator): def validate(self, document: Document) -> bool: @@ -200,7 +198,7 @@ def validate(self, document: Document) -> bool: return True raise ValidationError(message="Must be an integer") - class Locales(object): + class Locales: def __init__(self, appdir: str) -> None: self.translation_dir = os.path.realpath(os.path.join(appdir, "translations")) @@ -216,7 +214,7 @@ def __init__(self, basedir: str, supported: Set[str]) -> None: present = SiteConfig.Locales(basedir).get_translations() self.available = present & supported - super(SiteConfig.ValidateLocales, self).__init__() + super().__init__() def validate(self, document: Document) -> bool: desired = document.text.split() @@ -252,7 +250,7 @@ def validate(self, document: Document) -> bool: class ValidateOSSECEmail(ValidateEmail): def validate(self, document: Document) -> bool: - super(SiteConfig.ValidateOSSECEmail, self).validate(document) + super().validate(document) text = document.text if "ossec@ossec.test" != text: return True @@ -264,7 +262,7 @@ class ValidateOptionalEmail(ValidateEmail): def validate(self, document: Document) -> bool: if document.text == "": return True - return super(SiteConfig.ValidateOptionalEmail, self).validate(document) + return super().validate(document) def __init__(self, args: argparse.Namespace) -> None: self.args = args @@ -604,9 +602,9 @@ def validate_gpg_keys(self) -> bool: except subprocess.CalledProcessError as e: sdlog.debug(e.output) raise FingerprintException( - "fingerprint {} ".format(fingerprint) + f"fingerprint {fingerprint} " + "does not match " - + "the public key {}".format(public_key) + + f"the public key {public_key}" ) return True @@ -631,7 +629,7 @@ def exists(self) -> bool: return os.path.exists(self.args.site_config) def save(self) -> None: - with io.open(self.args.site_config, "w") as site_config_file: + with open(self.args.site_config, "w") as site_config_file: yaml.safe_dump(self.config, site_config_file, default_flow_style=False) def clean_config(self, config: Dict) -> Dict: @@ -683,14 +681,14 @@ def load(self, validate: bool = True) -> Dict: to current specifications. """ try: - with io.open(self.args.site_config) as site_config_file: + with open(self.args.site_config) as site_config_file: c = yaml.safe_load(site_config_file) return self.clean_config(c) if validate else c - except IOError: + except OSError: sdlog.error("Config file missing, re-run with sdconfig") raise except yaml.YAMLError: - sdlog.error("There was an issue processing {}".format(self.args.site_config)) + sdlog.error(f"There was an issue processing {self.args.site_config}") raise @@ -736,10 +734,10 @@ def wrapper(*args: Any, **kwargs: Any) -> Any: "You are not running the most recent signed SecureDrop release " "on this workstation." ) - sdlog.error("Latest available version: {}".format(latest_tag)) + sdlog.error(f"Latest available version: {latest_tag}") if branch_status is not None: - sdlog.error("Current branch status: {}".format(branch_status)) + sdlog.error(f"Current branch status: {branch_status}") else: sdlog.error("Problem determining current branch status.") @@ -805,7 +803,7 @@ def find_or_generate_new_torv3_keys(args: argparse.Namespace) -> int: """ secret_key_path = os.path.join(args.ansible_path, "tor_v3_keys.json") if os.path.exists(secret_key_path): - print("Tor v3 onion service keys already exist in: {}".format(secret_key_path)) + print(f"Tor v3 onion service keys already exist in: {secret_key_path}") return 0 # No old keys, generate and store them first app_journalist_public_key, app_journalist_private_key = generate_new_v3_keys() @@ -823,7 +821,7 @@ def find_or_generate_new_torv3_keys(args: argparse.Namespace) -> int: } with open(secret_key_path, "w") as fobj: json.dump(tor_v3_service_info, fobj, indent=4) - print("Tor v3 onion service keys generated and stored in: {}".format(secret_key_path)) + print(f"Tor v3 onion service keys generated and stored in: {secret_key_path}") return 0 @@ -886,7 +884,7 @@ def restore_securedrop(args: argparse.Namespace) -> int: ] ansible_cmd_extras = [ - "restore_file='{}'".format(restore_file_basename), + f"restore_file='{restore_file_basename}'", ] if args.restore_skip_tor: @@ -904,10 +902,8 @@ def run_tails_config(args: argparse.Namespace) -> int: """Configure Tails environment post SD install""" sdlog.info("Configuring Tails workstation environment") sdlog.info( - ( - "You'll be prompted for the temporary Tails admin password," - " which was set on Tails login screen" - ) + "You'll be prompted for the temporary Tails admin password," + " which was set on Tails login screen" ) ansible_cmd = [ os.path.join(args.ansible_path, "securedrop-tails.yml"), @@ -1034,7 +1030,7 @@ def update(args: argparse.Namespace) -> int: ): # Finally, we check that there is no branch of the same name # prior to reporting success. - cmd = ["git", "show-ref", "--heads", "--verify", "refs/heads/{}".format(latest_tag)] + cmd = ["git", "show-ref", "--heads", "--verify", f"refs/heads/{latest_tag}"] try: # We expect this to produce a non-zero exit code, which # will produce a subprocess.CalledProcessError @@ -1063,7 +1059,7 @@ def update(args: argparse.Namespace) -> int: git_checkout_cmd = ["git", "checkout", latest_tag] subprocess.check_call(git_checkout_cmd, cwd=args.root) - sdlog.info("Updated to SecureDrop {}.".format(latest_tag)) + sdlog.info(f"Updated to SecureDrop {latest_tag}.") return 0 @@ -1213,10 +1209,10 @@ def main(argv: List[str]) -> None: print("Process was interrupted.") sys.exit(EXIT_INTERRUPT) except subprocess.CalledProcessError as e: - print("ERROR (run with -v for more): {msg}".format(msg=e), file=sys.stderr) + print(f"ERROR (run with -v for more): {e}", file=sys.stderr) sys.exit(EXIT_SUBPROCESS_ERROR) except Exception as e: - raise SystemExit("ERROR (run with -v for more): {msg}".format(msg=e)) + raise SystemExit(f"ERROR (run with -v for more): {e}") if return_code == 0: sys.exit(EXIT_SUCCESS) else: diff --git a/admin/tests/test_integration.py b/admin/tests/test_integration.py index 7b624851d2..d580eadf51 100644 --- a/admin/tests/test_integration.py +++ b/admin/tests/test_integration.py @@ -1,4 +1,3 @@ -import io import os import re import shutil @@ -118,7 +117,7 @@ def setup_function(function): global SD_DIR SD_DIR = tempfile.mkdtemp() - ANSIBLE_BASE = "{0}/install_files/ansible-base".format(SD_DIR) + ANSIBLE_BASE = f"{SD_DIR}/install_files/ansible-base" for name in ["roles", "tasks"]: shutil.copytree( @@ -131,22 +130,20 @@ def setup_function(function): os.path.join(CURRENT_DIR, "../../install_files/ansible-base", name), ANSIBLE_BASE ) - cmd = "mkdir -p {0}/group_vars/all".format(ANSIBLE_BASE).split() + cmd = f"mkdir -p {ANSIBLE_BASE}/group_vars/all".split() subprocess.check_call(cmd) for name in ["sd_admin_test.pub", "ca.crt", "sd.crt", "key.asc"]: - subprocess.check_call( - "cp -r {0}/files/{1} {2}".format(CURRENT_DIR, name, ANSIBLE_BASE).split() - ) + subprocess.check_call(f"cp -r {CURRENT_DIR}/files/{name} {ANSIBLE_BASE}".split()) for name in ["de_DE", "es_ES", "fr_FR", "pt_BR"]: - dircmd = "mkdir -p {0}/securedrop/translations/{1}".format(SD_DIR, name) + dircmd = f"mkdir -p {SD_DIR}/securedrop/translations/{name}" subprocess.check_call(dircmd.split()) subprocess.check_call( - "cp {0}/files/securedrop/i18n.json {1}/securedrop".format(CURRENT_DIR, SD_DIR).split() + f"cp {CURRENT_DIR}/files/securedrop/i18n.json {SD_DIR}/securedrop".split() ) def teardown_function(function): - subprocess.check_call("rm -rf {0}".format(SD_DIR).split()) + subprocess.check_call(f"rm -rf {SD_DIR}".split()) def verify_username_prompt(child): @@ -290,7 +287,7 @@ def verify_install_has_valid_config(): Checks that securedrop-admin install validates the configuration. """ cmd = os.path.join(os.path.dirname(CURRENT_DIR), "securedrop_admin/__init__.py") - child = pexpect.spawn("python {0} --force --root {1} install".format(cmd, SD_DIR)) + child = pexpect.spawn(f"python {cmd} --force --root {SD_DIR} install") child.expect(b"SUDO password:", timeout=5) child.close() @@ -300,7 +297,7 @@ def test_install_with_no_config(): Checks that securedrop-admin install complains about a missing config file. """ cmd = os.path.join(os.path.dirname(CURRENT_DIR), "securedrop_admin/__init__.py") - child = pexpect.spawn("python {0} --force --root {1} install".format(cmd, SD_DIR)) + child = pexpect.spawn(f"python {cmd} --force --root {SD_DIR} install") child.expect(b'ERROR: Please run "securedrop-admin sdconfig" first.', timeout=5) child.expect(pexpect.EOF, timeout=5) child.close() @@ -310,7 +307,7 @@ def test_install_with_no_config(): def test_sdconfig_on_first_run(): cmd = os.path.join(os.path.dirname(CURRENT_DIR), "securedrop_admin/__init__.py") - child = pexpect.spawn("python {0} --force --root {1} sdconfig".format(cmd, SD_DIR)) + child = pexpect.spawn(f"python {cmd} --force --root {SD_DIR} sdconfig") verify_username_prompt(child) child.sendline("") verify_reboot_prompt(child) @@ -373,7 +370,7 @@ def test_sdconfig_on_first_run(): def test_sdconfig_enable_journalist_alerts(): cmd = os.path.join(os.path.dirname(CURRENT_DIR), "securedrop_admin/__init__.py") - child = pexpect.spawn("python {0} --force --root {1} sdconfig".format(cmd, SD_DIR)) + child = pexpect.spawn(f"python {cmd} --force --root {SD_DIR} sdconfig") verify_username_prompt(child) child.sendline("") verify_reboot_prompt(child) @@ -439,7 +436,7 @@ def test_sdconfig_enable_journalist_alerts(): def test_sdconfig_enable_https_on_source_interface(): cmd = os.path.join(os.path.dirname(CURRENT_DIR), "securedrop_admin/__init__.py") - child = pexpect.spawn("python {0} --force --root {1} sdconfig".format(cmd, SD_DIR)) + child = pexpect.spawn(f"python {cmd} --force --root {SD_DIR} sdconfig") verify_username_prompt(child) child.sendline("") verify_reboot_prompt(child) @@ -535,7 +532,7 @@ def securedrop_git_repo(tmpdir): os.chdir(os.path.join(str(tmpdir), "securedrop/admin")) subprocess.check_call("git reset --hard".split()) # Now we will put in our own git configuration - with io.open("../.git/config", "w") as fobj: + with open("../.git/config", "w") as fobj: fobj.write(GIT_CONFIG) # Let us move to an older tag subprocess.check_call("git checkout 0.6".split()) @@ -547,8 +544,8 @@ def securedrop_git_repo(tmpdir): subprocess.check_call( [ "cp", - "{}/securedrop/admin/.coverage".format(str(tmpdir)), - "{}/../.coverage.{}".format(CURRENT_DIR, test_name), + f"{str(tmpdir)}/securedrop/admin/.coverage", + f"{CURRENT_DIR}/../.coverage.{test_name}", ] ) except subprocess.CalledProcessError: @@ -575,7 +572,7 @@ def set_reliable_keyserver(gpgdir): def test_check_for_update_when_updates_needed(securedrop_git_repo): cmd = os.path.join(os.path.dirname(CURRENT_DIR), "securedrop_admin/__init__.py") ansible_base = os.path.join(str(securedrop_git_repo), "securedrop/install_files/ansible-base") - fullcmd = "coverage run {0} --root {1} check_for_updates".format(cmd, ansible_base) + fullcmd = f"coverage run {cmd} --root {ansible_base} check_for_updates" child = pexpect.spawn(fullcmd) child.expect(b"Update needed", timeout=20) @@ -598,7 +595,7 @@ def test_check_for_update_when_updates_not_needed(securedrop_git_repo): cmd = os.path.join(os.path.dirname(CURRENT_DIR), "securedrop_admin/__init__.py") ansible_base = os.path.join(str(securedrop_git_repo), "securedrop/install_files/ansible-base") - fullcmd = "coverage run {0} --root {1} check_for_updates".format(cmd, ansible_base) + fullcmd = f"coverage run {cmd} --root {ansible_base} check_for_updates" child = pexpect.spawn(fullcmd) child.expect(b"All updates applied", timeout=20) @@ -615,7 +612,7 @@ def test_update(securedrop_git_repo): cmd = os.path.join(os.path.dirname(CURRENT_DIR), "securedrop_admin/__init__.py") ansible_base = os.path.join(str(securedrop_git_repo), "securedrop/install_files/ansible-base") - child = pexpect.spawn("coverage run {0} --root {1} update".format(cmd, ansible_base)) + child = pexpect.spawn(f"coverage run {cmd} --root {ansible_base} update") output = child.read() assert b"Updated to SecureDrop" in output @@ -643,7 +640,7 @@ def test_update_fails_when_no_signature_present(securedrop_git_repo): cmd = os.path.join(os.path.dirname(CURRENT_DIR), "securedrop_admin/__init__.py") ansible_base = os.path.join(str(securedrop_git_repo), "securedrop/install_files/ansible-base") - child = pexpect.spawn("coverage run {0} --root {1} update".format(cmd, ansible_base)) + child = pexpect.spawn(f"coverage run {cmd} --root {ansible_base} update") output = child.read() assert b"Updated to SecureDrop" not in output assert b"Signature verification failed" in output @@ -675,7 +672,7 @@ def test_update_with_duplicate_branch_and_tag(securedrop_git_repo): cmd = os.path.join(os.path.dirname(CURRENT_DIR), "securedrop_admin/__init__.py") ansible_base = os.path.join(str(securedrop_git_repo), "securedrop/install_files/ansible-base") - child = pexpect.spawn("coverage run {0} --root {1} update".format(cmd, ansible_base)) + child = pexpect.spawn(f"coverage run {cmd} --root {ansible_base} update") output = child.read() # Verify that we do not falsely check out a branch instead of a tag. assert b"Switched to branch" not in output diff --git a/admin/tests/test_securedrop-admin-setup.py b/admin/tests/test_securedrop-admin-setup.py index 098fd9d7ec..dd902737c3 100644 --- a/admin/tests/test_securedrop-admin-setup.py +++ b/admin/tests/test_securedrop-admin-setup.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # # SecureDrop whistleblower submission system # Copyright (C) 2017 Loic Dachary @@ -20,13 +19,13 @@ import argparse import os import subprocess +from unittest import mock import bootstrap -import mock import pytest -class TestSecureDropAdmin(object): +class TestSecureDropAdmin: def test_verbose(self, capsys): bootstrap.setup_logger(verbose=True) bootstrap.sdlog.debug("VISIBLE") diff --git a/admin/tests/test_securedrop-admin.py b/admin/tests/test_securedrop-admin.py index bfb1a54386..882de4148e 100644 --- a/admin/tests/test_securedrop-admin.py +++ b/admin/tests/test_securedrop-admin.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # # SecureDrop whistleblower submission system # Copyright (C) 2017- Freedom of the Press Foundation and SecureDrop @@ -19,14 +18,13 @@ # import argparse -import io import json import os import subprocess import textwrap from os.path import basename, dirname, exists, join +from unittest import mock -import mock import pytest import securedrop_admin import yaml @@ -34,13 +32,13 @@ from prompt_toolkit.validation import ValidationError -class Document(object): +class Document: def __init__(self, text): self.text = text @flaky -class TestSecureDropAdmin(object): +class TestSecureDropAdmin: def test_verbose(self, capsys): securedrop_admin.setup_logger(verbose=True) securedrop_admin.sdlog.debug("VISIBLE") @@ -494,7 +492,7 @@ def test_exit_codes(self, tmpdir): assert e.value.code == securedrop_admin.EXIT_INTERRUPT -class TestSiteConfig(object): +class TestSiteConfig: def test_exists(self, tmpdir): args = argparse.Namespace( site_config="DOES_NOT_EXIST", @@ -689,7 +687,7 @@ def test_save(self, tmpdir): var2: val2 """ ) - assert expected == io.open(site_config_path).read() + assert expected == open(site_config_path).read() def test_validate_gpg_key(self, tmpdir, caplog): args = argparse.Namespace( diff --git a/install_files/ansible-base/callback_plugins/ansible_version_check.py b/install_files/ansible-base/callback_plugins/ansible_version_check.py index e2021003cb..cf8031ad08 100644 --- a/install_files/ansible-base/callback_plugins/ansible_version_check.py +++ b/install_files/ansible-base/callback_plugins/ansible_version_check.py @@ -1,6 +1,3 @@ -# -*- encoding:utf-8 -*- -from __future__ import absolute_import, division, print_function, unicode_literals - import sys import ansible diff --git a/install_files/ansible-base/roles/build-ossec-deb-pkg/library/ossec_urls.py b/install_files/ansible-base/roles/build-ossec-deb-pkg/library/ossec_urls.py index 9f3c19e2fa..c65f625086 100644 --- a/install_files/ansible-base/roles/build-ossec-deb-pkg/library/ossec_urls.py +++ b/install_files/ansible-base/roles/build-ossec-deb-pkg/library/ossec_urls.py @@ -48,11 +48,11 @@ def __init__(self, ossec_version): @property def ossec_tarball_filename(self): - return "ossec-hids-{}.tar.gz".format(self.ossec_version) + return f"ossec-hids-{self.ossec_version}.tar.gz" @property def ossec_tarball_url(self): - return self.REPO_URL + "/archive/{}.tar.gz".format(self.ossec_version) + return self.REPO_URL + f"/archive/{self.ossec_version}.tar.gz" @property def ossec_signature_url(self): @@ -62,7 +62,7 @@ def ossec_signature_url(self): @property def ossec_signature_filename(self): - return "ossec-hids-{}.tar.gz.asc".format(self.ossec_version) + return f"ossec-hids-{self.ossec_version}.tar.gz.asc" def main(): diff --git a/install_files/ansible-base/roles/restore/files/compare_torrc.py b/install_files/ansible-base/roles/restore/files/compare_torrc.py index c59c81cfa1..53c34aae6c 100644 --- a/install_files/ansible-base/roles/restore/files/compare_torrc.py +++ b/install_files/ansible-base/roles/restore/files/compare_torrc.py @@ -6,7 +6,6 @@ # print a warning and exit. # -from __future__ import print_function import os import re @@ -18,7 +17,7 @@ def get_tor_versions(path): Determine which service versions are offered in the given torrc. """ service_re = re.compile(r"HiddenServiceDir\s+(?:.*)/(.*)") - versions = set([]) + versions = set() with open(path) as f: for line in f: m = service_re.match(line) diff --git a/install_files/ansible-base/roles/tails-config/files/securedrop_init.py b/install_files/ansible-base/roles/tails-config/files/securedrop_init.py index cce79ba2c6..b78577837c 100644 --- a/install_files/ansible-base/roles/tails-config/files/securedrop_init.py +++ b/install_files/ansible-base/roles/tails-config/files/securedrop_init.py @@ -1,7 +1,6 @@ #!/usr/bin/python3 import grp -import io import os import pwd import subprocess @@ -43,28 +42,28 @@ # load torrc_additions if os.path.isfile(path_torrc_additions): - with io.open(path_torrc_additions) as f: + with open(path_torrc_additions) as f: torrc_additions = f.read() else: - sys.exit("Error opening {0} for reading".format(path_torrc_additions)) + sys.exit(f"Error opening {path_torrc_additions} for reading") # load torrc if os.path.isfile(path_torrc_backup): - with io.open(path_torrc_backup) as f: + with open(path_torrc_backup) as f: torrc = f.read() else: if os.path.isfile(path_torrc): - with io.open(path_torrc) as f: + with open(path_torrc) as f: torrc = f.read() else: - sys.exit("Error opening {0} for reading".format(path_torrc)) + sys.exit(f"Error opening {path_torrc} for reading") # save a backup - with io.open(path_torrc_backup, "w") as f: + with open(path_torrc_backup, "w") as f: f.write(torrc) # append the additions -with io.open(path_torrc, "w") as f: +with open(path_torrc, "w") as f: f.write(torrc + torrc_additions) # check for v3 aths files @@ -108,11 +107,11 @@ env["XDG_CURRENT_DESKTOP"] = "GNOME" env["DESKTOP_SESSION"] = "default" env["DISPLAY"] = ":1" -env["XDG_RUNTIME_DIR"] = "/run/user/{}".format(amnesia_uid) +env["XDG_RUNTIME_DIR"] = f"/run/user/{amnesia_uid}" env["XDG_DATA_DIR"] = "/usr/share/gnome:/usr/local/share/:/usr/share/" env["HOME"] = "/home/amnesia" env["LOGNAME"] = "amnesia" -env["DBUS_SESSION_BUS_ADDRESS"] = "unix:path=/run/user/{}/bus".format(amnesia_uid) +env["DBUS_SESSION_BUS_ADDRESS"] = f"unix:path=/run/user/{amnesia_uid}/bus" # remove existing shortcut, recreate symlink and change metadata attribute # to trust .desktop @@ -202,7 +201,7 @@ "/etc/ssl/certs/DST_Root_CA_X3.pem", pem_file.name, ], - universal_newlines=True, + text=True, env=env, ) @@ -226,7 +225,7 @@ except subprocess.CalledProcessError: sys.exit(0) # Don't break tailsconfig trying to fix this - except IOError: + except OSError: sys.exit(0) finally: diff --git a/journalist_gui/journalist_gui/SecureDropUpdater.py b/journalist_gui/journalist_gui/SecureDropUpdater.py index eb3cf72509..563e203251 100644 --- a/journalist_gui/journalist_gui/SecureDropUpdater.py +++ b/journalist_gui/journalist_gui/SecureDropUpdater.py @@ -168,7 +168,7 @@ def run(self): class UpdaterApp(QtWidgets.QMainWindow, updaterUI.Ui_MainWindow): def __init__(self, parent=None): - super(UpdaterApp, self).__init__(parent) + super().__init__(parent) self.setupUi(self) self.statusbar.setSizeGripEnabled(False) self.output = strings.initial_text_box diff --git a/journalist_gui/journalist_gui/resources_rc.py b/journalist_gui/journalist_gui/resources_rc.py index ab7413918a..743bb09b5a 100644 --- a/journalist_gui/journalist_gui/resources_rc.py +++ b/journalist_gui/journalist_gui/resources_rc.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - # Resource object code # # Created by: The Resource Compiler for PyQt5 (Qt v5.9.5) diff --git a/journalist_gui/journalist_gui/updaterUI.py b/journalist_gui/journalist_gui/updaterUI.py index 2f556bd3e4..cea7bcde80 100644 --- a/journalist_gui/journalist_gui/updaterUI.py +++ b/journalist_gui/journalist_gui/updaterUI.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - # Form implementation generated from reading ui file 'journalist_gui/mainwindow.ui' # # Created by: PyQt5 UI code generator 5.10 @@ -9,7 +7,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets -class Ui_MainWindow(object): +class Ui_MainWindow: def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(400, 500) diff --git a/journalist_gui/test_gui.py b/journalist_gui/test_gui.py index 6bb16e0926..13d7310c3c 100644 --- a/journalist_gui/test_gui.py +++ b/journalist_gui/test_gui.py @@ -75,7 +75,7 @@ def setUp(self): class WindowTestCase(AppTestCase): def setUp(self): - super(WindowTestCase, self).setUp() + super().setUp() self.window = UpdaterApp() self.window.show() QTest.qWaitForWindowExposed(self.window) diff --git a/molecule/ansible-config/tests/test_play_configuration.py b/molecule/ansible-config/tests/test_play_configuration.py index 5b0bbcd6bc..24925e6292 100644 --- a/molecule/ansible-config/tests/test_play_configuration.py +++ b/molecule/ansible-config/tests/test_play_configuration.py @@ -1,4 +1,3 @@ -import io import os import pytest @@ -58,7 +57,7 @@ def test_max_fail_percentage(host, playbook): the parameter, but we'll play it safe and require it everywhere, to avoid mistakes down the road. """ - with io.open(playbook, "r") as f: + with open(playbook) as f: playbook_yaml = yaml.safe_load(f) # Descend into playbook list structure to validate play attributes. for play in playbook_yaml: @@ -74,7 +73,7 @@ def test_any_errors_fatal(host, playbook): to "0", doing so ensures that any errors will cause an immediate failure on the playbook. """ - with io.open(playbook, "r") as f: + with open(playbook) as f: playbook_yaml = yaml.safe_load(f) # Descend into playbook list structure to validate play attributes. for play in playbook_yaml: @@ -89,7 +88,7 @@ def test_locale(host, playbook): The securedrop-prod and securedrop-staging playbooks should control the locale in the host environment by setting LC_ALL=C. """ - with io.open(os.path.join(ANSIBLE_BASE, playbook), "r") as f: + with open(os.path.join(ANSIBLE_BASE, playbook)) as f: playbook_yaml = yaml.safe_load(f) for play in playbook_yaml: assert "environment" in play diff --git a/molecule/builder-focal/tests/test_build_dependencies.py b/molecule/builder-focal/tests/test_build_dependencies.py index db314e4be7..bbfd95c231 100644 --- a/molecule/builder-focal/tests/test_build_dependencies.py +++ b/molecule/builder-focal/tests/test_build_dependencies.py @@ -6,7 +6,7 @@ SECUREDROP_PYTHON_VERSION = os.environ.get("SECUREDROP_PYTHON_VERSION", "3.8") DH_VIRTUALENV_VERSION = "1.2.2" -testinfra_hosts = ["docker://{}-sd-app".format(SECUREDROP_TARGET_DISTRIBUTION)] +testinfra_hosts = [f"docker://{SECUREDROP_TARGET_DISTRIBUTION}-sd-app"] @pytest.mark.xfail(reason="This check conflicts with the concept of pegging" "dependencies") @@ -29,7 +29,7 @@ def test_python_version(host): we must be careful not to change Python as well. """ c = host.run("python3 --version") - version_string = "Python {}".format(SECUREDROP_PYTHON_VERSION) + version_string = f"Python {SECUREDROP_PYTHON_VERSION}" assert c.stdout.startswith(version_string) @@ -38,6 +38,6 @@ def test_dh_virtualenv(host): Confirm the expected version of dh-virtualenv is found. """ expected_version = DH_VIRTUALENV_VERSION - version_string = "dh_virtualenv {}".format(expected_version) + version_string = f"dh_virtualenv {expected_version}" c = host.run("dh_virtualenv --version") assert c.stdout.startswith(version_string) diff --git a/molecule/builder-focal/tests/test_securedrop_deb_package.py b/molecule/builder-focal/tests/test_securedrop_deb_package.py index 7b7904aed7..2cab346263 100644 --- a/molecule/builder-focal/tests/test_securedrop_deb_package.py +++ b/molecule/builder-focal/tests/test_securedrop_deb_package.py @@ -8,7 +8,7 @@ from testinfra.host import Host SECUREDROP_TARGET_DISTRIBUTION = os.environ.get("SECUREDROP_TARGET_DISTRIBUTION") -testinfra_hosts = ["docker://{}-sd-dpkg-verification".format(SECUREDROP_TARGET_DISTRIBUTION)] +testinfra_hosts = [f"docker://{SECUREDROP_TARGET_DISTRIBUTION}-sd-dpkg-verification"] def extract_package_name_from_filepath(filepath: str) -> str: @@ -164,9 +164,9 @@ def test_deb_packages_appear_installable(host: Host, deb: Path) -> None: # sudo is required to call `dpkg --install`, even as dry-run. with host.sudo(): - c = host.run("dpkg --install --dry-run {}".format(deb)) - assert "Selecting previously unselected package {}".format(package_name) in c.stdout - regex = "Preparing to unpack [./]+{} ...".format(re.escape(deb.name)) + c = host.run(f"dpkg --install --dry-run {deb}") + assert f"Selecting previously unselected package {package_name}" in c.stdout + regex = f"Preparing to unpack [./]+{re.escape(deb.name)} ..." assert re.search(regex, c.stdout, re.M) assert c.rc == 0 @@ -181,7 +181,7 @@ def test_deb_package_control_fields(host: Host, deb: Path) -> None: """ package_name = extract_package_name_from_filepath(str(deb)) # The `--field` option will display all fields if none are specified. - c = host.run("dpkg-deb --field {}".format(deb)) + c = host.run(f"dpkg-deb --field {deb}") assert "Maintainer: SecureDrop Team " in c.stdout arch_all = ( @@ -196,14 +196,14 @@ def test_deb_package_control_fields(host: Host, deb: Path) -> None: else: assert "Architecture: amd64" in c.stdout - assert "Package: {}".format(package_name) in c.stdout + assert f"Package: {package_name}" in c.stdout assert c.rc == 0 @pytest.mark.parametrize("deb", deb_paths.values()) def test_deb_package_control_fields_homepage(host: Host, deb: Path): # The `--field` option will display all fields if none are specified. - c = host.run("dpkg-deb --field {}".format(deb)) + c = host.run(f"dpkg-deb --field {deb}") # The OSSEC source packages will have a different homepage; # all other packages should set securedrop.org as homepage. if deb.name.startswith("ossec-"): @@ -284,7 +284,7 @@ def test_deb_package_contains_expected_conffiles(host: Host, deb: Path): mktemp = host.run("mktemp -d") tmpdir = mktemp.stdout.strip() # The `--raw-extract` flag includes `DEBIAN/` dir with control files - host.run("dpkg-deb --raw-extract {} {}".format(deb, tmpdir)) + host.run(f"dpkg-deb --raw-extract {deb} {tmpdir}") conffiles_path = os.path.join(tmpdir, "DEBIAN", "conffiles") f = host.file(conffiles_path) @@ -349,7 +349,7 @@ def test_deb_package_lintian(host: Host, deb: Path, tag: str): """ Ensures lintian likes our Debian packages. """ - c = host.run("lintian --tags {} --no-tag-display-limit {}".format(tag, deb)) + c = host.run(f"lintian --tags {tag} --no-tag-display-limit {deb}") assert len(c.stdout) == 0 @@ -410,7 +410,7 @@ def test_jinja_files_not_present(host: Host, deb: Path): as-is into the debian packages. """ - c = host.run("dpkg-deb --contents {}".format(deb)) + c = host.run(f"dpkg-deb --contents {deb}") # There shouldn't be any files with a .j2 ending assert not re.search(r"^.*\.j2$", c.stdout, re.M) @@ -433,7 +433,7 @@ def test_ossec_binaries_are_present_agent(host: Host): c = host.run("dpkg-deb -c {}".format(deb_paths["ossec_agent"])) for wanted_file in wanted_files: assert re.search( - r"^.* .{}$".format(wanted_file), + rf"^.* .{wanted_file}$", c.stdout, re.M, ) @@ -474,7 +474,7 @@ def test_ossec_binaries_are_present_server(host: Host): c = host.run("dpkg-deb --contents {}".format(deb_paths["ossec_server"])) for wanted_file in wanted_files: assert re.search( - r"^.* .{}$".format(wanted_file), + rf"^.* .{wanted_file}$", c.stdout, re.M, ) @@ -494,7 +494,7 @@ def test_config_package_contains_expected_files(host: Host) -> None: c = host.run("dpkg-deb --contents {}".format(deb_paths["securedrop_config"])) for wanted_file in wanted_files: assert re.search( - r"^.* .{}$".format(wanted_file), + rf"^.* .{wanted_file}$", c.stdout, re.M, ) diff --git a/molecule/builder-focal/tests/test_security_updates.py b/molecule/builder-focal/tests/test_security_updates.py index 87a93cc3b7..7b91e30f82 100644 --- a/molecule/builder-focal/tests/test_security_updates.py +++ b/molecule/builder-focal/tests/test_security_updates.py @@ -5,7 +5,7 @@ import pytest SECUREDROP_TARGET_DISTRIBUTION = os.environ.get("SECUREDROP_TARGET_DISTRIBUTION") -testinfra_hosts = ["docker://{}-sd-sec-update".format(SECUREDROP_TARGET_DISTRIBUTION)] +testinfra_hosts = [f"docker://{SECUREDROP_TARGET_DISTRIBUTION}-sd-sec-update"] def test_should_run(): diff --git a/molecule/testinfra/app-code/test_securedrop_app_code.py b/molecule/testinfra/app-code/test_securedrop_app_code.py index aefdff60c8..02a86683c2 100644 --- a/molecule/testinfra/app-code/test_securedrop_app_code.py +++ b/molecule/testinfra/app-code/test_securedrop_app_code.py @@ -23,7 +23,7 @@ def test_apache_default_docroot_is_absent(host): "coreutils", "gnupg2", "libapache2-mod-xsendfile", - "libpython{}".format(python_version), + f"libpython{python_version}", "paxctld", "python3", "redis-server", @@ -57,7 +57,7 @@ def test_securedrop_application_test_locale(host): """ Ensure both SecureDrop DEFAULT_LOCALE and SUPPORTED_LOCALES are present. """ - securedrop_config = host.file("{}/config.py".format(securedrop_test_vars.securedrop_code)) + securedrop_config = host.file(f"{securedrop_test_vars.securedrop_code}/config.py") with host.sudo(): assert securedrop_config.is_file assert securedrop_config.contains("^DEFAULT_LOCALE") @@ -72,9 +72,7 @@ def test_securedrop_application_test_journalist_key(host): Ensure the SecureDrop Application GPG public key file is present. This is a test-only pubkey provided in the repository strictly for testing. """ - pubkey_file = host.file( - "{}/test_journalist_key.pub".format(securedrop_test_vars.securedrop_data) - ) + pubkey_file = host.file(f"{securedrop_test_vars.securedrop_data}/test_journalist_key.pub") # sudo is only necessary when testing against app hosts, since the # permissions are tighter. Let's elevate privileges so we're sure # we can read the correct file attributes and test them. @@ -86,7 +84,7 @@ def test_securedrop_application_test_journalist_key(host): # Let's make sure the corresponding fingerprint is specified # in the SecureDrop app configuration. - securedrop_config = host.file("{}/config.py".format(securedrop_test_vars.securedrop_code)) + securedrop_config = host.file(f"{securedrop_test_vars.securedrop_code}/config.py") with host.sudo(): assert securedrop_config.is_file assert securedrop_config.user == securedrop_test_vars.securedrop_code_owner @@ -105,7 +103,7 @@ def test_securedrop_application_sqlite_db(host): # sudo is necessary under the App hosts, which have restrictive file # permissions on the doc root. Not technically necessary under dev host. with host.sudo(): - f = host.file("{}/db.sqlite".format(securedrop_test_vars.securedrop_data)) + f = host.file(f"{securedrop_test_vars.securedrop_data}/db.sqlite") assert f.is_file assert f.user == securedrop_test_vars.securedrop_user assert f.group == securedrop_test_vars.securedrop_user diff --git a/molecule/testinfra/app-code/test_securedrop_rqrequeue.py b/molecule/testinfra/app-code/test_securedrop_rqrequeue.py index 026b741d45..16b414cdfa 100644 --- a/molecule/testinfra/app-code/test_securedrop_rqrequeue.py +++ b/molecule/testinfra/app-code/test_securedrop_rqrequeue.py @@ -28,12 +28,12 @@ def test_securedrop_rqrequeue_service(host): "PrivateTmp=yes", "ProtectSystem=full", "ReadOnlyDirectories=/", - "ReadWriteDirectories={}".format(securedrop_test_vars.securedrop_data), + f"ReadWriteDirectories={securedrop_test_vars.securedrop_data}", "Restart=always", "RestartSec=10s", "UMask=077", - "User={}".format(securedrop_test_vars.securedrop_user), - "WorkingDirectory={}".format(securedrop_test_vars.securedrop_code), + f"User={securedrop_test_vars.securedrop_user}", + f"WorkingDirectory={securedrop_test_vars.securedrop_code}", "", "[Install]", "WantedBy=multi-user.target\n", diff --git a/molecule/testinfra/app-code/test_securedrop_rqworker.py b/molecule/testinfra/app-code/test_securedrop_rqworker.py index 91fc23ee5d..737a4a9728 100644 --- a/molecule/testinfra/app-code/test_securedrop_rqworker.py +++ b/molecule/testinfra/app-code/test_securedrop_rqworker.py @@ -23,17 +23,17 @@ def test_securedrop_rqworker_service(host): securedrop_test_vars.securedrop_code, securedrop_test_vars.securedrop_venv_site_packages, ), - "ExecStart={}/rqworker".format(securedrop_test_vars.securedrop_venv_bin), + f"ExecStart={securedrop_test_vars.securedrop_venv_bin}/rqworker", "PrivateDevices=yes", "PrivateTmp=yes", "ProtectSystem=full", "ReadOnlyDirectories=/", - "ReadWriteDirectories={}".format(securedrop_test_vars.securedrop_data), + f"ReadWriteDirectories={securedrop_test_vars.securedrop_data}", "Restart=always", "RestartSec=10s", "UMask=077", - "User={}".format(securedrop_test_vars.securedrop_user), - "WorkingDirectory={}".format(securedrop_test_vars.securedrop_code), + f"User={securedrop_test_vars.securedrop_user}", + f"WorkingDirectory={securedrop_test_vars.securedrop_code}", "", "[Install]", "WantedBy=multi-user.target\n", diff --git a/molecule/testinfra/app-code/test_securedrop_shredder_configuration.py b/molecule/testinfra/app-code/test_securedrop_shredder_configuration.py index 2478806e03..a39164197f 100644 --- a/molecule/testinfra/app-code/test_securedrop_shredder_configuration.py +++ b/molecule/testinfra/app-code/test_securedrop_shredder_configuration.py @@ -27,12 +27,12 @@ def test_securedrop_shredder_service(host): "PrivateTmp=yes", "ProtectSystem=full", "ReadOnlyDirectories=/", - "ReadWriteDirectories={}".format(securedrop_test_vars.securedrop_data), + f"ReadWriteDirectories={securedrop_test_vars.securedrop_data}", "Restart=always", "RestartSec=10s", "UMask=077", - "User={}".format(securedrop_test_vars.securedrop_user), - "WorkingDirectory={}".format(securedrop_test_vars.securedrop_code), + f"User={securedrop_test_vars.securedrop_user}", + f"WorkingDirectory={securedrop_test_vars.securedrop_code}", "", "[Install]", "WantedBy=multi-user.target\n", diff --git a/molecule/testinfra/app-code/test_securedrop_source_deleter_configuration.py b/molecule/testinfra/app-code/test_securedrop_source_deleter_configuration.py index fb88bb5290..9de809a288 100644 --- a/molecule/testinfra/app-code/test_securedrop_source_deleter_configuration.py +++ b/molecule/testinfra/app-code/test_securedrop_source_deleter_configuration.py @@ -26,12 +26,12 @@ def test_securedrop_source_deleter_service(host): "PrivateTmp=yes", "ProtectSystem=full", "ReadOnlyDirectories=/", - "ReadWriteDirectories={}".format(securedrop_test_vars.securedrop_data), + f"ReadWriteDirectories={securedrop_test_vars.securedrop_data}", "Restart=always", "RestartSec=10s", "UMask=077", - "User={}".format(securedrop_test_vars.securedrop_user), - "WorkingDirectory={}".format(securedrop_test_vars.securedrop_code), + f"User={securedrop_test_vars.securedrop_user}", + f"WorkingDirectory={securedrop_test_vars.securedrop_code}", "", "[Install]", "WantedBy=multi-user.target\n", diff --git a/molecule/testinfra/app/apache/test_apache_journalist_interface.py b/molecule/testinfra/app/apache/test_apache_journalist_interface.py index ab1542dbf7..f6bbb3a7ef 100644 --- a/molecule/testinfra/app/apache/test_apache_journalist_interface.py +++ b/molecule/testinfra/app/apache/test_apache_journalist_interface.py @@ -17,9 +17,9 @@ def test_apache_headers_journalist_interface(host, header, value): assert f.user == "root" assert f.group == "root" assert f.mode == 0o644 - header_unset = "Header onsuccess unset {}".format(header) + header_unset = f"Header onsuccess unset {header}" assert f.contains(header_unset) - header_set = 'Header always set {} "{}"'.format(header, value) + header_set = f'Header always set {header} "{value}"' assert f.contains(header_set) @@ -27,7 +27,7 @@ def test_apache_headers_journalist_interface(host, header, value): @pytest.mark.parametrize( "apache_opt", [ - "".format(securedrop_test_vars.apache_listening_address), + f"", "WSGIDaemonProcess journalist processes=2 threads=30 display-name=%{{GROUP}} python-path={}".format( # noqa securedrop_test_vars.securedrop_code ), @@ -37,7 +37,7 @@ def test_apache_headers_journalist_interface(host, header, value): ), "WSGIPassAuthorization On", 'Header set Cache-Control "no-store"', - "Alias /static {}/static".format(securedrop_test_vars.securedrop_code), + f"Alias /static {securedrop_test_vars.securedrop_code}/static", "XSendFile On", "LimitRequestBody 524288000", "XSendFilePath /var/lib/securedrop/store/", @@ -60,7 +60,7 @@ def test_apache_config_journalist_interface(host, apache_opt): assert f.user == "root" assert f.group == "root" assert f.mode == 0o644 - regex = "^{}$".format(re.escape(apache_opt)) + regex = f"^{re.escape(apache_opt)}$" assert re.search(regex, f.content_string, re.M) @@ -148,5 +148,5 @@ def test_apache_config_journalist_interface_access_control(host, apache_opt): Verifies the access control directives for the Journalist Interface. """ f = host.file("/etc/apache2/sites-available/journalist.conf") - regex = "^{}$".format(re.escape(apache_opt)) + regex = f"^{re.escape(apache_opt)}$" assert re.search(regex, f.content_string, re.M) diff --git a/molecule/testinfra/app/apache/test_apache_service.py b/molecule/testinfra/app/apache/test_apache_service.py index 1a8d8c0f03..1ddfda57e6 100644 --- a/molecule/testinfra/app/apache/test_apache_service.py +++ b/molecule/testinfra/app/apache/test_apache_service.py @@ -17,8 +17,8 @@ def test_apache_enabled_sites(host, apache_site): Ensure the Source and Journalist interfaces are enabled. """ with host.sudo(): - c = host.run("/usr/sbin/a2query -s {}".format(apache_site)) - assert "{} (enabled".format(apache_site) in c.stdout + c = host.run(f"/usr/sbin/a2query -s {apache_site}") + assert f"{apache_site} (enabled" in c.stdout assert c.rc == 0 @@ -32,8 +32,8 @@ def test_apache_disabled_sites(host, apache_site): """ Ensure the default HTML document root is disabled. """ - c = host.run("a2query -s {}".format(apache_site)) - assert "No site matches {} (disabled".format(apache_site) in c.stderr + c = host.run(f"a2query -s {apache_site}") + assert f"No site matches {apache_site} (disabled" in c.stderr assert c.rc == 32 @@ -74,5 +74,5 @@ def test_apache_listening(host, port): """ # sudo is necessary to read from /proc/net/tcp. with host.sudo(): - s = host.socket("tcp://{}:{}".format(securedrop_test_vars.apache_listening_address, port)) + s = host.socket(f"tcp://{securedrop_test_vars.apache_listening_address}:{port}") assert s.is_listening diff --git a/molecule/testinfra/app/apache/test_apache_source_interface.py b/molecule/testinfra/app/apache/test_apache_source_interface.py index c59ee90b7d..487c201f5e 100644 --- a/molecule/testinfra/app/apache/test_apache_source_interface.py +++ b/molecule/testinfra/app/apache/test_apache_source_interface.py @@ -17,16 +17,16 @@ def test_apache_headers_source_interface(host, header, value): assert f.user == "root" assert f.group == "root" assert f.mode == 0o644 - header_unset = "Header onsuccess unset {}".format(header) + header_unset = f"Header onsuccess unset {header}" assert f.contains(header_unset) - header_set = 'Header always set {} "{}"'.format(header, value) + header_set = f'Header always set {header} "{value}"' assert f.contains(header_set) @pytest.mark.parametrize( "apache_opt", [ - "".format(securedrop_test_vars.apache_listening_address), + f"", "WSGIDaemonProcess source processes=2 threads=30 display-name=%{{GROUP}} python-path={}".format( # noqa securedrop_test_vars.securedrop_code ), @@ -34,10 +34,10 @@ def test_apache_headers_source_interface(host, header, value): "WSGIScriptAlias / /var/www/source.wsgi", 'Header set Cache-Control "no-store"', "Header unset Etag", - "Alias /static {}/static".format(securedrop_test_vars.securedrop_code), + f"Alias /static {securedrop_test_vars.securedrop_code}/static", "XSendFile Off", "LimitRequestBody 524288000", - "ErrorLog {}".format(securedrop_test_vars.apache_source_log), + f"ErrorLog {securedrop_test_vars.apache_source_log}", ], ) def test_apache_config_source_interface(host, apache_opt): @@ -54,7 +54,7 @@ def test_apache_config_source_interface(host, apache_opt): assert f.user == "root" assert f.group == "root" assert f.mode == 0o644 - regex = "^{}$".format(re.escape(apache_opt)) + regex = f"^{re.escape(apache_opt)}$" assert re.search(regex, f.content_string, re.M) @@ -116,5 +116,5 @@ def test_apache_config_source_interface_access_control(host, apache_opt): Verifies the access control directives for the Source Interface. """ f = host.file("/etc/apache2/sites-available/source.conf") - regex = "^{}$".format(re.escape(apache_opt)) + regex = f"^{re.escape(apache_opt)}$" assert re.search(regex, f.content_string, re.M) diff --git a/molecule/testinfra/app/apache/test_apache_system_config.py b/molecule/testinfra/app/apache/test_apache_system_config.py index b5e7f59801..b40a0e9cc4 100644 --- a/molecule/testinfra/app/apache/test_apache_system_config.py +++ b/molecule/testinfra/app/apache/test_apache_system_config.py @@ -66,7 +66,7 @@ def test_apache_config_settings(host, apache_opt): assert f.user == "root" assert f.group == "root" assert f.mode == 0o644 - assert re.search("^{}$".format(re.escape(apache_opt)), f.content_string, re.M) + assert re.search(f"^{re.escape(apache_opt)}$", f.content_string, re.M) @pytest.mark.parametrize( @@ -125,8 +125,8 @@ def test_apache_modules_present(host, apache_module): disabled modules. """ with host.sudo(): - c = host.run("/usr/sbin/a2query -m {}".format(apache_module)) - assert "{} (enabled".format(apache_module) in c.stdout + c = host.run(f"/usr/sbin/a2query -m {apache_module}") + assert f"{apache_module} (enabled" in c.stdout assert c.rc == 0 @@ -147,8 +147,8 @@ def test_apache_modules_absent(host, apache_module): A separate test will check for disabled modules. """ with host.sudo(): - c = host.run("/usr/sbin/a2query -m {}".format(apache_module)) - assert "No module matches {} (disabled".format(apache_module) in c.stderr + c = host.run(f"/usr/sbin/a2query -m {apache_module}") + assert f"No module matches {apache_module} (disabled" in c.stderr assert c.rc == 32 diff --git a/molecule/testinfra/app/test_app_network.py b/molecule/testinfra/app/test_app_network.py index 69b2bf000f..950c03e441 100644 --- a/molecule/testinfra/app/test_app_network.py +++ b/molecule/testinfra/app/test_app_network.py @@ -1,5 +1,4 @@ import difflib -import io import os import pytest @@ -38,7 +37,7 @@ def test_app_iptables_rules(host): ) # template out a local iptables jinja file - jinja_iptables = Template(io.open(iptables_file, "r").read()) + jinja_iptables = Template(open(iptables_file).read()) iptables_expected = jinja_iptables.render(**kwargs) with host.sudo(): diff --git a/molecule/testinfra/app/test_apparmor.py b/molecule/testinfra/app/test_apparmor.py index 5b1763027b..d6c91bbd9b 100644 --- a/molecule/testinfra/app/test_apparmor.py +++ b/molecule/testinfra/app/test_apparmor.py @@ -58,7 +58,7 @@ def test_apparmor_ensure_not_disabled(host, profile): Polling aa-status only checks the last config that was loaded, this ensures it wont be disabled on reboot. """ - f = host.file("/etc/apparmor.d/disabled/usr.sbin.{}".format(profile)) + f = host.file(f"/etc/apparmor.d/disabled/usr.sbin.{profile}") with host.sudo(): assert not f.exists @@ -68,7 +68,7 @@ def test_app_apparmor_complain(host, complain_pkg): """Ensure app-armor profiles are in complain mode for staging""" with host.sudo(): awk = "awk '/[0-9]+ profiles.*complain." "/{flag=1;next}/^[0-9]+.*/{flag=0}flag'" - c = host.check_output("aa-status | {}".format(awk)) + c = host.check_output(f"aa-status | {awk}") assert complain_pkg in c @@ -83,7 +83,7 @@ def test_app_apparmor_complain_count(host): def test_apparmor_enforced(host, aa_enforced): awk = "awk '/[0-9]+ profiles.*enforce./" "{flag=1;next}/^[0-9]+.*/{flag=0}flag'" with host.sudo(): - c = host.check_output("aa-status | {}".format(awk)) + c = host.check_output(f"aa-status | {awk}") assert aa_enforced in c diff --git a/molecule/testinfra/app/test_appenv.py b/molecule/testinfra/app/test_appenv.py index aa4c40bf64..88e25dec38 100644 --- a/molecule/testinfra/app/test_appenv.py +++ b/molecule/testinfra/app/test_appenv.py @@ -98,7 +98,7 @@ def test_gpg_key_in_keyring(host): def test_ensure_logo(host): """ensure default logo header file exists""" - f = host.file("{}/static/i/logo.png".format(sdvars.securedrop_code)) + f = host.file(f"{sdvars.securedrop_code}/static/i/logo.png") with host.sudo(): assert f.mode == 0o644 assert f.user == "root" @@ -109,7 +109,7 @@ def test_securedrop_tmp_clean_cron(host): """Ensure securedrop tmp clean cron job in place""" with host.sudo(): cronlist = host.run("crontab -u www-data -l").stdout - cronjob = "@daily {}/manage.py clean-tmp".format(sdvars.securedrop_code) + cronjob = f"@daily {sdvars.securedrop_code}/manage.py clean-tmp" assert cronjob in cronlist diff --git a/molecule/testinfra/app/test_ossec_agent.py b/molecule/testinfra/app/test_ossec_agent.py index fd0642408d..50d7071a72 100644 --- a/molecule/testinfra/app/test_ossec_agent.py +++ b/molecule/testinfra/app/test_ossec_agent.py @@ -16,7 +16,7 @@ def test_hosts_files(host): mon_host = sdvars.monitor_hostname assert f.contains(r"^127.0.0.1\s*localhost") - assert f.contains(r"^{}\s*{}\s*securedrop-monitor-server-alias$".format(mon_ip, mon_host)) + assert f.contains(rf"^{mon_ip}\s*{mon_host}\s*securedrop-monitor-server-alias$") def test_ossec_service_start_style(host): diff --git a/molecule/testinfra/app/test_tor_config.py b/molecule/testinfra/app/test_tor_config.py index ae9d7f85af..ba6ce93fec 100644 --- a/molecule/testinfra/app/test_tor_config.py +++ b/molecule/testinfra/app/test_tor_config.py @@ -52,7 +52,7 @@ def test_tor_torrc_options(host, torrc_option): assert f.is_file assert f.user == "debian-tor" assert f.mode == 0o644 - assert f.contains("^{}$".format(torrc_option)) + assert f.contains(f"^{torrc_option}$") def test_tor_torrc_sandbox(host): diff --git a/molecule/testinfra/app/test_tor_hidden_services.py b/molecule/testinfra/app/test_tor_hidden_services.py index 471d2f9347..24833b15b8 100644 --- a/molecule/testinfra/app/test_tor_hidden_services.py +++ b/molecule/testinfra/app/test_tor_hidden_services.py @@ -54,7 +54,7 @@ def test_tor_service_hostnames(host, tor_service): ) assert client_auth.is_file else: - assert re.search("^{}$".format(ths_hostname_regex_v3), f.content_string) + assert re.search(f"^{ths_hostname_regex_v3}$", f.content_string) @pytest.mark.skip_in_prod @@ -78,10 +78,10 @@ def test_tor_services_config(host, tor_service): except IndexError: local_port = remote_port - port_regex = "HiddenServicePort {} 127.0.0.1:{}".format(remote_port, local_port) + port_regex = f"HiddenServicePort {remote_port} 127.0.0.1:{local_port}" - assert f.contains("^{}$".format(dir_regex)) - assert f.contains("^{}$".format(port_regex)) + assert f.contains(f"^{dir_regex}$") + assert f.contains(f"^{port_regex}$") # Check for block in file, to ensure declaration order service_regex = "\n".join([dir_regex, port_regex]) diff --git a/molecule/testinfra/common/test_automatic_updates.py b/molecule/testinfra/common/test_automatic_updates.py index a94dd08db4..62ac79236a 100644 --- a/molecule/testinfra/common/test_automatic_updates.py +++ b/molecule/testinfra/common/test_automatic_updates.py @@ -54,7 +54,7 @@ def test_sources_list(host, repo): assert f.is_file assert f.user == "root" assert f.mode == 0o644 - repo_regex = "^{}$".format(re.escape(repo_config)) + repo_regex = f"^{re.escape(repo_config)}$" assert f.contains(repo_regex) @@ -70,7 +70,7 @@ def test_sources_list(host, repo): "APT::Periodic::Enable": "1", "Unattended-Upgrade::AutoFixInterruptedDpkg": "true", "Unattended-Upgrade::Automatic-Reboot": "true", - "Unattended-Upgrade::Automatic-Reboot-Time": "{}:00".format(test_vars.daily_reboot_time), + "Unattended-Upgrade::Automatic-Reboot-Time": f"{test_vars.daily_reboot_time}:00", "Unattended-Upgrade::Automatic-Reboot-WithUsers": "true", "Unattended-Upgrade::Origins-Pattern": [ "origin=${distro_id},archive=${distro_codename}", @@ -88,7 +88,7 @@ def test_unattended_upgrades_config(host, k, v): """ # Dump apt config to inspect end state, apt will build config # from all conf files on disk, e.g. 80securedrop. - c = host.run("apt-config dump --format '%v%n' {}".format(k)) + c = host.run(f"apt-config dump --format '%v%n' {k}") assert c.rc == 0 # Some values are lists, so support that in the params if hasattr(v, "__getitem__"): @@ -158,7 +158,7 @@ def test_apt_daily_timer_schedule(host): """ t = (int(test_vars.daily_reboot_time) - OFFSET_UPDATE) % 24 c = host.run("systemctl show apt-daily.timer") - assert "TimersCalendar={ OnCalendar=*-*-* " + "{:02d}".format(t) + ":00:00 ;" in c.stdout + assert "TimersCalendar={ OnCalendar=*-*-* " + f"{t:02d}" + ":00:00 ;" in c.stdout assert "RandomizedDelayUSec=20m" in c.stdout @@ -169,7 +169,7 @@ def test_apt_daily_upgrade_timer_schedule(host): """ t = (int(test_vars.daily_reboot_time) - OFFSET_UPGRADE) % 24 c = host.run("systemctl show apt-daily-upgrade.timer") - assert "TimersCalendar={ OnCalendar=*-*-* " + "{:02d}".format(t) + ":00:00 ;" in c.stdout + assert "TimersCalendar={ OnCalendar=*-*-* " + f"{t:02d}" + ":00:00 ;" in c.stdout assert "RandomizedDelayUSec=20m" in c.stdout diff --git a/molecule/testinfra/common/test_grsecurity.py b/molecule/testinfra/common/test_grsecurity.py index 31c4ac4ad3..49364e7b45 100644 --- a/molecule/testinfra/common/test_grsecurity.py +++ b/molecule/testinfra/common/test_grsecurity.py @@ -1,5 +1,4 @@ import difflib -import io import os import warnings @@ -52,9 +51,9 @@ def test_generic_kernels_absent(host, package): # Can't use the TestInfra Package module to check state=absent, # so let's check by shelling out to `dpkg -l`. Dpkg will automatically # honor simple regex in package names. - c = host.run("dpkg -l {}".format(package)) + c = host.run(f"dpkg -l {package}") assert c.rc == 1 - error_text = "dpkg-query: no packages found matching {}".format(package) + error_text = f"dpkg-query: no packages found matching {package}" assert error_text in c.stderr.strip() @@ -124,7 +123,7 @@ def test_grsecurity_paxtest(host): # https://github.com/freedomofpress/securedrop/issues/1039 if host.system_info.codename == "focal": memcpy_result = "Vulnerable" - with io.open(paxtest_template_path, "r") as f: + with open(paxtest_template_path) as f: paxtest_template = Template(f.read().rstrip()) paxtest_expected = paxtest_template.render(memcpy_result=memcpy_result) @@ -204,10 +203,10 @@ def test_wireless_disabled_in_kernel_config(host, kernel_opts): """ kernel_version = host.run("uname -r").stdout.strip() with host.sudo(): - kernel_config_path = "/boot/config-{}".format(kernel_version) + kernel_config_path = f"/boot/config-{kernel_version}" kernel_config = host.file(kernel_config_path).content_string - line = "# CONFIG_{} is not set".format(kernel_opts) + line = f"# CONFIG_{kernel_opts} is not set" assert line in kernel_config or kernel_opts not in kernel_config @@ -226,10 +225,10 @@ def test_kernel_options_enabled_config(host, kernel_opts): kernel_version = host.run("uname -r").stdout.strip() with host.sudo(): - kernel_config_path = "/boot/config-{}".format(kernel_version) + kernel_config_path = f"/boot/config-{kernel_version}" kernel_config = host.file(kernel_config_path).content_string - line = "{}=y".format(kernel_opts) + line = f"{kernel_opts}=y" assert line in kernel_config diff --git a/molecule/testinfra/common/test_release_upgrades.py b/molecule/testinfra/common/test_release_upgrades.py index 2d5d1409e1..5eb87a2c3b 100644 --- a/molecule/testinfra/common/test_release_upgrades.py +++ b/molecule/testinfra/common/test_release_upgrades.py @@ -23,7 +23,7 @@ def test_release_manager_upgrade_channel(host): config_path = "/etc/update-manager/release-upgrades" assert host.file(config_path).is_file - raw_output = host.check_output("grep '^Prompt' {}".format(config_path)) + raw_output = host.check_output(f"grep '^Prompt' {config_path}") _, channel = raw_output.split("=") assert channel == "never" diff --git a/molecule/testinfra/common/test_system_hardening.py b/molecule/testinfra/common/test_system_hardening.py index 8ad26193ad..bd1f456bcd 100644 --- a/molecule/testinfra/common/test_system_hardening.py +++ b/molecule/testinfra/common/test_system_hardening.py @@ -65,7 +65,7 @@ def test_blacklisted_kernel_modules(host, kernel_module): assert kernel_module not in c.stdout f = host.file("/etc/modprobe.d/blacklist.conf") - assert f.contains("^blacklist {}$".format(kernel_module)) + assert f.contains(f"^blacklist {kernel_module}$") def test_swap_disabled(host): @@ -124,7 +124,7 @@ def test_sshd_config(host, sshd_opts): sshd_config_file = host.file("/etc/ssh/sshd_config").content_string - line = "{} {}".format(sshd_opts[0], sshd_opts[1]) + line = f"{sshd_opts[0]} {sshd_opts[1]}" assert line in sshd_config_file diff --git a/molecule/testinfra/common/test_tor_mirror.py b/molecule/testinfra/common/test_tor_mirror.py index ecbccdb32d..d3b26e65f2 100644 --- a/molecule/testinfra/common/test_tor_mirror.py +++ b/molecule/testinfra/common/test_tor_mirror.py @@ -32,9 +32,9 @@ def test_tor_keyring_absent(host): # so let's check by shelling out to `dpkg -l`. Dpkg will automatically # honor simple regex in package names. package = "deb.torproject.org-keyring" - c = host.run("dpkg -l {}".format(package)) + c = host.run(f"dpkg -l {package}") assert c.rc == 1 - error_text = "dpkg-query: no packages found matching {}".format(package) + error_text = f"dpkg-query: no packages found matching {package}" assert error_text in c.stderr.strip() @@ -76,7 +76,7 @@ def test_tor_repo_absent(host, repo_pattern): in that repo. We're mirroring it to avoid breakage caused by untested updates (which has broken prod twice to date). """ - cmd = "grep -rF '{}' /etc/apt/".format(repo_pattern) + cmd = f"grep -rF '{repo_pattern}' /etc/apt/" c = host.run(cmd) # Grep returns non-zero when no matches, and we want no matches. assert c.rc != 0 diff --git a/molecule/testinfra/common/test_user_config.py b/molecule/testinfra/common/test_user_config.py index 1fc0ec00f4..339aaaa2d8 100644 --- a/molecule/testinfra/common/test_user_config.py +++ b/molecule/testinfra/common/test_user_config.py @@ -98,5 +98,5 @@ def test_sudoers_tmux_env_deprecated(host): old setting isn't still active. """ - f = host.file("/home/{}/.bashrc".format(sdvars.admin_user)) + f = host.file(f"/home/{sdvars.admin_user}/.bashrc") assert not f.contains(r"^. \/etc\/bashrc\.securedrop_additions$") diff --git a/molecule/testinfra/conftest.py b/molecule/testinfra/conftest.py index f3e86e6f14..adfc4dc036 100644 --- a/molecule/testinfra/conftest.py +++ b/molecule/testinfra/conftest.py @@ -6,7 +6,6 @@ Vars should be placed in `testinfra/vars/.yml`. """ -import io import os from typing import Any, Dict @@ -26,7 +25,7 @@ def securedrop_import_testinfra_vars(hostname, with_header=False): Vars must be stored in `testinfra/vars/.yml`. """ filepath = os.path.join(os.path.dirname(__file__), "vars", hostname + ".yml") - with io.open(filepath, "r") as f: + with open(filepath) as f: hostvars = yaml.safe_load(f) hostvars["securedrop_venv_site_packages"] = hostvars["securedrop_venv_site_packages"].format( @@ -41,7 +40,7 @@ def securedrop_import_testinfra_vars(hostname, with_header=False): os.path.dirname(__file__), "../../install_files/ansible-base/group_vars/all/site-specific" ) if os.path.isfile(prod_filepath): - with io.open(prod_filepath, "r") as f: + with open(prod_filepath) as f: prodvars = yaml.safe_load(f) def _prod_override(vars_key, prod_key): @@ -63,7 +62,7 @@ def _prod_override(vars_key, prod_key): "../../install_files/ansible-base/roles/install-fpf-repo/defaults/main.yml", ) # noqa: E501 if os.path.isfile(repo_filepath): - with io.open(repo_filepath, "r") as f: + with open(repo_filepath) as f: repovars = yaml.safe_load(f) if "apt_repo_url" in repovars: hostvars["fpf_apt_repo_url"] = repovars["apt_repo_url"] diff --git a/molecule/testinfra/mon/test_mon_network.py b/molecule/testinfra/mon/test_mon_network.py index 60d79cf50e..2edb94f640 100644 --- a/molecule/testinfra/mon/test_mon_network.py +++ b/molecule/testinfra/mon/test_mon_network.py @@ -1,5 +1,4 @@ import difflib -import io import os import pytest @@ -38,7 +37,7 @@ def test_mon_iptables_rules(host): ) # template out a local iptables jinja file - jinja_iptables = Template(io.open(iptables_file, "r").read()) + jinja_iptables = Template(open(iptables_file).read()) iptables_expected = jinja_iptables.render(**kwargs) with host.sudo(): diff --git a/molecule/testinfra/mon/test_ossec_server.py b/molecule/testinfra/mon/test_ossec_server.py index 93ed7ed590..a515b836ef 100644 --- a/molecule/testinfra/mon/test_ossec_server.py +++ b/molecule/testinfra/mon/test_ossec_server.py @@ -89,7 +89,7 @@ def test_hosts_files(host): app_host = securedrop_test_vars.app_hostname assert f.contains("^127.0.0.1.*localhost") - assert f.contains(r"^{}\s*{}$".format(app_ip, app_host)) + assert f.contains(rf"^{app_ip}\s*{app_host}$") def test_ossec_log_contains_no_malformed_events(host): diff --git a/molecule/testinfra/mon/test_postfix.py b/molecule/testinfra/mon/test_postfix.py index 8133964fbb..3801bb9eaf 100644 --- a/molecule/testinfra/mon/test_postfix.py +++ b/molecule/testinfra/mon/test_postfix.py @@ -26,7 +26,7 @@ def test_postfix_headers(host, header): f = host.file("/etc/postfix/header_checks") assert f.is_file assert f.mode == 0o644 - regex = "^{}$".format(re.escape(header)) + regex = f"^{re.escape(header)}$" assert re.search(regex, f.content_string, re.M) diff --git a/molecule/testinfra/ossec/test_journalist_mail.py b/molecule/testinfra/ossec/test_journalist_mail.py index a88d3ee3ec..48612264db 100644 --- a/molecule/testinfra/ossec/test_journalist_mail.py +++ b/molecule/testinfra/ossec/test_journalist_mail.py @@ -9,7 +9,7 @@ SKIP_REASON = "unimplemented, see GH#3689" -class TestBase(object): +class TestBase: @pytest.fixture(autouse=True) def only_mon_staging_sudo(self, host): if host.backend.host != "mon-staging": @@ -47,22 +47,16 @@ def wait_for_command(self, host, cmd): # legacy only found in /etc/init.d such as postfix # def service_started(self, host, name): - assert self.run(host, "service {name} start".format(name=name)) - assert self.wait_for_command( - host, "service {name} status | grep -q 'is running'".format(name=name) - ) + assert self.run(host, f"service {name} start") + assert self.wait_for_command(host, f"service {name} status | grep -q 'is running'") def service_restarted(self, host, name): - assert self.run(host, "service {name} restart".format(name=name)) - assert self.wait_for_command( - host, "service {name} status | grep -q 'is running'".format(name=name) - ) + assert self.run(host, f"service {name} restart") + assert self.wait_for_command(host, f"service {name} status | grep -q 'is running'") def service_stopped(self, host, name): - assert self.run(host, "service {name} stop".format(name=name)) - assert self.wait_for_command( - host, "service {name} status | grep -q 'not running'".format(name=name) - ) + assert self.run(host, f"service {name} stop") + assert self.wait_for_command(host, f"service {name} status | grep -q 'not running'") class TestJournalistMail(TestBase): @@ -79,10 +73,8 @@ def test_procmail(self, host): self.ansible(host, "copy", "dest=/tmp/{f} src={d}/{f}".format(f=f, d=current_dir)) assert self.run(host, "/var/ossec/process_submissions_today.sh forget") assert self.run(host, "postsuper -d ALL") - assert self.run(host, "cat /tmp/{f} | mail -s 'abc' root@localhost".format(f=f)) - assert self.wait_for_command( - host, "mailq | grep -q {destination}@ossec.test".format(destination=destination) - ) + assert self.run(host, f"cat /tmp/{f} | mail -s 'abc' root@localhost") + assert self.wait_for_command(host, f"mailq | grep -q {destination}@ossec.test") self.service_stopped(host, "postfix") @pytest.mark.skip(reason=SKIP_REASON) @@ -96,12 +88,12 @@ def test_process_submissions_today(self, host): def test_send_encrypted_alert(self, host): self.service_started(host, "postfix") src = "../../install_files/ansible-base/roles/ossec/files/" "test_admin_key.sec" - self.ansible(host, "copy", "dest=/tmp/test_admin_key.sec src={src}".format(src=src)) + self.ansible(host, "copy", f"dest=/tmp/test_admin_key.sec src={src}") self.run(host, "gpg --homedir /var/ossec/.gnupg" " --import /tmp/test_admin_key.sec") def trigger(who, payload): - assert self.run(host, "! mailq | grep -q {who}@ossec.test".format(who=who)) + assert self.run(host, f"! mailq | grep -q {who}@ossec.test") assert self.run( host, """ @@ -111,7 +103,7 @@ def trigger(who, payload): who=who, payload=payload ), ) - assert self.wait_for_command(host, "mailq | grep -q {who}@ossec.test".format(who=who)) + assert self.wait_for_command(host, f"mailq | grep -q {who}@ossec.test") # # encrypted mail to journalist or ossec contact diff --git a/securedrop/alembic/env.py b/securedrop/alembic/env.py index 608ea0407a..32148bce4e 100644 --- a/securedrop/alembic/env.py +++ b/securedrop/alembic/env.py @@ -1,5 +1,3 @@ -from __future__ import with_statement - import os import sys from logging.config import fileConfig diff --git a/securedrop/db.py b/securedrop/db.py index 6aeb4916c6..f0b13d6f2a 100644 --- a/securedrop/db.py +++ b/securedrop/db.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - from flask_sqlalchemy import SQLAlchemy db = SQLAlchemy() diff --git a/securedrop/debian/ossec-common/var/ossec/checksdconfig.py b/securedrop/debian/ossec-common/var/ossec/checksdconfig.py index 510f5d721f..ecfb085907 100755 --- a/securedrop/debian/ossec-common/var/ossec/checksdconfig.py +++ b/securedrop/debian/ossec-common/var/ossec/checksdconfig.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -# -*- coding: utf-8 -*- import argparse import subprocess @@ -33,7 +32,7 @@ def list_iptables_rules() -> dict: - result = subprocess.run(["iptables", "-S"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + result = subprocess.run(["iptables", "-S"], capture_output=True) rules = result.stdout.decode("utf-8").splitlines() policies = [r for r in rules if r.startswith("-P")] input_rules = [r for r in rules if r.startswith("-A INPUT")] diff --git a/securedrop/encryption.py b/securedrop/encryption.py index 3a144c3190..494a60bfd9 100644 --- a/securedrop/encryption.py +++ b/securedrop/encryption.py @@ -116,7 +116,7 @@ def __init__(self, gpg_key_dir: Path, journalist_key_fingerprint: str) -> None: try: self.get_journalist_public_key() except GpgKeyNotFoundError: - raise EnvironmentError( + raise OSError( f"The journalist public key with fingerprint {journalist_key_fingerprint}" f" has not been imported into GPG." ) diff --git a/securedrop/i18n_tool.py b/securedrop/i18n_tool.py index 093b7f20ea..e8bbb631fc 100755 --- a/securedrop/i18n_tool.py +++ b/securedrop/i18n_tool.py @@ -1,9 +1,7 @@ #!/opt/venvs/securedrop-app-code/bin/python -# -*- coding: utf-8 -*- import argparse import glob -import io import json import logging import os @@ -102,7 +100,7 @@ def translate_messages(self, args: argparse.Namespace) -> None: self.file_is_modified(str(messages_file)) and len(os.listdir(args.translations_dir)) > 1 ): - tglob = "{}/*/LC_MESSAGES/*.po".format(args.translations_dir) + tglob = f"{args.translations_dir}/*/LC_MESSAGES/*.po" for translation in glob.iglob(tglob): subprocess.check_call( [ @@ -217,7 +215,7 @@ def set_translate_parser( parser.add_argument( "--translations-dir", default=translations_dir, - help="Base directory for translation files (default {})".format(translations_dir), + help=f"Base directory for translation files (default {translations_dir})", ) parser.add_argument( "--version", @@ -230,7 +228,7 @@ def set_translate_parser( parser.add_argument( "--sources", default=sources, - help="Source files and directories to extract (default {})".format(sources), + help=f"Source files and directories to extract (default {sources})", ) def set_translate_messages_parser(self, subps: _SubParsersAction) -> None: @@ -244,7 +242,7 @@ def set_translate_messages_parser(self, subps: _SubParsersAction) -> None: parser.add_argument( "--mapping", default=mapping, - help="Mapping of files to consider (default {})".format(mapping), + help=f"Mapping of files to consider (default {mapping})", ) parser.set_defaults(func=self.translate_messages) @@ -269,7 +267,7 @@ def require_git_email_name(git_dir: str) -> bool: ) # nosemgrep: python.lang.security.audit.subprocess-shell-true.subprocess-shell-true if subprocess.call(cmd, shell=True): # nosec - if "docker" in io.open("/proc/1/cgroup").read(): + if "docker" in open("/proc/1/cgroup").read(): log.error( "remember ~/.gitconfig does not exist " "in the dev-shell Docker container, " @@ -284,7 +282,7 @@ def update_docs(self, args: argparse.Namespace) -> None: l10n_content += "* " + info["name"] + " (``" + code + "``)\n" includes = abspath(join(args.docs_repo_dir, "docs/includes")) l10n_txt = join(includes, "l10n.txt") - io.open(l10n_txt, mode="w").write(l10n_content) + open(l10n_txt, mode="w").write(l10n_content) self.require_git_email_name(includes) if self.file_is_modified(l10n_txt): subprocess.check_call(["git", "add", "l10n.txt"], cwd=includes) @@ -355,7 +353,7 @@ def add(path: str) -> None: desktop_code = info["desktop"] path = join( LOCALE_DIR["desktop"], - "{l}.po".format(l=desktop_code), # noqa: E741 + f"{desktop_code}.po", # noqa: E741 ) add(path) except KeyError: @@ -400,7 +398,7 @@ def translators( if len(c) > 1 and c[2] != since_commit and self.translated_commit_re.match(c[1]) ] log.debug("Path changes for %s: %s", path, path_changes) - translators = set([c[0] for c in path_changes]) + translators = {c[0] for c in path_changes} log.debug("Translators for %s: %s", path, translators) return translators @@ -586,9 +584,9 @@ def list_translators(self, args: argparse.Namespace) -> None: print("Listing all translators who have ever helped") else: since = args.since if args.since else self.get_last_release(args.root) - print("Listing translators who have helped since {}".format(since)) + print(f"Listing translators who have helped since {since}") for code, info in sorted(self.supported_languages.items()): - translators = set([]) + translators = set() paths = [ app_template.format(LOCALE_DIR["securedrop"], code), desktop_template.format(info["desktop"]), @@ -598,7 +596,7 @@ def list_translators(self, args: argparse.Namespace) -> None: t = self.translators(args, path, since) translators.update(t) except Exception as e: - print("Could not check git history of {}: {}".format(path, e), file=sys.stderr) + print(f"Could not check git history of {path}: {e}", file=sys.stderr) print( "{} ({}):{}".format( code, diff --git a/securedrop/journalist.py b/securedrop/journalist.py index 2d25a2a27c..94f67c0041 100644 --- a/securedrop/journalist.py +++ b/securedrop/journalist.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from encryption import EncryptionManager, GpgKeyNotFoundError from execution import asynchronous from journalist_app import create_app diff --git a/securedrop/journalist_app/__init__.py b/securedrop/journalist_app/__init__.py index 7c093b4dbe..905baf64e8 100644 --- a/securedrop/journalist_app/__init__.py +++ b/securedrop/journalist_app/__init__.py @@ -61,7 +61,7 @@ class JSONEncoder(json.JSONEncoder): def default(self, obj: "Any") -> "Any": if isinstance(obj, datetime): return obj.strftime(API_DATETIME_FORMAT) - super(JSONEncoder, self).default(obj) + super().default(obj) app.json_encoder = JSONEncoder diff --git a/securedrop/journalist_app/account.py b/securedrop/journalist_app/account.py index 64280e4b0d..20e6e3039f 100644 --- a/securedrop/journalist_app/account.py +++ b/securedrop/journalist_app/account.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from typing import Union import werkzeug diff --git a/securedrop/journalist_app/admin.py b/securedrop/journalist_app/admin.py index 5c8450b48b..78529fbb77 100644 --- a/securedrop/journalist_app/admin.py +++ b/securedrop/journalist_app/admin.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - import binascii import os from typing import Optional, Union @@ -329,9 +327,7 @@ def delete_user(user_id: int) -> werkzeug.Response: if user_id == session.get_uid(): # Do not flash because the interface already has safe guards. # It can only happen by manually crafting a POST request - current_app.logger.error( - "Admin {} tried to delete itself".format(session.get_user().username) - ) + current_app.logger.error(f"Admin {session.get_user().username} tried to delete itself") abort(403) elif not user: current_app.logger.error( @@ -344,7 +340,7 @@ def delete_user(user_id: int) -> werkzeug.Response: # Do not flash because the interface does not expose this. # It can only happen by manually crafting a POST request current_app.logger.error( - 'Admin {} tried to delete "deleted" user'.format(session.get_user().username) + f'Admin {session.get_user().username} tried to delete "deleted" user' ) abort(403) else: diff --git a/securedrop/journalist_app/api.py b/securedrop/journalist_app/api.py index 82bebf75c9..dd3e83c9e5 100644 --- a/securedrop/journalist_app/api.py +++ b/securedrop/journalist_app/api.py @@ -329,19 +329,19 @@ def seen() -> Tuple[flask.Response, int]: for file_uuid in request.json.get("files", []): f = Submission.query.filter(Submission.uuid == file_uuid).one_or_none() if f is None or not f.is_file: - abort(404, "file not found: {}".format(file_uuid)) + abort(404, f"file not found: {file_uuid}") targets.add(f) for message_uuid in request.json.get("messages", []): m = Submission.query.filter(Submission.uuid == message_uuid).one_or_none() if m is None or not m.is_message: - abort(404, "message not found: {}".format(message_uuid)) + abort(404, f"message not found: {message_uuid}") targets.add(m) for reply_uuid in request.json.get("replies", []): r = Reply.query.filter(Reply.uuid == reply_uuid).one_or_none() if r is None: - abort(404, "reply not found: {}".format(reply_uuid)) + abort(404, f"reply not found: {reply_uuid}") targets.add(r) # now mark everything seen. diff --git a/securedrop/journalist_app/col.py b/securedrop/journalist_app/col.py index 01ed748855..773eb9a580 100644 --- a/securedrop/journalist_app/col.py +++ b/securedrop/journalist_app/col.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - from pathlib import Path import werkzeug @@ -145,7 +143,7 @@ def download_single_file(filesystem_id: str, fn: str) -> werkzeug.Response: ), "error", ) - current_app.logger.error("File {} not found".format(file)) + current_app.logger.error(f"File {file} not found") return redirect(url_for("col.col", filesystem_id=filesystem_id)) # mark as seen by the current user @@ -161,7 +159,7 @@ def download_single_file(filesystem_id: str, fn: str) -> werkzeug.Response: message = Submission.query.filter(Submission.filename == fn).one() mark_seen([message], journalist) except NoResultFound as e: - current_app.logger.error("Could not mark {} as seen: {}".format(fn, e)) + current_app.logger.error(f"Could not mark {fn} as seen: {e}") return send_file( Storage.get_default().path(filesystem_id, fn), diff --git a/securedrop/journalist_app/decorators.py b/securedrop/journalist_app/decorators.py index 82fec096ce..6a44b5d39c 100644 --- a/securedrop/journalist_app/decorators.py +++ b/securedrop/journalist_app/decorators.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from functools import wraps from typing import Any, Callable diff --git a/securedrop/journalist_app/forms.py b/securedrop/journalist_app/forms.py index 3927bcf626..6eaff23e10 100644 --- a/securedrop/journalist_app/forms.py +++ b/securedrop/journalist_app/forms.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - import typing from typing import Any @@ -47,7 +45,7 @@ def __call__(self, form: FlaskForm, field: Field) -> None: other_name=self.other_field_name, name=field.name ) ) - super(RequiredIf, self).__call__(form, field) + super().__call__(form, field) else: field.errors[:] = [] raise StopValidation() diff --git a/securedrop/journalist_app/main.py b/securedrop/journalist_app/main.py index 4fcb15295a..58976bf98a 100644 --- a/securedrop/journalist_app/main.py +++ b/securedrop/journalist_app/main.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from datetime import datetime, timezone from pathlib import Path from typing import Union @@ -141,7 +140,7 @@ def reply() -> werkzeug.Response: return redirect(url_for("col.col", filesystem_id=g.filesystem_id)) g.source.interaction_count += 1 - filename = "{0}-{1}-reply.gpg".format( + filename = "{}-{}-reply.gpg".format( g.source.interaction_count, g.source.journalist_filename ) EncryptionManager.get_default().encrypt_journalist_reply( diff --git a/securedrop/journalist_app/utils.py b/securedrop/journalist_app/utils.py index 5232e61d42..dbbd0fdd20 100644 --- a/securedrop/journalist_app/utils.py +++ b/securedrop/journalist_app/utils.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- import binascii import os from datetime import datetime, timezone @@ -45,7 +44,7 @@ def commit_account_changes(user: Journalist) -> None: gettext("An unexpected error occurred! Please " "inform your admin."), "error", ) - current_app.logger.error("Account changes for '{}' failed: {}".format(user, e)) + current_app.logger.error(f"Account changes for '{user}' failed: {e}") db.session.rollback() else: flash(gettext("Account updated."), "success") @@ -90,7 +89,7 @@ def validate_user( LoginThrottledException, InvalidPasswordLength, ) as e: - current_app.logger.error("Login for '{}' failed: {}".format(username, e)) + current_app.logger.error(f"Login for '{username}' failed: {e}") login_flashed_msg = error_message if error_message else gettext("Login failed.") if isinstance(e, LoginThrottledException): @@ -161,9 +160,7 @@ def validate_hotp_secret(user: Journalist, otp_secret: str) -> bool: gettext("An unexpected error occurred! " "Please inform your admin."), "error", ) - current_app.logger.error( - "set_hotp_secret '{}' (id {}) failed: {}".format(otp_secret, user.id, e) - ) + current_app.logger.error(f"set_hotp_secret '{otp_secret}' (id {user.id}) failed: {e}") return False return True diff --git a/securedrop/loaddata.py b/securedrop/loaddata.py index 70b49ca0af..62d1fdcb20 100755 --- a/securedrop/loaddata.py +++ b/securedrop/loaddata.py @@ -1,5 +1,4 @@ #!/opt/venvs/securedrop-app-code/bin/python -# -*- coding: utf-8 -*- """ Loads test data into the SecureDrop database. @@ -49,7 +48,7 @@ def fraction(s: str) -> float: f = float(s) if 0 <= f <= 1: return f - raise ValueError("{} should be a float between 0 and 1".format(s)) + raise ValueError(f"{s} should be a float between 0 and 1") def non_negative_int(s: str) -> int: @@ -59,7 +58,7 @@ def non_negative_int(s: str) -> int: f = float(s) if f.is_integer() and f >= 0: return int(f) - raise ValueError("{} is not a non-negative integer".format(s)) + raise ValueError(f"{s} is not a non-negative integer") def random_bool() -> bool: @@ -220,7 +219,7 @@ def add_reply( Adds a single reply to a source. """ record_source_interaction(source) - fname = "{}-{}-reply.gpg".format(source.interaction_count, source.journalist_filename) + fname = f"{source.interaction_count}-{source.journalist_filename}-reply.gpg" EncryptionManager.get_default().encrypt_journalist_reply( for_source_with_filesystem_id=source.filesystem_id, reply_in=next(replies), diff --git a/securedrop/manage.py b/securedrop/manage.py index 9cc6538eef..e1d22374f9 100755 --- a/securedrop/manage.py +++ b/securedrop/manage.py @@ -1,5 +1,4 @@ #!/opt/venvs/securedrop-app-code/bin/python -# -*- coding: utf-8 -*- import argparse import logging @@ -183,7 +182,7 @@ def _add_user(is_admin: bool = False, context: Optional[AppContext] = None) -> i print("Note: Passwords are now autogenerated.") password = PassphraseGenerator.get_default().generate_passphrase() - print("This user's password is: {}".format(password)) + print(f"This user's password is: {password}") is_hotp = _get_yubikey_usage() otp_secret = None @@ -197,7 +196,7 @@ def _add_user(is_admin: bool = False, context: Optional[AppContext] = None) -> i if len(tmp_str) != 40: print( "The length of the secret is not correct. " - "Expected 40 characters, but received {0}. " + "Expected 40 characters, but received {}. " "Try again.".format(len(tmp_str)) ) continue @@ -224,7 +223,7 @@ def _add_user(is_admin: bool = False, context: Optional[AppContext] = None) -> i print(repr(traceback.format_exception(exc_type, exc_value, exc_traceback))) return 1 else: - print('User "{}" successfully added'.format(username)) + print(f'User "{username}" successfully added') if not otp_secret: # Print the QR code for FreeOTP print("\nScan the QR code below with FreeOTP:\n") @@ -288,14 +287,14 @@ def delete_user(args: argparse.Namespace, context: Optional[AppContext] = None) else: raise e - print('User "{}" successfully deleted'.format(username)) + print(f'User "{username}" successfully deleted') return 0 def clean_tmp(args: argparse.Namespace) -> int: """Cleanup the SecureDrop temp directory.""" if not os.path.exists(args.directory): - log.debug("{} does not exist, do nothing".format(args.directory)) + log.debug(f"{args.directory} does not exist, do nothing") return 0 def listdir_fullpath(d: str) -> List[str]: @@ -305,9 +304,9 @@ def listdir_fullpath(d: str) -> List[str]: for path in listdir_fullpath(args.directory): if time.time() - os.stat(path).st_mtime > too_old: os.remove(path) - log.debug("{} removed".format(path)) + log.debug(f"{path} removed") else: - log.debug("{} modified less than {} days ago".format(path, args.days)) + log.debug(f"{path} modified less than {args.days} days ago") return 0 diff --git a/securedrop/management/run.py b/securedrop/management/run.py index 54ca060d31..339d2065f2 100644 --- a/securedrop/management/run.py +++ b/securedrop/management/run.py @@ -51,7 +51,7 @@ def __init__(self, label: str, cmd: List[str], color: str) -> None: self.cmd = cmd self.color = color - super(DevServerProcess, self).__init__( # type: ignore + super().__init__( # type: ignore self.cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, @@ -60,7 +60,7 @@ def __init__(self, label: str, cmd: List[str], color: str) -> None: ) def print_label(self, to: TextIO) -> None: - label = "\n => {} <= \n\n".format(self.label) + label = f"\n => {self.label} <= \n\n" if to.isatty(): label = colorize(label, self.color, True) to.write(label) diff --git a/securedrop/management/submissions.py b/securedrop/management/submissions.py index 1ff9f9add4..7db0149ac9 100644 --- a/securedrop/management/submissions.py +++ b/securedrop/management/submissions.py @@ -71,7 +71,7 @@ def delete_disconnected_db_submissions(args: argparse.Namespace) -> None: if not args.force: remove = input("Enter 'y' to delete all submissions missing files: ") == "y" if remove: - print("Removing submission IDs {}...".format(ids)) + print(f"Removing submission IDs {ids}...") db.session.query(Submission).filter(Submission.id.in_(ids)).delete( synchronize_session="fetch" ) @@ -152,13 +152,13 @@ def delete_disconnected_fs_submissions(args: argparse.Namespace) -> None: for i, f in enumerate(disconnected_files, 1): remove = args.force if not args.force: - remove = input("Enter 'y' to delete {}: ".format(f)) == "y" + remove = input(f"Enter 'y' to delete {f}: ") == "y" if remove: filesize = os.stat(f).st_size if i > 1: eta = filesize / rate - eta_msg = " (ETA to remove {:d} bytes: {:.0f}s )".format(filesize, eta) - print("Securely removing file {}/{} {}{}...".format(i, filecount, f, eta_msg)) + eta_msg = f" (ETA to remove {filesize:d} bytes: {eta:.0f}s )" + print(f"Securely removing file {i}/{filecount} {f}{eta_msg}...") start = time.time() secure_delete(f) file_elapsed = time.time() - start @@ -171,7 +171,7 @@ def delete_disconnected_fs_submissions(args: argparse.Namespace) -> None: ) ) else: - print("Not removing {}.".format(f)) + print(f"Not removing {f}.") def were_there_submissions_today( diff --git a/securedrop/models.py b/securedrop/models.py index a6601f9dd2..7600e99770 100644 --- a/securedrop/models.py +++ b/securedrop/models.py @@ -55,7 +55,7 @@ def get_one_or_else( ) failure_method(500) except NoResultFound as e: - logger.error("Found none when one was expected: %s" % (e,)) + logger.error(f"Found none when one was expected: {e}") failure_method(404) @@ -338,14 +338,14 @@ class FirstOrLastNameError(Exception): """Generic error for names that are invalid.""" def __init__(self, msg: str) -> None: - super(FirstOrLastNameError, self).__init__(msg) + super().__init__(msg) class InvalidNameLength(FirstOrLastNameError): """Raised when attempting to create a Journalist with an invalid name length.""" def __init__(self) -> None: - super(InvalidNameLength, self).__init__(gettext("Name too long")) + super().__init__(gettext("Name too long")) class LoginThrottledException(Exception): @@ -451,7 +451,7 @@ def __init__( self.set_hotp_secret(otp_secret) def __repr__(self) -> str: - return "".format(self.username, " [admin]" if self.is_admin else "") + return "".format(self.username, " [admin]" if self.is_admin else "") def _scrypt_hash(self, password: str, salt: bytes) -> bytes: backend = default_backend() @@ -557,7 +557,7 @@ def valid_password(self, passphrase: "Optional[str]") -> bool: # legacy support if self.pw_salt is None: raise ValueError( - "Should never happen: pw_salt is none for legacy Journalist {}".format(self.id) + f"Should never happen: pw_salt is none for legacy Journalist {self.id}" ) # For type checking @@ -609,14 +609,14 @@ def totp(self) -> "TOTP": if self.is_totp: return pyotp.TOTP(self.otp_secret) else: - raise ValueError("{} is not using TOTP".format(self)) + raise ValueError(f"{self} is not using TOTP") @property def hotp(self) -> "HOTP": if not self.is_totp: return pyotp.HOTP(self.otp_secret) else: - raise ValueError("{} is not using HOTP".format(self)) + raise ValueError(f"{self} is not using HOTP") @property def shared_secret_qrcode(self) -> Markup: diff --git a/securedrop/passphrases.py b/securedrop/passphrases.py index f4a1b94746..1635681128 100644 --- a/securedrop/passphrases.py +++ b/securedrop/passphrases.py @@ -38,7 +38,7 @@ def __init__( self._language_to_words = language_to_words if self._fallback_language not in self._language_to_words: raise InvalidWordListError( - "Missing words list for fallback language '{}'".format(self._fallback_language) + f"Missing words list for fallback language '{self._fallback_language}'" ) # Validate each words list diff --git a/securedrop/rm.py b/securedrop/rm.py index d9e083d196..bdb1750f7a 100644 --- a/securedrop/rm.py +++ b/securedrop/rm.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # # SecureDrop whistleblower submission system # Copyright (C) 2017 Loic Dachary @@ -39,7 +38,7 @@ def shred(path: str, delete: bool = True) -> None: """ if not os.path.exists(path): - raise EnvironmentError(path) + raise OSError(path) if not os.path.isfile(path): raise ValueError("The shred function only works on files.") @@ -95,7 +94,7 @@ def check_secure_delete_capability() -> bool: try: subprocess.check_output(["shred", "--help"]) return True - except EnvironmentError as e: + except OSError as e: if e.errno != errno.ENOENT: raise logging.error("The shred utility is missing.") diff --git a/securedrop/secure_tempfile.py b/securedrop/secure_tempfile.py index 4a70f60470..916391c334 100644 --- a/securedrop/secure_tempfile.py +++ b/securedrop/secure_tempfile.py @@ -1,6 +1,4 @@ -# -*- coding: utf-8 -*- import base64 -import io import os from tempfile import _TemporaryFileWrapper # type: ignore from typing import Optional, Union @@ -13,7 +11,7 @@ from pretty_bad_protocol._util import _STREAMLIKE_TYPES -class SecureTemporaryFile(_TemporaryFileWrapper, object): +class SecureTemporaryFile(_TemporaryFileWrapper): """Temporary file that provides on-the-fly encryption. Buffering large submissions in memory as they come in requires too @@ -53,9 +51,9 @@ def __init__(self, store_dir: str) -> None: data = base64.urlsafe_b64encode(os.urandom(32)) self.tmp_file_id = data.decode("utf-8").strip("=") - self.filepath = os.path.join(store_dir, "{}.aes".format(self.tmp_file_id)) - self.file = io.open(self.filepath, "w+b") - super(SecureTemporaryFile, self).__init__(self.file, self.filepath) + self.filepath = os.path.join(store_dir, f"{self.tmp_file_id}.aes") + self.file = open(self.filepath, "w+b") + super().__init__(self.file, self.filepath) def create_key(self) -> None: """Generates a unique, pseudorandom AES key, stored ephemerally in @@ -135,7 +133,7 @@ def close(self) -> None: # Since tempfile._TemporaryFileWrapper.close() does other cleanup, # (i.e. deleting the temp file on disk), we need to call it also. - super(SecureTemporaryFile, self).close() + super().close() # python-gnupg will not recognize our SecureTemporaryFile as a stream-like type diff --git a/securedrop/server_os.py b/securedrop/server_os.py index 2e76d7291f..4b3ec92209 100644 --- a/securedrop/server_os.py +++ b/securedrop/server_os.py @@ -3,7 +3,7 @@ FOCAL_VERSION = "20.04" -@functools.lru_cache() +@functools.lru_cache def get_os_release() -> str: with open("/etc/os-release") as f: os_release = f.readlines() diff --git a/securedrop/source_app/info.py b/securedrop/source_app/info.py index 73fe5b8de2..e9b03b20fe 100644 --- a/securedrop/source_app/info.py +++ b/securedrop/source_app/info.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from io import BytesIO # noqa import flask diff --git a/securedrop/source_app/main.py b/securedrop/source_app/main.py index 2f4e3bbe46..2ddc490b4e 100644 --- a/securedrop/source_app/main.py +++ b/securedrop/source_app/main.py @@ -1,4 +1,3 @@ -import io import operator import os from base64 import urlsafe_b64encode @@ -118,7 +117,7 @@ def create() -> werkzeug.Response: source_app_storage=Storage.get_default(), ) except (SourcePassphraseCollisionError, SourceDesignationCollisionError) as e: - current_app.logger.error("Could not create a source: {}".format(e)) + current_app.logger.error(f"Could not create a source: {e}") flash_msg( "error", None, @@ -159,7 +158,7 @@ def lookup(logged_in_source: SourceUser) -> str: reply.filename, ) try: - with io.open(reply_path, "rb") as f: + with open(reply_path, "rb") as f: contents = f.read() decrypted_reply = EncryptionManager.get_default().decrypt_journalist_reply( for_source_user=logged_in_source, ciphertext_in=contents diff --git a/securedrop/source_app/utils.py b/securedrop/source_app/utils.py index 589f416c91..88ddc56e78 100644 --- a/securedrop/source_app/utils.py +++ b/securedrop/source_app/utils.py @@ -93,14 +93,14 @@ def check_url_file(path: str, regexp: str) -> "Optional[str]": files in /var/lib/securedrop (as the Apache user can't read Tor config) """ try: - f = open(path, "r") + f = open(path) contents = f.readline().strip() f.close() if re.match(regexp, contents): return contents else: return None - except IOError: + except OSError: return None diff --git a/securedrop/source_user.py b/securedrop/source_user.py index e7433d4c74..7987d2bb8a 100644 --- a/securedrop/source_user.py +++ b/securedrop/source_user.py @@ -109,7 +109,7 @@ def create_source_user( except IntegrityError: db_session.rollback() raise SourcePassphraseCollisionError( - "Passphrase already used by another Source (filesystem_id {})".format(filesystem_id) + f"Passphrase already used by another Source (filesystem_id {filesystem_id})" ) # Create the source's folder diff --git a/securedrop/specialstrings.py b/securedrop/specialstrings.py index 1f2995b720..1a40a79aa4 100644 --- a/securedrop/specialstrings.py +++ b/securedrop/specialstrings.py @@ -1,6 +1,6 @@ strings = [ """This is a test message without markup!""", - """This is a test message with markup and characters such as \, \\, \', \" and ". """ + """This is a test message with markup and characters such as \\, \\, \', \" and ". """ + """This text should not be bold!""", # noqa: W605, E501 """~!@#$%^&*()_+{}|:"<>?~!@#$%^&*()_+{}|:"<>?~!@#$%^&*()_+{}|:"<>?~!@#$%""", """Ω≈ç√∫˜µ≤≥÷ diff --git a/securedrop/store.py b/securedrop/store.py index 0a72173dc2..1ee015fd30 100644 --- a/securedrop/store.py +++ b/securedrop/store.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- import binascii import gzip import os @@ -96,11 +95,11 @@ def safe_renames(old: str, new: str) -> None: class Storage: def __init__(self, storage_path: str, temp_dir: str) -> None: if not os.path.isabs(storage_path): - raise PathException("storage_path {} is not absolute".format(storage_path)) + raise PathException(f"storage_path {storage_path} is not absolute") self.__storage_path = storage_path if not os.path.isabs(temp_dir): - raise PathException("temp_dir {} is not absolute".format(temp_dir)) + raise PathException(f"temp_dir {temp_dir} is not absolute") self.__temp_dir = temp_dir # where files and directories are sent to be securely deleted @@ -159,7 +158,7 @@ def verify(self, p: str) -> bool: if os.path.isfile(p) and VALIDATE_FILENAME(os.path.basename(p)): return True - raise PathException("Path not valid in store: {}".format(p)) + raise PathException(f"Path not valid in store: {p}") def path(self, filesystem_id: str, filename: str = "") -> str: """ @@ -192,14 +191,12 @@ def path_without_filesystem_id(self, filename: str) -> str: if len(joined_paths) > 1: raise TooManyFilesException("Found duplicate files!") elif len(joined_paths) == 0: - raise NoFileFoundException("File not found: {}".format(filename)) + raise NoFileFoundException(f"File not found: {filename}") else: absolute = joined_paths[0] if not self.verify(absolute): - raise PathException( - """Could not resolve "{}" to a path within the store.""".format(filename) - ) + raise PathException(f"""Could not resolve "{filename}" to a path within the store.""") return absolute def get_bulk_archive( @@ -209,7 +206,7 @@ def get_bulk_archive( zip_file = tempfile.NamedTemporaryFile( prefix="tmp_securedrop_bulk_dl_", dir=self.__temp_dir, delete=False ) - sources = set([i.source.journalist_designation for i in selected_submissions]) + sources = {i.source.journalist_designation for i in selected_submissions} # The below nested for-loops are there to create a more usable # folder structure per #383 missing_files = False @@ -233,13 +230,13 @@ def get_bulk_archive( filename, arcname=os.path.join( fname, - "%s_%s" % (document_number, submission.source.last_updated.date()), + f"{document_number}_{submission.source.last_updated.date()}", os.path.basename(filename), ), ) else: missing_files = True - current_app.logger.error("File {} not found".format(filename)) + current_app.logger.error(f"File {filename} not found") if missing_files: raise FileNotFoundError @@ -261,14 +258,14 @@ def move_to_shredder(self, path: str) -> None: shredder directory. """ if not self.verify(path): - raise ValueError("""Path is not within the store: "{}" """.format(path)) + raise ValueError(f"""Path is not within the store: "{path}" """) if not os.path.exists(path): - raise ValueError("""Path does not exist: "{}" """.format(path)) + raise ValueError(f"""Path does not exist: "{path}" """) relpath = os.path.relpath(path, start=self.storage_path) dest = os.path.join(tempfile.mkdtemp(dir=self.__shredder_path), relpath) - current_app.logger.info("Moving {} to shredder: {}".format(path, dest)) + current_app.logger.info(f"Moving {path} to shredder: {dest}") safe_renames(path, dest) def clear_shredder(self) -> None: @@ -291,27 +288,25 @@ def clear_shredder(self) -> None: # again, shouldn't occur in the store -- will # result in the file data being shredded once for # each link. - current_app.logger.info( - "Deleting link {} to {}".format(abs_file, os.readlink(abs_file)) - ) + current_app.logger.info(f"Deleting link {abs_file} to {os.readlink(abs_file)}") os.unlink(abs_file) continue if self.shredder_contains(abs_file): targets.append(abs_file) target_count = len(targets) - current_app.logger.info("Files to delete: {}".format(target_count)) + current_app.logger.info(f"Files to delete: {target_count}") for i, t in enumerate(targets, 1): - current_app.logger.info("Securely deleting file {}/{}: {}".format(i, target_count, t)) + current_app.logger.info(f"Securely deleting file {i}/{target_count}: {t}") rm.secure_delete(t) - current_app.logger.info("Securely deleted file {}/{}: {}".format(i, target_count, t)) + current_app.logger.info(f"Securely deleted file {i}/{target_count}: {t}") directories_to_remove = set(directories) dir_count = len(directories_to_remove) for i, d in enumerate(reversed(sorted(directories_to_remove)), 1): - current_app.logger.debug("Removing directory {}/{}: {}".format(i, dir_count, d)) + current_app.logger.debug(f"Removing directory {i}/{dir_count}: {d}") os.rmdir(d) - current_app.logger.debug("Removed directory {}/{}: {}".format(i, dir_count, d)) + current_app.logger.debug(f"Removed directory {i}/{dir_count}: {d}") def save_file_submission( self, @@ -340,7 +335,7 @@ def save_file_submission( # file. Given various usability constraints in GPG and Tails, this # is the most user-friendly way we have found to do this. - encrypted_file_name = "{0}-{1}-doc.gz.gpg".format(count, journalist_filename) + encrypted_file_name = f"{count}-{journalist_filename}-doc.gz.gpg" encrypted_file_path = self.path(filesystem_id, encrypted_file_name) with SecureTemporaryFile("/tmp") as stf: # nosec with gzip.GzipFile(filename=sanitized_filename, mode="wb", fileobj=stf, mtime=0) as gzf: @@ -365,7 +360,7 @@ def save_pre_encrypted_reply( if "-----BEGIN PGP MESSAGE-----" not in content.split("\n")[0]: raise NotEncrypted - encrypted_file_name = "{0}-{1}-reply.gpg".format(count, journalist_filename) + encrypted_file_name = f"{count}-{journalist_filename}-reply.gpg" encrypted_file_path = self.path(filesystem_id, encrypted_file_name) with open(encrypted_file_path, "w") as fh: @@ -376,7 +371,7 @@ def save_pre_encrypted_reply( def save_message_submission( self, filesystem_id: str, count: int, journalist_filename: str, message: str ) -> str: - filename = "{0}-{1}-msg.gpg".format(count, journalist_filename) + filename = f"{count}-{journalist_filename}-msg.gpg" msg_loc = self.path(filesystem_id, filename) EncryptionManager.get_default().encrypt_source_message( message_in=message, diff --git a/securedrop/template_filters.py b/securedrop/template_filters.py index 21e6345dcb..741e1f0654 100644 --- a/securedrop/template_filters.py +++ b/securedrop/template_filters.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- import math from datetime import datetime diff --git a/securedrop/tests/config_from_2014.py b/securedrop/tests/config_from_2014.py index 6af5850cbc..cc8db20127 100644 --- a/securedrop/tests/config_from_2014.py +++ b/securedrop/tests/config_from_2014.py @@ -8,7 +8,7 @@ # Default values for production, may be overridden later based on environment -class FlaskConfig(object): +class FlaskConfig: DEBUG = False TESTING = False WTF_CSRF_ENABLED = True diff --git a/securedrop/tests/conftest.py b/securedrop/tests/conftest.py index b54e7bb265..5aac75c6a2 100644 --- a/securedrop/tests/conftest.py +++ b/securedrop/tests/conftest.py @@ -368,5 +368,5 @@ def _stop_test_rqworker(worker_pid_file: Path) -> None: def _get_pid_from_file(pid_file_name: Path) -> int: try: return int(open(pid_file_name).read()) - except IOError: + except OSError: return -1 diff --git a/securedrop/tests/i18n/code.py b/securedrop/tests/i18n/code.py index dc1af9b937..f59db5ee4c 100644 --- a/securedrop/tests/i18n/code.py +++ b/securedrop/tests/i18n/code.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from flask_babel import gettext print(gettext("code hello i18n")) diff --git a/securedrop/tests/migrations/helpers.py b/securedrop/tests/migrations/helpers.py index 96fedb1003..8fea8820b0 100644 --- a/securedrop/tests/migrations/helpers.py +++ b/securedrop/tests/migrations/helpers.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - import random import secrets import string diff --git a/securedrop/tests/migrations/migration_15ac9509fc68.py b/securedrop/tests/migrations/migration_15ac9509fc68.py index 83d0c1aacb..31153c3b86 100644 --- a/securedrop/tests/migrations/migration_15ac9509fc68.py +++ b/securedrop/tests/migrations/migration_15ac9509fc68.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - import random import string diff --git a/securedrop/tests/migrations/migration_1ddb81fb88c2.py b/securedrop/tests/migrations/migration_1ddb81fb88c2.py index f4a9018053..7954a96880 100644 --- a/securedrop/tests/migrations/migration_1ddb81fb88c2.py +++ b/securedrop/tests/migrations/migration_1ddb81fb88c2.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - from db import db from journalist_app import create_app from sqlalchemy import text diff --git a/securedrop/tests/migrations/migration_2d0ce3ee5bdc.py b/securedrop/tests/migrations/migration_2d0ce3ee5bdc.py index 19d6ae11e9..bc4c523f34 100644 --- a/securedrop/tests/migrations/migration_2d0ce3ee5bdc.py +++ b/securedrop/tests/migrations/migration_2d0ce3ee5bdc.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - import random import string from uuid import uuid4 diff --git a/securedrop/tests/migrations/migration_35513370ba0d.py b/securedrop/tests/migrations/migration_35513370ba0d.py index 38747c8756..a6d168ebd2 100644 --- a/securedrop/tests/migrations/migration_35513370ba0d.py +++ b/securedrop/tests/migrations/migration_35513370ba0d.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - import random from uuid import uuid4 diff --git a/securedrop/tests/migrations/migration_3d91d6948753.py b/securedrop/tests/migrations/migration_3d91d6948753.py index 0b16e1ab8f..50db3e89b9 100644 --- a/securedrop/tests/migrations/migration_3d91d6948753.py +++ b/securedrop/tests/migrations/migration_3d91d6948753.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - import random import uuid diff --git a/securedrop/tests/migrations/migration_3da3fcab826a.py b/securedrop/tests/migrations/migration_3da3fcab826a.py index cff0469844..1c4be816d2 100644 --- a/securedrop/tests/migrations/migration_3da3fcab826a.py +++ b/securedrop/tests/migrations/migration_3da3fcab826a.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - import os import random from uuid import uuid4 diff --git a/securedrop/tests/migrations/migration_48a75abc0121.py b/securedrop/tests/migrations/migration_48a75abc0121.py index 018056e1d8..fdffd502f8 100644 --- a/securedrop/tests/migrations/migration_48a75abc0121.py +++ b/securedrop/tests/migrations/migration_48a75abc0121.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - import random import secrets import string diff --git a/securedrop/tests/migrations/migration_60f41bb14d98.py b/securedrop/tests/migrations/migration_60f41bb14d98.py index 7049cb5f11..15f5419316 100644 --- a/securedrop/tests/migrations/migration_60f41bb14d98.py +++ b/securedrop/tests/migrations/migration_60f41bb14d98.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - import random import string import uuid diff --git a/securedrop/tests/migrations/migration_6db892e17271.py b/securedrop/tests/migrations/migration_6db892e17271.py index 4d9be23d1a..4019925f26 100644 --- a/securedrop/tests/migrations/migration_6db892e17271.py +++ b/securedrop/tests/migrations/migration_6db892e17271.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - import random import string import uuid diff --git a/securedrop/tests/migrations/migration_92fba0be98e9.py b/securedrop/tests/migrations/migration_92fba0be98e9.py index 45ffcd700c..27ede1f823 100644 --- a/securedrop/tests/migrations/migration_92fba0be98e9.py +++ b/securedrop/tests/migrations/migration_92fba0be98e9.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - import pytest import sqlalchemy from db import db diff --git a/securedrop/tests/migrations/migration_a9fe328b053a.py b/securedrop/tests/migrations/migration_a9fe328b053a.py index 326d5aac72..d9c2693b14 100644 --- a/securedrop/tests/migrations/migration_a9fe328b053a.py +++ b/securedrop/tests/migrations/migration_a9fe328b053a.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- import random import uuid diff --git a/securedrop/tests/migrations/migration_b060f38c0c31.py b/securedrop/tests/migrations/migration_b060f38c0c31.py index b2640e8808..6840a70297 100644 --- a/securedrop/tests/migrations/migration_b060f38c0c31.py +++ b/securedrop/tests/migrations/migration_b060f38c0c31.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - import random import uuid from typing import Any, Dict diff --git a/securedrop/tests/migrations/migration_b58139cfdc8c.py b/securedrop/tests/migrations/migration_b58139cfdc8c.py index 6e7a31d0c1..93e5d2e372 100644 --- a/securedrop/tests/migrations/migration_b58139cfdc8c.py +++ b/securedrop/tests/migrations/migration_b58139cfdc8c.py @@ -1,11 +1,9 @@ -# -*- coding: utf-8 -*- -import io import os import random import uuid from os import path +from unittest import mock -import mock from db import db from journalist_app import create_app from sqlalchemy import text @@ -48,7 +46,7 @@ def create_source(self): if self.source_id is not None: raise RuntimeError("Source already created") - self.source_filesystem_id = "aliruhglaiurhgliaurg-{}".format(self.counter) + self.source_filesystem_id = f"aliruhglaiurhgliaurg-{self.counter}" params = { "filesystem_id": self.source_filesystem_id, "uuid": str(uuid.uuid4()), @@ -148,7 +146,7 @@ def load_data(self): if not path.exists(dirname): os.mkdir(dirname) - with io.open(full_path, "wb") as f: + with open(full_path, "wb") as f: f.write(DATA) def check_upgrade(self): diff --git a/securedrop/tests/migrations/migration_c5a02eb52f2d.py b/securedrop/tests/migrations/migration_c5a02eb52f2d.py index 22066f20d2..c224c6a5cb 100644 --- a/securedrop/tests/migrations/migration_c5a02eb52f2d.py +++ b/securedrop/tests/migrations/migration_c5a02eb52f2d.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- import random import uuid diff --git a/securedrop/tests/migrations/migration_d9d36b6f4d1e.py b/securedrop/tests/migrations/migration_d9d36b6f4d1e.py index 037f1b51e5..bdfe4b6d63 100644 --- a/securedrop/tests/migrations/migration_d9d36b6f4d1e.py +++ b/securedrop/tests/migrations/migration_d9d36b6f4d1e.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- import secrets import pytest diff --git a/securedrop/tests/migrations/migration_de00920916bf.py b/securedrop/tests/migrations/migration_de00920916bf.py index 600f4c541a..48ebb2f68f 100644 --- a/securedrop/tests/migrations/migration_de00920916bf.py +++ b/securedrop/tests/migrations/migration_de00920916bf.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- import random import uuid diff --git a/securedrop/tests/migrations/migration_e0a525cbab83.py b/securedrop/tests/migrations/migration_e0a525cbab83.py index 856b19cf40..4533410676 100644 --- a/securedrop/tests/migrations/migration_e0a525cbab83.py +++ b/securedrop/tests/migrations/migration_e0a525cbab83.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - import random import string import uuid diff --git a/securedrop/tests/migrations/migration_f2833ac34bb6.py b/securedrop/tests/migrations/migration_f2833ac34bb6.py index 963c833d2a..7e762a4292 100644 --- a/securedrop/tests/migrations/migration_f2833ac34bb6.py +++ b/securedrop/tests/migrations/migration_f2833ac34bb6.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - import random import string import uuid diff --git a/securedrop/tests/migrations/migration_faac8092c123.py b/securedrop/tests/migrations/migration_faac8092c123.py index 0459b3d068..ab29e5f145 100644 --- a/securedrop/tests/migrations/migration_faac8092c123.py +++ b/securedrop/tests/migrations/migration_faac8092c123.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- - - class UpgradeTester: """This migration has no upgrade because it is only the enabling of pragmas which do not affect database contents. diff --git a/securedrop/tests/migrations/migration_fccf57ceef02.py b/securedrop/tests/migrations/migration_fccf57ceef02.py index e9d2596467..6810db68d5 100644 --- a/securedrop/tests/migrations/migration_fccf57ceef02.py +++ b/securedrop/tests/migrations/migration_fccf57ceef02.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - import random import uuid diff --git a/securedrop/tests/test_alembic.py b/securedrop/tests/test_alembic.py index 80590be9b5..a826b0d5e1 100644 --- a/securedrop/tests/test_alembic.py +++ b/securedrop/tests/test_alembic.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - import os import re import subprocess @@ -181,7 +179,7 @@ def test_upgrade_with_data(alembic_config, config, migration, _reset_db): upgrade(alembic_config, last_migration) # Dynamic module import - mod_name = "tests.migrations.migration_{}".format(migration) + mod_name = f"tests.migrations.migration_{migration}" mod = __import__(mod_name, fromlist=["UpgradeTester"]) # Load the test data @@ -201,7 +199,7 @@ def test_downgrade_with_data(alembic_config, config, migration, _reset_db): upgrade(alembic_config, migration) # Dynamic module import - mod_name = "tests.migrations.migration_{}".format(migration) + mod_name = f"tests.migrations.migration_{migration}" mod = __import__(mod_name, fromlist=["DowngradeTester"]) # Load the test data diff --git a/securedrop/tests/test_db.py b/securedrop/tests/test_db.py index 2eace3d135..80859f7bd8 100644 --- a/securedrop/tests/test_db.py +++ b/securedrop/tests/test_db.py @@ -1,6 +1,6 @@ -# -*- coding: utf-8 -*- +from unittest.mock import MagicMock + import pytest -from mock import MagicMock from models import ( InstanceConfig, Journalist, diff --git a/securedrop/tests/test_i18n.py b/securedrop/tests/test_i18n.py index 0b626b9fc8..1beadcf9c0 100644 --- a/securedrop/tests/test_i18n.py +++ b/securedrop/tests/test_i18n.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # # SecureDrop whistleblower submission system # Copyright (C) 2017 Loic Dachary @@ -300,7 +299,7 @@ def test_i18n(): def test_parse_locale_set(): - assert parse_locale_set([FALLBACK_LOCALE]) == set([Locale.parse(FALLBACK_LOCALE)]) + assert parse_locale_set([FALLBACK_LOCALE]) == {Locale.parse(FALLBACK_LOCALE)} def test_no_usable_fallback_locale(): diff --git a/securedrop/tests/test_i18n_tool.py b/securedrop/tests/test_i18n_tool.py index 91bb90dc78..cd46c99d87 100644 --- a/securedrop/tests/test_i18n_tool.py +++ b/securedrop/tests/test_i18n_tool.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- - -import io import os import shutil import signal @@ -8,14 +5,14 @@ import time from os.path import abspath, dirname, exists, getmtime, join, realpath from pathlib import Path +from unittest.mock import patch import i18n_tool import pytest -from mock import patch from tests.test_i18n import set_msg_translation_in_po_file -class TestI18NTool(object): +class TestI18NTool: def setup(self): self.dir = abspath(dirname(realpath(__file__))) @@ -48,7 +45,7 @@ def test_translate_desktop_l10n(self, tmpdir): ) messages_file = join(str(tmpdir), "desktop.pot") assert exists(messages_file) - with io.open(messages_file) as fobj: + with open(messages_file) as fobj: pot = fobj.read() assert "SecureDrop Source Interfaces" in pot # pretend this happened a few seconds ago @@ -113,11 +110,11 @@ def test_translate_desktop_l10n(self, tmpdir): ] ) assert old_messages_mtime == getmtime(messages_file) - with io.open(po_file) as fobj: + with open(po_file) as fobj: po = fobj.read() assert "SecureDrop Source Interfaces" in po assert "SecureDrop Journalist Interfaces" not in po - with io.open(i18n_file) as fobj: + with open(i18n_file) as fobj: i18n = fobj.read() assert "SOURCE FR" in i18n @@ -141,7 +138,7 @@ def test_translate_messages_l10n(self, tmpdir): i18n_tool.I18NTool().main(args) messages_file = join(str(tmpdir), "messages.pot") assert exists(messages_file) - with io.open(messages_file, "rb") as fobj: + with open(messages_file, "rb") as fobj: pot = fobj.read() assert b"code hello i18n" in pot assert b"template hello i18n" in pot @@ -174,7 +171,7 @@ def test_translate_messages_l10n(self, tmpdir): assert not exists(mo_file) i18n_tool.I18NTool().main(args) assert exists(mo_file) - with io.open(mo_file, mode="rb") as fobj: + with open(mo_file, mode="rb") as fobj: mo = fobj.read() assert b"code hello i18n" in mo assert b"template hello i18n" in mo @@ -198,7 +195,7 @@ def test_translate_messages_compile_arg(self, tmpdir): ) messages_file = join(str(tmpdir), "messages.pot") assert exists(messages_file) - with io.open(messages_file) as fobj: + with open(messages_file) as fobj: pot = fobj.read() assert "code hello i18n" in pot @@ -257,7 +254,7 @@ def test_translate_messages_compile_arg(self, tmpdir): ] ) assert current_po_mtime == getmtime(po_file) - with io.open(mo_file, mode="rb") as fobj: + with open(mo_file, mode="rb") as fobj: mo = fobj.read() assert b"code hello i18n" in mo assert b"template hello i18n" not in mo diff --git a/securedrop/tests/test_integration.py b/securedrop/tests/test_integration.py index c4874062e8..173c8333a3 100644 --- a/securedrop/tests/test_integration.py +++ b/securedrop/tests/test_integration.py @@ -6,9 +6,9 @@ from base64 import b32encode from binascii import unhexlify from io import BytesIO +from unittest import mock import journalist_app as journalist_app_module -import mock from bs4 import BeautifulSoup from db import db from encryption import EncryptionManager @@ -464,10 +464,7 @@ def test_delete_collection(mocker, source_app, journalist_app, test_journo): assert resp.status_code == 200 text = resp.data.decode("utf-8") - assert ( - escape("The account and data for the source {} have been deleted.".format(col_name)) - in text - ) + assert escape(f"The account and data for the source {col_name} have been deleted.") in text assert "There are no submissions!" in text @@ -517,7 +514,7 @@ def test_delete_collections(mocker, journalist_app, source_app, test_journo): ) assert resp.status_code == 200 text = resp.data.decode("utf-8") - assert "The accounts and all data for {} sources".format(num_sources) in text + assert f"The accounts and all data for {num_sources} sources" in text # simulate the source_deleter's work journalist_app_module.utils.purge_deleted_sources() diff --git a/securedrop/tests/test_journalist.py b/securedrop/tests/test_journalist.py index 16cfdaeafb..a6d89bb7dd 100644 --- a/securedrop/tests/test_journalist.py +++ b/securedrop/tests/test_journalist.py @@ -10,6 +10,7 @@ from io import BytesIO from pathlib import Path from typing import Tuple +from unittest.mock import call, patch import journalist_app as journalist_app_module import pytest @@ -20,7 +21,6 @@ from flask_babel import gettext, ngettext from journalist_app.sessions import session from journalist_app.utils import mark_seen -from mock import call, patch from models import ( InstanceConfig, InvalidPasswordLength, @@ -2303,7 +2303,7 @@ def test_logo_default_available(journalist_app, config): def test_logo_upload_with_valid_image_succeeds(config, journalist_app, test_admin, locale): # Save original logo to restore after test run logo_image_location = os.path.join(config.SECUREDROP_ROOT, "static/i/logo.png") - with io.open(logo_image_location, "rb") as logo_file: + with open(logo_image_location, "rb") as logo_file: original_image = logo_file.read() try: @@ -2342,7 +2342,7 @@ def test_logo_upload_with_valid_image_succeeds(config, journalist_app, test_admi assert response.data == logo_bytes finally: # Restore original image to logo location for subsequent tests - with io.open(logo_image_location, "wb") as logo_file: + with open(logo_image_location, "wb") as logo_file: logo_file.write(original_image) @@ -2376,7 +2376,7 @@ def test_logo_upload_with_invalid_filetype_fails(config, journalist_app, test_ad def test_logo_upload_save_fails(config, journalist_app, test_admin, locale): # Save original logo to restore after test run logo_image_location = os.path.join(config.SECUREDROP_ROOT, "static/i/logo.png") - with io.open(logo_image_location, "rb") as logo_file: + with open(logo_image_location, "rb") as logo_file: original_image = logo_file.read() try: @@ -2414,7 +2414,7 @@ def test_logo_upload_save_fails(config, journalist_app, test_admin, locale): ins.assert_message_flashed(gettext(msgids[0]), "logo-error") finally: # Restore original image to logo location for subsequent tests - with io.open(logo_image_location, "wb") as logo_file: + with open(logo_image_location, "wb") as logo_file: logo_file.write(original_image) @@ -3140,7 +3140,7 @@ def test_download_selected_submissions_and_replies( os.path.join( source.journalist_filename, source.journalist_designation, - "%s_%s" % (filename.split("-")[0], source.last_updated.date()), + "{}_{}".format(filename.split("-")[0], source.last_updated.date()), filename, ) ) @@ -3214,7 +3214,7 @@ def test_download_selected_submissions_and_replies_previously_seen( os.path.join( source.journalist_filename, source.journalist_designation, - "%s_%s" % (filename.split("-")[0], source.last_updated.date()), + "{}_{}".format(filename.split("-")[0], source.last_updated.date()), filename, ) ) @@ -3274,7 +3274,7 @@ def test_download_selected_submissions_previously_downloaded( os.path.join( source.journalist_filename, source.journalist_designation, - "%s_%s" % (filename.split("-")[0], source.last_updated.date()), + "{}_{}".format(filename.split("-")[0], source.last_updated.date()), filename, ) ) @@ -3329,7 +3329,7 @@ def test_download_selected_submissions_missing_files( .joinpath(file) .as_posix() ) - expected_calls.append(call("File {} not found".format(missing_file))) + expected_calls.append(call(f"File {missing_file} not found")) mocked_error_logger.assert_has_calls(expected_calls) @@ -3366,7 +3366,7 @@ def test_download_single_submission_missing_file( .as_posix() ) - mocked_error_logger.assert_called_once_with("File {} not found".format(missing_file)) + mocked_error_logger.assert_called_once_with(f"File {missing_file} not found") def test_download_unread_all_sources(journalist_app, test_journo, app_storage): diff --git a/securedrop/tests/test_journalist_api.py b/securedrop/tests/test_journalist_api.py index 6cd7f6afd1..61c2d03790 100644 --- a/securedrop/tests/test_journalist_api.py +++ b/securedrop/tests/test_journalist_api.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- import json import random from datetime import datetime @@ -1020,16 +1019,16 @@ def test_malformed_auth_token(journalist_app, journalist_api_token): with journalist_app.test_client() as app: # precondition to ensure token is even valid - resp = app.get(url, headers={"Authorization": "Token {}".format(journalist_api_token)}) + resp = app.get(url, headers={"Authorization": f"Token {journalist_api_token}"}) assert resp.status_code == 200 - resp = app.get(url, headers={"Authorization": "not-token {}".format(journalist_api_token)}) + resp = app.get(url, headers={"Authorization": f"not-token {journalist_api_token}"}) assert resp.status_code == 403 resp = app.get(url, headers={"Authorization": journalist_api_token}) assert resp.status_code == 403 - resp = app.get(url, headers={"Authorization": "too many {}".format(journalist_api_token)}) + resp = app.get(url, headers={"Authorization": f"too many {journalist_api_token}"}) assert resp.status_code == 403 diff --git a/securedrop/tests/test_manage.py b/securedrop/tests/test_manage.py index 5149003110..c11bff2b28 100644 --- a/securedrop/tests/test_manage.py +++ b/securedrop/tests/test_manage.py @@ -1,12 +1,11 @@ import argparse import datetime -import io import logging import os import time +from unittest import mock import manage -import mock from management import submissions from models import Journalist, db from passphrases import PassphraseGenerator @@ -180,7 +179,7 @@ def test_clean_tmp_do_nothing(caplog): def test_clean_tmp_too_young(config, caplog): args = argparse.Namespace(days=24 * 60 * 60, directory=config.TEMP_DIR, verbose=logging.DEBUG) # create a file - io.open(os.path.join(config.TEMP_DIR, "FILE"), "a").close() + open(os.path.join(config.TEMP_DIR, "FILE"), "a").close() manage.setup_verbosity(args) manage.clean_tmp(args) @@ -190,7 +189,7 @@ def test_clean_tmp_too_young(config, caplog): def test_clean_tmp_removed(config, caplog): args = argparse.Namespace(days=0, directory=config.TEMP_DIR, verbose=logging.DEBUG) fname = os.path.join(config.TEMP_DIR, "FILE") - with io.open(fname, "a"): + with open(fname, "a"): old = time.time() - 24 * 60 * 60 os.utime(fname, (old, old)) manage.setup_verbosity(args) @@ -214,8 +213,8 @@ def test_were_there_submissions_today(source_app, config, app_storage): source.last_updated = datetime.datetime.utcnow() - datetime.timedelta(hours=24 * 2) db.session.commit() submissions.were_there_submissions_today(args, context) - assert io.open(count_file).read() == "0" + assert open(count_file).read() == "0" source.last_updated = datetime.datetime.utcnow() db.session.commit() submissions.were_there_submissions_today(args, context) - assert io.open(count_file).read() == "1" + assert open(count_file).read() == "1" diff --git a/securedrop/tests/test_rm.py b/securedrop/tests/test_rm.py index 8c72c75265..e62ea2c1ae 100644 --- a/securedrop/tests/test_rm.py +++ b/securedrop/tests/test_rm.py @@ -12,7 +12,7 @@ def test_secure_delete_capability(config): path = os.environ["PATH"] try: - os.environ["PATH"] = "{}".format(config.TEMP_DIR) + os.environ["PATH"] = f"{config.TEMP_DIR}" assert rm.check_secure_delete_capability() is False fakeshred = os.path.join(config.TEMP_DIR, "shred") with open(fakeshred, "w") as f: diff --git a/securedrop/tests/test_secure_tempfile.py b/securedrop/tests/test_secure_tempfile.py index 326b56348d..fe880d4557 100644 --- a/securedrop/tests/test_secure_tempfile.py +++ b/securedrop/tests/test_secure_tempfile.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- -import io import os import pytest @@ -56,7 +54,7 @@ def test_read_write_unicode(): def test_file_seems_encrypted(): f = SecureTemporaryFile("/tmp") f.write(MESSAGE) - with io.open(f.filepath, "rb") as fh: + with open(f.filepath, "rb") as fh: contents = fh.read() assert MESSAGE.encode("utf-8") not in contents diff --git a/securedrop/tests/test_source.py b/securedrop/tests/test_source.py index 1aeb2a7bbf..f09e7c44e9 100644 --- a/securedrop/tests/test_source.py +++ b/securedrop/tests/test_source.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # flake8: noqa: E741 import gzip import os @@ -10,6 +9,7 @@ from io import BytesIO, StringIO from pathlib import Path from unittest import mock +from unittest.mock import ANY, patch import pytest import version @@ -19,7 +19,6 @@ from flask import escape, g, request, session, url_for from flask_babel import gettext from journalist_app.utils import delete_collection -from mock import ANY, patch from models import InstanceConfig, Reply, Source from passphrases import PassphraseGenerator from source_app import api as source_app_api diff --git a/securedrop/tests/test_source_utils.py b/securedrop/tests/test_source_utils.py index 6816122484..3d94074c75 100644 --- a/securedrop/tests/test_source_utils.py +++ b/securedrop/tests/test_source_utils.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- import json import os @@ -17,7 +16,7 @@ def test_check_url_file(config): def write_url_file(path, content): url_file = open(path, "w") - url_file.write("{}\n".format(content)) + url_file.write(f"{content}\n") url_path = "test_source_url" diff --git a/securedrop/tests/test_store.py b/securedrop/tests/test_store.py index 178f127b15..156b36990b 100644 --- a/securedrop/tests/test_store.py +++ b/securedrop/tests/test_store.py @@ -1,4 +1,3 @@ -import io import logging import os import re @@ -42,7 +41,7 @@ def create_file_in_source_dir(base_dir, filesystem_id, filename): os.makedirs(source_directory) file_path = os.path.join(source_directory, filename) - with io.open(file_path, "a"): + with open(file_path, "a"): os.utime(file_path, None) return source_directory, file_path @@ -119,7 +118,7 @@ def test_verify_in_store_dir(test_storage): with pytest.raises(store.PathException) as e: path = test_storage.storage_path + "_backup" test_storage.verify(path) - assert e.message == "Path not valid in store: {}".format(path) + assert e.message == f"Path not valid in store: {path}" def test_verify_store_path_not_absolute(test_storage): @@ -137,7 +136,7 @@ def test_verify_rejects_symlinks(test_storage): os.symlink("/foo", link) with pytest.raises(store.PathException) as e: test_storage.verify(link) - assert e.message == "Path not valid in store: {}".format(link) + assert e.message == f"Path not valid in store: {link}" finally: os.unlink(link) @@ -181,7 +180,7 @@ def test_verify_invalid_file_extension_in_sourcedir_raises_exception(test_storag with pytest.raises(store.PathException) as e: test_storage.verify(file_path) - assert "Path not valid in store: {}".format(file_path) in str(e) + assert f"Path not valid in store: {file_path}" in str(e) def test_verify_invalid_filename_in_sourcedir_raises_exception(test_storage): @@ -192,7 +191,7 @@ def test_verify_invalid_filename_in_sourcedir_raises_exception(test_storage): with pytest.raises(store.PathException) as e: test_storage.verify(file_path) - assert e.message == "Path not valid in store: {}".format(file_path) + assert e.message == f"Path not valid in store: {file_path}" def test_get_zip(journalist_app, test_source, app_storage, config): @@ -207,7 +206,7 @@ def test_get_zip(journalist_app, test_source, app_storage, config): archivefile_contents = archive.namelist() for archived_file, actual_file in zip(archivefile_contents, filenames): - with io.open(actual_file, "rb") as f: + with open(actual_file, "rb") as f: actual_file_content = f.read() zipped_file_content = archive.read(archived_file) assert zipped_file_content == actual_file_content @@ -379,7 +378,7 @@ def test_shredder_deletes_symlinks(journalist_app, app_storage, caplog): link = os.path.abspath(os.path.join(app_storage.shredder_path, "foo")) os.symlink(link_target, link) app_storage.clear_shredder() - assert "Deleting link {} to {}".format(link, link_target) in caplog.text + assert f"Deleting link {link} to {link_target}" in caplog.text assert not os.path.exists(link) @@ -396,6 +395,6 @@ def test_shredder_shreds(journalist_app, app_storage, caplog): f.write("testdata\n") app_storage.clear_shredder() - assert "Securely deleted file 1/1: {}".format(testfile) in caplog.text + assert f"Securely deleted file 1/1: {testfile}" in caplog.text assert not os.path.isfile(testfile) assert not os.path.isdir(testdir) diff --git a/securedrop/tests/test_worker.py b/securedrop/tests/test_worker.py index 211c9b1954..1cdc9a2d81 100644 --- a/securedrop/tests/test_worker.py +++ b/securedrop/tests/test_worker.py @@ -82,7 +82,7 @@ def test_job_interruption(config, caplog): # the running job should not be requeued worker.requeue_interrupted_jobs(queue_name) - skipped = "Skipping job {}, which is already being run by worker {}".format(job.id, w.key) + skipped = f"Skipping job {job.id}, which is already being run by worker {w.key}" assert skipped in caplog.text # kill the process group, to kill the worker and its workhorse @@ -93,7 +93,7 @@ def test_job_interruption(config, caplog): # after killing the worker, the interrupted job should be requeued worker.requeue_interrupted_jobs(queue_name) print(caplog.text) - assert "Requeuing job {}".format(job) in caplog.text + assert f"Requeuing job {job}" in caplog.text assert len(q.get_job_ids()) == 1 finally: q.delete() @@ -132,7 +132,7 @@ def test_worker_for_job(config): logging.debug( [ - "{}: state={}, job={}".format(w.pid, w.get_state(), w.get_current_job_id()) + f"{w.pid}: state={w.get_state()}, job={w.get_current_job_id()}" for w in worker.rq_workers(q) ] ) diff --git a/securedrop/tests/utils/api_helper.py b/securedrop/tests/utils/api_helper.py index aa0bd862f2..1030b38397 100644 --- a/securedrop/tests/utils/api_helper.py +++ b/securedrop/tests/utils/api_helper.py @@ -1,7 +1,7 @@ def get_api_headers(token=""): if token: return { - "Authorization": "Token {}".format(token), + "Authorization": f"Token {token}", "Accept": "application/json", "Content-Type": "application/json", } diff --git a/securedrop/tests/utils/asynchronous.py b/securedrop/tests/utils/asynchronous.py index 258c837ef3..f56a5c879a 100644 --- a/securedrop/tests/utils/asynchronous.py +++ b/securedrop/tests/utils/asynchronous.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """Testing utilities to block on and react to the success, failure, or timeout of asynchronous processes. """ diff --git a/securedrop/tests/utils/db_helper.py b/securedrop/tests/utils/db_helper.py index ec64ee1e75..fb5bfb7668 100644 --- a/securedrop/tests/utils/db_helper.py +++ b/securedrop/tests/utils/db_helper.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """Testing utilities that involve database (and often related filesystem) interaction. """ @@ -10,8 +9,8 @@ import subprocess from pathlib import Path from typing import Dict, List +from unittest import mock -import mock from db import db from encryption import EncryptionManager from journalist_app.utils import mark_seen @@ -73,7 +72,7 @@ def reply(storage, journalist, source, num_replies): replies = [] for _ in range(num_replies): source.interaction_count += 1 - fname = "{}-{}-reply.gpg".format(source.interaction_count, source.journalist_filename) + fname = f"{source.interaction_count}-{source.journalist_filename}-reply.gpg" EncryptionManager.get_default().encrypt_journalist_reply( for_source_with_filesystem_id=source.filesystem_id, diff --git a/securedrop/tests/utils/i18n.py b/securedrop/tests/utils/i18n.py index a8de7a64b4..7b9f57eaf9 100644 --- a/securedrop/tests/utils/i18n.py +++ b/securedrop/tests/utils/i18n.py @@ -60,7 +60,7 @@ def message_catalog(translation_dir: Path, locale: str) -> Catalog: >>> german.get("Password").string 'Passwort' """ - return read_po(open((translation_dir / locale / "LC_MESSAGES" / "messages.po"))) + return read_po(open(translation_dir / locale / "LC_MESSAGES" / "messages.po")) def page_language(page_text: str) -> Optional[str]: @@ -95,7 +95,7 @@ def xfail_untranslated_messages( for msgid in msgids: m = catalog.get(msgid) if not m: - pytest.xfail("locale {} message catalog lacks msgid: {}".format(locale, msgid)) + pytest.xfail(f"locale {locale} message catalog lacks msgid: {msgid}") if not m.string: - pytest.xfail("locale {} has no translation for msgid: {}".format(locale, msgid)) + pytest.xfail(f"locale {locale} has no translation for msgid: {msgid}") yield diff --git a/securedrop/tests/utils/instrument.py b/securedrop/tests/utils/instrument.py index 270e2daa81..fd10ef09d6 100644 --- a/securedrop/tests/utils/instrument.py +++ b/securedrop/tests/utils/instrument.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ Taken from: flask_testing.utils @@ -61,9 +60,7 @@ def assert_message_flashed(self, message, category="message"): if _message == message and _category == category: return True - raise AssertionError( - "Message '{}' in category '{}' wasn't flashed".format(message, category) - ) + raise AssertionError(f"Message '{message}' in category '{category}' wasn't flashed") def assert_template_used(self, name, tmpl_name_attribute="name"): """ @@ -116,7 +113,7 @@ def assert_context(self, name, value, message=None): try: assert self.get_context_variable(name) == value, message except ContextVariableDoesNotExist: - pytest.fail(message or "Context variable does not exist: {}".format(name)) + pytest.fail(message or f"Context variable does not exist: {name}") def assert_redirects(self, response, location, message=None): """ diff --git a/securedrop/upload-screenshots.py b/securedrop/upload-screenshots.py index 1c62323cbf..84ffabef06 100755 --- a/securedrop/upload-screenshots.py +++ b/securedrop/upload-screenshots.py @@ -107,7 +107,7 @@ def __init__( self.session = requests.Session() headers = { "User-Agent": self.user_agent, - "Authorization": "Token {}".format(token), + "Authorization": f"Token {token}", } self.session.headers.update(headers) @@ -130,7 +130,7 @@ def get_existing_screenshots(self) -> List[Dict[str, str]]: screenshots += screenshots_page["results"] request_count += 1 if request_count >= self.request_limit: - msg = "Request limit of {} exceeded. Aborting.".format(self.request_limit) + msg = f"Request limit of {self.request_limit} exceeded. Aborting." raise RequestLimitError(msg) return screenshots @@ -168,7 +168,7 @@ def upload(self, check_existing_screenshots: bool = True) -> None: image = {"image": open(file, "rb")} if existing_screenshot_url is not None: - print("Replacing existing screenshot {}".format(basename)) + print(f"Replacing existing screenshot {basename}") response = self.session.post(existing_screenshot_url, files=image) response.raise_for_status() else: @@ -177,14 +177,12 @@ def upload(self, check_existing_screenshots: bool = True) -> None: "project_slug": "securedrop", "component_slug": "securedrop", } - print("Uploading new screenshot {}".format(basename)) + print(f"Uploading new screenshot {basename}") response = self.session.post(self.screenshots_endpoint, files=image, data=fields) response.raise_for_status() - result_url = urljoin( - self.base_url, "screenshots/{}/{}".format(self.project, self.component) - ) - print("Upload complete. Visit {} to review the results.".format(result_url)) + result_url = urljoin(self.base_url, f"screenshots/{self.project}/{self.component}") + print(f"Upload complete. Visit {result_url} to review the results.") class BadOrMissingTokenError(Exception): diff --git a/securedrop/worker.py b/securedrop/worker.py index 4072784e2b..4082d5b73b 100644 --- a/securedrop/worker.py +++ b/securedrop/worker.py @@ -73,11 +73,11 @@ def requeue_interrupted_jobs(queue_name: str) -> None: started_job_registry = StartedJobRegistry(queue=queue) queued_job_ids = queue.get_job_ids() - logging.debug("queued jobs: {}".format(queued_job_ids)) + logging.debug(f"queued jobs: {queued_job_ids}") started_job_ids = started_job_registry.get_job_ids() - logging.debug("started jobs: {}".format(started_job_ids)) + logging.debug(f"started jobs: {started_job_ids}") job_ids = [j for j in started_job_ids if j not in queued_job_ids] - logging.debug("candidate job ids: {}".format(job_ids)) + logging.debug(f"candidate job ids: {job_ids}") if not job_ids: logging.debug("No interrupted jobs found in started job registry.")