diff --git a/Makefile b/Makefile index eab7048c..55ea4527 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,22 @@ APP_UID := $(shell id -u) -setup_mounts: +## make setup : Bootstrap local secret env files + config.json from samples (idempotent) +.PHONY: setup +setup: setup_secrets setup_config + +setup_secrets: + @bash scripts/bootstrap_secrets.sh + +# config.json is gitignored and baked into the image, but the `.:/srv/code/dev` +# bind mount shadows the baked copy, so a fresh clone must materialise it locally +# or settings.py fails with FileNotFoundError. Idempotent: existing file is kept. +setup_config: + @if [ ! -f config.json ]; then \ + cp config.json.sample config.json; \ + echo " created config.json from sample"; \ + fi + +setup_mounts: setup_secrets setup_config @mkdir -p mounts/db @mkdir -p mounts/mysql_db @mkdir -p mounts/logs @@ -27,7 +43,7 @@ dev: setup_mounts ## make build : Build and start docker containers - (web and db) .PHONY: build build: export APPUID = $(APP_UID) -build: +build: setup_secrets setup_config @docker-compose up --build -d web ## make build_only : Only build the web container diff --git a/pytest.ini b/pytest.ini index 711480b3..e50a3baf 100644 --- a/pytest.ini +++ b/pytest.ini @@ -2,7 +2,10 @@ DJANGO_SETTINGS_MODULE = EnigmaAutomation.settings ; # -- recommended but optional: ; python_files = tests.py test_*.py *_tests.py -addopts = --ignore=mounts +# -p no:pylama disables pylama's pytest11 plugin, whose pytest_collect_file(path,...) +# hook uses an argument removed in pytest 9 (it aborts collection otherwise). +# Linting still runs via standalone `python -m pylama` (see [pylama] below). +addopts = --ignore=mounts -p no:pylama [pylama] skip = env/* diff --git a/scripts/bootstrap_secrets.sh b/scripts/bootstrap_secrets.sh new file mode 100755 index 00000000..a36c4329 --- /dev/null +++ b/scripts/bootstrap_secrets.sh @@ -0,0 +1,63 @@ +#!/usr/bin/env bash +# +# Create local secret env files (secrets/*.env) from their committed +# *.env.sample templates. Idempotent: existing files are left untouched. +# +# Secrets are gitignored, so a fresh clone / CI runner has only the samples. +# Running `make dev` (or build/test) without the real files fails with +# "env file ... not found". This script bootstraps them for local dev. +# +# Coupling: MYSQL_ROOT_PASSWORD must be identical in ops_mysql_dev.env and +# ops_app_celery.env or the app/celery containers cannot auth to MySQL. +# We generate the password once and reuse it (and reuse an existing one if +# only some files are present) to keep them in sync. + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +SECRETS_DIR="$(cd "${SCRIPT_DIR}/../secrets" && pwd)" + +randstr() { LC_ALL=C tr -dc 'A-Za-z0-9' < /dev/urandom | head -c "$1"; } + +# Extract a KEY=value from a file, or empty string if absent. +readval() { + local key="$1" file="$2" + [ -f "$file" ] && sed -n "s/^${key}=//p" "$file" | head -n1 || true +} + +# Precedence: env override (CI/deterministic) > existing file (stay consistent +# with an already-initialised MySQL volume) > freshly generated random value. +PW="${MYSQL_ROOT_PASSWORD:-}" +[ -n "$PW" ] || PW="$(readval MYSQL_ROOT_PASSWORD "${SECRETS_DIR}/ops_mysql_dev.env")" +[ -n "$PW" ] || PW="$(readval MYSQL_ROOT_PASSWORD "${SECRETS_DIR}/ops_app_celery.env")" +[ -n "$PW" ] || PW="$(randstr 24)" + +TOKEN="${APP_TOKEN:-}" +[ -n "$TOKEN" ] || TOKEN="$(readval TOKEN "${SECRETS_DIR}/ops_app_dev.env")" +[ -n "$TOKEN" ] || TOKEN="$(readval TOKEN "${SECRETS_DIR}/ops_app_test.env")" +[ -n "$TOKEN" ] || TOKEN="$(randstr 32)" + +created=0 +gen() { + local out="$1"; shift + if [ -f "${SECRETS_DIR}/${out}" ]; then + return 0 + fi + # Remaining args: sed substitution expressions. + local sed_args=() + for expr in "$@"; do sed_args+=(-e "$expr"); done + sed "${sed_args[@]}" "${SECRETS_DIR}/${out}.sample" > "${SECRETS_DIR}/${out}" + echo " created secrets/${out}" + created=1 +} + +gen ops_mysql_dev.env "s|__CHANGE_ME__|${PW}|g" +gen ops_app_celery.env "s|__CHANGE_ME__|${PW}|g" +gen ops_app_dev.env "s|__CHANGE_ME__|${TOKEN}|g" +gen ops_app_test.env "s|__CHANGE_ME__|${TOKEN}|g" + +if [ "$created" -eq 1 ]; then + echo "Local secret env files ready. These are gitignored — edit values as needed." +else + echo "Secret env files already present — nothing to do." +fi