Merge pull request #2025 from yarikoptic/bf-0.10-debian

A number of fixes toward making tests pass while building Debian pkg for 0.10.2
pull/2030/merge
Sergey G. Brester 2018-01-24 08:42:36 +01:00 committed by GitHub
commit 6b7cca07ae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 1156 additions and 1020 deletions

View File

@ -52,6 +52,7 @@ class SMTPActionTest(unittest.TestCase):
def setUp(self): def setUp(self):
"""Call before every test case.""" """Call before every test case."""
unittest.F2B.SkipIfCfgMissing(action='smtp.py')
super(SMTPActionTest, self).setUp() super(SMTPActionTest, self).setUp()
self.jail = DummyJail() self.jail = DummyJail()
pythonModule = os.path.join(CONFIG_DIR, "action.d", "smtp.py") pythonModule = os.path.join(CONFIG_DIR, "action.d", "smtp.py")

View File

@ -45,8 +45,6 @@ TEST_FILES_DIR_SHARE_CFG = {}
from .utils import CONFIG_DIR from .utils import CONFIG_DIR
CONFIG_DIR_SHARE_CFG = unittest.F2B.share_config CONFIG_DIR_SHARE_CFG = unittest.F2B.share_config
STOCK = os.path.exists(os.path.join('config', 'fail2ban.conf'))
IMPERFECT_CONFIG = os.path.join(os.path.dirname(__file__), 'config') IMPERFECT_CONFIG = os.path.join(os.path.dirname(__file__), 'config')
IMPERFECT_CONFIG_SHARE_CFG = {} IMPERFECT_CONFIG_SHARE_CFG = {}
@ -246,8 +244,8 @@ class JailReaderTest(LogCaptureTestCase):
self.assertTrue(jail.isEnabled()) self.assertTrue(jail.isEnabled())
self.assertLogged("Invalid filter definition 'flt[test'") self.assertLogged("Invalid filter definition 'flt[test'")
if STOCK:
def testStockSSHJail(self): def testStockSSHJail(self):
unittest.F2B.SkipIfCfgMissing(stock=True)
jail = JailReader('sshd', basedir=CONFIG_DIR, share_config=CONFIG_DIR_SHARE_CFG) # we are running tests from root project dir atm jail = JailReader('sshd', basedir=CONFIG_DIR, share_config=CONFIG_DIR_SHARE_CFG) # we are running tests from root project dir atm
self.assertTrue(jail.read()) self.assertTrue(jail.read())
self.assertTrue(jail.getOptions()) self.assertTrue(jail.getOptions())
@ -307,6 +305,7 @@ class JailReaderTest(LogCaptureTestCase):
self.assertEqual(expected2, result) self.assertEqual(expected2, result)
def testVersionAgent(self): def testVersionAgent(self):
unittest.F2B.SkipIfCfgMissing(stock=True)
jail = JailReader('blocklisttest', force_enable=True, basedir=CONFIG_DIR) jail = JailReader('blocklisttest', force_enable=True, basedir=CONFIG_DIR)
# emulate jail.read(), because such jail not exists: # emulate jail.read(), because such jail not exists:
ConfigReader.read(jail, "jail"); ConfigReader.read(jail, "jail");
@ -597,8 +596,8 @@ class JailsReaderTest(LogCaptureTestCase):
self.assertNotLogged("Skipping...") self.assertNotLogged("Skipping...")
self.assertLogged("No file(s) found for glob /weapons/of/mass/destruction") self.assertLogged("No file(s) found for glob /weapons/of/mass/destruction")
if STOCK:
def testReadStockActionConf(self): def testReadStockActionConf(self):
unittest.F2B.SkipIfCfgMissing(stock=True)
for actionConfig in glob.glob(os.path.join(CONFIG_DIR, 'action.d', '*.conf')): for actionConfig in glob.glob(os.path.join(CONFIG_DIR, 'action.d', '*.conf')):
actionName = os.path.basename(actionConfig).replace('.conf', '') actionName = os.path.basename(actionConfig).replace('.conf', '')
actionReader = ActionReader(actionName, "TEST", {}, basedir=CONFIG_DIR) actionReader = ActionReader(actionName, "TEST", {}, basedir=CONFIG_DIR)
@ -625,6 +624,7 @@ class JailsReaderTest(LogCaptureTestCase):
msg="Action file %r: interpolation of actionstart does not contains jail-name 'f2b-TEST'" % actionConfig) msg="Action file %r: interpolation of actionstart does not contains jail-name 'f2b-TEST'" % actionConfig)
def testReadStockJailConf(self): def testReadStockJailConf(self):
unittest.F2B.SkipIfCfgMissing(stock=True)
jails = JailsReader(basedir=CONFIG_DIR, share_config=CONFIG_DIR_SHARE_CFG) # we are running tests from root project dir atm jails = JailsReader(basedir=CONFIG_DIR, share_config=CONFIG_DIR_SHARE_CFG) # we are running tests from root project dir atm
self.assertTrue(jails.read()) # opens fine self.assertTrue(jails.read()) # opens fine
self.assertTrue(jails.getOptions()) # reads fine self.assertTrue(jails.getOptions()) # reads fine
@ -687,6 +687,7 @@ class JailsReaderTest(LogCaptureTestCase):
# Verify that all filters found under config/ have a jail # Verify that all filters found under config/ have a jail
def testReadStockJailFilterComplete(self): def testReadStockJailFilterComplete(self):
unittest.F2B.SkipIfCfgMissing(stock=True)
jails = JailsReader(basedir=CONFIG_DIR, force_enable=True, share_config=CONFIG_DIR_SHARE_CFG) jails = JailsReader(basedir=CONFIG_DIR, force_enable=True, share_config=CONFIG_DIR_SHARE_CFG)
self.assertTrue(jails.read()) # opens fine self.assertTrue(jails.read()) # opens fine
self.assertTrue(jails.getOptions()) # reads fine self.assertTrue(jails.getOptions()) # reads fine
@ -705,6 +706,7 @@ class JailsReaderTest(LogCaptureTestCase):
"Stock jail.conf references non-existent filters %r" % filters_jail.difference(filters)) "Stock jail.conf references non-existent filters %r" % filters_jail.difference(filters))
def testReadStockJailConfForceEnabled(self): def testReadStockJailConfForceEnabled(self):
unittest.F2B.SkipIfCfgMissing(stock=True)
# more of a smoke test to make sure that no obvious surprises # more of a smoke test to make sure that no obvious surprises
# on users' systems when enabling shipped jails # on users' systems when enabling shipped jails
jails = JailsReader(basedir=CONFIG_DIR, force_enable=True, share_config=CONFIG_DIR_SHARE_CFG) # we are running tests from root project dir atm jails = JailsReader(basedir=CONFIG_DIR, force_enable=True, share_config=CONFIG_DIR_SHARE_CFG) # we are running tests from root project dir atm
@ -767,6 +769,7 @@ class JailsReaderTest(LogCaptureTestCase):
% (target_command, str(commands)) ) % (target_command, str(commands)) )
def testStockConfigurator(self): def testStockConfigurator(self):
unittest.F2B.SkipIfCfgMissing(stock=True)
configurator = Configurator() configurator = Configurator()
configurator.setBaseDir(CONFIG_DIR) configurator.setBaseDir(CONFIG_DIR)
self.assertEqual(configurator.getBaseDir(), CONFIG_DIR) self.assertEqual(configurator.getBaseDir(), CONFIG_DIR)

View File

@ -43,16 +43,14 @@ from .. import protocol
from ..server import server from ..server import server
from ..server.mytime import MyTime from ..server.mytime import MyTime
from ..server.utils import Utils from ..server.utils import Utils
from .utils import LogCaptureTestCase, logSys as DefLogSys, with_tmpdir, shutil, logging from .utils import LogCaptureTestCase, logSys as DefLogSys, with_tmpdir, shutil, logging, \
STOCK, CONFIG_DIR as STOCK_CONF_DIR
from ..helpers import getLogger from ..helpers import getLogger
# Gets the instance of the logger. # Gets the instance of the logger.
logSys = getLogger(__name__) logSys = getLogger(__name__)
STOCK_CONF_DIR = "config"
STOCK = exists(pjoin(STOCK_CONF_DIR, 'fail2ban.conf'))
CLIENT = "fail2ban-client" CLIENT = "fail2ban-client"
SERVER = "fail2ban-server" SERVER = "fail2ban-server"
BIN = dirname(Fail2banServer.getServerPath()) BIN = dirname(Fail2banServer.getServerPath())
@ -153,7 +151,7 @@ def _start_params(tmp, use_stock=False, use_stock_cfg=None,
"""Filters list of 'files' to contain only directories (under dir)""" """Filters list of 'files' to contain only directories (under dir)"""
return [f for f in files if isdir(pjoin(dir, f))] return [f for f in files if isdir(pjoin(dir, f))]
shutil.copytree(STOCK_CONF_DIR, cfg, ignore=ig_dirs) shutil.copytree(STOCK_CONF_DIR, cfg, ignore=ig_dirs)
use_stock_cfg = ('action.d', 'filter.d') if use_stock_cfg is None: use_stock_cfg = ('action.d', 'filter.d')
# replace fail2ban params (database with memory): # replace fail2ban params (database with memory):
r = re.compile(r'^dbfile\s*=') r = re.compile(r'^dbfile\s*=')
for line in fileinput.input(pjoin(cfg, "fail2ban.conf"), inplace=True): for line in fileinput.input(pjoin(cfg, "fail2ban.conf"), inplace=True):
@ -1171,6 +1169,7 @@ class Fail2banServerTest(Fail2banClientServerBase):
"Jail 'test-jail1' started", all=True) "Jail 'test-jail1' started", all=True)
# test action.d/nginx-block-map.conf -- # test action.d/nginx-block-map.conf --
@unittest.F2B.skip_if_cfg_missing(action="nginx-block-map")
@with_foreground_server_thread(startextra={ @with_foreground_server_thread(startextra={
# create log-file (avoid "not found" errors): # create log-file (avoid "not found" errors):
'create_before_start': ('%(tmp)s/blck-failures.log',), 'create_before_start': ('%(tmp)s/blck-failures.log',),

View File

@ -24,7 +24,6 @@ __license__ = "GPL"
from __builtin__ import open as fopen from __builtin__ import open as fopen
import unittest import unittest
import getpass
import os import os
import sys import sys
import time, datetime import time, datetime
@ -43,14 +42,12 @@ from ..server.failmanager import FailManagerEmpty
from ..server.ipdns import DNSUtils, IPAddr from ..server.ipdns import DNSUtils, IPAddr
from ..server.mytime import MyTime from ..server.mytime import MyTime
from ..server.utils import Utils, uni_decode from ..server.utils import Utils, uni_decode
from .utils import setUpMyTime, tearDownMyTime, mtimesleep, with_tmpdir, LogCaptureTestCase from .utils import setUpMyTime, tearDownMyTime, mtimesleep, with_tmpdir, LogCaptureTestCase, \
CONFIG_DIR as STOCK_CONF_DIR
from .dummyjail import DummyJail from .dummyjail import DummyJail
TEST_FILES_DIR = os.path.join(os.path.dirname(__file__), "files") TEST_FILES_DIR = os.path.join(os.path.dirname(__file__), "files")
STOCK_CONF_DIR = "config"
STOCK = os.path.exists(os.path.join(STOCK_CONF_DIR, 'fail2ban.conf'))
# yoh: per Steven Hiscocks's insight while troubleshooting # yoh: per Steven Hiscocks's insight while troubleshooting
# https://github.com/fail2ban/fail2ban/issues/103#issuecomment-15542836 # https://github.com/fail2ban/fail2ban/issues/103#issuecomment-15542836
@ -445,8 +442,7 @@ class IgnoreIPDNS(LogCaptureTestCase):
self.assertFalse(self.filter.inIgnoreIPList("128.178.222.70")) self.assertFalse(self.filter.inIgnoreIPList("128.178.222.70"))
def testIgnoreCmdApacheFakegooglebot(self): def testIgnoreCmdApacheFakegooglebot(self):
if not STOCK: # pragma: no cover unittest.F2B.SkipIfCfgMissing(stock=True)
raise unittest.SkipTest('Skip test because of no STOCK config')
cmd = os.path.join(STOCK_CONF_DIR, "filter.d/ignorecommands/apache-fakegooglebot") cmd = os.path.join(STOCK_CONF_DIR, "filter.d/ignorecommands/apache-fakegooglebot")
## below test direct as python module: ## below test direct as python module:
mod = Utils.load_python_module(cmd) mod = Utils.load_python_module(cmd)
@ -675,7 +671,15 @@ class LogFileMonitor(LogCaptureTestCase):
os.chmod(self.name, 0) os.chmod(self.name, 0)
self.filter.getFailures(self.name) self.filter.getFailures(self.name)
failure_was_logged = self._is_logged('Unable to open %s' % self.name) failure_was_logged = self._is_logged('Unable to open %s' % self.name)
is_root = getpass.getuser() == 'root' # verify that we cannot access the file. Checking by name of user is not
# sufficient since could be a fakeroot or some other super-user
try:
with open(self.name) as f:
f.read()
is_root = True
except IOError:
is_root = False
# If ran as root, those restrictive permissions would not # If ran as root, those restrictive permissions would not
# forbid log to be read. # forbid log to be read.
self.assertTrue(failure_was_logged != is_root) self.assertTrue(failure_was_logged != is_root)
@ -1173,11 +1177,22 @@ def get_monitor_failures_journal_testcase(Filter_): # pragma: systemd no cover
super(MonitorJournalFailures, self).tearDown() super(MonitorJournalFailures, self).tearDown()
def _getRuntimeJournal(self): def _getRuntimeJournal(self):
# retrieve current system journal path """Retrieve current system journal path
tmp = Utils.executeCmd('find "$(systemd-path system-runtime-logs)" -name system.journal',
timeout=10, shell=True, output=True); If none found, None will be returned
"""
# Depending on the system, it could be found under /run or /var/log (e.g. Debian)
# which are pointed by different systemd-path variables. We will
# check one at at time until the first hit
for systemd_var in 'system-runtime-logs', 'system-state-logs':
tmp = Utils.executeCmd(
'find "$(systemd-path %s)" -name system.journal' % systemd_var,
timeout=10, shell=True, output=True
)
self.assertTrue(tmp) self.assertTrue(tmp)
return str(tmp[1].decode('utf-8')).split('\n')[0] out = str(tmp[1].decode('utf-8')).split('\n')[0]
if out:
return out
def testJournalFilesArg(self): def testJournalFilesArg(self):
# retrieve current system journal path # retrieve current system journal path

View File

@ -1034,7 +1034,7 @@ class LoggingTests(LogCaptureTestCase):
os.remove(f) os.remove(f)
from clientreadertestcase import ActionReader, JailsReader, CONFIG_DIR, STOCK from clientreadertestcase import ActionReader, JailsReader, CONFIG_DIR
class ServerConfigReaderTests(LogCaptureTestCase): class ServerConfigReaderTests(LogCaptureTestCase):
@ -1091,9 +1091,8 @@ class ServerConfigReaderTests(LogCaptureTestCase):
logSys.debug('# === stop ==='); self.pruneLog() logSys.debug('# === stop ==='); self.pruneLog()
action.stop() action.stop()
if STOCK:
def testCheckStockJailActions(self): def testCheckStockJailActions(self):
unittest.F2B.SkipIfCfgMissing(stock=True)
# we are running tests from root project dir atm # we are running tests from root project dir atm
jails = JailsReader(basedir=CONFIG_DIR, force_enable=True, share_config=self.__share_cfg) jails = JailsReader(basedir=CONFIG_DIR, force_enable=True, share_config=self.__share_cfg)
self.assertTrue(jails.read()) # opens fine self.assertTrue(jails.read()) # opens fine
@ -1159,6 +1158,7 @@ class ServerConfigReaderTests(LogCaptureTestCase):
return stream return stream
def testCheckStockAllActions(self): def testCheckStockAllActions(self):
unittest.F2B.SkipIfCfgMissing(stock=True)
unittest.F2B.SkipIfFast() unittest.F2B.SkipIfFast()
import glob import glob
@ -1178,6 +1178,7 @@ class ServerConfigReaderTests(LogCaptureTestCase):
def testCheckStockCommandActions(self): def testCheckStockCommandActions(self):
unittest.F2B.SkipIfCfgMissing(stock=True)
# test cases to check valid ipv4/ipv6 action definition, tuple with (('jail', 'action[params]', 'tests', ...) # test cases to check valid ipv4/ipv6 action definition, tuple with (('jail', 'action[params]', 'tests', ...)
# where tests is a dictionary contains: # where tests is a dictionary contains:
# 'ip4' - should not be found (logged) on ban/unban of IPv6 (negative test), # 'ip4' - should not be found (logged) on ban/unban of IPv6 (negative test),
@ -1813,6 +1814,7 @@ class ServerConfigReaderTests(LogCaptureTestCase):
return _actions.CommandAction.executeCmd(realCmd, timeout=timeout) return _actions.CommandAction.executeCmd(realCmd, timeout=timeout)
def testComplexMailActionMultiLog(self): def testComplexMailActionMultiLog(self):
unittest.F2B.SkipIfCfgMissing(stock=True)
testJailsActions = ( testJailsActions = (
# mail-whois-lines -- # mail-whois-lines --
('j-mail-whois-lines', ('j-mail-whois-lines',

View File

@ -59,6 +59,9 @@ if not CONFIG_DIR:
else: else:
CONFIG_DIR = '/etc/fail2ban' CONFIG_DIR = '/etc/fail2ban'
# Indicates that we've stock config:
STOCK = os.path.exists(os.path.join(CONFIG_DIR, 'fail2ban.conf'))
# During the test cases (or setup) use fail2ban modules from main directory: # During the test cases (or setup) use fail2ban modules from main directory:
os.putenv('PYTHONPATH', os.path.dirname(os.path.dirname(os.path.dirname( os.putenv('PYTHONPATH', os.path.dirname(os.path.dirname(os.path.dirname(
os.path.abspath(__file__))))) os.path.abspath(__file__)))))
@ -187,6 +190,31 @@ class F2B(DefaultTestOptions):
pass pass
def SkipIfNoNetwork(self): def SkipIfNoNetwork(self):
pass pass
def SkipIfCfgMissing(self, **kwargs):
"""Helper to check action/filter config is available
"""
if not STOCK: # pragma: no cover
if kwargs.get('stock'):
raise unittest.SkipTest('Skip test because of missing stock-config files')
for t in ('action', 'filter'):
v = kwargs.get(t)
if v is None: continue
if os.path.splitext(v)[1] == '': v += '.conf'
if not os.path.exists(os.path.join(CONFIG_DIR, t+'.d', v)):
raise unittest.SkipTest('Skip test because of missing %s-config for %r' % (t, v))
def skip_if_cfg_missing(self, **decargs):
"""Helper decorator to check action/filter config is available
"""
def _deco_wrapper(f):
@wraps(f)
def wrapper(self, *args, **kwargs):
unittest.F2B.SkipIfCfgMissing(**decargs)
return f(self, *args, **kwargs)
return wrapper
return _deco_wrapper
def maxWaitTime(self,wtime): def maxWaitTime(self,wtime):
if self.fast: if self.fast:
wtime = float(wtime) / 10 wtime = float(wtime) / 10

72
man/fail2ban-python.1 Normal file
View File

@ -0,0 +1,72 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.5.
.TH FAIL2BAN-PYTHON "1" "January 2018" "fail2ban-python f2bversion" "User Commands"
.SH NAME
fail2ban-python \- a helper for Fail2Ban to assure that the same Python is used
.SH DESCRIPTION
usage: ../bin/fail2ban\-python [option] ... [\-c cmd | \fB\-m\fR mod | file | \fB\-]\fR [arg] ...
Options and arguments (and corresponding environment variables):
\fB\-b\fR : issue warnings about comparing bytearray with unicode
.IP
(\fB\-bb\fR: issue errors)
.PP
\fB\-B\fR : don't write .py[co] files on import; also PYTHONDONTWRITEBYTECODE=x
\fB\-c\fR cmd : program passed in as string (terminates option list)
\fB\-d\fR : debug output from parser; also PYTHONDEBUG=x
\fB\-E\fR : ignore PYTHON* environment variables (such as PYTHONPATH)
\fB\-h\fR : print this help message and exit (also \fB\-\-help\fR)
\fB\-i\fR : inspect interactively after running script; forces a prompt even
.IP
if stdin does not appear to be a terminal; also PYTHONINSPECT=x
.PP
\fB\-m\fR mod : run library module as a script (terminates option list)
\fB\-O\fR : optimize generated bytecode slightly; also PYTHONOPTIMIZE=x
\fB\-OO\fR : remove doc\-strings in addition to the \fB\-O\fR optimizations
\fB\-R\fR : use a pseudo\-random salt to make hash() values of various types be
.IP
unpredictable between separate invocations of the interpreter, as
a defense against denial\-of\-service attacks
.PP
\fB\-Q\fR arg : division options: \fB\-Qold\fR (default), \fB\-Qwarn\fR, \fB\-Qwarnall\fR, \fB\-Qnew\fR
\fB\-s\fR : don't add user site directory to sys.path; also PYTHONNOUSERSITE
\fB\-S\fR : don't imply 'import site' on initialization
\fB\-t\fR : issue warnings about inconsistent tab usage (\fB\-tt\fR: issue errors)
\fB\-u\fR : unbuffered binary stdout and stderr; also PYTHONUNBUFFERED=x
.IP
see man page for details on internal buffering relating to '\-u'
.PP
\fB\-v\fR : verbose (trace import statements); also PYTHONVERBOSE=x
.IP
can be supplied multiple times to increase verbosity
.PP
\fB\-V\fR : print the Python version number and exit (also \fB\-\-version\fR)
\fB\-W\fR arg : warning control; arg is action:message:category:module:lineno
.IP
also PYTHONWARNINGS=arg
.PP
\fB\-x\fR : skip first line of source, allowing use of non\-Unix forms of #!cmd
\fB\-3\fR : warn about Python 3.x incompatibilities that 2to3 cannot trivially fix
file : program read from script file
\- : program read from stdin (default; interactive mode if a tty)
arg ...: arguments passed to program in sys.argv[1:]
.PP
Other environment variables:
PYTHONSTARTUP: file executed on interactive startup (no default)
PYTHONPATH : ':'\-separated list of directories prefixed to the
.TP
default module search path.
The result is sys.path.
.PP
PYTHONHOME : alternate <prefix> directory (or <prefix>:<exec_prefix>).
.IP
The default module search path uses <prefix>/pythonX.X.
.PP
PYTHONCASEOK : ignore case in 'import' statements (Windows).
PYTHONIOENCODING: Encoding[:errors] used for stdin/stdout/stderr.
PYTHONHASHSEED: if this variable is set to 'random', the effect is the same
.IP
as specifying the \fB\-R\fR option: a random value is used to seed the hashes of
str, bytes and datetime objects. It can also be set to an integer
in the range [0,4294967295] to get hash values with a predictable seed.
.SH "SEE ALSO"
.br
fail2ban-client(1)

9
man/fail2ban-python.h2m Normal file
View File

@ -0,0 +1,9 @@
Include file for help2man man page
$Id: $
[name]
fail2ban-python \- a helper for Fail2Ban to assure that the same Python is used
[see also]
.br
fail2ban-client(1)

View File

@ -4,6 +4,8 @@ set -eu
export PYTHONPATH=.. export PYTHONPATH=..
f2bversion=$(../bin/fail2ban-client --version | head -n1 | sed -e 's,.* v,,g')
# fail2ban-client # fail2ban-client
echo -n "Generating fail2ban-client " echo -n "Generating fail2ban-client "
help2man --section=1 --no-info --include=fail2ban-client.h2m --output fail2ban-client.1 ../bin/fail2ban-client help2man --section=1 --no-info --include=fail2ban-client.h2m --output fail2ban-client.1 ../bin/fail2ban-client
@ -35,6 +37,11 @@ for LINE in $LINES; do
done done
echo "[done]" echo "[done]"
# fail2ban-python
echo -n "Generating fail2ban-python "
help2man --version-string=f2bversion --section=1 --no-info --include=fail2ban-python.h2m --output fail2ban-python.1 ../bin/fail2ban-python
echo "[done]"
# fail2ban-server # fail2ban-server
echo -n "Generating fail2ban-server " echo -n "Generating fail2ban-server "
help2man --section=1 --no-info --include=fail2ban-server.h2m --output fail2ban-server.1 ../bin/fail2ban-server help2man --section=1 --no-info --include=fail2ban-server.h2m --output fail2ban-server.1 ../bin/fail2ban-server