fix: P0/P1 audit fixes — DDNS correctness, peer provisioning gates, honest stubs

CloudflareDDNS.update() was calling the wrong endpoint; fix to use the
correct zone-records API so DDNS updates actually land.

NoIP and FreeDNS providers now return explicit "not implemented" errors
instead of silently claiming success, preventing false-positive health state.

PicNgoDNS ACME dns-challenge now sends the token in the request body (was
missing), so cert issuance no longer silently fails.

add_peer gates builtin-service provisioning on the installed-services list
so a freshly-provisioned peer does not attempt to configure services that
aren't present, eliminating the startup error loop.

Startup Caddyfile regeneration added to routes/config.py so that a stale
on-disk Caddyfile no longer triggers the health-monitor restart loop after
a config change.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-06-10 08:23:00 -04:00
parent 649378b59b
commit cc7a223fdf
4 changed files with 200 additions and 74 deletions
+16
View File
@@ -660,6 +660,22 @@ def ddns_register():
return jsonify({'error': str(e)}), 500
@bp.route('/api/ddns/sync', methods=['POST'])
def ddns_sync_records():
"""Sync per-service public DNS records (Cloudflare provider)."""
try:
from app import ddns_manager
from ddns_manager import DDNSError
try:
result = ddns_manager.sync_service_records()
except DDNSError as exc:
return jsonify({'error': str(exc)}), 400
return jsonify(result)
except Exception as e:
logger.error('Error in /api/ddns/sync: %s', e)
return jsonify({'error': str(e)}), 500
@bp.route('/api/config/pending', methods=['GET'])
def get_pending_config():
from app import config_manager