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"] 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" 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/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 diff --git a/src/__init__.py b/src/__init__.py new file mode 100644 index 0000000..e69de29 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 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 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..6c716d1 --- /dev/null +++ b/tests/unit/test_check_ip.py @@ -0,0 +1,26 @@ +""" +Unit tests for checkIP function of GeoWhitelist +""" +import pytest +from geowhitelist import checkIP + + +@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