diff --git a/.dockerignore b/.dockerignore index 0c536ce..7b7c120 100644 --- a/.dockerignore +++ b/.dockerignore @@ -2,6 +2,7 @@ .credentials .secrets auth.yaml +config.yaml *._py_ # Editors (Editor-specific config files) @@ -124,3 +125,11 @@ dmypy.json .pyre/ .pytype/ cython_debug/ + +design_documents/ +distro_client/subdomain_client.tar.gz +distro_client/ +config/config.yaml +config/ +scripts/ +template_vars.env \ No newline at end of file diff --git a/.gitignore b/.gitignore index 8a7da67..31af1d9 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ .credentials .secrets auth.yaml +config.yaml *._py_ # Editors @@ -75,12 +76,6 @@ cover/ *.mo *.pot -# Django stuff: -*.log -local_settings.py -db.sqlite3 -db.sqlite-journal - # Flask stuff: instance/ .webassets-cache @@ -119,13 +114,6 @@ pdm.lock __pypackages__/ -# celery beat schedule file -celerybeat-schedule -celerybeat.pid - -# SageMath parsed files -*.sage.py - # Environments .env .venv @@ -135,13 +123,6 @@ ENV/ env.bak/ venv.bak/ -# Spyder project settings -.spyderproject -.spyproject - -# Rope project settings -.ropeproject - # mkdocs documentation /site @@ -156,15 +137,10 @@ dmypy.json # pytype static type analyzer .pytype/ -# Cython debug symbols -cython_debug/ - -# PyCharm -# JetBrains specific template is maintained in a separate JetBrains.gitignore that can -# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore -# and can be added to the global gitignore or merged into this file. For a more nuclear -# option (not recommended) you can uncomment the following to ignore the entire idea folder. -#.idea/ - distro_client/subdomain_client.tar.gz +distro_client/ config/config.yaml +config/ +scripts/project-cli +scripts/update-variables.sh +template_vars.env diff --git a/Dockerfile b/Dockerfile index 59f0341..834bf33 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,24 +1,26 @@ # Dockerfile -FROM python:3.10-slim +FROM python:3.10-slim-trixie # Set working directory WORKDIR /app -# Copy requirements file and install dependencies -# COPY requirements.txt . +# Apply security updates +RUN apt update && apt-get install -y --only-upgrade $(apt-get --just-print upgrade | awk 'tolower($4) ~ /.*security.*/ || tolower($5) ~ /.*security.*/ {print $2}' | sort | uniq) && rm -rf /var/lib/apt/lists/* + RUN pip install --no-cache-dir hatch -# Copy the entire project to the working directory -COPY ./src /app/src -COPY ./README.md /app/README.md -COPY ./LICENSE /app/LICENSE -COPY ./pyproject.toml /app/pyproject.toml -COPY ./scripts /app/scripts -#COPY ./tests /app/tests -COPY ./docs /app/docs +# Copy first part of project that needs to be rebuilt +# if it changes +COPY ./pyproject.toml ./src /app/ -# Expose the port the app runs on (adjust based on your app's settings) +# Pre-installed files needed at runtime +RUN hatch env create default -- --no-cache-dir + +# Copy the rest of the project; readme and license +COPY ./README.md ./LICENSE /app/ + +# Expose the default port the app runs on EXPOSE 5232 # Command to run the app -CMD ["hatch","run","subdomain_server","--port","5232","--config-path","/app/config/config.yaml","--debug"] +CMD ["hatch","run","subdomain_server","--config-path","/app/config/config.yaml"] diff --git a/docker-compose.yaml b/docker-compose.yaml index be9e348..3d555fd 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -13,6 +13,9 @@ services: - /home/doc/src/my/subdomain_server/config:/app/config:ro environment: - AUTH_FILE=/app/config/config.yaml + - LOG_LEVEL=DEBUG + - PORT=5232 + - BINDING=0.0.0.0 restart: always networks: diff --git a/pyproject.toml b/pyproject.toml index 556c4bd..b30e4a4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,9 +11,9 @@ authors = [ { name = "BipolarExpedition(Doc1979)" }, { name = "Doc1979", email = "lastdoc39@gmail.com" }, ] -requires-python = ">=3.8" +requires-python = ">=3.10" license = { file = "LICENSE" } -# keywords = [] +keywords = ["server", "domain", "subdomain", "dns", "dynamic"] classifiers = [ # How mature is this project? Common values are # 3 - Alpha @@ -23,38 +23,45 @@ classifiers = [ "Programming Language :: Python :: 3", "Operating System :: OS Independent", ] -dependencies = ["Flask", "PyYAML", "Typer", "requests"] - -[project.urls] -homepage = "https://github.com/BipolarExpedition/subdomain_server" -repository = "https://github.com/BipolarExpedition/subdomain_server" -issues = "https://github.com/BipolarExpedition/subdomain_server/issues" -# documentation = "https://readthedocs.org" -# changelog = "https://github.com/me/spam/blob/master/CHANGELOG.md" +dependencies = [ + "Flask==3.1.1", + "PyYAML==6.0.2", + "requests==2.32.4", + "typer==0.16.0", +] [project.scripts] subdomain_server = "bpe_subdomain_server.cli:daemon" -# [project.gui-scripts] -# subdomain_server_gui = "bpe_subdomain_server.gui-tk:main" - -#[project.optional-dependencies] -# gui = ["tkinter"] -# cli = [ -# "rich", -# "click", -# ] +[project.optional-dependencies] +dev = [ + "ruff", + "mypy", + "pytest", + "types-PyYAML", + "types-requests", + "typing_extensions", +] [tool.hatch.build] skip-excluded-dirs = true -exclude = [".secrets", ".credentials", ".vscode", ".idea"] +exclude = [ + ".secrets", + ".credentials", + ".vscode", + ".idea", + "auth.yaml", + "config.yaml", + "config/auth.yaml", + "config/config.yaml", +] [tool.hatch.envs.default] python = "3.10" [tool.hatch.envs.test] python = "3.10" -dependencies = ["ruff", "myst-parser", "sphinx", "pytest"] +dependencies = ["ruff", "myst-parser", "sphinx", "pytest", "mypy"] [tool.pytest.ini_options] testpaths = ["tests"] diff --git a/src/bpe_subdomain_server/app.py b/src/bpe_subdomain_server/app.py index 6ba4d80..dc80c60 100644 --- a/src/bpe_subdomain_server/app.py +++ b/src/bpe_subdomain_server/app.py @@ -15,8 +15,24 @@ from bpe_subdomain_server.__about__ import ( # __repository__, ) -# last_update = None -# DEBUG = False +# Changelog: +# 2025-09-03: - Changelog started. Existing version 0.0.2 +# - Adding section for application wide TODOs. Each to be moved to changelog when done +# - Adjusted .gitignore and .dockerignore +# - Updated Dockerfile image base to python:3.10-slim-trixie. Cleaned up image build. +# - Added default environment values to compose file +# - Cleaned up pyproject.toml. Deleted unused gui-tk.py. Added requirements.txt + +# Application level TODOs +# TODO: Refactor Config class to be in utils.py +# TODO: add routes for lookup and health +# TODO: add proper google style documentation comments. Consider local LLM for first pass then manual edit/review +# FIXME: Move api-key to header +# TODO: Consilidate redundant debug messages "Request json" and "Received data" +# FIXME: Create solution to sanitize keys and passwords from log. Likely [filters in logging library](https://docs.python.org/3.10/library/logging.html#filter-objects) +# TODO: Consider to use Pydantic and its SecretStr type to better hide secrects from logs AND exceptions +# TODO: Remove unused Makefile. Centralize version information for project. Make script to fascilitate docker image creation (auto versioning) +# TODO: Refactor to BPE parent path for "branding" class Config(object): @@ -143,8 +159,6 @@ def setup_logging( flask_app = Flask(__name__) -# TODO: add routes for lookup and health - @flask_app.route("/get-ip", methods=["GET", "POST"]) def request_get_ip(): @@ -163,6 +177,7 @@ def request_get_ip(): @flask_app.route("/update", methods=["POST"]) def update(): # Refresh API keys if the file was modified + Config.auth_table.load_api_keys() api_keys_config = Config.auth_table.auth logger.debug(f"API keys: {api_keys_config}") @@ -199,7 +214,7 @@ def update(): logger.warning("Update request missing ip and auto_ip is false") return jsonify({"error": "ip is required unless auto_ip is true"}), 400 - # Authenticate API token and check permissions + # Check token and permissions if ( api_token not in api_keys_config["api_keys"] or subdomain not in api_keys_config["api_keys"][api_token]["allowed_subdomains"] diff --git a/src/bpe_subdomain_server/gui-tk.py b/src/bpe_subdomain_server/gui-tk.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/bpe_subdomain_server/utils.py b/src/bpe_subdomain_server/utils.py index f9dfe33..818293c 100644 --- a/src/bpe_subdomain_server/utils.py +++ b/src/bpe_subdomain_server/utils.py @@ -69,9 +69,6 @@ def get_ip(addr: str) -> str: return res -# TODO: At either update_domain, update_namecheap, or both, make sure IP is not a reserved address - - def update_domain(subdomain, ip, auth_table: AuthTable) -> bool: # Verify that the IP address is not a reserved address if not is_public_ip(ip): diff --git a/src/bpe_subdomain_server/version.txt b/src/bpe_subdomain_server/version.txt index 8a9ecc2..7bcd0e3 100644 --- a/src/bpe_subdomain_server/version.txt +++ b/src/bpe_subdomain_server/version.txt @@ -1 +1 @@ -0.0.1 \ No newline at end of file +0.0.2 \ No newline at end of file