The following issues were found

certbot-apache/tests/entrypoint_test.py
5 issues
Unable to import 'certbot_apache._internal'
Error

Line: 9 Column: 1

              except ImportError: # pragma: no cover
    from unittest import mock # type: ignore

from certbot_apache._internal import configurator
from certbot_apache._internal import entrypoint


class EntryPointTest(unittest.TestCase):
    """Entrypoint tests"""

            

Reported by Pylint.

Unable to import 'certbot_apache._internal'
Error

Line: 10 Column: 1

                  from unittest import mock # type: ignore

from certbot_apache._internal import configurator
from certbot_apache._internal import entrypoint


class EntryPointTest(unittest.TestCase):
    """Entrypoint tests"""


            

Reported by Pylint.

Missing function or method docstring
Error

Line: 18 Column: 5

              
    _multiprocess_can_split_ = True

    def test_get_configurator(self):

        with mock.patch("certbot.util.get_os_info") as mock_info:
            for distro in entrypoint.OVERRIDE_CLASSES:
                return_value = (distro, "whatever")
                if distro == 'fedora_old':

            

Reported by Pylint.

Missing function or method docstring
Error

Line: 31 Column: 5

                              self.assertEqual(entrypoint.get_configurator(),
                                 entrypoint.OVERRIDE_CLASSES[distro])

    def test_nonexistent_like(self):
        with mock.patch("certbot.util.get_os_info") as mock_info:
            mock_info.return_value = ("nonexistent", "irrelevant")
            with mock.patch("certbot.util.get_systemd_os_like") as mock_like:
                for like in entrypoint.OVERRIDE_CLASSES:
                    mock_like.return_value = [like]

            

Reported by Pylint.

Missing function or method docstring
Error

Line: 40 Column: 5

                                  self.assertEqual(entrypoint.get_configurator(),
                                     entrypoint.OVERRIDE_CLASSES[like])

    def test_nonexistent_generic(self):
        with mock.patch("certbot.util.get_os_info") as mock_info:
            mock_info.return_value = ("nonexistent", "irrelevant")
            with mock.patch("certbot.util.get_systemd_os_like") as mock_like:
                mock_like.return_value = ["unknonwn"]
                self.assertEqual(entrypoint.get_configurator(),

            

Reported by Pylint.

certbot/certbot/compat/filesystem.py
5 issues
Bad option value 'os-module-forbidden'
Error

Line: 5 Column: 1

              from __future__ import absolute_import

import errno
import os  # pylint: disable=os-module-forbidden
import stat
import sys
from typing import List

try:

            

Reported by Pylint.

Consider explicitly re-raising using the 'from' keyword
Error

Line: 241 Column: 17

                          # Handle native windows errors into python errors to be consistent with the API
            # of os.open in the situation of a file already existing or locked.
            if err.winerror == winerror.ERROR_FILE_EXISTS:
                raise OSError(errno.EEXIST, err.strerror)
            if err.winerror == winerror.ERROR_SHARING_VIOLATION:
                raise OSError(errno.EACCES, err.strerror)
            raise err
        finally:
            if handle:

            

Reported by Pylint.

Consider explicitly re-raising using the 'from' keyword
Error

Line: 243 Column: 17

                          if err.winerror == winerror.ERROR_FILE_EXISTS:
                raise OSError(errno.EEXIST, err.strerror)
            if err.winerror == winerror.ERROR_SHARING_VIOLATION:
                raise OSError(errno.EACCES, err.strerror)
            raise err
        finally:
            if handle:
                handle.Close()


            

Reported by Pylint.

Consider explicitly re-raising using the 'from' keyword
Error

Line: 317 Column: 13

                      # Handle native windows error into python error to be consistent with the API
        # of os.mkdir in the situation of a directory already existing.
        if err.winerror == winerror.ERROR_ALREADY_EXISTS:
            raise OSError(errno.EEXIST, err.strerror, file_path, err.winerror)
        raise err

    return None



            

Reported by Pylint.

Too few public methods (0/2)
Error

Line: 29 Column: 1

              # it is a decent choice to not have write permissions for group owner and everybody by default.
# We use a class here to avoid needing to define a global variable, and the potential mistakes
# that could happen with this kind of pattern.
class _WindowsUmask:
    """Store the current umask to apply on Windows"""
    def __init__(self):
        self.mask = 0o022



            

Reported by Pylint.

certbot/certbot/compat/misc.py
5 issues
subprocess call with shell=True identified, security issue.
Security injection

Line: 158
Suggestion: https://bandit.readthedocs.io/en/latest/plugins/b602_subprocess_popen_with_shell_equals_true.html

                  logger.info("Running %s command: %s", cmd_name, shell_cmd)

    if POSIX_MODE:
        proc = subprocess.run(shell_cmd, shell=True, stdout=subprocess.PIPE,
                              stderr=subprocess.PIPE, universal_newlines=True,
                              check=False, env=env)
    else:
        line = ['powershell.exe', '-Command', shell_cmd]
        proc = subprocess.run(line, stdout=subprocess.PIPE, stderr=subprocess.PIPE,

            

Reported by Bandit.

Consider possible security implications associated with subprocess module.
Security blacklist

Line: 9
Suggestion: https://bandit.readthedocs.io/en/latest/blacklists/blacklist_imports.html#b404-import-subprocess

              
import logging
import select
import subprocess
import sys
import warnings
from typing import Optional
from typing import Tuple


            

Reported by Bandit.

Variable name "ENABLE_VIRTUAL_TERMINAL_PROCESSING" doesn't conform to snake_case naming style
Error

Line: 53 Column: 5

                      return

    # https://docs.microsoft.com/en-us/windows/console/setconsolemode
    ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004

    # stdout/stderr will be the same console screen buffer, but this could return None or raise
    try:
        h = GetStdHandle(STD_OUTPUT_HANDLE)
        if h:

            

Reported by Pylint.

Variable name "h" doesn't conform to snake_case naming style
Error

Line: 57 Column: 9

              
    # stdout/stderr will be the same console screen buffer, but this could return None or raise
    try:
        h = GetStdHandle(STD_OUTPUT_HANDLE)
        if h:
            h.SetConsoleMode(h.GetConsoleMode() | ENABLE_VIRTUAL_TERMINAL_PROCESSING)
    except pywinerror:
        logger.debug("Failed to set console mode", exc_info=True)


            

Reported by Pylint.

subprocess call - check for execution of untrusted input.
Security injection

Line: 163
Suggestion: https://bandit.readthedocs.io/en/latest/plugins/b603_subprocess_without_shell_equals_true.html

                                            check=False, env=env)
    else:
        line = ['powershell.exe', '-Command', shell_cmd]
        proc = subprocess.run(line, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
                              universal_newlines=True, check=False, env=env)

    # universal_newlines causes stdout and stderr to be str objects instead of
    # bytes in Python 3
    out, err = proc.stdout, proc.stderr

            

Reported by Bandit.

certbot/certbot/compat/os.py
5 issues
Bad option value 'os-module-forbidden'
Error

Line: 24 Column: 1

              # First round of wrapping: we import statically all public attributes exposed by the os module
# This allows in particular to have pylint, mypy, IDEs be aware that most of os members are
# available in certbot.compat.os.
from os import *  # type: ignore  # pylint: disable=wildcard-import,unused-wildcard-import,redefined-builtin,os-module-forbidden

# Second round of wrapping: we import dynamically all attributes from the os module that have not
# yet been imported by the first round (static import). This covers in particular the case of
# specific python 3.x versions where not all public attributes are in the special __all__ of os,
# and so not in `from os import *`.

            

Reported by Pylint.

Bad option value 'os-module-forbidden'
Error

Line: 30 Column: 1

              # yet been imported by the first round (static import). This covers in particular the case of
# specific python 3.x versions where not all public attributes are in the special __all__ of os,
# and so not in `from os import *`.
import os as std_os  # pylint: disable=os-module-forbidden
import sys as std_sys

ourselves = std_sys.modules[__name__]
# Adding all of stdlib os to this module confuses Sphinx so we skip this when
# building the documentation.

            

Reported by Pylint.

Module 'os' has no 'environ' member
Error

Line: 36 Column: 8

              ourselves = std_sys.modules[__name__]
# Adding all of stdlib os to this module confuses Sphinx so we skip this when
# building the documentation.
if not std_os.environ.get("CERTBOT_DOCS") == "1":
    for attribute in dir(std_os):
        # Check if the attribute does not already exist in our module. It could
        # be internal attributes of the module (__name__, __doc__), or
        # attributes from standard os already imported with `from os import *`.
        if not hasattr(ourselves, attribute):

            

Reported by Pylint.

Module import itself
Error

Line: 24 Column: 1

              # First round of wrapping: we import statically all public attributes exposed by the os module
# This allows in particular to have pylint, mypy, IDEs be aware that most of os members are
# available in certbot.compat.os.
from os import *  # type: ignore  # pylint: disable=wildcard-import,unused-wildcard-import,redefined-builtin,os-module-forbidden

# Second round of wrapping: we import dynamically all attributes from the os module that have not
# yet been imported by the first round (static import). This covers in particular the case of
# specific python 3.x versions where not all public attributes are in the special __all__ of os,
# and so not in `from os import *`.

            

Reported by Pylint.

Module import itself
Error

Line: 30 Column: 1

              # yet been imported by the first round (static import). This covers in particular the case of
# specific python 3.x versions where not all public attributes are in the special __all__ of os,
# and so not in `from os import *`.
import os as std_os  # pylint: disable=os-module-forbidden
import sys as std_sys

ourselves = std_sys.modules[__name__]
# Adding all of stdlib os to this module confuses Sphinx so we skip this when
# building the documentation.

            

Reported by Pylint.

certbot/certbot/display/ops.py
5 issues
Consider explicitly re-raising using the 'from' keyword
Error

Line: 51 Column: 13

                      except errors.MissingCommandlineFlag:
            msg = ("You should register before running non-interactively, "
                   "or provide --agree-tos and --email <email_address> flags.")
            raise errors.MissingCommandlineFlag(msg)

        if code != display_util.OK:
            if optional:
                raise errors.Error(
                    "An e-mail address or "

            

Reported by Pylint.

Consider explicitly re-raising using the 'from' keyword
Error

Line: 316 Column: 13

                                       default,
                         message,
                         exc_info=True)
            raise AssertionError('Invalid default "{0}"'.format(default))

    while True:
        code, raw = method(message, default=default, **kwargs)
        if code == display_util.OK:
            try:

            

Reported by Pylint.

Argument name "FQDNs" doesn't conform to snake_case naming style
Error

Line: 145 Column: 1

                  return valid_domains


def _sort_names(FQDNs):
    """Sort FQDNs by SLD (and if many, by their subdomains)

    :param list FQDNs: list of domain names

    :returns: Sorted list of domain names

            

Reported by Pylint.

Variable name "e" doesn't conform to snake_case naming style
Error

Line: 208 Column: 13

                      for i, domain in enumerate(domain_list):
            try:
                domain_list[i] = util.enforce_domain_sanity(domain)
            except errors.ConfigurationError as e:
                invalid_domains[domain] = str(e)

        if invalid_domains:
            retry_message = (
                "One or more of the entered domain names was not valid:"

            

Reported by Pylint.

Unnecessary "elif" after "return"
Error

Line: 294 Column: 5

                  :param list domains: Each domain is a 'str'

    """
    if len(domains) == 1:
        return "https://{0}".format(domains[0])
    elif len(domains) == 2:
        return "https://{dom[0]} and https://{dom[1]}".format(dom=domains)
    elif len(domains) > 2:
        return "{0}{1}{2}".format(

            

Reported by Pylint.

certbot-apache/tests/apache-conf-files/apache-conf-test-pebble.py
5 issues
Unable to import 'certbot_integration_tests.utils'
Error

Line: 10 Column: 1

              import subprocess
import sys

from certbot_integration_tests.utils import acme_server

SCRIPT_DIRNAME = os.path.dirname(__file__)


def main(args=None):

            

Reported by Pylint.

Module name "apache-conf-test-pebble" doesn't conform to snake_case naming style
Error

Line: 1 Column: 1

              #!/usr/bin/env python
"""
This executable script wraps the apache-conf-test bash script, in order to setup a pebble instance
before its execution. Directory URL is passed through the SERVER environment variable.
"""
import os
import subprocess
import sys


            

Reported by Pylint.

Consider possible security implications associated with subprocess module.
Security blacklist

Line: 7
Suggestion: https://bandit.readthedocs.io/en/latest/blacklists/blacklist_imports.html#b404-import-subprocess

              before its execution. Directory URL is passed through the SERVER environment variable.
"""
import os
import subprocess
import sys

from certbot_integration_tests.utils import acme_server

SCRIPT_DIRNAME = os.path.dirname(__file__)

            

Reported by Bandit.

Missing function or method docstring
Error

Line: 15 Column: 1

              SCRIPT_DIRNAME = os.path.dirname(__file__)


def main(args=None):
    if not args:
        args = sys.argv[1:]
    with acme_server.ACMEServer('pebble', [], False) as acme_xdist:
        environ = os.environ.copy()
        environ['SERVER'] = acme_xdist['directory_url']

            

Reported by Pylint.

subprocess call - check for execution of untrusted input.
Security injection

Line: 23
Suggestion: https://bandit.readthedocs.io/en/latest/plugins/b603_subprocess_without_shell_equals_true.html

                      environ['SERVER'] = acme_xdist['directory_url']
        command = [os.path.join(SCRIPT_DIRNAME, 'apache-conf-test')]
        command.extend(args)
        return subprocess.call(command, env=environ)


if __name__ == '__main__':
    sys.exit(main())

            

Reported by Bandit.

certbot-ci/certbot_integration_tests/utils/pebble_ocsp_server.py
5 issues
Requests call with verify=False disabling SSL certificate checks, security issue.
Security criptography

Line: 26
Suggestion: https://bandit.readthedocs.io/en/latest/plugins/b501_request_with_no_cert_validation.html

              class _ProxyHandler(BaseHTTPServer.BaseHTTPRequestHandler):
    # pylint: disable=missing-function-docstring
    def do_POST(self):
        request = requests.get(PEBBLE_MANAGEMENT_URL + '/intermediate-keys/0', verify=False)
        issuer_key = serialization.load_pem_private_key(request.content, None, default_backend())

        request = requests.get(PEBBLE_MANAGEMENT_URL + '/intermediates/0', verify=False)
        issuer_cert = x509.load_pem_x509_certificate(request.content, default_backend())


            

Reported by Bandit.

Requests call with verify=False disabling SSL certificate checks, security issue.
Security criptography

Line: 29
Suggestion: https://bandit.readthedocs.io/en/latest/plugins/b501_request_with_no_cert_validation.html

                      request = requests.get(PEBBLE_MANAGEMENT_URL + '/intermediate-keys/0', verify=False)
        issuer_key = serialization.load_pem_private_key(request.content, None, default_backend())

        request = requests.get(PEBBLE_MANAGEMENT_URL + '/intermediates/0', verify=False)
        issuer_cert = x509.load_pem_x509_certificate(request.content, default_backend())

        content_len = int(self.headers.get('Content-Length'))

        ocsp_request = ocsp.load_der_ocsp_request(self.rfile.read(content_len))

            

Reported by Bandit.

Requests call with verify=False disabling SSL certificate checks, security issue.
Security criptography

Line: 37
Suggestion: https://bandit.readthedocs.io/en/latest/plugins/b501_request_with_no_cert_validation.html

                      ocsp_request = ocsp.load_der_ocsp_request(self.rfile.read(content_len))
        response = requests.get('{0}/cert-status-by-serial/{1}'.format(
            PEBBLE_MANAGEMENT_URL, str(hex(ocsp_request.serial_number)).replace('0x', '')),
            verify=False
        )

        if not response.ok:
            ocsp_response = ocsp.OCSPResponseBuilder.build_unsuccessful(
                ocsp.OCSPResponseStatus.UNAUTHORIZED

            

Reported by Bandit.

Use of insecure MD2, MD4, MD5, or SHA1 hash function.
Security blacklist

Line: 61
Suggestion: https://bandit.readthedocs.io/en/latest/blacklists/blacklist_calls.html#b303-md5

                              revocation_time = parser.parse(revoked_at)

            ocsp_response = ocsp.OCSPResponseBuilder().add_response(
                cert=cert, issuer=issuer_cert, algorithm=hashes.SHA1(),
                cert_status=ocsp_status,
                this_update=now, next_update=now + datetime.timedelta(hours=1),
                revocation_time=revocation_time, revocation_reason=revocation_reason
            ).responder_id(
                ocsp.OCSPResponderEncoding.NAME, issuer_cert

            

Reported by Bandit.

Method name "do_POST" doesn't conform to snake_case naming style
Error

Line: 25 Column: 5

              
class _ProxyHandler(BaseHTTPServer.BaseHTTPRequestHandler):
    # pylint: disable=missing-function-docstring
    def do_POST(self):
        request = requests.get(PEBBLE_MANAGEMENT_URL + '/intermediate-keys/0', verify=False)
        issuer_key = serialization.load_pem_private_key(request.content, None, default_backend())

        request = requests.get(PEBBLE_MANAGEMENT_URL + '/intermediates/0', verify=False)
        issuer_cert = x509.load_pem_x509_certificate(request.content, default_backend())

            

Reported by Pylint.

letstest/scripts/test_openssl_version.py
5 issues
No value for argument 'apache_version' in function call
Error

Line: 30 Column: 5

                              "but SSLSessionTickets is not set.")

if __name__ == '__main__':
    main(*sys.argv[1:])

            

Reported by Pylint.

No value for argument 'openssl_version' in function call
Error

Line: 30 Column: 5

                              "but SSLSessionTickets is not set.")

if __name__ == '__main__':
    main(*sys.argv[1:])

            

Reported by Pylint.

Missing module docstring
Error

Line: 1 Column: 1

              #!/usr/bin/env python
# Test script for OpenSSL version checking
from distutils.version import LooseVersion
import sys


def main(openssl_version, apache_version):
    if not openssl_version.strip():
        raise Exception("No OpenSSL version found.")

            

Reported by Pylint.

Missing function or method docstring
Error

Line: 7 Column: 1

              import sys


def main(openssl_version, apache_version):
    if not openssl_version.strip():
        raise Exception("No OpenSSL version found.")
    if not apache_version.strip():
        raise Exception("No Apache version found.")
    conf_file_location = "/etc/letsencrypt/options-ssl-apache.conf"

            

Reported by Pylint.

Variable name "f" doesn't conform to snake_case naming style
Error

Line: 13 Column: 38

                  if not apache_version.strip():
        raise Exception("No Apache version found.")
    conf_file_location = "/etc/letsencrypt/options-ssl-apache.conf"
    with open(conf_file_location) as f:
        contents = f.read()
    if LooseVersion(apache_version.strip()) < LooseVersion('2.4.11') or \
        LooseVersion(openssl_version.strip()) < LooseVersion('1.0.2l'):
        # should be old version
        # assert SSLSessionTickets not in conf file

            

Reported by Pylint.

certbot/certbot/interfaces.py
5 issues
Unable to import 'acme.challenges'
Error

Line: 15 Column: 1

              
import zope.interface

from acme.challenges import Challenge
from acme.challenges import ChallengeResponse
from certbot.achallenges import AnnotatedChallenge
from certbot import configuration



            

Reported by Pylint.

Unable to import 'acme.challenges'
Error

Line: 16 Column: 1

              import zope.interface

from acme.challenges import Challenge
from acme.challenges import ChallengeResponse
from certbot.achallenges import AnnotatedChallenge
from certbot import configuration


class AccountStorage(metaclass=ABCMeta):

            

Reported by Pylint.

Too many arguments (6/5)
Error

Line: 248 Column: 5

                      """

    @abstractmethod
    def deploy_cert(self, domain: str, cert_path: str, key_path: str,
                    chain_path: str, fullchain_path: str) -> None:
        """Deploy certificate.

        :param str domain: domain to deploy certificate file
        :param str cert_path: absolute path to the certificate file

            

Reported by Pylint.

Too few public methods (1/2)
Error

Line: 429 Column: 1

              # :func:`IInstaller.deploy_cert` is called.


class GenericUpdater(metaclass=ABCMeta):
    """Interface for update types not currently specified by Certbot.

    This class allows plugins to perform types of updates that Certbot hasn't
    defined (yet).


            

Reported by Pylint.

Too few public methods (1/2)
Error

Line: 461 Column: 1

                      """


class RenewDeployer(metaclass=ABCMeta):
    """Interface for update types run when a lineage is renewed

    This class allows plugins to perform types of updates that need to run at
    lineage renewal that Certbot hasn't defined (yet).


            

Reported by Pylint.

certbot/certbot/_internal/plugins/webroot.py
5 issues
Unable to import 'acme'
Error

Line: 11 Column: 1

              from typing import List
from typing import Set

from acme import challenges
from certbot import errors
from certbot import interfaces
from certbot._internal import cli
from certbot.achallenges import KeyAuthorizationAnnotatedChallenge as AnnotatedChallenge
from certbot.compat import filesystem

            

Reported by Pylint.

Method could be a function
Error

Line: 137 Column: 5

                                  "webroot when using the webroot plugin.")
            return None if index == 0 else known_webroots[index - 1]  # code == display_util.OK

    def _prompt_for_new_webroot(self, domain, allowraise=False):
        code, webroot = ops.validated_directory(
            _validate_webroot,
            "Input the webroot for {0}:".format(domain),
            force_interactive=True)
        if code == display_util.CANCEL:

            

Reported by Pylint.

Method could be a function
Error

Line: 195 Column: 5

                          finally:
                filesystem.umask(old_umask)

    def _get_validation_path(self, root_path, achall):
        return os.path.join(root_path, achall.chall.encode("token"))

    def _perform_single(self, achall):
        response, validation = achall.response_and_validation()


            

Reported by Pylint.

Too few public methods (1/2)
Error

Line: 239 Column: 1

                      logger.debug("All challenges cleaned up")


class _WebrootMapAction(argparse.Action):
    """Action class for parsing webroot_map."""

    def __call__(self, parser, namespace, webroot_map, option_string=None):
        for domains, webroot_path in json.loads(webroot_map).items():
            webroot_path = _validate_webroot(webroot_path)

            

Reported by Pylint.

Too few public methods (1/2)
Error

Line: 249 Column: 1

                              (d, webroot_path) for d in cli.add_domains(namespace, domains))


class _WebrootPathAction(argparse.Action):
    """Action class for parsing webroot_path."""

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._domain_before_webroot = False

            

Reported by Pylint.