make show-admin-password — prints the admin password from the initial
setup file if the API hasn't consumed it yet; otherwise prompts to reset
make reset-admin-password — generates a strong random password, updates
auth_users.json directly, writes it back to the setup file, and prints
it prominently so it's easy to copy
Also enhances reset_admin_password.py with --show, --generate flags and
a clear banner output, and adds both targets to make help.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- All test targets now use python3 -m pytest (not bare pytest)
- test-e2e-deps uses sudo pip3 --break-system-packages and
sudo python3 -m playwright install (Debian externally-managed env)
- test-e2e-wg uses sudo -E python3 -m pytest (preserves PATH/env)
- reset-test-admin-pass uses make ifndef guard instead of shell ?: expansion
- Remove stale -m markers from test targets (filters were redundant)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sprint 1 — Security & correctness:
- Restore all 10 commented-out is_local_request() checks (vault, containers, images, volumes)
- Fix XFF spoofing: only trust the LAST X-Forwarded-For entry (Caddy's append), not all
- Require prefix length in wireguard.address (was accepting bare IPs like 10.0.0.1)
- Validate service_access list in add_peer (valid: calendar/files/mail/webdav)
- Fix dhcp/reservations POST/DELETE: unpack mac/ip/hostname from body (was passing dict as positional arg)
- Fix network/test POST: remove spurious data arg (test_connectivity takes no args)
- Fix remove_peer: clear iptables rules and regenerate DNS ACLs on deletion (was leaving stale rules)
- Fix CoreDNS reload: SIGHUP → SIGUSR1 (SIGHUP kills the process; SIGUSR1 triggers reload plugin)
- Remove local.{domain} block from Corefile template (local.zone doesn't exist, caused log spam)
- Fix routing_manager._remove_nat_rule: targeted -D instead of flushing entire POSTROUTING chain
Sprint 2 — State consistency:
- Atomic config writes in config_manager, ip_utils, firewall_manager, network_manager
(write to .tmp → fsync → os.replace, prevents truncated files on kill)
- backup_config: now also backs up Caddyfile, Corefile, .env, DNS zone files
- restore_config: restores all of the above so config stays consistent after restore
Sprint 3 — Dead code / documentation:
- Remove CellManager instantiation from app startup (was never called, double-instantiated all managers)
- Document routing_manager scope (targets host, not cell-wireguard; methods not called by any active route)
Sprint 4 — Test infrastructure:
- Add tests/conftest.py with shared tmp_dir, tmp_config_dir, tmp_data_dir, flask_client fixtures
- Add tests/test_config_validation.py: 400 paths for ip_range, port, wireguard.address validation
- Add tests/test_ip_utils_caddyfile.py: 14 tests for write_caddyfile (was completely untested)
- Expand test_app_misc.py: 7 new is_local_request tests covering XFF spoofing and cell-network IPs
- Add --cov-fail-under=70 to make test-coverage
- Add pre-commit hook that runs pytest before every commit
414 tests pass (was 372).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Previously 'n' still ran --rmi all, removing Docker images. Now:
- n (default): docker-compose down only — containers gone, images and
data/config untouched; 'make start' brings everything back immediately
- y: full wipe — containers, images, config/ and data/ all removed
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
After make uninstall (which wipes config/ and data/), running make update
directly failed with "Couldn't find env file: config/mail/mailserver.env"
because docker-compose needs the generated config files to exist.
make update now checks for the sentinel config file and calls make setup
first if it's missing, so uninstall → update works as a valid flow.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Shows a warning then asks: y = full wipe, n/Enter = stop+remove images
only (keep config/data), anything else = cancel. Updates help + README.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- update: git pull + rebuild + restart
- reinstall: full wipe (config/data) + setup + start
- uninstall: stop, remove images, wipe config/data
- logs-<svc>: follow logs for any single service
- shell-<svc>: exec into any container (bash with sh fallback)
- backup: use sudo tar to read container-owned files
- help: restructured with all commands documented
- README: updated Quick Start + added Management Commands reference
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
scripts/check_deps.sh now checks and installs all prerequisites:
git, curl, openssl, python3, python3-cryptography, docker, docker-compose.
Runs apt-get update only once if anything needs installing.
Also adds current user to docker group if missing.
Makefile calls it with sudo so it has the rights to install packages.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
sudo -n skips apt silently if no sudo rights (SSH non-interactive).
Falls back to python3 -m pip install --user which never needs root,
then ensurepip if pip module is missing. Friendly error if all fail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add check-deps target: auto-installs python3, pip3, cryptography via
apt (with pip fallback) before running setup_cell.py
- Add sudo chown in setup to reclaim config/data dirs if containers have
taken ownership (e.g. re-running setup after make start)
- Pass PUID/PGID=$(id -u/g) to docker-compose so linuxserver/wireguard
chowns its config dir to the host user instead of hardcoded UID 911
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
docker compose up --build ensures the API and webui images are always built
from the current source on first install or after code changes, so users
don't need a separate make build-api step.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Allows running make setup on hosts without wg binary or Python cryptography
library by passing pre-generated keys from another machine.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
DC variable auto-detects available command at build time.
Also fixes backup and dev targets that incorrectly used $(DC).yml.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- app.py: ConfigManager now uses CONFIG_DIR env var for config file path
instead of hardcoded './config/cell_config.json' — config was being read
from the image's working directory, making all settings writes ephemeral
(lost on container restart)
- wireguard_manager: generate_config uses configured address/port instead of
hardcoded 10.0.0.1 in DNAT rules and Address field
- scripts/setup_cell.py: full setup script — generates WireGuard keys (wg
binary or Python cryptography fallback), writes wg0.conf and cell_config.json
with correct _identity key; CELL_NAME / VPN_ADDRESS / WG_PORT env vars
- Makefile: setup target passes env vars through; build-api / build-webui targets
- README: replace install.sh references with make setup && make start
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>