Add isolated development environment

This commit is contained in:
lussierj committed 2026-07-27 19:06:01 +00:00
1 parent 421fa98292
commit f5af75f305
7 files changed
+240

No files matched your search

+20
View File
@@ -0,0 +1,20 @@
# Copying this file is optional. scripts/dev-env-init.sh generates strong secrets.
APP_ENV=development
APP_TIMEZONE=America/Winnipeg
POSTGRES_DB=minerops_dev
POSTGRES_USER=minerops_dev
POSTGRES_PASSWORD=replace-with-a-random-local-only-secret
POSTGRES_HOST=postgres
POSTGRES_PORT=5432
DATABASE_URL=postgresql://minerops_dev:replace-with-a-random-local-only-secret@postgres:5432/minerops_dev
REDIS_URL=redis://redis:6379/0
JWT_SECRET_KEY=replace-with-a-random-local-only-secret
MINEROPS_AGENT_SHARED_SECRET=replace-with-a-random-local-only-secret
MINEROPS_DEV_PORT=18000
# Safety interlocks: keep these values disabled for development.
SCHEDULED_SCAN_ENABLED=false
MINEROPS_HUB_MODE=true
MINEROPS_DISABLE_LOCAL_SCANNER=true
MINEROPS_ENABLE_REAL_REBOOT=false
MINEROPS_ENABLE_REAL_POWER_CONTROL=false
+2
View File
@@ -2,6 +2,8 @@
.env .env
.env.* .env.*
*.env *.env
!.env.example
!.env.dev.example
# Backups / dumps / generated data # Backups / dumps / generated data
backups/ backups/
+30
View File
@@ -74,9 +74,39 @@ Git status:
pct exec 306 -- bash -lc "cd /opt/minerops && git status --short" pct exec 306 -- bash -lc "cd /opt/minerops && git status --short"
## Safe local development
Development uses a separate Compose project, database volume, Redis volume, and
localhost-only backend port. It does not reuse the production `.env` file.
Scheduled scanning and real miner power/reboot controls are disabled.
First-time setup:
```bash
./scripts/dev-env-init.sh
docker compose --env-file .env.dev -f compose.dev.yaml up -d --build
```
Verify the environment:
```bash
docker compose --env-file .env.dev -f compose.dev.yaml ps
curl --fail --silent http://127.0.0.1:18000/api/health
```
Stop development services without deleting their data:
```bash
docker compose --env-file .env.dev -f compose.dev.yaml down
```
The generated `.env.dev` file is mode `0600` and ignored by Git. To use a
different local port, change `MINEROPS_DEV_PORT` in `.env.dev`.
## Safety notes ## Safety notes
- Do not commit .env. - Do not commit .env.
- Do not commit backups, logs, database dumps, imports, or runtime data. - Do not commit backups, logs, database dumps, imports, or runtime data.
- Do not enable scanning or real miner controls in the development environment.
- Check /system-health after major changes. - Check /system-health after major changes.
- Commit and push after each stable working change. - Commit and push after each stable working change.
+6
View File
@@ -0,0 +1,6 @@
__pycache__/
*.py[cod]
*.bak
*.bak.*
.pytest_cache/
.mypy_cache/
+105
View File
@@ -0,0 +1,105 @@
name: minerops-dev
services:
postgres:
image: postgres:16-alpine
environment:
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- postgres-dev:/var/lib/postgresql/data
networks:
- dev
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
interval: 5s
timeout: 5s
retries: 12
redis:
image: redis:7-alpine
command: ["redis-server", "--appendonly", "yes"]
volumes:
- redis-dev:/data
networks:
- dev
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 5s
retries: 12
backend:
build:
context: ./backend
env_file:
- .env.dev
command:
- /bin/sh
- -ec
- alembic upgrade head && exec uvicorn app.main:app --host 0.0.0.0 --port 8000
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
networks:
- dev
read_only: true
tmpfs:
- /tmp
cap_drop:
- ALL
security_opt:
- no-new-privileges:true
healthcheck:
test:
- CMD
- python
- -c
- "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/api/health', timeout=3)"
interval: 10s
timeout: 5s
retries: 12
start_period: 20s
gateway:
image: nginx:1.29-alpine
depends_on:
backend:
condition: service_healthy
ports:
- "127.0.0.1:${MINEROPS_DEV_PORT:-18000}:8080"
networks:
- dev
- edge
volumes:
- ./dev/nginx.conf:/etc/nginx/nginx.conf:ro
read_only: true
tmpfs:
- /tmp
cap_drop:
- ALL
security_opt:
- no-new-privileges:true
user: "101:101"
healthcheck:
test:
- CMD
- wget
- --quiet
- --spider
- http://127.0.0.1:8080/api/health
interval: 10s
timeout: 5s
retries: 12
networks:
dev:
internal: true
edge:
volumes:
postgres-dev:
redis-dev:
+30
View File
@@ -0,0 +1,30 @@
worker_processes 1;
pid /tmp/nginx.pid;
events {
worker_connections 128;
}
http {
access_log /dev/stdout;
error_log /dev/stderr notice;
client_body_temp_path /tmp/client_body;
proxy_temp_path /tmp/proxy;
fastcgi_temp_path /tmp/fastcgi;
uwsgi_temp_path /tmp/uwsgi;
scgi_temp_path /tmp/scgi;
server {
listen 8080;
server_name _;
location / {
proxy_pass http://backend:8000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
}
+47
View File
@@ -0,0 +1,47 @@
#!/usr/bin/env bash
set -euo pipefail
project_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
env_file="${project_dir}/.env.dev"
if [[ -e "${env_file}" ]]; then
echo "Keeping existing ${env_file}"
exit 0
fi
umask 077
generate_secret() {
if command -v openssl >/dev/null 2>&1; then
openssl rand -hex 32
else
python3 -c 'import secrets; print(secrets.token_hex(32))'
fi
}
postgres_password="$(generate_secret)"
jwt_secret="$(generate_secret)"
agent_secret="$(generate_secret)"
{
echo "APP_ENV=development"
echo "APP_TIMEZONE=America/Winnipeg"
echo "POSTGRES_DB=minerops_dev"
echo "POSTGRES_USER=minerops_dev"
echo "POSTGRES_PASSWORD=${postgres_password}"
echo "POSTGRES_HOST=postgres"
echo "POSTGRES_PORT=5432"
echo "DATABASE_URL=postgresql://minerops_dev:${postgres_password}@postgres:5432/minerops_dev"
echo "REDIS_URL=redis://redis:6379/0"
echo "JWT_SECRET_KEY=${jwt_secret}"
echo "MINEROPS_AGENT_SHARED_SECRET=${agent_secret}"
echo "MINEROPS_DEV_PORT=18000"
echo "SCHEDULED_SCAN_ENABLED=false"
echo "MINEROPS_HUB_MODE=true"
echo "MINEROPS_DISABLE_LOCAL_SCANNER=true"
echo "MINEROPS_ENABLE_REAL_REBOOT=false"
echo "MINEROPS_ENABLE_REAL_POWER_CONTROL=false"
} >"${env_file}"
chmod 0600 "${env_file}"
echo "Created ${env_file} with development-only secrets and safety interlocks."