From 26e540c71a37ca81d5adc37116e5c15ddd0214c4 Mon Sep 17 00:00:00 2001 From: Kit Date: Tue, 23 Jul 2024 12:07:50 +0200 Subject: [PATCH 1/7] Move main application file to source folder and change name to be package compliant --- GeoWhitelist.py => src/geowhitelist.py | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) rename GeoWhitelist.py => src/geowhitelist.py (94%) diff --git a/GeoWhitelist.py b/src/geowhitelist.py similarity index 94% rename from GeoWhitelist.py rename to src/geowhitelist.py index f267b1e..91c993b 100644 --- a/GeoWhitelist.py +++ b/src/geowhitelist.py @@ -1,6 +1,7 @@ from starlette.requests import Request from starlette.responses import Response +import os import redis import ipaddress import logging @@ -11,7 +12,17 @@ import datetime import yaml -with open('./config/config.yaml', 'r') as config_file: +# Set config paths (should probably turn this into a bootstrap function) +absolutepath = os.path.abspath(__file__) +fileDirectory = os.path.dirname(absolutepath) + +if fileDirectory == "/app": + configDirectory = "/app/config/" +else: + configDirectory = os.path.dirname(fileDirectory) + "/config" + + +with open(configDirectory + "/config.yaml", 'r') as config_file: config = yaml.safe_load(config_file) # Default 3h window to keep in Redis @@ -20,7 +31,7 @@ serviceURL = config.get('service_url') # Set Logging config -logging.config.fileConfig(config.get('logging')) +logging.config.dictConfig(config.get('logging')) # Setup cache cache = False @@ -47,7 +58,7 @@ logging.info("Internal Cache set") # Create whitelist (change to an async function with watchgod) -with open('./config/whitelist.yaml', 'r') as f: +with open(configDirectory + '/whitelist.yaml', 'r') as f: wl_config = yaml.safe_load(f) wl_ip = set() @@ -261,10 +272,11 @@ async def getGeo(address): """ # Encode IP (especially v6) into URL url = serviceURL + urllib.parse.quote(address) - + logging.debug(f"URL: {url}") async with ClientSession() as session: async with session.get(url) as response: html = await response.json() + logging.debug(f"Response from geojs.io:\n{html}") return html From 7efc149295bcc924ba40de7f97d19978bb8eae8d Mon Sep 17 00:00:00 2001 From: Kit Date: Tue, 23 Jul 2024 12:08:36 +0200 Subject: [PATCH 2/7] Update Dockerfile to use python 3.12 and requirements.txt instead of manually installing deps --- Dockerfile | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index 262867b..9e30ddf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,8 +1,10 @@ -FROM python:3.10-alpine +FROM python:3.12-alpine -RUN pip install redis aiohttp starlette uvicorn +COPY ./requirements.txt / -COPY ./GeoWhitelist.py /app/ +RUN pip install -r /requirements.txt + +COPY ./src/geowhitelist.py /app/ COPY ./config /app/config/ @@ -19,4 +21,4 @@ WORKDIR /app ENTRYPOINT ["python3"] -CMD ["/usr/local/bin/uvicorn","--port","9500","--host","0.0.0.0","GeoWhitelist:app"] +CMD ["/usr/local/bin/uvicorn","--port","9500","--host","0.0.0.0","geowhitelist:app"] From edbd174cb7d2fb05cd5eb4b8d2a833b42774624b Mon Sep 17 00:00:00 2001 From: Kit Date: Tue, 23 Jul 2024 12:09:13 +0200 Subject: [PATCH 3/7] Add a version to logging config due to switching to dictConfig from fileConfig --- config/config.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/config/config.yaml b/config/config.yaml index ca7a2bc..124bed0 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -16,6 +16,7 @@ redis: #password: "" logging: + version: 1 formatters: form01: format: "%(asctime)s - %(levelname)s - %(message)s" From 98b3780855372da29266788b66e18b0d812841fb Mon Sep 17 00:00:00 2001 From: Kit Date: Tue, 23 Jul 2024 12:09:30 +0200 Subject: [PATCH 4/7] update requirements.txt with correct dependencies --- requirements.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 7c8dec3..2bd24a2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ redis -starlette aiohttp -gunicorn +starlette +uvicorn pyyaml \ No newline at end of file From 38899edb6059e854c9dcfc0fec21b6d8bc597876 Mon Sep 17 00:00:00 2001 From: Kit Date: Tue, 23 Jul 2024 12:09:48 +0200 Subject: [PATCH 5/7] First attempt at unit test --- pyproject.toml | 12 ++++++++++++ pytest.ini | 2 ++ src/__init__.py | 0 tests/unit/__init__.py | 0 tests/unit/test_check_ip.py | 13 +++++++++++++ 5 files changed, 27 insertions(+) create mode 100644 pyproject.toml create mode 100644 pytest.ini create mode 100644 src/__init__.py create mode 100644 tests/unit/__init__.py create mode 100644 tests/unit/test_check_ip.py diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..c6b9ff7 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,12 @@ +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "geowhitelist" +version = "0.2.2" + +[tool.pytest.ini_options] +addopts = [ + "--import-mode=importlib", +] \ No newline at end of file diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000..d5a16fe --- /dev/null +++ b/pytest.ini @@ -0,0 +1,2 @@ +[pytest] +pythonpath = src \ No newline at end of file diff --git a/src/__init__.py b/src/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/unit/__init__.py b/tests/unit/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/unit/test_check_ip.py b/tests/unit/test_check_ip.py new file mode 100644 index 0000000..8f7e4de --- /dev/null +++ b/tests/unit/test_check_ip.py @@ -0,0 +1,13 @@ +""" +Unit tests for checkIP function of GeoWhitelist +""" +import pytest +from geowhitelist import checkIP +#target = __import__("geowhitelist.py") +#checkIP = target.checkIP + + +def test_bad_ip(): + data = "123.456.789.012" + with pytest.raises(ValueError): + checkIP(data) From 4557265a59b473adb4d0cab7b30dd44956a37f86 Mon Sep 17 00:00:00 2001 From: Kit Date: Tue, 23 Jul 2024 15:20:02 +0200 Subject: [PATCH 6/7] add requirements.txt for tests --- tests/requirements.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 tests/requirements.txt diff --git a/tests/requirements.txt b/tests/requirements.txt new file mode 100644 index 0000000..a90a4dc --- /dev/null +++ b/tests/requirements.txt @@ -0,0 +1,3 @@ +pytest +pytest-asyncio +pytest-mock \ No newline at end of file From cd20b3ebbc2894a08a9d98a816a932b5629a3e6b Mon Sep 17 00:00:00 2001 From: Kit Date: Tue, 23 Jul 2024 15:20:35 +0200 Subject: [PATCH 7/7] tests for the CheckIP function --- tests/unit/test_check_ip.py | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/tests/unit/test_check_ip.py b/tests/unit/test_check_ip.py index 8f7e4de..6c716d1 100644 --- a/tests/unit/test_check_ip.py +++ b/tests/unit/test_check_ip.py @@ -3,11 +3,24 @@ """ import pytest from geowhitelist import checkIP -#target = __import__("geowhitelist.py") -#checkIP = target.checkIP -def test_bad_ip(): - data = "123.456.789.012" - with pytest.raises(ValueError): - checkIP(data) +@pytest.mark.parametrize("maybe_ip, expected_result", [ + ("", False), + ("not an IP", False), + ("10.0.0.1", True), + ("6.7.8.9", True), + (['1.2.3.4', '4.6.7.8'], False), + (None, False), +]) +@pytest.mark.asyncio +async def test_bad_ip( + maybe_ip, + expected_result, + monkeypatch, + mocker + ): + mock_access_control = mocker.patch('geowhitelist.accessControl', + return_value=True) + res = await checkIP(maybe_ip) + assert res == expected_result