mirror of
https://github.com/jtesta/ssh-audit.git
synced 2024-12-23 06:27:41 +01:00
Refactor output level/colors, fix python:S1845.
This commit is contained in:
parent
72a6b9eeaf
commit
1d1f842bed
34
ssh-audit.py
34
ssh-audit.py
@ -83,7 +83,7 @@ class AuditConf(object):
|
|||||||
self.batch = False
|
self.batch = False
|
||||||
self.colors = True
|
self.colors = True
|
||||||
self.verbose = False
|
self.verbose = False
|
||||||
self.minlevel = 'info'
|
self.level = 'info'
|
||||||
self.ipvo = () # type: Sequence[int]
|
self.ipvo = () # type: Sequence[int]
|
||||||
self.ipv4 = False
|
self.ipv4 = False
|
||||||
self.ipv6 = False
|
self.ipv6 = False
|
||||||
@ -118,7 +118,7 @@ class AuditConf(object):
|
|||||||
if port < 1 or port > 65535:
|
if port < 1 or port > 65535:
|
||||||
raise ValueError('invalid port: {0}'.format(value))
|
raise ValueError('invalid port: {0}'.format(value))
|
||||||
value = port
|
value = port
|
||||||
elif name in ['minlevel']:
|
elif name in ['level']:
|
||||||
if value not in ('info', 'warn', 'fail'):
|
if value not in ('info', 'warn', 'fail'):
|
||||||
raise ValueError('invalid level: {0}'.format(value))
|
raise ValueError('invalid level: {0}'.format(value))
|
||||||
valid = True
|
valid = True
|
||||||
@ -164,7 +164,7 @@ class AuditConf(object):
|
|||||||
elif o in ('-l', '--level'):
|
elif o in ('-l', '--level'):
|
||||||
if a not in ('info', 'warn', 'fail'):
|
if a not in ('info', 'warn', 'fail'):
|
||||||
usage_cb('level {0} is not valid'.format(a))
|
usage_cb('level {0} is not valid'.format(a))
|
||||||
aconf.minlevel = a
|
aconf.level = a
|
||||||
if len(args) == 0:
|
if len(args) == 0:
|
||||||
usage_cb()
|
usage_cb()
|
||||||
if oport is not None:
|
if oport is not None:
|
||||||
@ -189,30 +189,30 @@ class AuditConf(object):
|
|||||||
|
|
||||||
|
|
||||||
class Output(object):
|
class Output(object):
|
||||||
LEVELS = ['info', 'warn', 'fail']
|
LEVELS = ('info', 'warn', 'fail') # type: Sequence[str]
|
||||||
COLORS = {'head': 36, 'good': 32, 'warn': 33, 'fail': 31}
|
COLORS = {'head': 36, 'good': 32, 'warn': 33, 'fail': 31}
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
# type: () -> None
|
# type: () -> None
|
||||||
self.batch = False
|
self.batch = False
|
||||||
self.colors = True
|
|
||||||
self.verbose = False
|
self.verbose = False
|
||||||
self.__minlevel = 0
|
self.use_colors = True
|
||||||
|
self.__level = 0
|
||||||
self.__colsupport = 'colorama' in sys.modules or os.name == 'posix'
|
self.__colsupport = 'colorama' in sys.modules or os.name == 'posix'
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def minlevel(self):
|
def level(self):
|
||||||
# type: () -> str
|
# type: () -> str
|
||||||
if self.__minlevel < len(self.LEVELS):
|
if self.__level < len(self.LEVELS):
|
||||||
return self.LEVELS[self.__minlevel]
|
return self.LEVELS[self.__level]
|
||||||
return 'unknown'
|
return 'unknown'
|
||||||
|
|
||||||
@minlevel.setter
|
@level.setter
|
||||||
def minlevel(self, name):
|
def level(self, name):
|
||||||
# type: (str) -> None
|
# type: (str) -> None
|
||||||
self.__minlevel = self.getlevel(name)
|
self.__level = self.get_level(name)
|
||||||
|
|
||||||
def getlevel(self, name):
|
def get_level(self, name):
|
||||||
# type: (str) -> int
|
# type: (str) -> int
|
||||||
cname = 'info' if name == 'good' else name
|
cname = 'info' if name == 'good' else name
|
||||||
if cname not in self.LEVELS:
|
if cname not in self.LEVELS:
|
||||||
@ -238,9 +238,9 @@ class Output(object):
|
|||||||
# type: (str) -> Callable[[text_type], None]
|
# type: (str) -> Callable[[text_type], None]
|
||||||
if name == 'head' and self.batch:
|
if name == 'head' and self.batch:
|
||||||
return lambda x: None
|
return lambda x: None
|
||||||
if not self.getlevel(name) >= self.__minlevel:
|
if not self.get_level(name) >= self.__level:
|
||||||
return lambda x: None
|
return lambda x: None
|
||||||
if self.colors and self.colors_supported and name in self.COLORS:
|
if self.use_colors and self.colors_supported and name in self.COLORS:
|
||||||
color = '\033[0;{0}m'.format(self.COLORS[name])
|
color = '\033[0;{0}m'.format(self.COLORS[name])
|
||||||
return self._colorized(color)
|
return self._colorized(color)
|
||||||
else:
|
else:
|
||||||
@ -2160,9 +2160,9 @@ class Utils(object):
|
|||||||
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
|
||||||
out.colors = aconf.colors
|
|
||||||
out.verbose = aconf.verbose
|
out.verbose = aconf.verbose
|
||||||
out.minlevel = aconf.minlevel
|
out.level = aconf.level
|
||||||
|
out.use_colors = aconf.colors
|
||||||
s = SSH.Socket(aconf.host, aconf.port)
|
s = SSH.Socket(aconf.host, aconf.port)
|
||||||
s.connect(aconf.ipvo)
|
s.connect(aconf.ipvo)
|
||||||
if sshv is None:
|
if sshv is None:
|
||||||
|
@ -10,8 +10,8 @@ class TestAuditConf(object):
|
|||||||
self.AuditConf = ssh_audit.AuditConf
|
self.AuditConf = ssh_audit.AuditConf
|
||||||
self.usage = ssh_audit.usage
|
self.usage = ssh_audit.usage
|
||||||
|
|
||||||
@classmethod
|
@staticmethod
|
||||||
def _test_conf(cls, conf, **kwargs):
|
def _test_conf(conf, **kwargs):
|
||||||
options = {
|
options = {
|
||||||
'host': None,
|
'host': None,
|
||||||
'port': 22,
|
'port': 22,
|
||||||
@ -20,7 +20,7 @@ class TestAuditConf(object):
|
|||||||
'batch': False,
|
'batch': False,
|
||||||
'colors': True,
|
'colors': True,
|
||||||
'verbose': False,
|
'verbose': False,
|
||||||
'minlevel': 'info',
|
'level': 'info',
|
||||||
'ipv4': True,
|
'ipv4': True,
|
||||||
'ipv6': True,
|
'ipv6': True,
|
||||||
'ipvo': ()
|
'ipvo': ()
|
||||||
@ -34,7 +34,7 @@ class TestAuditConf(object):
|
|||||||
assert conf.batch is options['batch']
|
assert conf.batch is options['batch']
|
||||||
assert conf.colors is options['colors']
|
assert conf.colors is options['colors']
|
||||||
assert conf.verbose is options['verbose']
|
assert conf.verbose is options['verbose']
|
||||||
assert conf.minlevel == options['minlevel']
|
assert conf.level == options['level']
|
||||||
assert conf.ipv4 == options['ipv4']
|
assert conf.ipv4 == options['ipv4']
|
||||||
assert conf.ipv6 == options['ipv6']
|
assert conf.ipv6 == options['ipv6']
|
||||||
assert conf.ipvo == options['ipvo']
|
assert conf.ipvo == options['ipvo']
|
||||||
@ -115,14 +115,14 @@ class TestAuditConf(object):
|
|||||||
conf.ipvo = (4, 4, 4, 6, 6)
|
conf.ipvo = (4, 4, 4, 6, 6)
|
||||||
assert conf.ipvo == (4, 6)
|
assert conf.ipvo == (4, 6)
|
||||||
|
|
||||||
def test_audit_conf_minlevel(self):
|
def test_audit_conf_level(self):
|
||||||
conf = self.AuditConf()
|
conf = self.AuditConf()
|
||||||
for level in ['info', 'warn', 'fail']:
|
for level in ['info', 'warn', 'fail']:
|
||||||
conf.minlevel = level
|
conf.level = level
|
||||||
assert conf.minlevel == level
|
assert conf.level == level
|
||||||
for level in ['head', 'good', 'unknown', None]:
|
for level in ['head', 'good', 'unknown', None]:
|
||||||
with pytest.raises(ValueError) as excinfo:
|
with pytest.raises(ValueError) as excinfo:
|
||||||
conf.minlevel = level
|
conf.level = level
|
||||||
excinfo.match(r'.*invalid level.*')
|
excinfo.match(r'.*invalid level.*')
|
||||||
|
|
||||||
def test_audit_conf_cmdline(self):
|
def test_audit_conf_cmdline(self):
|
||||||
@ -183,10 +183,10 @@ class TestAuditConf(object):
|
|||||||
conf = c('-v localhost')
|
conf = c('-v localhost')
|
||||||
self._test_conf(conf, host='localhost', verbose=True)
|
self._test_conf(conf, host='localhost', verbose=True)
|
||||||
conf = c('-l info localhost')
|
conf = c('-l info localhost')
|
||||||
self._test_conf(conf, host='localhost', minlevel='info')
|
self._test_conf(conf, host='localhost', level='info')
|
||||||
conf = c('-l warn localhost')
|
conf = c('-l warn localhost')
|
||||||
self._test_conf(conf, host='localhost', minlevel='warn')
|
self._test_conf(conf, host='localhost', level='warn')
|
||||||
conf = c('-l fail localhost')
|
conf = c('-l fail localhost')
|
||||||
self._test_conf(conf, host='localhost', minlevel='fail')
|
self._test_conf(conf, host='localhost', level='fail')
|
||||||
with pytest.raises(SystemExit):
|
with pytest.raises(SystemExit):
|
||||||
conf = c('-l something localhost')
|
conf = c('-l something localhost')
|
||||||
|
@ -41,13 +41,13 @@ class TestOutput(object):
|
|||||||
out = self.Output()
|
out = self.Output()
|
||||||
# default: on
|
# default: on
|
||||||
assert out.batch is False
|
assert out.batch is False
|
||||||
assert out.colors is True
|
assert out.use_colors is True
|
||||||
assert out.minlevel == 'info'
|
assert out.level == 'info'
|
||||||
|
|
||||||
def test_output_colors(self, output_spy):
|
def test_output_colors(self, output_spy):
|
||||||
out = self.Output()
|
out = self.Output()
|
||||||
# test without colors
|
# test without colors
|
||||||
out.colors = False
|
out.use_colors = False
|
||||||
output_spy.begin()
|
output_spy.begin()
|
||||||
out.info('info color')
|
out.info('info color')
|
||||||
assert output_spy.flush() == [u'info color']
|
assert output_spy.flush() == [u'info color']
|
||||||
@ -66,7 +66,7 @@ class TestOutput(object):
|
|||||||
if not out.colors_supported:
|
if not out.colors_supported:
|
||||||
return
|
return
|
||||||
# test with colors
|
# test with colors
|
||||||
out.colors = True
|
out.use_colors = True
|
||||||
output_spy.begin()
|
output_spy.begin()
|
||||||
out.info('info color')
|
out.info('info color')
|
||||||
assert output_spy.flush() == [u'info color']
|
assert output_spy.flush() == [u'info color']
|
||||||
@ -93,29 +93,29 @@ class TestOutput(object):
|
|||||||
|
|
||||||
def test_output_levels(self):
|
def test_output_levels(self):
|
||||||
out = self.Output()
|
out = self.Output()
|
||||||
assert out.getlevel('info') == 0
|
assert out.get_level('info') == 0
|
||||||
assert out.getlevel('good') == 0
|
assert out.get_level('good') == 0
|
||||||
assert out.getlevel('warn') == 1
|
assert out.get_level('warn') == 1
|
||||||
assert out.getlevel('fail') == 2
|
assert out.get_level('fail') == 2
|
||||||
assert out.getlevel('unknown') > 2
|
assert out.get_level('unknown') > 2
|
||||||
|
|
||||||
def test_output_minlevel_property(self):
|
def test_output_level_property(self):
|
||||||
out = self.Output()
|
out = self.Output()
|
||||||
out.minlevel = 'info'
|
out.level = 'info'
|
||||||
assert out.minlevel == 'info'
|
assert out.level == 'info'
|
||||||
out.minlevel = 'good'
|
out.level = 'good'
|
||||||
assert out.minlevel == 'info'
|
assert out.level == 'info'
|
||||||
out.minlevel = 'warn'
|
out.level = 'warn'
|
||||||
assert out.minlevel == 'warn'
|
assert out.level == 'warn'
|
||||||
out.minlevel = 'fail'
|
out.level = 'fail'
|
||||||
assert out.minlevel == 'fail'
|
assert out.level == 'fail'
|
||||||
out.minlevel = 'invalid level'
|
out.level = 'invalid level'
|
||||||
assert out.minlevel == 'unknown'
|
assert out.level == 'unknown'
|
||||||
|
|
||||||
def test_output_minlevel(self, output_spy):
|
def test_output_level(self, output_spy):
|
||||||
out = self.Output()
|
out = self.Output()
|
||||||
# visible: all
|
# visible: all
|
||||||
out.minlevel = 'info'
|
out.level = 'info'
|
||||||
output_spy.begin()
|
output_spy.begin()
|
||||||
out.info('info color')
|
out.info('info color')
|
||||||
out.head('head color')
|
out.head('head color')
|
||||||
@ -124,7 +124,7 @@ class TestOutput(object):
|
|||||||
out.fail('fail color')
|
out.fail('fail color')
|
||||||
assert len(output_spy.flush()) == 5
|
assert len(output_spy.flush()) == 5
|
||||||
# visible: head, warn, fail
|
# visible: head, warn, fail
|
||||||
out.minlevel = 'warn'
|
out.level = 'warn'
|
||||||
output_spy.begin()
|
output_spy.begin()
|
||||||
out.info('info color')
|
out.info('info color')
|
||||||
out.head('head color')
|
out.head('head color')
|
||||||
@ -133,7 +133,7 @@ class TestOutput(object):
|
|||||||
out.fail('fail color')
|
out.fail('fail color')
|
||||||
assert len(output_spy.flush()) == 3
|
assert len(output_spy.flush()) == 3
|
||||||
# visible: head, fail
|
# visible: head, fail
|
||||||
out.minlevel = 'fail'
|
out.level = 'fail'
|
||||||
output_spy.begin()
|
output_spy.begin()
|
||||||
out.info('info color')
|
out.info('info color')
|
||||||
out.head('head color')
|
out.head('head color')
|
||||||
@ -142,7 +142,7 @@ class TestOutput(object):
|
|||||||
out.fail('fail color')
|
out.fail('fail color')
|
||||||
assert len(output_spy.flush()) == 2
|
assert len(output_spy.flush()) == 2
|
||||||
# visible: head
|
# visible: head
|
||||||
out.minlevel = 'invalid level'
|
out.level = 'invalid level'
|
||||||
output_spy.begin()
|
output_spy.begin()
|
||||||
out.info('info color')
|
out.info('info color')
|
||||||
out.head('head color')
|
out.head('head color')
|
||||||
@ -155,7 +155,7 @@ class TestOutput(object):
|
|||||||
out = self.Output()
|
out = self.Output()
|
||||||
# visible: all
|
# visible: all
|
||||||
output_spy.begin()
|
output_spy.begin()
|
||||||
out.minlevel = 'info'
|
out.level = 'info'
|
||||||
out.batch = False
|
out.batch = False
|
||||||
out.info('info color')
|
out.info('info color')
|
||||||
out.head('head color')
|
out.head('head color')
|
||||||
@ -165,7 +165,7 @@ class TestOutput(object):
|
|||||||
assert len(output_spy.flush()) == 5
|
assert len(output_spy.flush()) == 5
|
||||||
# visible: all except head
|
# visible: all except head
|
||||||
output_spy.begin()
|
output_spy.begin()
|
||||||
out.minlevel = 'info'
|
out.level = 'info'
|
||||||
out.batch = True
|
out.batch = True
|
||||||
out.info('info color')
|
out.info('info color')
|
||||||
out.head('head color')
|
out.head('head color')
|
||||||
|
Loading…
Reference in New Issue
Block a user