ffe1dbeed6
Unit Tests / test (push) Failing after 8m57s
setup_cell.py: register_with_ddns() called at end of setup — detects public IP via api.ipify.org, generates TOTP code from DDNS_TOTP_SECRET, POSTs to DDNS /register, saves token to data/api/.ddns_token (mode 600). Idempotent: skips if token file already exists. Fails gracefully if DDNS_TOTP_SECRET is unset or network is unreachable. scripts/ddns_update.py: standalone script for periodic IP updates. Reads token from data/api/.ddns_token, fetches current public IP, compares to cached last IP (data/api/.ddns_last_ip) and calls /update only when the IP has actually changed. Makefile: add ddns-update (run update script) and ddns-register (force re-registration by removing old token then calling register_with_ddns). Usage: DDNS_TOTP_SECRET=<secret> make ddns-register Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>