diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e346635d..ff31db19 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -22,7 +22,7 @@ jobs: runs-on: ubuntu-20.04 strategy: matrix: - python-version: [2.7, 3.5, 3.6, 3.7, 3.8, 3.9, '3.10.0-rc.2', pypy2, pypy3] + python-version: [2.7, 3.5, 3.6, 3.7, 3.8, 3.9, '3.10', '3.11.0-alpha.1', pypy2, pypy3] fail-fast: false # Steps represent a sequence of tasks that will be executed as part of the job steps: @@ -40,33 +40,56 @@ jobs: - name: Python version run: | F2B_PY=$(python -c "import sys; print(sys.version)") - echo "Python: ${{ matrix.python-version }} -- $F2B_PY" + echo "Python: ${{ matrix.python-version }} -- ${F2B_PY/$'\n'/ }" + F2B_PYV=$(echo "${F2B_PY}" | grep -oP '^\d+(?:\.\d+)') F2B_PY=${F2B_PY:0:1} - echo "Set F2B_PY=$F2B_PY" + echo "Set F2B_PY=$F2B_PY, F2B_PYV=$F2B_PYV" echo "F2B_PY=$F2B_PY" >> $GITHUB_ENV + echo "F2B_PYV=$F2B_PYV" >> $GITHUB_ENV + # for GHA we need to monitor all journals, since it cannot be found using SYSTEM_ONLY(4): + echo "F2B_SYSTEMD_DEFAULT_FLAGS=0" >> $GITHUB_ENV - name: Install dependencies run: | - #python -m pip install --upgrade pip + if [[ "$F2B_PY" = 3 ]]; then python -m pip install --upgrade pip || echo "can't upgrade pip"; fi if [[ "$F2B_PY" = 3 ]] && ! command -v 2to3x -v 2to3 > /dev/null; then #pip install 2to3 sudo apt-get -y install 2to3 fi - #pip install systemd-python || echo 'systemd not available' - #pip install pyinotify || echo 'inotify not available' - sudo apt-get -y install python${F2B_PY/2/}-systemd || echo 'systemd not available' - sudo apt-get -y install python${F2B_PY/2/}-pyinotify || echo 'inotify not available' + #sudo apt-get -y install python${F2B_PY/2/}-pyinotify || echo 'inotify not available' + python -m pip install pyinotify || echo 'inotify not available' + #sudo apt-get -y install python${F2B_PY/2/}-systemd || echo 'systemd not available' + sudo apt-get -y install libsystemd-dev || echo 'systemd dependencies seems to be unavailable' + python -m pip install systemd-python || echo 'systemd not available' - name: Before scripts run: | cd "$GITHUB_WORKSPACE" # Manually execute 2to3 for now if [[ "$F2B_PY" = 3 ]]; then echo "2to3 ..." && ./fail2ban-2to3; fi + _debug() { echo -n "$1 "; err=$("${@:2}" 2>&1) && echo 'OK' || echo -e "FAIL\n$err"; } # (debug) output current preferred encoding: - python -c 'import locale, sys; from fail2ban.helpers import PREFER_ENC; print(PREFER_ENC, locale.getpreferredencoding(), (sys.stdout and sys.stdout.encoding))' - + _debug 'Encodings:' python -c 'import locale, sys; from fail2ban.helpers import PREFER_ENC; print(PREFER_ENC, locale.getpreferredencoding(), (sys.stdout and sys.stdout.encoding))' + # (debug) backend availabilities: + echo 'Backends:' + _debug '- systemd:' python -c 'from fail2ban.server.filtersystemd import FilterSystemd' + #_debug '- systemd (root): ' sudo python -c 'from fail2ban.server.filtersystemd import FilterSystemd' + _debug '- pyinotify:' python -c 'from fail2ban.server.filterpyinotify import FilterPyinotify' + - name: Test suite - run: if [[ "$F2B_PY" = 2 ]]; then python setup.py test; else python bin/fail2ban-testcases --verbosity=2; fi + run: | + if [[ "$F2B_PY" = 2 ]]; then + python setup.py test + elif dpkg --compare-versions "$F2B_PYV" lt 3.10; then + python bin/fail2ban-testcases --verbosity=2 + else + echo "Skip systemd backend since systemd-python module must be fixed for python >= v.3.10 in GHA ..." + python bin/fail2ban-testcases --verbosity=2 -i "[sS]ystemd|[jJ]ournal" + fi + + #- name: Test suite (debug some systemd tests only) + #run: python bin/fail2ban-testcases --verbosity=2 "[sS]ystemd|[jJ]ournal" + #run: python bin/fail2ban-testcases --verbosity=2 -l 5 "test_WrongChar" - name: Build run: python setup.py build diff --git a/fail2ban/server/filtersystemd.py b/fail2ban/server/filtersystemd.py index e2220105..6301b93a 100644 --- a/fail2ban/server/filtersystemd.py +++ b/fail2ban/server/filtersystemd.py @@ -23,6 +23,7 @@ __copyright__ = "Copyright (c) 2013 Steven Hiscocks" __license__ = "GPL" import datetime +import os import time from distutils.version import LooseVersion @@ -93,7 +94,7 @@ class FilterSystemd(JournalFilter): # pragma: systemd no cover except KeyError: # be sure all journal types will be opened if files/path specified (don't set flags): if ('files' not in args or not len(args['files'])) and ('path' not in args or not args['path']): - args['flags'] = 4 + args['flags'] = int(os.getenv("F2B_SYSTEMD_DEFAULT_FLAGS", 4)) try: args['namespace'] = kwargs.pop('namespace') diff --git a/fail2ban/server/mytime.py b/fail2ban/server/mytime.py index 377fd821..315d8a30 100644 --- a/fail2ban/server/mytime.py +++ b/fail2ban/server/mytime.py @@ -191,34 +191,45 @@ class MyTime: def __str__(self): # s = str(datetime.timedelta(seconds=int(self.sec))) # return s if s[-3:] != ":00" else s[:-3] - s = self.sec; r = ""; c = 3 - # automatic accuracy: round by large values (upto 1 minute, or 1 day by year): - if s >= 3570: - if s >= 31536000: - s = int(round(float(s)/86400)*86400) - elif s >= 86400: - s = int(round(float(s)/60)*60) - else: - s = int(round(float(s)/10)*10) - for n, m in ( - ('y', 31536000), # a year as 365*24*60*60 (don't need to consider leap year by this accuracy) - ('w', 604800), # a week as 24*60*60*7 - ('d', 86400), # a day as 24*60*60 - ('h', 3600), # a hour as 60*60 - ('m', 60), # a minute - ('s', 1) # a second - ): - if s >= m: - c -= 1 - r += ' ' + str(s//m) + n - s %= m - # stop if no remaining part or no repeat needed (too small granularity): - if not s or not c: break - elif c < 3: - # avoid too small granularity: - c -= 1 - if not c: break - # - return r[1:] + s = self.sec; c = 3 + # automatic accuracy: round by large values (and maximally 3 groups) + if s >= 31536000: # a year as 365*24*60*60 (don't need to consider leap year by this accuracy) + s = int(round(float(s)/86400)) # round by a day + r = str(s//365) + 'y '; s %= 365 + if s >= 7: + r += str(s//7) + 'w '; s %= 7 + if s: + r += str(s) + 'd ' + return r[:-1] + if s >= 604800: # a week as 24*60*60*7 + s = int(round(float(s)/3600)) # round by a hour + r = str(s//168) + 'w '; s %= 168 + if s >= 24: + r += str(s//24) + 'd '; s %= 24 + if s: + r += str(s) + 'h ' + return r[:-1] + if s >= 86400: # a day as 24*60*60 + s = int(round(float(s)/60)) # round by a minute + r = str(s//1440) + 'd '; s %= 1440 + if s >= 60: + r += str(s//60) + 'h '; s %= 60 + if s: + r += str(s) + 'm ' + return r[:-1] + if s >= 3595: # a hour as 60*60 (- 5 seconds) + s = int(round(float(s)/10)) # round by 10 seconds + r = str(s//360) + 'h '; s %= 360 + if s >= 6: # a minute + r += str(s//6) + 'm '; s %= 6 + return r[:-1] + r = '' + if s >= 60: # a minute + r += str(s//60) + 'm '; s %= 60 + if s: # remaining seconds + r += str(s) + 's ' + elif not self.sec: # 0s + r = '0 ' + return r[:-1] def __repr__(self): return self.__str__() diff --git a/fail2ban/tests/misctestcase.py b/fail2ban/tests/misctestcase.py index d6fdee65..e2faa6fd 100644 --- a/fail2ban/tests/misctestcase.py +++ b/fail2ban/tests/misctestcase.py @@ -466,6 +466,9 @@ class MyTimeTest(unittest.TestCase): self.assertEqual(sec2str(86400*14-10), '2w') self.assertEqual(sec2str(86400*2+3600*7+60*15), '2d 7h 15m') self.assertEqual(sec2str(86400*2+3599), '2d 1h') + self.assertEqual(sec2str(3600*3.52), '3h 31m') + self.assertEqual(sec2str(3600*2-5), '2h') self.assertEqual(sec2str(3600-5), '1h') self.assertEqual(sec2str(3600-10), '59m 50s') self.assertEqual(sec2str(59), '59s') + self.assertEqual(sec2str(0), '0')