Flake8 fixes (#35)

* Apply Flake8 also on `setup.py`

modified:   tox.ini

* Fix W605 - invalid escape syntax

modified:   packages/setup.py
modified:   tox.ini

* Update comment about Flake8: W504

W503 and W504 are mutual exclusive - so we have to keep one of them.

modified:   tox.ini

* Fix F841 - variable assigned but never used

modified:   ssh-audit.py
modified:   tox.ini

* Fix E741 - ambiguous variable name 'l'

modified:   ssh-audit.py
modified:   tox.ini

* Fix E712 - comparison to False should be 'if cond is False'

... and not 'if conf == False'.

modified:   ssh-audit.py
modified:   tox.ini

* Fix E711 - comparison to None should be 'if cond is not None'

... and not 'if cond != None'.

modified:   ssh-audit.py
modified:   tox.ini

* Fix E305 - expected 2 blank lines

... after class or function definition, found 1.

modified:   ssh-audit.py
modified:   tox.ini

* Fix E303 - too many blank lines

modified:   ssh-audit.py
modified:   tox.ini

* Fix E303 - too many blank lines

modified:   ssh-audit.py
modified:   tox.ini

* Fix E301 - expected 1 blank line, found 0

No code change necessary, probably fixed by another commit.

modified:   tox.ini

* Fix E265 - block comment should start with '# '

There is lots of commented out code, which usually should be just
deleted.

I will keep it for now, as I am not yet very familiar with the code
base.

modified:   ssh-audit.py
modified:   tox.ini

* Fix E261 - at least two spaces before inline comment

modified:   ssh-audit.py
modified:   tox.ini

* Fix E251 - unexpected spaces around keyword / parameter equals

modified:   packages/setup.py
modified:   tox.ini

* Fix E231 - missing whitespace after ','

No code change necessary, probably fixed by previous commit.

modified:   tox.ini

* Fix E226 - missing whitespace around arithmetic operator

modified:   ssh-audit.py
modified:   tox.ini

* Fix W293 - blank line contains whitespace

modified:   ssh-audit.py
modified:   tox.ini

* Fix E221 - multiple spaces before operator

modified:   ssh-audit.py
modified:   tox.ini

* Update comment about Flake 8 E241

Lots of data is formatted as tables, so this warning is disabled for a
good reason.

modified:   tox.ini

* Fix E401 - multiple imports on one line

modified:   ssh-audit.py
modified:   tox.ini

* Do not ignore Flake8 warning F401

... as there were no errors in source code anyway.

modified:   tox.ini

* Fix F821 - undefined name

modified:   ssh-audit.py
modified:   tox.ini

* Reformat ignore section for Flake8

modified:   tox.ini

* Flake8 test suite

modified:   test/conftest.py
modified:   test/test_auditconf.py
modified:   test/test_banner.py
modified:   test/test_buffer.py
modified:   test/test_errors.py
modified:   test/test_output.py
modified:   test/test_resolve.py
modified:   test/test_socket.py
modified:   test/test_software.py
modified:   test/test_ssh1.py
modified:   test/test_ssh2.py
modified:   test/test_ssh_algorithm.py
modified:   test/test_utils.py
modified:   test/test_version_compare.py
modified:   tox.ini
This commit is contained in:
Jürgen Gmach 2020-06-09 23:54:07 +02:00 committed by GitHub
parent 29d874b450
commit 246a41d46f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 459 additions and 485 deletions

View File

@ -5,7 +5,7 @@ import re
from setuptools import setup from setuptools import setup
version = re.search('^VERSION\s*=\s*\'v(\d\.\d\.\d)\'', open('sshaudit/sshaudit.py').read(), re.M).group(1) version = re.search(r'^VERSION\s*=\s*\'v(\d\.\d\.\d)\'', open('sshaudit/sshaudit.py').read(), re.M).group(1)
print("\n\nPackaging ssh-audit v%s...\n\n" % version) print("\n\nPackaging ssh-audit v%s...\n\n" % version)
with open("sshaudit/README.md", "rb") as f: with open("sshaudit/README.md", "rb") as f:
@ -13,20 +13,20 @@ with open("sshaudit/README.md", "rb") as f:
setup( setup(
name = "ssh-audit", name="ssh-audit",
packages = ["sshaudit"], packages=["sshaudit"],
license = 'MIT', license='MIT',
entry_points = { entry_points={
"console_scripts": ['ssh-audit = sshaudit.sshaudit:main'] "console_scripts": ['ssh-audit = sshaudit.sshaudit:main']
}, },
version = version, version=version,
description = "An SSH server & client configuration security auditing tool", description="An SSH server & client configuration security auditing tool",
long_description = long_descr, long_description=long_descr,
long_description_content_type = "text/markdown", long_description_content_type="text/markdown",
author = "Joe Testa", author="Joe Testa",
author_email = "jtesta@positronsecurity.com", author_email="jtesta@positronsecurity.com",
url = "https://github.com/jtesta/ssh-audit", url="https://github.com/jtesta/ssh-audit",
classifiers = [ classifiers=[
"Development Status :: 5 - Production/Stable", "Development Status :: 5 - Production/Stable",
"Intended Audience :: Information Technology", "Intended Audience :: Information Technology",
"Intended Audience :: System Administrators", "Intended Audience :: System Administrators",

View File

@ -25,7 +25,20 @@
THE SOFTWARE. THE SOFTWARE.
""" """
from __future__ import print_function from __future__ import print_function
import base64, binascii, errno, hashlib, getopt, io, os, random, re, select, socket, struct, sys, json import base64
import binascii
import errno
import getopt
import hashlib
import io
import json
import os
import random
import re
import select
import socket
import struct
import sys
VERSION = 'v2.2.1-dev' VERSION = 'v2.2.1-dev'
@ -41,7 +54,7 @@ if sys.version_info >= (3,): # pragma: nocover
else: # pragma: nocover else: # pragma: nocover
import StringIO as _StringIO # pylint: disable=import-error import StringIO as _StringIO # pylint: disable=import-error
StringIO = BytesIO = _StringIO.StringIO StringIO = BytesIO = _StringIO.StringIO
text_type = unicode # pylint: disable=undefined-variable text_type = unicode # pylint: disable=undefined-variable # noqa: F821
binary_type = str binary_type = str
try: # pragma: nocover try: # pragma: nocover
# pylint: disable=unused-import # pylint: disable=unused-import
@ -190,9 +203,9 @@ class AuditConf(object):
elif o in ('-t', '--timeout'): elif o in ('-t', '--timeout'):
aconf.timeout = float(a) aconf.timeout = float(a)
aconf.timeout_set = True aconf.timeout_set = True
if len(args) == 0 and aconf.client_audit == False: if len(args) == 0 and aconf.client_audit is False:
usage_cb() usage_cb()
if aconf.client_audit == False: if aconf.client_audit is False:
if oport is not None: if oport is not None:
host = args[0] host = args[0]
else: else:
@ -700,7 +713,7 @@ class SSH2(object): # pylint: disable=too-few-public-methods
'ecdh-sha2-nistp256': KexNISTP256, 'ecdh-sha2-nistp256': KexNISTP256,
'ecdh-sha2-nistp384': KexNISTP384, 'ecdh-sha2-nistp384': KexNISTP384,
'ecdh-sha2-nistp521': KexNISTP521, 'ecdh-sha2-nistp521': KexNISTP521,
#'kexguess2@matt.ucc.asn.au': ??? # 'kexguess2@matt.ucc.asn.au': ???
} }
# Pick the first kex algorithm that the server supports, which we # Pick the first kex algorithm that the server supports, which we
@ -798,7 +811,6 @@ class SSH2(object): # pylint: disable=too-few-public-methods
else: else:
host_key_types[host_key_type]['parsed'] = True host_key_types[host_key_type]['parsed'] = True
# Performs DH group exchanges to find what moduli are supported, and checks # Performs DH group exchanges to find what moduli are supported, and checks
# their size. # their size.
class GEXTest(object): class GEXTest(object):
@ -865,7 +877,7 @@ class SSH2(object): # pylint: disable=too-few-public-methods
# got here, doesn't mean the server is vulnerable... # got here, doesn't mean the server is vulnerable...
smallest_modulus = kex_group.get_dh_modulus_size() smallest_modulus = kex_group.get_dh_modulus_size()
except Exception as e: # pylint: disable=bare-except except Exception: # pylint: disable=bare-except
pass pass
finally: finally:
s.close() s.close()
@ -887,9 +899,9 @@ class SSH2(object): # pylint: disable=too-few-public-methods
kex_group.send_init_gex(s, bits, bits, bits) kex_group.send_init_gex(s, bits, bits, bits)
kex_group.recv_reply(s, False) kex_group.recv_reply(s, False)
smallest_modulus = kex_group.get_dh_modulus_size() smallest_modulus = kex_group.get_dh_modulus_size()
except Exception as e: # pylint: disable=bare-except except Exception: # pylint: disable=bare-except
#import traceback # import traceback
#print(traceback.format_exc()) # print(traceback.format_exc())
pass pass
finally: finally:
# The server is in a state that is not re-testable, # The server is in a state that is not re-testable,
@ -897,7 +909,6 @@ class SSH2(object): # pylint: disable=too-few-public-methods
# connection. # connection.
s.close() s.close()
if smallest_modulus > 0: if smallest_modulus > 0:
kex.set_dh_modulus_size(gex_alg, smallest_modulus) kex.set_dh_modulus_size(gex_alg, smallest_modulus)
@ -919,6 +930,7 @@ class SSH2(object): # pylint: disable=too-few-public-methods
if reconnect_failed: if reconnect_failed:
break break
class SSH1(object): class SSH1(object):
class CRC32(object): class CRC32(object):
def __init__(self): def __init__(self):
@ -935,8 +947,8 @@ class SSH1(object):
def calc(self, v): def calc(self, v):
# type: (binary_type) -> int # type: (binary_type) -> int
crc, l = 0, len(v) crc, length = 0, len(v)
for i in range(l): for i in range(length):
n = ord(v[i:i + 1]) n = ord(v[i:i + 1])
n = n ^ (crc & 0xff) n = n ^ (crc & 0xff)
crc = (crc >> 8) ^ self._table[n] crc = (crc >> 8) ^ self._table[n]
@ -1189,6 +1201,7 @@ class ReadBuf(object):
self._len = 0 self._len = 0
super(ReadBuf, self).reset() super(ReadBuf, self).reset()
class WriteBuf(object): class WriteBuf(object):
def __init__(self, data=None): def __init__(self, data=None):
# type: (Optional[binary_type]) -> None # type: (Optional[binary_type]) -> None
@ -1609,7 +1622,7 @@ class SSH(object): # pylint: disable=too-few-public-methods
def __getitem__(self, product): def __getitem__(self, product):
# type: (str) -> Sequence[Optional[str]] # type: (str) -> Sequence[Optional[str]]
return tuple(self.__storage.get(product, [None]*4)) return tuple(self.__storage.get(product, [None] * 4))
def __str__(self): def __str__(self):
# type: () -> str # type: () -> str
@ -1640,7 +1653,7 @@ class SSH(object): # pylint: disable=too-few-public-methods
ssh_versions[ssh_prod] = ssh_ver ssh_versions[ssh_prod] = ssh_ver
for ssh_product, ssh_version in ssh_versions.items(): for ssh_product, ssh_version in ssh_versions.items():
if ssh_product not in self.__storage: if ssh_product not in self.__storage:
self.__storage[ssh_product] = [None]*4 self.__storage[ssh_product] = [None] * 4
prev = self[ssh_product][pos] prev = self[ssh_product][pos]
if (prev is None or if (prev is None or
(prev < ssh_version and pos % 2 == 0) or (prev < ssh_version and pos % 2 == 0) or
@ -1783,19 +1796,18 @@ class SSH(object): # pylint: disable=too-few-public-methods
if software is not None: if software is not None:
if software.product not in vproducts: if software.product not in vproducts:
unknown_software = True unknown_software = True
#
# The code below is commented out because it would try to guess what the server is, # The code below is commented out because it would try to guess what the server is,
# usually resulting in wild & incorrect recommendations. # usually resulting in wild & incorrect recommendations.
# # if software is None:
# if software is None: # ssh_timeframe = self.get_ssh_timeframe(for_server)
# ssh_timeframe = self.get_ssh_timeframe(for_server) # for product in vproducts:
# for product in vproducts: # if product not in ssh_timeframe:
# if product not in ssh_timeframe: # continue
# continue # version = ssh_timeframe.get_from(product, for_server)
# version = ssh_timeframe.get_from(product, for_server) # if version is not None:
# if version is not None: # software = SSH.Software(None, product, version, None, None)
# software = SSH.Software(None, product, version, None, None) # break
# break
rec = {} # type: Dict[int, Dict[str, Dict[str, Dict[str, int]]]] rec = {} # type: Dict[int, Dict[str, Dict[str, Dict[str, int]]]]
if software is None: if software is None:
unknown_software = True unknown_software = True
@ -2057,7 +2069,6 @@ class SSH(object): # pylint: disable=too-few-public-methods
self.client_host = None self.client_host = None
self.client_port = None self.client_port = None
def _resolve(self, ipvo): def _resolve(self, ipvo):
# type: (Sequence[int]) -> Iterable[Tuple[int, Tuple[Any, ...]]] # type: (Sequence[int]) -> Iterable[Tuple[int, Tuple[Any, ...]]]
ipvo = tuple([x for x in utils.unique_seq(ipvo) if x in (4, 6)]) ipvo = tuple([x for x in utils.unique_seq(ipvo) if x in (4, 6)])
@ -2081,7 +2092,6 @@ class SSH(object): # pylint: disable=too-few-public-methods
out.fail('[exception] {0}'.format(e)) out.fail('[exception] {0}'.format(e))
sys.exit(1) sys.exit(1)
# Listens on a server socket and accepts one connection (used for # Listens on a server socket and accepts one connection (used for
# auditing client connections). # auditing client connections).
def listen_and_accept(self): def listen_and_accept(self):
@ -2093,7 +2103,7 @@ class SSH(object): # pylint: disable=too-few-public-methods
s.bind(('0.0.0.0', self.__port)) s.bind(('0.0.0.0', self.__port))
s.listen() s.listen()
self.__sock_map[s.fileno()] = s self.__sock_map[s.fileno()] = s
except Exception as e: except Exception:
print("Warning: failed to listen on any IPv4 interfaces.") print("Warning: failed to listen on any IPv4 interfaces.")
pass pass
@ -2105,7 +2115,7 @@ class SSH(object): # pylint: disable=too-few-public-methods
s.bind(('::', self.__port)) s.bind(('::', self.__port))
s.listen() s.listen()
self.__sock_map[s.fileno()] = s self.__sock_map[s.fileno()] = s
except Exception as e: except Exception:
print("Warning: failed to listen on any IPv6 interfaces.") print("Warning: failed to listen on any IPv6 interfaces.")
pass pass
@ -2139,7 +2149,6 @@ class SSH(object): # pylint: disable=too-few-public-methods
c.settimeout(self.__timeout) c.settimeout(self.__timeout)
self.__sock = c self.__sock = c
def connect(self): def connect(self):
# type: () -> None # type: () -> None
err = None err = None
@ -2169,10 +2178,10 @@ class SSH(object): # pylint: disable=too-few-public-methods
banner = SSH_HEADER.format('1.5' if sshv == 1 else '2.0') banner = SSH_HEADER.format('1.5' if sshv == 1 else '2.0')
if self.__state < self.SM_BANNER_SENT: if self.__state < self.SM_BANNER_SENT:
self.send_banner(banner) self.send_banner(banner)
# rto = self.__sock.gettimeout() # rto = self.__sock.gettimeout()
# self.__sock.settimeout(0.7) # self.__sock.settimeout(0.7)
s, e = self.recv() s, e = self.recv()
# self.__sock.settimeout(rto) # self.__sock.settimeout(rto)
if s < 0: if s < 0:
return self.__banner, self.__header, e return self.__banner, self.__header, e
e = None e = None
@ -2357,7 +2366,6 @@ class KexDH(object): # pragma: nocover
self.__f = 0 self.__f = 0
self.__h_sig = 0 self.__h_sig = 0
def set_params(self, g, p): def set_params(self, g, p):
self.__g = g self.__g = g
self.__p = p self.__p = p
@ -2365,7 +2373,6 @@ class KexDH(object): # pragma: nocover
self.__x = 0 self.__x = 0
self.__e = 0 self.__e = 0
def send_init(self, s, init_msg=SSH.Protocol.MSG_KEXDH_INIT): def send_init(self, s, init_msg=SSH.Protocol.MSG_KEXDH_INIT):
# type: (SSH.Socket) -> None # type: (SSH.Socket) -> None
r = random.SystemRandom() r = random.SystemRandom()
@ -2403,7 +2410,6 @@ class KexDH(object): # pragma: nocover
key_id = principles = None # pylint: disable=unused-variable key_id = principles = None # pylint: disable=unused-variable
critical_options = extensions = None # pylint: disable=unused-variable critical_options = extensions = None # pylint: disable=unused-variable
valid_after = valid_before = None # pylint: disable=unused-variable
nonce = ca_key = ca_key_type = None # pylint: disable=unused-variable nonce = ca_key = ca_key_type = None # pylint: disable=unused-variable
ca_key_e = ca_key_n = None # pylint: disable=unused-variable ca_key_e = ca_key_n = None # pylint: disable=unused-variable
@ -2455,12 +2461,10 @@ class KexDH(object): # pragma: nocover
# The principles, which are... I don't know what. # The principles, which are... I don't know what.
principles, principles_len, ptr = KexDH.__get_bytes(hostkey, ptr) principles, principles_len, ptr = KexDH.__get_bytes(hostkey, ptr)
# The timestamp that this certificate is valid after. # Skip over the timestamp that this certificate is valid after.
valid_after = hostkey[ptr:ptr + 8]
ptr += 8 ptr += 8
# The timestamp that this certificate is valid before. # Skip over the timestamp that this certificate is valid before.
valid_before = hostkey[ptr:ptr + 8]
ptr += 8 ptr += 8
# TODO: validate the principles, and time range. # TODO: validate the principles, and time range.
@ -2895,7 +2899,7 @@ def output_fingerprints(algs, sha256=True):
if algs.ssh1kex is not None: if algs.ssh1kex is not None:
name = 'ssh-rsa1' name = 'ssh-rsa1'
fp = SSH.Fingerprint(algs.ssh1kex.host_key_fingerprint_data) fp = SSH.Fingerprint(algs.ssh1kex.host_key_fingerprint_data)
#bits = algs.ssh1kex.host_key_bits # bits = algs.ssh1kex.host_key_bits
fps.append((name, fp)) fps.append((name, fp))
if algs.ssh2kex is not None: if algs.ssh2kex is not None:
host_keys = algs.ssh2kex.host_keys() host_keys = algs.ssh2kex.host_keys()
@ -2917,8 +2921,8 @@ def output_fingerprints(algs, sha256=True):
for fpp in fps: for fpp in fps:
name, fp = fpp name, fp = fpp
fpo = fp.sha256 if sha256 else fp.md5 fpo = fp.sha256 if sha256 else fp.md5
#p = '' if out.batch else ' ' * (padlen - len(name)) # p = '' if out.batch else ' ' * (padlen - len(name))
#out.good('(fin) {0}{1} -- {2} {3}'.format(name, p, bits, fpo)) # out.good('(fin) {0}{1} -- {2} {3}'.format(name, p, bits, fpo))
out.good('(fin) {0}: {1}'.format(name, fpo)) out.good('(fin) {0}: {1}'.format(name, fpo))
if len(obuf) > 0: if len(obuf) > 0:
out.head('# fingerprints') out.head('# fingerprints')
@ -3018,7 +3022,7 @@ def output_info(algs, software, client_audit, any_problems, padlen=0):
def output(banner, header, client_host=None, kex=None, pkm=None): def output(banner, header, client_host=None, kex=None, pkm=None):
# type: (Optional[SSH.Banner], List[text_type], Optional[SSH2.Kex], Optional[SSH1.PublicKeyMessage]) -> None # type: (Optional[SSH.Banner], List[text_type], Optional[SSH2.Kex], Optional[SSH1.PublicKeyMessage]) -> None
client_audit = (client_host != None) # If set, this is a client audit. client_audit = client_host is not None # If set, this is a client audit.
sshv = 1 if pkm is not None else 2 sshv = 1 if pkm is not None else 2
algs = SSH.Algorithms(pkm, kex) algs = SSH.Algorithms(pkm, kex)
with OutputBuffer() as obuf: with OutputBuffer() as obuf:
@ -3077,11 +3081,11 @@ def output(banner, header, client_host=None, kex=None, pkm=None):
perfect_config = output_recommendations(algs, software, maxlen) perfect_config = output_recommendations(algs, software, maxlen)
output_info(algs, software, client_audit, not perfect_config) output_info(algs, software, client_audit, not perfect_config)
# If we encountered any unknown algorithms, ask the user to report them. # If we encountered any unknown algorithms, ask the user to report them.
if len(unknown_algorithms) > 0: if len(unknown_algorithms) > 0:
out.warn("\n\n!!! WARNING: unknown algorithm(s) found!: %s. Please email the full output above to the maintainer (jtesta@positronsecurity.com), or create a Github issue at <https://github.com/jtesta/ssh-audit/issues>.\n" % ','.join(unknown_algorithms)) out.warn("\n\n!!! WARNING: unknown algorithm(s) found!: %s. Please email the full output above to the maintainer (jtesta@positronsecurity.com), or create a Github issue at <https://github.com/jtesta/ssh-audit/issues>.\n" % ','.join(unknown_algorithms))
class Utils(object): class Utils(object):
@classmethod @classmethod
def _type_err(cls, v, target): def _type_err(cls, v, target):
@ -3204,6 +3208,7 @@ class Utils(object):
except: # pylint: disable=bare-except except: # pylint: disable=bare-except
return -1.0 return -1.0
def build_struct(banner, kex=None, pkm=None, client_host=None): def build_struct(banner, kex=None, pkm=None, client_host=None):
res = { res = {
"banner": { "banner": {
@ -3281,6 +3286,7 @@ def build_struct(banner, kex=None, pkm=None, client_host=None):
return res return res
def audit(aconf, sshv=None): def audit(aconf, sshv=None):
# type: (AuditConf, Optional[int]) -> None # type: (AuditConf, Optional[int]) -> None
out.batch = aconf.batch out.batch = aconf.batch
@ -3350,9 +3356,11 @@ def audit(aconf, sshv=None):
utils = Utils() utils = Utils()
out = Output() out = Output()
def main(): def main():
conf = AuditConf.from_cmdline(sys.argv[1:], usage) conf = AuditConf.from_cmdline(sys.argv[1:], usage)
audit(conf) audit(conf)
if __name__ == '__main__': # pragma: nocover if __name__ == '__main__': # pragma: nocover
main() main()

View File

@ -52,7 +52,6 @@ class TestErrors(object):
assert 'timed out' in lines[-1] assert 'timed out' in lines[-1]
def test_recv_empty(self, output_spy, virtual_socket): def test_recv_empty(self, output_spy, virtual_socket):
vsocket = virtual_socket
lines = self._audit(output_spy) lines = self._audit(output_spy)
assert len(lines) == 1 assert len(lines) == 1
assert 'did not receive banner' in lines[-1] assert 'did not receive banner' in lines[-1]

View File

@ -25,7 +25,7 @@ class TestResolve(object):
conf = self._conf() conf = self._conf()
output_spy.begin() output_spy.begin()
with pytest.raises(SystemExit): with pytest.raises(SystemExit):
r = list(s._resolve(conf.ipvo)) list(s._resolve(conf.ipvo))
lines = output_spy.flush() lines = output_spy.flush()
assert len(lines) == 1 assert len(lines) == 1
assert 'hostname nor servname provided' in lines[-1] assert 'hostname nor servname provided' in lines[-1]
@ -40,7 +40,6 @@ class TestResolve(object):
assert len(r) == 0 assert len(r) == 0
def test_resolve_ipv4(self, virtual_socket): def test_resolve_ipv4(self, virtual_socket):
vsocket = virtual_socket
conf = self._conf() conf = self._conf()
conf.ipv4 = True conf.ipv4 = True
s = self.ssh.Socket('localhost', 22) s = self.ssh.Socket('localhost', 22)
@ -49,7 +48,6 @@ class TestResolve(object):
assert r[0] == (socket.AF_INET, ('127.0.0.1', 22)) assert r[0] == (socket.AF_INET, ('127.0.0.1', 22))
def test_resolve_ipv6(self, virtual_socket): def test_resolve_ipv6(self, virtual_socket):
vsocket = virtual_socket
s = self.ssh.Socket('localhost', 22) s = self.ssh.Socket('localhost', 22)
conf = self._conf() conf = self._conf()
conf.ipv6 = True conf.ipv6 = True
@ -58,7 +56,6 @@ class TestResolve(object):
assert r[0] == (socket.AF_INET6, ('::1', 22)) assert r[0] == (socket.AF_INET6, ('::1', 22))
def test_resolve_ipv46_both(self, virtual_socket): def test_resolve_ipv46_both(self, virtual_socket):
vsocket = virtual_socket
s = self.ssh.Socket('localhost', 22) s = self.ssh.Socket('localhost', 22)
conf = self._conf() conf = self._conf()
r = list(s._resolve(conf.ipvo)) r = list(s._resolve(conf.ipvo))
@ -67,7 +64,6 @@ class TestResolve(object):
assert r[1] == (socket.AF_INET6, ('::1', 22)) assert r[1] == (socket.AF_INET6, ('::1', 22))
def test_resolve_ipv46_order(self, virtual_socket): def test_resolve_ipv46_order(self, virtual_socket):
vsocket = virtual_socket
s = self.ssh.Socket('localhost', 22) s = self.ssh.Socket('localhost', 22)
conf = self._conf() conf = self._conf()
conf.ipv4 = True conf.ipv4 = True

View File

@ -1,6 +1,5 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import socket
import pytest import pytest
@ -12,17 +11,17 @@ class TestSocket(object):
def test_invalid_host(self, virtual_socket): def test_invalid_host(self, virtual_socket):
with pytest.raises(ValueError): with pytest.raises(ValueError):
s = self.ssh.Socket(None, 22) self.ssh.Socket(None, 22)
def test_invalid_port(self, virtual_socket): def test_invalid_port(self, virtual_socket):
with pytest.raises(ValueError): with pytest.raises(ValueError):
s = self.ssh.Socket('localhost', 'abc') self.ssh.Socket('localhost', 'abc')
with pytest.raises(ValueError): with pytest.raises(ValueError):
s = self.ssh.Socket('localhost', -1) self.ssh.Socket('localhost', -1)
with pytest.raises(ValueError): with pytest.raises(ValueError):
s = self.ssh.Socket('localhost', 0) self.ssh.Socket('localhost', 0)
with pytest.raises(ValueError): with pytest.raises(ValueError):
s = self.ssh.Socket('localhost', 65536) self.ssh.Socket('localhost', 65536)
def test_not_connected_socket(self, virtual_socket): def test_not_connected_socket(self, virtual_socket):
sock = self.ssh.Socket('localhost', 22) sock = self.ssh.Socket('localhost', 22)

View File

@ -95,10 +95,10 @@ class TestSSH1(object):
skey, hkey = self._server_key(), self._host_key() skey, hkey = self._server_key(), self._host_key()
pkm = self.ssh1.PublicKeyMessage(cookie, skey, hkey, pflags, cmask, amask) pkm = self.ssh1.PublicKeyMessage(cookie, skey, hkey, pflags, cmask, amask)
self._assert_pkm_fields(pkm, skey, hkey) self._assert_pkm_fields(pkm, skey, hkey)
for skey2 in ([], [0], [0,1], [0,1,2,3]): for skey2 in ([], [0], [0, 1], [0, 1, 2, 3]):
with pytest.raises(ValueError): with pytest.raises(ValueError):
pkm = self.ssh1.PublicKeyMessage(cookie, skey2, hkey, pflags, cmask, amask) pkm = self.ssh1.PublicKeyMessage(cookie, skey2, hkey, pflags, cmask, amask)
for hkey2 in ([], [0], [0,1], [0,1,2,3]): for hkey2 in ([], [0], [0, 1], [0, 1, 2, 3]):
with pytest.raises(ValueError): with pytest.raises(ValueError):
print(hkey2) print(hkey2)
pkm = self.ssh1.PublicKeyMessage(cookie, skey, hkey2, pflags, cmask, amask) pkm = self.ssh1.PublicKeyMessage(cookie, skey, hkey2, pflags, cmask, amask)

View File

@ -1,6 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import struct, os import os
import struct
import pytest import pytest

View File

@ -105,15 +105,15 @@ class TestVersionCompare(object):
versions.append('2015.{0}'.format(i)) versions.append('2015.{0}'.format(i))
for i in range(72, 75): for i in range(72, 75):
versions.append('2016.{0}'.format(i)) versions.append('2016.{0}'.format(i))
l = len(versions) length = len(versions)
for i in range(l): for i in range(length):
v = versions[i] v = versions[i]
s = self.get_dropbear_software(v) s = self.get_dropbear_software(v)
assert s.compare_version(v) == 0 assert s.compare_version(v) == 0
if i - 1 >= 0: if i - 1 >= 0:
vbefore = versions[i - 1] vbefore = versions[i - 1]
assert s.compare_version(vbefore) > 0 assert s.compare_version(vbefore) > 0
if i + 1 < l: if i + 1 < length:
vnext = versions[i + 1] vnext = versions[i + 1]
assert s.compare_version(vnext) < 0 assert s.compare_version(vnext) < 0
@ -164,15 +164,15 @@ class TestVersionCompare(object):
versions.append('6.{0}'.format(i)) versions.append('6.{0}'.format(i))
for i in range(0, 4): for i in range(0, 4):
versions.append('7.{0}'.format(i)) versions.append('7.{0}'.format(i))
l = len(versions) length = len(versions)
for i in range(l): for i in range(length):
v = versions[i] v = versions[i]
s = self.get_openssh_software(v) s = self.get_openssh_software(v)
assert s.compare_version(v) == 0 assert s.compare_version(v) == 0
if i - 1 >= 0: if i - 1 >= 0:
vbefore = versions[i - 1] vbefore = versions[i - 1]
assert s.compare_version(vbefore) > 0 assert s.compare_version(vbefore) > 0
if i + 1 < l: if i + 1 < length:
vnext = versions[i + 1] vnext = versions[i + 1]
assert s.compare_version(vnext) < 0 assert s.compare_version(vnext) < 0
@ -202,14 +202,14 @@ class TestVersionCompare(object):
versions.append('0.6.{0}'.format(i)) versions.append('0.6.{0}'.format(i))
for i in range(0, 5): for i in range(0, 5):
versions.append('0.7.{0}'.format(i)) versions.append('0.7.{0}'.format(i))
l = len(versions) length = len(versions)
for i in range(l): for i in range(length):
v = versions[i] v = versions[i]
s = self.get_libssh_software(v) s = self.get_libssh_software(v)
assert s.compare_version(v) == 0 assert s.compare_version(v) == 0
if i - 1 >= 0: if i - 1 >= 0:
vbefore = versions[i - 1] vbefore = versions[i - 1]
assert s.compare_version(vbefore) > 0 assert s.compare_version(vbefore) > 0
if i + 1 < l: if i + 1 < length:
vnext = versions[i + 1] vnext = versions[i + 1]
assert s.compare_version(vnext) < 0 assert s.compare_version(vnext) < 0

41
tox.ini
View File

@ -80,7 +80,7 @@ commands =
deps = deps =
flake8 flake8
commands = commands =
flake8 {posargs:{env:SSHAUDIT}} flake8 {posargs:{env:SSHAUDIT} {toxinidir}/packages/setup.py {toxinidir}/test} --statistics
[testenv:vulture] [testenv:vulture]
deps = deps =
@ -137,42 +137,13 @@ max-module-lines = 2500
[flake8] [flake8]
ignore = ignore =
# indentation contains tabs W191, # indentation contains tabs
W191, E101, # indentation contains mixed spaces and tabs
# blank line contains whitespace E241, # multiple spaces after operator; should be kept for tabular data
W293, E501, # line too long
# indentation contains mixed spaces and tabs
E101,
# multiple spaces before operator
E221,
# multiple spaces after operator
E241,
# multiple imports on one line
E401,
# line too long
E501,
# module imported but unused
F401,
# undefined name
F821,
# these exceptions should be handled one by one
E117, # over-indented E117, # over-indented
E126, # continuation line over-indented for hanging indent E126, # continuation line over-indented for hanging indent
E128, # continuation line under-indented for visual indent E128, # continuation line under-indented for visual indent
E226, # missing whitespace around arithmetic operator
E231, # missing whitespace after ','
E251, # unexpected spaces around keyword / parameter equals
E261, # at least two spaces before inline comment
E265, # block comment should start with '# '
E301, # expected 1 blank line, found 0
E302, # expected 2 blank lines, found 1
E303, # too many blank lines (2)
E305, # expected 2 blank lines after class or function definition, found 1
E711, # comparison to None should be 'if cond is not None:'
E712, # comparison to False should be 'if cond is False:' or 'if not cond:'
E722, # do not use bare 'except' E722, # do not use bare 'except'
E741, # ambiguous variable name 'l'
F601, # dictionary key 'ecdsa-sha2-1.3.132.0.10' repeated with different values F601, # dictionary key 'ecdsa-sha2-1.3.132.0.10' repeated with different values
F841, # local variable 'e' is assigned to but never used W504, # line break after binary operator; this (or W503) has to stay
W504, # line break after binary operator
W605, # invalid escape sequence '\s'