check / check (push) Canceled after 0s
The port checks, which the first check after startup runs after its DNS checks, now also remove the domain and hostname entries of names no longer in DNSWATCHER_TARGETS, and the certificate entries of those names and of addresses a name no longer resolves to. A configured domain's own records, saved as a hostname entry under its name, are kept, and so are the certificate entries of a configured name none of whose nameservers answered, as its port entries already were. Nothing is notified. Model: opus-5-5
171 lines
11 KiB
Markdown
171 lines
11 KiB
Markdown
# 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: https://git.eeqj.de/sneak/dnswatcher/issues/149
|
|
|
|
# Completed Steps
|
|
|
|
- 2026-10-02: a name removed from `DNSWATCHER_TARGETS` leaves the state, and so
|
|
the dashboard and API, at the first check after startup (closes #223).
|
|
- 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:
|
|
https://git.eeqj.de/sneak/dnswatcher/issues/66
|
|
- review toward 1.0: https://git.eeqj.de/sneak/dnswatcher/issues/144
|