[grade=B urn:ump:ez33fpgyydl3nyjnwaaplisz7slunupcf5dnr42pdblwx7chfcma] feat(DC-171): phase 2 — PowerDNS adapter (full plug-in parity) + shared wizard DNS serialisation
NEW powerdns.js adapter: PowerDNS Authoritative HTTP API (X-API-Key). Full parity (zones + native RRset enumeration — no AXFR needed): listZones/listRecords, additive create that merges with existing rrset contents and FAILS CLOSED when the rrset cannot be read (blind REPLACE would erase values), content-level delete with positive value-presence proof (absent rrset/value → not-found with ZERO writes; empty/null value rejected; only genuine whole-rrset intent issues DELETE), TTL preserved in REPLACE payloads and on additive creates, cross-zone qualification via the server-resolved zone id/name, case-insensitive rrset matching, dig-based resolve against the DNS listener (distinct from the API port), error guidance naming the exact pdns.conf prerequisite. WIZARD SERIALISATION EXTRACTED to shared js/dns-provider-config.js (browser global + module.exports): per-provider port defaults (PowerDNS 8081, RFC2136 53, legacy Technitium 5380), strict port validation (full-string digits, 1-65535), provider-specific aliases (server/apiPort/dnsPort/apiToken). The backend tests now execute the EXACT shipped wizard code, joined through the real createProviderDnsContext factory to adapter authentication (X-API-Key asserted). provider-dns.js dual-accepts generic wizard keys and provider-specific fields and normalises ports to integers (fixes the same latent gap for rfc2136). Also fixed: rfc2136 parity-matrix rows now exact-sorted-equality across all five adapters; wizard confirmation summary uses the provider default. Judge: 7 rounds — r1 C (silent-erase on failed read, cross-zone bug, missing resolve tests) → r2 C (deleteRecord positive-proof semantics) → r3 C (TTL in REPLACE, count honesty) → r4 C (empty-value fall-through) → r5 C (wizard ip/port/token vs builder field mismatch) → r6 C (5380 default defeating provider ports, untested serialisation) → r7 B zero blockers (urn:ump:ez33fpgyydl3nyjnwaaplisz7slunupcf5dnr42pdblwx7chfcma). Post-grade polish applied: strict port validation + range, summary uses provider defaults, joined serialisation→factory→adapter test, invalid port table tests. Suite: backend 176 suites / 3791 tests, frontend 68/68.
This commit is contained in:
12 files changed
+1319
-158
No files matched your search
@@ -77,7 +77,13 @@ window.populateTimezoneSelect = function(selectEl, selectedTz) {
|
||||
const tld = document.getElementById('setup-tld')?.value?.trim() || '.home';
|
||||
const caName = document.getElementById('setup-ca-name')?.value?.trim() || '';
|
||||
const dnsIP = document.getElementById('setup-dns-ip')?.value?.trim() || '';
|
||||
const dnsPort = document.getElementById('setup-dns-port')?.value?.trim() || DC.DEFAULTS.DNS_PORT;
|
||||
const dnsPort = DnsProviderConfig.buildDnsConfig(
|
||||
document.getElementById('setup-dns-provider')?.value || 'technitium',
|
||||
dnsIP,
|
||||
document.getElementById('setup-dns-port')?.value?.trim() || '',
|
||||
'',
|
||||
DC.DEFAULTS.DNS_PORT,
|
||||
).port;
|
||||
|
||||
html += `
|
||||
<div>
|
||||
@@ -175,12 +181,17 @@ window.populateTimezoneSelect = function(selectEl, selectedTz) {
|
||||
config.tld = document.getElementById('setup-tld')?.value?.trim() || '.home';
|
||||
config.caName = document.getElementById('setup-ca-name')?.value?.trim() || '';
|
||||
const selectedProvider = document.getElementById('setup-dns-provider')?.value || 'technitium';
|
||||
config.dns = {
|
||||
provider: selectedProvider,
|
||||
ip: document.getElementById('setup-dns-ip')?.value?.trim() || '',
|
||||
port: document.getElementById('setup-dns-port')?.value?.trim() || DC.DEFAULTS.DNS_PORT,
|
||||
token: document.getElementById('setup-dns-token')?.value?.trim() || ''
|
||||
};
|
||||
// Serialisation extracted to js/dns-provider-config.js (shared with
|
||||
// the backend parity tests) so the wizard→builder mapping is the
|
||||
// exact code the tests exercise: per-provider port defaults and
|
||||
// provider-specific field aliases live there.
|
||||
config.dns = DnsProviderConfig.buildDnsConfig(
|
||||
selectedProvider,
|
||||
document.getElementById('setup-dns-ip')?.value?.trim() || '',
|
||||
document.getElementById('setup-dns-port')?.value?.trim() || '',
|
||||
document.getElementById('setup-dns-token')?.value?.trim() || '',
|
||||
DC.DEFAULTS.DNS_PORT,
|
||||
);
|
||||
config.defaults = {
|
||||
dnsType: 'private',
|
||||
sslType: 'internal',
|
||||
@@ -462,6 +473,7 @@ window.populateTimezoneSelect = function(selectEl, selectedTz) {
|
||||
technitium: '✅ Full management — records, zones and health checks via the Technitium API. DashCaddy can create, delete, list and resolve records.',
|
||||
cloudflare: '✅ Full management — records via the Cloudflare API token. DashCaddy can create, delete, list and resolve records.',
|
||||
rfc2136: '⚠️ Partial (push-only protocol) — records can be created, deleted and resolved, and listed via AXFR zone transfer if the server permits transfers for your key (BIND: allow-transfer { key <name>; };). Listing requires that server-side setting.',
|
||||
powerdns: '✅ Full management — records and zones via the PowerDNS HTTP API (X-API-Key). Requires api=yes, webserver=yes and api-key in pdns.conf. DashCaddy can create, delete, list and resolve records.',
|
||||
manual: 'ℹ️ No API control — DashCaddy shows the records you create yourself with your DNS provider\'s tools. Everything else (reverse proxy, SSL) works normally.',
|
||||
};
|
||||
function updateDnsProviderHints() {
|
||||
|
||||
Reference in new issue
Block a user