check / check (push) Canceled after 0s
LookupNS now follows the delegation for the domain alone. When the parent zone's servers answer that it has no delegation, as for a domain that does not exist, the set is empty, and the watcher's NS comparison reports every nameserver removed. FindAuthoritativeNameservers, used for hostnames, still moves to a parent name when the servers answer that the name has no delegation of its own, but returns the error when they do not answer, where it used to take a parent zone's nameservers. The fallback walk treats an authoritative answer the same way. A domain with no delegation still has its own records asked at the servers of the zone it is in. Model: opus-5-5
11 KiB
11 KiB
Workflow
- branch (from
next) - do the work in Next Step
- move Next Step to the top of Completed Steps
- move the top item of Future Steps into Next Step
- commit (
TODO.mdchanges in the same commit as the work) - push
- open a PR against
next
Status
pre-1.0. No git tags. Work lands on next by PR. Open work for 1.0 is tracked
on the 1.0 milestone: https://git.eeqj.de/sneak/dnswatcher/milestone/7
Next Step
trial run of the finished image: #149
Completed Steps
- 2026-10-02: a domain that does not exist has no nameservers, not its parent zone's; no name gets a parent's when its servers did not answer (closes #222).
- 2026-10-02: a record type whose query to a nameserver fails keeps its previous records and alerts nothing; the other types are still saved (closes #231).
- 2026-10-02: a Port Change notification lists the port's domains on a
Domains:line and its hostnames on aHostnames:line (closes #248). - 2026-10-02: the dashboard's Ports table and
/api/v1/statusport entries list a port's domains apart from its hostnames (closes #245). - 2026-10-02: nameservers a referral names without addresses are looked up,
three deep at most;
pool.ntp.org's nameservers resolve (closes #221). - 2026-10-02: an apex domain is not counted or listed as a hostname; its records
show under Domains, and notifications about them say
Domain:(closes #224). - 2026-10-02: the dashboard lists each nameserver's record types in one fixed order, the README's, then any other type, not a random one (closes #226).
- 2026-10-02: the dashboard and
/api/v1/statusshow why a nameserver query or a certificate check failed, which only the state file showed (closes #225). - 2026-10-02: a name's CNAME is stored once per nameserver, not once per record type asked for; a state file with repeats loads each value once (closes #220).
- 2026-10-02: a DNS lookup that shutdown cuts short logs no error; one that fails otherwise, or runs out of time, still does (closes #229).
- 2026-10-02: Record Change and Inconsistency notifications list only the record types that differ, each with its values as plain text (closes #219).
- 2026-10-02: the startup notification no longer says every notification endpoint works; it says it is a test sent to each of them (closes #230).
- 2026-10-02: a Mattermost webhook that answers an HTTP error is logged as
mattermost notification failed, not as a Slack failure (closes #227). - 2026-10-02: durations in the log are written as text such as
2m0s, not as a bare count of nanoseconds (closes #228). - 2026-10-02: a watched name whose nameservers answer with a CNAME and no address gets port and TLS checks at the end of its CNAME chain (closes #203).
- 2026-10-02: a resolver test that reads one record type from a nameserver's answer asks again when that type is missing from it (closes #218).
- 2026-10-02: a plain
docker build .of a clone stamps its tag or short commit, notdev: the build context now carries.git(closes #210). - 2026-10-02: a query a server refuses is not resent asking for recursion, and every root server refusing is reported as DNS interception (closes #206).
- 2026-10-02: a push to a branch cancels that branch's older CI run, and the
checkout leaves no token in
.git/config(closes #216). - 2026-10-02: watcher tests send far fewer queries and a live attempt may take 18s; nameserver addresses are asked only for A, AAAA, CNAME (closes #214).
- 2026-10-02: the resolver tries root servers, and every other server list it walks, in a random order each time, not always from the top (closes #138).
- 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 every TLS check, where some checks used to skip it at random (closes #204).
- 2026-10-01: a domain's NS set is its delegation from the parent zone's servers, not whichever of its own servers answered first (closes #200).
- 2026-10-01: README has Getting Started, Rationale and TODO sections, and its Architecture section is now Design, in the order policy sets (closes #173).
- 2026-10-01: a zone's server that answers SERVFAIL or a referral leading no closer is passed over for the next, as one that times out is (closes #197).
- 2026-10-01: when none of a configured name's nameservers answered, the port state saved for its addresses is kept, not removed (closes #193).
- 2026-10-01:
ResolveIPAddressesreturns an error, not no addresses, when no nameserver of the name's zone answered (closes #190). - 2026-10-01:
make fmtandmake fmt-checkcover Markdown with prettier, run in Docker at the version pinned byyarn.lock(closes #119). - 2026-10-01:
make fmt-checkfails on a filegoimportswould change; both format scripts rungoimportsat its pinned commit, not fromPATH(#119). - 2026-10-01: a hostname is queried at the servers of the zone it is in, found by following delegations for the name, not its last two labels (closes #189).
- 2026-10-01: each nameserver's addresses are saved with its domain, and a change while it stays in the delegation is notified (closes #105).
- 2026-10-01: the watcher saves state when it stops, and shutdown waits for that save, so it no longer relies on the state's own stop hook (closes #114).
- 2026-10-01:
DNSWATCHER_SENTRY_DSNreports panics in HTTP handlers to Sentry, and a DSN Sentry cannot parse stops startup (closes #107). - 2026-10-01: a port or TLS check that shutdown cuts short saves nothing and sends no notification, as a cut-short DNS lookup already did (closes #185).
- 2026-10-01: the client address from
X-Forwarded-Foris the last entry that is not a trusted proxy, not the first, which the client sets (closes #181). - 2026-10-01: a nameserver that does not answer is saved as
errorwith the reason, and NS failure and NS recovery are notified (closes #104). - 2026-10-01: a
DNSWATCHER_DNS_INTERVALorDNSWATCHER_TLS_INTERVALthat is not a positive duration stops startup; empty means the default (closes #177). - 2026-10-01:
/metricsallows each client address 30 requests a minute, counted before Basic Auth, and answers 429 beyond that (closes #101). - 2026-10-01: the image built by
make dockerreports thegit describeversion, notdev, and the startup log now shows it (closes #109). - 2026-10-01: two notify shutdown tests always release the delivery they hold, so a drain that returns early fails them instead of hanging (closes #176).
- 2026-10-01:
script/install-precommitasks git for the repository's git directory, somake hooksalso works where.gitis a file (closes #129). - 2026-10-01:
TODO.mdbrought up to date: open issues listed by URL, every Completed Steps entry cut to at most two lines (closes #146). - 2026-10-01: wildcard CORS now applies only to the public routes, not to
/metrics, and allows only the methods they serve (closes #100). - 2026-10-01:
internal/stateandinternal/watcherno longer export test-only constructors: two moved toexport_test.go, one is deleted (closes #111). - 2026-10-01: notify shutdown tests use one timing constant per meaning, name the bound they check, and require the drain's debug line (closes #116).
- 2026-09-29: the entrypoint chowns the data directory to
dnswatcherand runs dnswatcher as that user, so a host bind mount needs no chown (closes #166). - 2026-09-29: the live-DNS test package is renamed
internal/livednstest;make lintfails when program code imports it (closes #164). - 2026-09-29:
.golangci.ymlre-fetched fromsneak/prompts, withgomodguard_v2and the orgdepguardtest-supportrule (closes #123). - 2026-09-29: watcher and resolver tests that look something up in DNS use the real resolver against live DNS servers (closes #159).
- 2026-09-28: the inconsistency alert is sent once, when two nameservers start to disagree; every pair of nameservers is compared (closes #158).
- 2026-09-28: DNS names in record values (CNAME, MX, SRV and NS targets) are lower-cased, so letter case alone is not a change (closes #157).
- 2026-09-28: lint and tests run on every build:
script/cibuildandscript/dockerpass--no-cache-filter=lint,builder(closes #115). - 2026-09-28: the server timeout test drives
Runand checks the timeouts on thehttp.Serverit serves (closes #120). - 2026-09-28: upaas deploy readiness: the image runs as user
dnswatcherwith aHEALTHCHECK; README "Running under upaas" (closes #147). - 2026-09-21: added behavioural tests for
internal/globals,internal/healthcheck, andinternal/logger(closes #110). - 2026-09-21:
go mod tidydropped the redundantgolang.org/x/sync// indirectline soscript/bootstrapleaves a clean tree (#132) - 2026-08-10: comment-only corrections to
script/bootstrap,script/cibuildandDockerfile.lint; no behaviour changed. - 2026-08-10: MIT
LICENSEadded at the repository root; the README's first line and License section name the licence. - 2026-08-10: policy scaffold present:
REPO_POLICIES.md,.editorconfig,.dockerignore, CI workflow,make fmt-check,make docker,make hooks. - 2026-08-10: Go's test cache disabled in
script/test(-count=1), so every run queries live DNS; a failed run is rerun with-v. - 2026-08-10: live-DNS tests made robust rather than gated (#93): a limit on concurrent lookups, retries, and a quorum across nameservers.
- 2026-08-10: all linting moved into Docker:
script/lintbuildsDockerfile.lint, and the rootDockerfilehas its own lint stage. - 2026-08-09: in-flight notification deliveries are drained at shutdown, bounded by the shutdown deadline (#106).
- 2026-08-09:
http.Serversets all four socket timeouts;WriteTimeoutstays above the 60s handler timeout (#99). - 2026-08-09:
SecurityHeaders()middleware sets HSTS, CSP and the other security headersREPO_POLICIES.mdrequires on every response. - 2026-08-07: golangci-lint bumped to v2.12.2 and
.golangci.ymlset to the org config; fixed the resultinggoconst,duplandlllfindings. - 2026-07-07 Adopted scripts-to-rule-them-all:
script/entrypoints, Makefile shims, README Entrypoints section - 2026-02-20: iterative DNS resolver implemented
- 2026-02-20: CI actions and go install refs pinned to commit SHAs; Gitea Actions workflow added
- 2026-02-20: watcher monitoring orchestrator merged to main (#8)
- 2026-02-20: DOMAINS/HOSTNAMES unified into single TARGETS config (#11)
- 2026-02-19: TCP port connectivity checker, made concurrent with port validation; gosec G704 SSRF findings fixed without suppression
- 2026-02-19: TLS certificate inspector with no-peer-certificates error path and IP SANs
- 2026-02-19: gosec SSRF and formatting fixes on main
- 2026-02-19: initial scaffold with per-nameserver DNS monitoring model