Files
dnswatcher/TODO.md
T
sneak bd9e3e27b9
check / check (push) Waiting to run
dashboard and status API list a port's domains apart from its hostnames (closes #245)
A port entry in the state saves the apex domains that resolve to its
address with its hostnames. The dashboard's Ports table now has a
Domains column next to Hostnames, and a port entry in /api/v1/status
has a `domains` list, with `hostnames` no longer holding a domain. A
name is taken as a domain when it has a domain entry, as the dashboard
and API already tell a domain's own records from a hostname's. Both
read the split from one function, buildPorts. The state file is
unchanged; README says its port `hostnames` include domains.

Model: opus-5-5
2026-10-02 08:18:21 +00:00

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.md changes 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: the dashboard's Ports table and /api/v1/status port 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/status show 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, not dev: 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: ResolveIPAddresses returns an error, not no addresses, when no nameserver of the name's zone answered (closes #190).
  • 2026-10-01: make fmt and make fmt-check cover Markdown with prettier, run in Docker at the version pinned by yarn.lock (closes #119).
  • 2026-10-01: make fmt-check fails on a file goimports would change; both format scripts run goimports at its pinned commit, not from PATH (#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_DSN reports 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-For is 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 error with the reason, and NS failure and NS recovery are notified (closes #104).
  • 2026-10-01: a DNSWATCHER_DNS_INTERVAL or DNSWATCHER_TLS_INTERVAL that is not a positive duration stops startup; empty means the default (closes #177).
  • 2026-10-01: /metrics allows 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 docker reports the git describe version, not dev, 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-precommit asks git for the repository's git directory, so make hooks also works where .git is a file (closes #129).
  • 2026-10-01: TODO.md brought 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/state and internal/watcher no longer export test-only constructors: two moved to export_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 dnswatcher and 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 lint fails when program code imports it (closes #164).
  • 2026-09-29: .golangci.yml re-fetched from sneak/prompts, with gomodguard_v2 and the org depguard test-support rule (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/cibuild and script/docker pass --no-cache-filter=lint,builder (closes #115).
  • 2026-09-28: the server timeout test drives Run and checks the timeouts on the http.Server it serves (closes #120).
  • 2026-09-28: upaas deploy readiness: the image runs as user dnswatcher with a HEALTHCHECK; README "Running under upaas" (closes #147).
  • 2026-09-21: added behavioural tests for internal/globals, internal/healthcheck, and internal/logger (closes #110).
  • 2026-09-21: go mod tidy dropped the redundant golang.org/x/sync // indirect line so script/bootstrap leaves a clean tree (#132)
  • 2026-08-10: comment-only corrections to script/bootstrap, script/cibuild and Dockerfile.lint; no behaviour changed.
  • 2026-08-10: MIT LICENSE added 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/lint builds Dockerfile.lint, and the root Dockerfile has 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.Server sets all four socket timeouts; WriteTimeout stays above the 60s handler timeout (#99).
  • 2026-08-09: SecurityHeaders() middleware sets HSTS, CSP and the other security headers REPO_POLICIES.md requires on every response.
  • 2026-08-07: golangci-lint bumped to v2.12.2 and .golangci.yml set to the org config; fixed the resulting goconst, dupl and lll findings.
  • 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

Future Steps

  • 1.0 readiness: run it with a real config and read the logs: #66
  • review toward 1.0: #144