Skip to content

feat: add admin DNS record management API#222

Open
ZPascal wants to merge 13 commits into
mainfrom
feature/dns-api-extended
Open

feat: add admin DNS record management API#222
ZPascal wants to merge 13 commits into
mainfrom
feature/dns-api-extended

Conversation

@ZPascal
Copy link
Copy Markdown
Owner

@ZPascal ZPascal commented May 30, 2026

Summary

  • Adds [api.admin] config section with bearer token authentication
  • New dns_records table with full CRUD: GET/POST /admin/records, PUT/DELETE /admin/records/:id
  • Supported record types: A, AAAA, CNAME, MX, TXT, NS, SRV, CAA, PTR
  • DNS server falls through to dns_records table when no static/ACME records match a query
  • Record names normalized to lowercase on ingress to match DNS query normalization
  • Admin routes only registered when [api.admin].token is non-empty (disabled by default)
  • CORS extended to allow PUT and DELETE methods + Authorization header

Test Plan

  • go test ./... passes
  • go build ./... builds cleanly
  • POST /admin/records with valid bearer token creates a record (201)
  • GET /admin/records without token returns 401
  • GET /admin/records?type=A filters by record type
  • DNS query for a managed record returns the correct answer
  • Admin routes absent when token = "" in config

ZPascal added 11 commits May 30, 2026 17:18
- feature/dns-api-extended: admin API for full DNS record management
- feature/ai-agent-support: OpenAPI 3.1 spec + MCP server binary
- feature/security-ha: security hardening + active-active HA deployment guide
- dns-api-extended: 7 tasks, TDD, admin CRUD API + DNS integration
- ai-agent-support: 7 tasks, OpenAPI spec + MCP binary
- security-ha: 7 tasks, 5 security fixes + HA deployment guide
Implements adminBearerMiddleware, adminListRecords, adminCreateRecord,
adminUpdateRecord, and adminDeleteRecord HTTP handlers behind Bearer
token auth; adds corresponding tests with DB teardown via t.Cleanup.
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an authenticated admin HTTP surface and backing storage to manage DNS records, and wires those records into the DNS response path as a fallback when no static/ACME records match.

Changes:

  • Introduce /admin/records CRUD endpoints guarded by an admin bearer token, enabled only when [api.admin].token is set.
  • Add dns_records persistence and integrate DB-backed records into DNS answers as a fallback path.
  • Add record type/TTL/value validators and related unit tests; extend CORS configuration for admin endpoints.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 16 comments.

Show a summary per file
File Description
main.go Registers admin routes conditionally; expands CORS methods/headers.
api.go Implements admin bearer middleware and record CRUD handlers.
db.go Adds dns_records DDL and CRUD methods.
dns.go Falls through to DB-managed records when static/ACME records don’t match.
types.go Adds [api.admin] config struct, DNSRecord, and DB interface extensions.
validation.go Adds record type/value/TTL validation helpers.
validation_test.go Adds unit tests for the new validation helpers.
config.cfg Adds [api.admin] section and token configuration.
docs/superpowers/specs/2026-05-30-dns-api-extended-design.md Design doc describing the admin DNS management API and DNS integration.
docs/superpowers/specs/2026-05-30-security-ha-design.md Security/HA design doc (appears unrelated to this PR’s stated scope).
docs/superpowers/specs/2026-05-30-ai-agent-support-design.md AI agent support design doc (appears unrelated to this PR’s stated scope).
docs/superpowers/plans/2026-05-30-security-ha.md Security/HA implementation plan (appears unrelated to this PR’s stated scope).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread main.go Outdated
AllowedOrigins: config.API.CorsOrigins,
AllowedMethods: []string{"GET", "POST"},
AllowedMethods: []string{"GET", "POST", "PUT", "DELETE"},
AllowedHeaders: []string{"Authorization", "Content-Type"},
Comment thread api.go
Comment on lines +201 to +208
rec := DNSRecord{
ID: uuid.New().String(),
Name: strings.ToLower(req.Name),
Type: req.Type,
Value: req.Value,
TTL: ttl,
Created: time.Now().Unix(),
}
Comment thread api.go Outdated
Comment on lines +150 to +152
filterType := r.URL.Query().Get("type")
filterName := r.URL.Query().Get("name")
records, err := DB.ListRecords(filterType, filterName)
Comment thread dns.go
Comment on lines +251 to +269
func (d *DNSServer) answerManaged(q dns.Question) []dns.RR {
name := strings.ToLower(q.Name)
records, err := d.DB.ListRecords(dns.TypeToString[q.Qtype], name)
if err != nil {
log.WithFields(log.Fields{"error": err.Error()}).Debug("Error querying managed records")
return nil
}
var rrs []dns.RR
for _, rec := range records {
rrStr := fmt.Sprintf("%s %d IN %s %s", rec.Name, rec.TTL, rec.Type, rec.Value)
rr, err := dns.NewRR(rrStr)
if err != nil {
log.WithFields(log.Fields{"error": err.Error(), "record": rrStr}).Warning("Could not parse managed RR")
continue
}
rrs = append(rrs, rr)
}
return rrs
}
Comment thread main.go Outdated
AllowedOrigins: config.API.CorsOrigins,
AllowedMethods: []string{"GET", "POST"},
AllowedMethods: []string{"GET", "POST", "PUT", "DELETE"},
AllowedHeaders: []string{"Authorization", "Content-Type"},
Comment thread validation.go
Comment on lines +75 to +76
case "CNAME", "MX", "NS", "PTR", "SRV", "TXT", "CAA":
return true // non-empty check handled above; structural validation deferred to dns.NewRR
Comment on lines +1 to +16
# Design: feature/ai-agent-support

**Date:** 2026-05-30
**Branch:** `feature/ai-agent-support`
**Status:** Approved

## Overview

Add two AI agent integration surfaces to acme-dns:

1. **OpenAPI 3.1 spec** — served at `GET /openapi.json`, enables any OpenAPI-aware agent or tool to discover and call the API via function calling
2. **MCP server binary** — `cmd/acme-dns-mcp/`, a standalone stdio-based MCP server that wraps the acme-dns HTTP API as structured tools for Claude and other MCP-capable agents

The core acme-dns server is minimally changed. The MCP server is a separate binary that proxies to the HTTP API — it has no direct DB or DNS access.

**Dependency:** This branch builds on `feature/dns-api-extended`. The OpenAPI spec and MCP tools for admin record management (`list_dns_records`, `create_dns_record`, `update_dns_record`, `delete_dns_record`) require the admin API from that branch to be merged first, or this branch should be built on top of it.
Comment on lines +1 to +9
# Security Hardening and HA Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Fix five security issues in the acme-dns codebase (SQL injection, bcrypt cost, rate limiting, CORS default, JSON error encoding) and add an HA deployment guide.

**Architecture:** All changes are in existing files — no new packages, no new dependencies. The rate limiter uses stdlib `sync` + `time` only. HA support is purely documentation (active-active with shared PostgreSQL requires no code changes).

**Tech Stack:** Go 1.26, `encoding/json`, `sync`, `time` (all stdlib)
Comment on lines +1 to +16
# Design: feature/ai-agent-support

**Date:** 2026-05-30
**Branch:** `feature/ai-agent-support`
**Status:** Approved

## Overview

Add two AI agent integration surfaces to acme-dns:

1. **OpenAPI 3.1 spec** — served at `GET /openapi.json`, enables any OpenAPI-aware agent or tool to discover and call the API via function calling
2. **MCP server binary** — `cmd/acme-dns-mcp/`, a standalone stdio-based MCP server that wraps the acme-dns HTTP API as structured tools for Claude and other MCP-capable agents

The core acme-dns server is minimally changed. The MCP server is a separate binary that proxies to the HTTP API — it has no direct DB or DNS access.

**Dependency:** This branch builds on `feature/dns-api-extended`. The OpenAPI spec and MCP tools for admin record management (`list_dns_records`, `create_dns_record`, `update_dns_record`, `delete_dns_record`) require the admin API from that branch to be merged first, or this branch should be built on top of it.
Comment on lines +1 to +9
# Security Hardening and HA Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Fix five security issues in the acme-dns codebase (SQL injection, bcrypt cost, rate limiting, CORS default, JSON error encoding) and add an HA deployment guide.

**Architecture:** All changes are in existing files — no new packages, no new dependencies. The rate limiter uses stdlib `sync` + `time` only. HA support is purely documentation (active-active with shared PostgreSQL requires no code changes).

**Tech Stack:** Go 1.26, `encoding/json`, `sync`, `time` (all stdlib)
@ZPascal ZPascal assigned ZPascal and unassigned ZPascal May 31, 2026
@ZPascal ZPascal force-pushed the feature/dns-api-extended branch from d8fbc00 to e929f6d Compare May 31, 2026 20:07
ZPascal added 2 commits May 31, 2026 22:44
…g, RR validation, DB index

- CORS: restore X-Api-User and X-Api-Key to AllowedHeaders (required by /update endpoint)
- api: normalize record names to FQDN (trailing dot) on create/update/list-filter so DNS
  lookups against q.Name (which always ends with dot) match stored records
- api: normalize type filter to uppercase for case-insensitive GET /admin/records?type=
- api: add probeRR helper — validates record value parses as a real DNS RR before storing,
  preventing values that are silently dropped at serve time
- dns: guard answerManaged against unknown QTYPEs (empty TypeToString result)
- dns: quote TXT and CAA values in RR string so values with spaces parse correctly
- db: add index on dns_records(name, type) to avoid full table scans on every DNS request
@ZPascal ZPascal force-pushed the feature/dns-api-extended branch from e929f6d to c941f89 Compare May 31, 2026 20:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants