fix: address code review findings for DNS management

- CRITICAL: Change DNS zones endpoint from GET to POST to avoid
  leaking API token in URL query parameters
- HIGH: Add sync.RWMutex to protect dnsProvider field in Server,
  Deployer, and proxy Manager against concurrent read/write races
- HIGH: Capture old DNS provider reference synchronously before
  launching background cleanup goroutine
- HIGH: Use getDNS()/getDNSProviderLocked() accessors instead of
  direct field reads in all DNS operations
This commit is contained in:
2026-04-02 14:54:15 +03:00
parent c730cfaa45
commit 670948f113
243 changed files with 15971 additions and 535 deletions
+17 -4
View File
@@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"log/slog"
"sync"
"github.com/alexei/docker-watcher/internal/dns"
"github.com/alexei/docker-watcher/internal/npm"
@@ -15,6 +16,7 @@ import (
type Manager struct {
store *store.Store
npm *npm.Client
dnsMu sync.RWMutex
dns dns.Provider // nil when wildcard DNS is active
}
@@ -28,9 +30,18 @@ func NewManager(st *store.Store, npmClient *npm.Client) *Manager {
// SetDNSProvider sets the DNS provider for managing DNS records.
func (m *Manager) SetDNSProvider(provider dns.Provider) {
m.dnsMu.Lock()
defer m.dnsMu.Unlock()
m.dns = provider
}
// getDNS returns the current DNS provider under read lock.
func (m *Manager) getDNS() dns.Provider {
m.dnsMu.RLock()
defer m.dnsMu.RUnlock()
return m.dns
}
// CreateProxyRequest is the input for creating a standalone proxy.
type CreateProxyRequest struct {
Domain string `json:"domain"`
@@ -315,7 +326,8 @@ func (m *Manager) ListAllProxies() ([]ProxyView, error) {
// ensureDNS creates or updates a DNS record for a standalone proxy domain. Best-effort.
func (m *Manager) ensureDNS(ctx context.Context, domain, proxyID string) {
if m.dns == nil {
dnsProvider := m.getDNS()
if dnsProvider == nil {
return
}
settings, err := m.store.GetSettings()
@@ -328,7 +340,7 @@ func (m *Manager) ensureDNS(ctx context.Context, domain, proxyID string) {
return
}
recordID, err := m.dns.EnsureRecord(ctx, domain, settings.ServerIP)
recordID, err := dnsProvider.EnsureRecord(ctx, domain, settings.ServerIP)
if err != nil {
slog.Warn("dns: failed to create/update record for standalone proxy", "domain", domain, "error", err)
return
@@ -350,10 +362,11 @@ func (m *Manager) ensureDNS(ctx context.Context, domain, proxyID string) {
// removeDNS deletes a DNS record for a standalone proxy domain. Best-effort.
func (m *Manager) removeDNS(ctx context.Context, domain string) {
if m.dns == nil {
dnsProvider := m.getDNS()
if dnsProvider == nil {
return
}
if err := m.dns.DeleteRecord(ctx, domain); err != nil {
if err := dnsProvider.DeleteRecord(ctx, domain); err != nil {
slog.Warn("dns: failed to delete record for standalone proxy", "domain", domain, "error", err)
return
}