1 Commits
Author SHA1 Message Date
sneak 251f05010f README: correct claims the code does not bear out (closes #108)
check / check (push) Successful in 1m28s
Checked every README claim against the code on next and fixed the ones
that were wrong or missing: what /metrics serves and when, what
DNSWATCHER_MAINTENANCE_MODE does, CORS on the public routes,
notification retries and the in-memory alert history, the certificate
error field and old port entries in the state file, and the Design
tree's missing files. Also corrected: CNAMEs are not followed for
watched names, the root server list is never refreshed, the NS set is
the delegation from the domain's parent zone, notification contents,
and the system resolver being used for webhooks. Code problems found
are filed separately.

Model: opus-5-5
2026-10-02 00:31:28 +00:00
4 changed files with 3 additions and 35 deletions
+1 -2
View File
@@ -352,8 +352,7 @@ following precedence (highest to lowest):
monitoring targets are configured. A monitoring daemon with nothing to monitor
is a misconfiguration, so dnswatcher fails fast with a clear error message
rather than running silently. Set `DNSWATCHER_TARGETS` to a comma-separated list
of DNS names before starting. A name listed more than once, in any letter case
or with a trailing dot, is watched once.
of DNS names before starting.
**`/metrics` is rate limited.** Each client address may send it 30 requests a
minute, failed logins included; beyond that it answers `429 Too Many Requests`
-2
View File
@@ -19,8 +19,6 @@ trial run of the finished image: https://git.eeqj.de/sneak/dnswatcher/issues/149
# Completed Steps
- 2026-10-02: a name listed more than once in `DNSWATCHER_TARGETS`, in any
letter case or with a trailing dot, is watched once (closes #207).
- 2026-10-01: README checked against the code and corrected: metrics, CORS,
notification retries, CNAMEs, state file fields, Design tree (closes #108).
- 2026-10-01: a certificate within the expiry warning period is warned about on
+2 -7
View File
@@ -57,22 +57,17 @@ func ClassifyDNSName(name string) (DNSNameType, error) {
// ClassifyTargets splits a list of DNS names into apex domains and
// hostnames using the Public Suffix List. It returns an error if any
// name cannot be classified. A name given more than once, in any letter
// case or with a trailing dot, is kept once.
// name cannot be classified.
func ClassifyTargets(targets []string) ([]string, []string, error) {
var domains, hostnames []string
seen := make(map[string]bool)
for _, t := range targets {
normalized := strings.ToLower(strings.TrimSuffix(strings.TrimSpace(t), "."))
if normalized == "" || seen[normalized] {
if normalized == "" {
continue
}
seen[normalized] = true
typ, classErr := ClassifyDNSName(normalized)
if classErr != nil {
return nil, nil, classErr
-24
View File
@@ -1,7 +1,6 @@
package config_test
import (
"slices"
"testing"
"sneak.berlin/go/dnswatcher/internal/config"
@@ -94,29 +93,6 @@ func TestClassifyTargets(t *testing.T) {
}
}
func TestClassifyTargetsKeepsEachNameOnce(t *testing.T) {
t.Parallel()
domains, hostnames, err := config.ClassifyTargets([]string{
"example.org",
"Example.org.",
"www.example.org",
"EXAMPLE.ORG",
"WWW.Example.org.",
})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if !slices.Equal(domains, []string{"example.org"}) {
t.Errorf("domains = %v, want [example.org]", domains)
}
if !slices.Equal(hostnames, []string{"www.example.org"}) {
t.Errorf("hostnames = %v, want [www.example.org]", hostnames)
}
}
func TestClassifyTargetsRejectsPublicSuffix(t *testing.T) {
t.Parallel()