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
37 changes: 37 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Python bytecode
__pycache__/
*.py[cod]
*$py.class

# Virtual environments
.venv/
venv/
env/
ENV/

# Packaging / build artifacts
build/
dist/
*.egg-info/
.eggs/
pip-wheel-metadata/

# Test / coverage / type-check caches
.pytest_cache/
.coverage
.coverage.*
.mypy_cache/
.pyre/
.ruff_cache/

Comment on lines +19 to +26

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Add common Django/Python development artifacts to reduce build context bloat.

The following patterns are missing and commonly appear in Django projects:

  • .tox/ — tox virtualenv directories
  • db.sqlite3 — local SQLite database
  • *.mo — compiled translation files
  • node_modules/ — if any frontend assets use npm

Also verify that docker-compose*.yml and Dockerfile* are intentionally ignored; these are safe since Docker consumes them directly, but document this if other compose files exist.

Also applies to: 36-37

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.dockerignore around lines 19 - 26, The .dockerignore cache section is
missing several common Django/Python artifacts, so update the ignore list to
include .tox/, db.sqlite3, *.mo, and node_modules/ alongside the existing cache
patterns. Also review the current Dockerfile* and docker-compose*.yml ignore
rules in .dockerignore to confirm they are intentional, and keep or adjust them
consistently with any other compose files in the repo.

# Git / editor / OS files
.git/
.gitignore
.gitattributes
.vscode/
.idea/
.DS_Store
Thumbs.db

docker-compose*.yml
Dockerfile*
45 changes: 45 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# NOTE: This Docker image is for development purposes only.

FROM python:3.12-slim-bookworm

# System dependencies from the developer installation guide
RUN apt-get update && \
apt-get install -y --no-install-recommends \
xmlsec1 \
gettext \
fping \
gdal-bin \
libproj-dev \
libgeos-dev \
libspatialite-dev \
spatialite-bin \
libsqlite3-mod-spatialite \
sqlite3 \
libsqlite3-dev \
zlib1g-dev \
libjpeg-dev \
openssl \
libssl-dev \
libglib2.0-0 \
libcairo2 \
libpango-1.0-0 \
libpangocairo-1.0-0 \
libgdk-pixbuf-2.0-0 \
shared-mime-info \
&& rm -rf /var/lib/apt/lists/*

# Install test requirements first so this layer is cached separately
# from the source code copy below.
COPY requirements-test.txt .
RUN pip install --no-cache-dir -r requirements-test.txt

# Copy source and install the package with all optional extras
COPY . .
RUN pip install --no-cache-dir -e ".[saml,openvpn_status]"

ENV PYTHONUNBUFFERED=1 \
REDIS_HOST=redis \
INFLUXDB_HOST=influxdb

EXPOSE 8000
CMD ["bash", "docker-entrypoint.sh"]
30 changes: 26 additions & 4 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
version: "3"

services:
influxdb:
image: influxdb:1.8-alpine
Expand All @@ -11,12 +9,36 @@ services:
INFLUXDB_DB: openwisp2
INFLUXDB_USER: openwisp
INFLUXDB_USER_PASSWORD: openwisp
networks:
- openwisp

redis:
image: redis:alpine
ports:
- "6379:6379"
entrypoint: redis-server --appendonly yes
command: redis-server --appendonly yes
networks:
- openwisp

radius:
build:
context: .
dockerfile: Dockerfile
image: openwisp-radius-dev
working_dir: /opt/openwisp/tests
ports:
- "8000:8000"
volumes:
- .:/opt/openwisp/
depends_on:
- redis
- influxdb
networks:
- openwisp

volumes:
influxdb-data: {}
influxdb-data:

networks:
openwisp:
driver: bridge
49 changes: 49 additions & 0 deletions docs/developer/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,55 @@ Run quality assurance tests with:

./run-qa-checks

.. _radius_dev_docker:

Install and Run on Docker
-------------------------

.. warning::

This Docker image is for development purposes only.

For the official OpenWISP Docker images, see: :doc:`docker-openwisp
</docker/index>`.

Ensure `Docker <https://docs.docker.com/get-docker/>`_ and `Docker Compose
<https://docs.docker.com/compose/install/>`_ are installed on your system.

Fork and clone the forked repository:

.. code-block:: shell

git clone git://github.com/<your_fork>/openwisp-radius

Navigate into the cloned repository:

.. code-block:: shell

cd openwisp-radius/

Build the development image:

.. code-block:: shell

docker compose build

Start all services (Redis, InfluxDB, and the development server):

.. code-block:: shell

docker compose up

The development server will be available at ``http://127.0.0.1:8000/``.
The admin interface is at ``http://127.0.0.1:8000/admin/`` with
credentials ``admin`` / ``admin``.

To run the test suite inside the container:

.. code-block:: shell

docker compose run --rm radius bash -c "cd /opt/openwisp && ./runtests"

Alternative Sources
-------------------

Expand Down
23 changes: 23 additions & 0 deletions tests/docker-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/bin/bash

set -euo pipefail

create_superuser() {
local username="$1"
local email="$2"
local password="$3"
cat <<EOF | python manage.py shell
from django.contrib.auth import get_user_model

User = get_user_model()

if not User.objects.filter(username="$username").exists():
User.objects.create_superuser("$username", "$email", "$password")
else:
print('User "{}" exists already, not created'.format("$username"))
EOF
}

python manage.py migrate --no-input
create_superuser admin admin@example.com admin
Comment on lines +21 to +22

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Do not bootstrap the Docker admin with fixed admin/admin credentials.

Line 22 creates the same superuser in every environment, and the new docs advertise those credentials for the published admin UI. That makes any reachable dev instance trivially compromiseable. Read these values from environment variables and require an explicit choice instead of a built-in password.

Proposed fix
 python manage.py migrate --no-input
-create_superuser admin admin@example.com admin
+create_superuser \
+  "${DJANGO_SUPERUSER_USERNAME:?set DJANGO_SUPERUSER_USERNAME}" \
+  "${DJANGO_SUPERUSER_EMAIL:?set DJANGO_SUPERUSER_EMAIL}" \
+  "${DJANGO_SUPERUSER_PASSWORD:?set DJANGO_SUPERUSER_PASSWORD}"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
python manage.py migrate --no-input
create_superuser admin admin@example.com admin
python manage.py migrate --no-input
create_superuser \
"${DJANGO_SUPERUSER_USERNAME:?set DJANGO_SUPERUSER_USERNAME}" \
"${DJANGO_SUPERUSER_EMAIL:?set DJANGO_SUPERUSER_EMAIL}" \
"${DJANGO_SUPERUSER_PASSWORD:?set DJANGO_SUPERUSER_PASSWORD}"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/docker-entrypoint.sh` around lines 21 - 22, The Docker bootstrap
currently hardcodes the admin superuser credentials, which should not be created
with fixed values. Update the bootstrap logic in create_superuser within the
Docker entrypoint flow to read the username, email, and password from
environment variables instead of using admin/admin@example.com/admin, and
require explicit configuration before creating the account. Make sure the
migrate-and-bootstrap sequence still works when those variables are provided,
but does not silently fall back to built-in credentials.

exec python manage.py runserver 0.0.0.0:8000
Loading