Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions .github/workflows/pytest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,16 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Install UV
run: astral-sh/setup-uv@v5
python-version: ${{ matrix.python-version }}
- uses: astral-sh/ruff-action@v3
uses: astral-sh/setup-uv@v5
with:
python-version: ${{ matrix.python-version }}
- name: UV sync
run: uv sync
- name: Install pytest
run: |
uv tool install pytest
uv add pytest-cov
- uses: astral-sh/ruff-action@v3
- name: Run the tests
run: pytest --cov --cov-report=json:coverage.json tests/
- name: Extract coverage
Expand All @@ -31,10 +38,10 @@ jobs:
uses: schneegans/dynamic-badges-action@v1.4.0
with:
auth: ${{ secrets.GIST_TOKEN }}
gistID: 88ae1c5c4c732ba28346b3fac87b44a3
gistID: 88ae1c5c4c732ba28346b3fac87b44a3
filename: covbadge.json
label: Coverage
message: ${{ env.total }}%
minColorRange: 50
maxColorRange: 90
valColorRange: ${{ env.total }}
valColorRange: ${{ env.total }}
24 changes: 17 additions & 7 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
- repo: https://github.com/astral-sh/uv-pre-commit
rev: 0.5.18
hooks:
- id: uv-lock
- id: ruff
args: [ --fix ]
- id: ruff-format
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v2.3.0
hooks:
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.9.1
hooks:
- id: ruff
args: [ --fix ]
- id: ruff-format
- repo: https://github.com/astral-sh/uv-pre-commit
rev: 0.5.18
hooks:
- id: uv-lock
- id: uv-export
99 changes: 46 additions & 53 deletions lib/pyclamd.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,17 +157,8 @@ class ConnectionError(socket.error):
"""Class for errors communication with clamd"""


# Python 2/3 compatibility
try:
basestring # attempt to evaluate basestring

def isstr(s):
return isinstance(s, basestring)

except NameError:

def isstr(s):
return isinstance(s, str)
def isstr(s):
return isinstance(s, str)


############################################################################
Expand Down Expand Up @@ -311,9 +302,9 @@ def scan_file(self, file):
- socket.timeout: if timeout has expired
"""

assert isstr(
file
), "Wrong type for [file], should be a string [was {0}]".format(type(file))
assert isstr(file), (
"Wrong type for [file], should be a string [was {0}]".format(type(file))
)

try:
self._init_socket()
Expand Down Expand Up @@ -359,9 +350,9 @@ def multiscan_file(self, file):
May raise:
- ConnectionError: in case of communication problem
"""
assert isstr(
file
), "Wrong type for [file], should be a string [was {0}]".format(type(file))
assert isstr(file), (
"Wrong type for [file], should be a string [was {0}]".format(type(file))
)

try:
self._init_socket()
Expand Down Expand Up @@ -407,9 +398,9 @@ def allmatchscan(self, file):
- ConnectionError: in case of communication problem
- socket.timeout: if timeout has expired
"""
assert isstr(
file
), "Wrong type for [file], should be a string [was {0}]".format(type(file))
assert isstr(file), (
"Wrong type for [file], should be a string [was {0}]".format(type(file))
)

dr = {}

Expand Down Expand Up @@ -469,9 +460,9 @@ def contscan_file(self, file):
May raise:
- ConnectionError: in case of communication problem
"""
assert isstr(
file
), "Wrong type for [file], should be a string [was {0}]".format(type(file))
assert isstr(file), (
"Wrong type for [file], should be a string [was {0}]".format(type(file))
)

try:
self._init_socket()
Expand Down Expand Up @@ -521,17 +512,17 @@ def scan_stream(self, stream, chunk_size=4096):
"""
if sys.version_info[0] <= 2:
# Python2
assert hasattr(stream, "read") or isinstance(
stream, str
), "Wrong type for [stream], should be str/file-like [was {0}]".format(
type(stream)
assert hasattr(stream, "read") or isinstance(stream, str), (
"Wrong type for [stream], should be str/file-like [was {0}]".format(
type(stream)
)
)
else:
# Python3
assert hasattr(stream, "read") or isinstance(
stream, (bytes, bytearray)
), "Wrong type for [stream], should be bytes/bytearray/file-like [was {0}]".format(
type(stream)
assert hasattr(stream, "read") or isinstance(stream, (bytes, bytearray)), (
"Wrong type for [stream], should be bytes/bytearray/file-like [was {0}]".format(
type(stream)
)
)

is_file_like = hasattr(stream, "read")
Expand Down Expand Up @@ -580,7 +571,6 @@ def scan_stream(self, stream, chunk_size=4096):
raise ConnectionError("Unable to scan stream")

if len(result) > 0:

if result == "INSTREAM size limit exceeded. ERROR":
raise BufferTooLongError(result)

Expand Down Expand Up @@ -693,7 +683,11 @@ def __init__(self, filename=None, timeout=None):

# try to get unix socket from clamd.conf
if filename is None:
for clamdpath in ["/etc/clamav/clamd.conf", "/etc/clamd.conf", "/opt/homebrew/etc/clamav/clamd.conf"]:
for clamdpath in [
"/etc/clamav/clamd.conf",
"/etc/clamd.conf",
"/opt/homebrew/etc/clamav/clamd.conf",
]:
if os.path.isfile(clamdpath):
break
else:
Expand All @@ -715,13 +709,13 @@ def __init__(self, filename=None, timeout=None):
"Could not find clamd unix socket from /etc/clamav/clamd.conf or /etc/clamd.conf"
)

assert isstr(
filename
), "Wrong type for [file], should be a string [was {0}]".format(type(file))
assert (
isinstance(timeout, (float, int)) or timeout is None
), "Wrong type for [timeout], should be either None or a float [was {0}]".format(
type(timeout)
assert isstr(filename), (
"Wrong type for [file], should be a string [was {0}]".format(type(filename))
)
assert isinstance(timeout, (float, int)) or timeout is None, (
"Wrong type for [timeout], should be either None or a float [was {0}]".format(
type(timeout)
)
)

_ClamdGeneric.__init__(self)
Expand All @@ -740,7 +734,7 @@ def _init_socket(self):
internal use only
"""
self.clamd_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
if not self.timeout is None:
if self.timeout:
self.clamd_socket.settimeout(self.timeout)

try:
Expand Down Expand Up @@ -770,16 +764,16 @@ def __init__(self, host="127.0.0.1", port=3310, timeout=None):
timeout (float or None) : socket timeout
"""

assert isinstance(
host, str
), "Wrong type for [host], should be a string [was {0}]".format(type(host))
assert isinstance(
port, int
), "Wrong type for [port], should be an int [was {0}]".format(type(port))
assert (
isinstance(timeout, (float, int)) or timeout is None
), "Wrong type for [timeout], should be either None or a float [was {0}]".format(
type(timeout)
assert isinstance(host, str), (
"Wrong type for [host], should be a string [was {0}]".format(type(host))
)
assert isinstance(port, int), (
"Wrong type for [port], should be an int [was {0}]".format(type(port))
)
assert isinstance(timeout, (float, int)) or timeout is None, (
"Wrong type for [timeout], should be either None or a float [was {0}]".format(
type(timeout)
)
)

_ClamdGeneric.__init__(self)
Expand All @@ -799,7 +793,7 @@ def _init_socket(self):
internal use only
"""
self.clamd_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
if not self.timeout is None:
if self.timeout:
self.clamd_socket.settimeout(self.timeout)
try:
self.clamd_socket.connect((self.host, self.port))
Expand Down Expand Up @@ -920,7 +914,6 @@ def _print_doc():

# MAIN -------------------
if __name__ == "__main__":

_non_regression_test()


Expand Down
2 changes: 1 addition & 1 deletion lib/scan.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def scan_file(self, file):
self.logger.debug(message, extra={"filepath": filepath})
elif result == "FOUND":
self.logger.info(
f"File match", extra={"file": filepath, "signature": message}
"File match", extra={"file": filepath, "signature": message}
)
return True
else:
Expand Down
10 changes: 5 additions & 5 deletions pyclamav.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import os

from lib.config import load_config
from lib.log import get_logger

Expand All @@ -11,13 +9,15 @@ def main():
logger = get_logger(config.log_folder, config.verbose)
scanner = Scan(config.modified_file_datetime, logger)

logger.info(f"Scanning {len(config.folders)} folders with files changed during the last {config.modified_file_since}")
logger.info(
f"Scanning {len(config.folders)} folders with files changed during the last {config.modified_file_since}"
)
for folder in config.folders:
logger.info(
f"Scanning folder",
"Scanning folder",
extra={"folder": folder},
)
r = scanner.scan_folder(folder)
scanner.scan_folder(folder)


if __name__ == "__main__":
Expand Down
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ requires-python = ">=3.11"
dependencies = [
"dateparser>=1.2.0",
"logging>=0.4.9.6",
"pre-commit>=4.0.1",
"pyclamd>=0.4.0",
"pydantic>=2.10.5",
"pytest>=8.3.4",
"python-json-logger>=3.2.1",
"requests>=2.32.3",
"ruff>=0.9.1",
]
Loading
Loading