[grade=B urn:ump:wokpmecjfauc7jvnxyyyu4fq3zkkvwge455a5mxlmi3pdzkfdw3a] feat(DC-171): DNS provider plug-in parity phase 1 — BIND 9 AXFR listing + capability honesty
RFC2136/BIND9 adapter gains listRecords via AXFR zone transfer (dig with the same TSIG identity as nsupdate; temp 0600 keyfile, always cleaned up; transfer-denial errors carry the exact allow-transfer fix). TSIG fields validated (name charset, HMAC algorithm whitelist, base64 secret) before keyfile interpolation. Capability honesty at every surface: GET /dns/records 501s name the active provider + its supported capabilities + zone-transfer pointer; MCP dashcaddy_list_dns attaches actionable guidance for AI clients; setup wizard shows per-provider capability hints at choice time (parity-pinned by tests against the adapters). Also fixed a latent rfc2136 bug: this._log instance property shadowed the prototype logging method — every nsupdate call threw since the DC-170-era refactor. CHANGELOG stale 'protocol-impossible' DC-171 entry superseded. Judge: grade B, zero blockers (urn:ump:wokpmecjfauc7jvnxyyyu4fq3zkkvwge455a5mxlmi3pdzkfdw3a). Polish applied post-grade: stale changelog entry corrected, TSIG field validation + 4 extra failure-path tests (exact dig argv, ENOENT install hint, non-denial failure passthrough, hostile-field rejection), dns-records 501 test strengthened to pin provider name + capabilities. Suite: backend 174 suites / 3754 tests, frontend 68/68.
This commit is contained in:
10 files changed
+704
-238
No files matched your search
@@ -59,11 +59,22 @@ describe('GET /dns/records (DC-170 route + DC-171 capability behavior)', () => {
|
||||
});
|
||||
|
||||
test('provider WITHOUT list-records capability answers 501 with guidance', async () => {
|
||||
// RFC2136-style: push-only protocol, cannot enumerate records
|
||||
const dns = { getActiveProvider: () => ({ supportsCapability: () => false }) };
|
||||
// RFC2136-style: push-only protocol, cannot enumerate records.
|
||||
// DC-171: the guidance must name the provider and its supported capabilities.
|
||||
const dns = {
|
||||
getActiveProvider: () => ({
|
||||
supportsCapability: () => false,
|
||||
getCapabilities: () => ['create-record', 'delete-record', 'resolve'],
|
||||
}),
|
||||
getProviderId: () => 'rfc2136',
|
||||
};
|
||||
const res = await request(buildApp(dns)).get('/dns/records');
|
||||
expect(res.status).toBe(501);
|
||||
expect(String(res.body.error || res.body.message)).toMatch(/not supported/i);
|
||||
const msg = String(res.body.error || res.body.message);
|
||||
expect(msg).toMatch(/not supported/i);
|
||||
expect(msg).toMatch(/rfc2136/);
|
||||
expect(msg).toMatch(/create-record, delete-record, resolve/);
|
||||
expect(msg).toMatch(/zone transfers/i);
|
||||
});
|
||||
|
||||
test('missing/unresolvable active provider answers 501, does not crash', async () => {
|
||||
|
||||
Reference in new issue
Block a user