check / check (push) Successful in 1m9s
Stopping dnswatcher during a DNS check logged every lookup the stop cut short as an error, "context canceled". The four places in the watcher that log a failed lookup, checkDomain, checkHostname, resolveNameserverAddresses and resolveCNAMEAddresses, now do it through logFailedLookup, which logs nothing when the watcher's context was cancelled. It asks the context, not the lookup's error: the resolver reports a cancelled lookup with its own error, which does not wrap context.Canceled. A context whose deadline passed is not cancelled, so a lookup that ran out of time is still logged. The tests run each of these lookups on a cancelled context and on one whose deadline passed; neither sends a query. Model: opus-5-5
159 lines
9.8 KiB
Markdown
159 lines
9.8 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 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
|