Skip to content
Open
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
11 changes: 7 additions & 4 deletions intelmq/bots/experts/asn_lookup/expert.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,13 @@ def update_database(cls, verbose=False):
raise MissingDependencyError("pyasn")

for database_path in set(bots.values()):
if not Path(database_path).is_file():
raise ValueError('Database file does not exist or is not a file.')
elif not os.access(database_path, os.W_OK):
raise ValueError('Database file is not writeable.')
database_file = Path(database_path)
if database_file.exists():
if not database_file.is_file():
raise ValueError('Database path exists and is not a file.')
if not os.access(database_path, os.W_OK):
raise ValueError('Database file is not writeable.')
# A missing database file is fine, it will be created below.

try:
if verbose:
Expand Down
63 changes: 63 additions & 0 deletions intelmq/tests/bots/experts/asn_lookup/test_expert.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@
Testing asn_lookup with a faked local database
"""

import tempfile
import unittest
from pathlib import Path
from unittest import mock

import pkg_resources

Expand Down Expand Up @@ -62,5 +65,65 @@ def test_ipv6_lookup(self):
self.assertMessageEqual(0, EXAMPLE_OUTPUT6)


class TestASNLookupUpdateDatabase(unittest.TestCase):
"""
update_database() must not reject a database file that doesn't exist yet
(first-time setup): the file is created by the update itself, only an
existing-but-unwritable file (or a path that isn't a plain file) should
be rejected.
"""

def _run_with_fake_bots(self, database_path):
settings = {
'bot-1': {
'module': 'intelmq.bots.experts.asn_lookup.expert',
'parameters': {'database': str(database_path)},
}
}
with mock.patch(
'intelmq.bots.experts.asn_lookup.expert.get_bots_settings',
return_value=settings,
):
with mock.patch(
'intelmq.bots.experts.asn_lookup.expert.pyasn',
new=mock.Mock(),
):
with mock.patch(
'intelmq.bots.experts.asn_lookup.expert.create_request_session',
side_effect=RuntimeError('reached the network step'),
):
with self.assertRaises((RuntimeError, SystemExit)) as ctx:
ASNLookupExpertBot.update_database(verbose=False)
return ctx.exception

def test_missing_database_file_is_allowed(self):
with tempfile.TemporaryDirectory() as tmp_dir:
database_path = Path(tmp_dir) / 'does-not-exist-yet' / 'ipasn.dat'
exc = self._run_with_fake_bots(database_path)
# Got past the file check and reached the (mocked) network step,
# instead of raising ValueError('Database file does not exist...').
self.assertIsInstance(exc, RuntimeError)

def test_existing_unwritable_database_file_still_rejected(self):
with tempfile.TemporaryDirectory() as tmp_dir:
database_path = Path(tmp_dir) / 'ipasn.dat'
database_path.touch()
database_path.chmod(0o400)
try:
with self.assertRaises(ValueError) as ctx:
self._run_with_fake_bots(database_path)
self.assertIn('not writeable', str(ctx.exception))
finally:
database_path.chmod(0o600)

def test_existing_directory_as_database_path_rejected(self):
with tempfile.TemporaryDirectory() as tmp_dir:
database_path = Path(tmp_dir) / 'ipasn.dat'
database_path.mkdir()
with self.assertRaises(ValueError) as ctx:
self._run_with_fake_bots(database_path)
self.assertIn('not a file', str(ctx.exception))


if __name__ == '__main__': # pragma: no cover
unittest.main()