Commit Graph
8 Commits
Author SHA1 Message Date
clawbot 67b67b8475 resolver, watcher: a domain's nameservers are only its own delegation (closes #222)
check / check (push) Canceled after 0s
When a domain's parent zone's servers answer NXDOMAIN, LookupNS returns
ErrNXDomain. The watcher then saves the domain with no nameservers and
nxdomain set, shown on the dashboard and in /api/v1/status, asks for none
of its records and removes those saved, so its old nameservers go in one
NS Change. A domain with no delegation of its own gets an empty set and
its records are still asked at the zone it is in.
FindAuthoritativeNameservers moves to a parent name only on one of those
two answers; when the servers do not answer, it returns the error. After
an upgrade, a domain without its own delegation that was saved with its
parent zone's nameservers gets one NS Change; the README says so.

Model: opus-5-5
2026-10-02 12:38:45 +02:00
clawbot b43402a631 dashboard and status API list a port's domains apart from its hostnames (closes #245)
check / check (push) Canceled after 0s
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 10:31:07 +02:00
clawbot e46db71821 dashboard, status API and notifications tell apex domains from hostnames (closes #224)
check / check (push) Canceled after 0s
An apex domain's own records are still saved with the hostnames'
records, under the domain's name, so the port and TLS checks find its
addresses. Notifications about them now start `Domain:`, decided by the
configured domains. The dashboard and /api/v1/status, which read only
the saved state, take a hostname entry whose name also has a domain
entry as that domain's own records: the dashboard shows them in a second
table under Domains, the API in the domain's `recordsByNameserver`, and
neither lists or counts them as hostnames. The startup notification
counts domains and hostnames from the configuration. README says which
of a domain's own records are watched and how their changes are
notified.

Model: opus-5-5
2026-10-02 10:08:32 +02:00
clawbot 1218df9467 dashboard: list record types in the README's order (closes #226)
check / check (push) Canceled after 0s
Each row of the Hostnames table listed a nameserver's record types in
the order Go happens to walk the record map, which changed from row to
row and on every page load, so two nameservers with the same records
looked different. formatRecords now sorts the types by their place in
the README's list (A, AAAA, CNAME, MX, TXT, SRV, CAA, NS); any other
type comes after them in alphabetical order. Values within a type were
already sorted by the resolver.

Model: opus-5-5
2026-10-02 09:55:07 +02:00
clawbot 250f3dd687 dashboard and status API show why a check failed (closes #225)
check / check (push) Canceled after 0s
/api/v1/status now gives `error` for each nameserver entry and
certificate entry whose status is `error`, copied from the state, which
already kept it. The dashboard shows that reason in place of the records
for a failed nameserver, which used to show the same `-` as one that
answered with no records, and across the CN, issuer and expiry cells
for a failed certificate, wrapped at a width of 20rem so the long TLS
error does not narrow the Endpoint column. The dashboard stylesheet is a
trimmed build, so the new markup uses only classes the page already had.
README Web Dashboard and HTTP API say so.

Model: opus-5-5
2026-10-02 09:14:28 +02:00
clawbotandclawbot b64db3e10f feat: enhance /api/v1/status endpoint with full monitoring data (#86)
check / check (push) Successful in 1m27s
## Summary

Enhances the `/api/v1/status` endpoint to return comprehensive monitoring state instead of just `{"status": "ok"}`.

## Changes

The endpoint now returns:

- **Summary counts**: domains, hostnames, ports (total + open), certificates (total + ok + error)
- **Domains**: each monitored domain with its discovered nameservers and last check timestamp
- **Hostnames**: each monitored hostname with per-nameserver DNS records, status, and last check timestamps
- **Ports**: each monitored IP:port with open/closed state, associated hostnames, and last check timestamp
- **Certificates**: each TLS certificate with CN, issuer, expiry, SANs, status, and last check timestamp
- **Last updated**: timestamp of the overall monitoring state

All data is derived from the existing `state.GetSnapshot()`, consistent with how the dashboard works. No configuration details (webhook URLs, API tokens) are exposed.

## Example response structure

```json
{
  "status": "ok",
  "lastUpdated": "2026-03-10T12:00:00Z",
  "counts": {
    "domains": 2,
    "hostnames": 3,
    "ports": 10,
    "portsOpen": 8,
    "certificates": 4,
    "certificatesOk": 3,
    "certificatesError": 1
  },
  "domains": { ... },
  "hostnames": { ... },
  "ports": { ... },
  "certificates": { ... }
}
```

closes #73

Co-authored-by: clawbot <clawbot@noreply.git.eeqj.de>
Reviewed-on: #86
Co-authored-by: clawbot <clawbot@noreply.example.org>
Co-committed-by: clawbot <clawbot@noreply.example.org>
2026-03-10 12:20:11 +01:00
1076543c23 feat: add unauthenticated web dashboard showing monitoring state and recent alerts (#83)
check / check (push) Successful in 4s
## Summary

Adds a read-only web dashboard at `GET /` that shows the current monitoring state and recent alerts. Unauthenticated, single-page, no navigation.

## What it shows

- **Summary bar**: counts of monitored domains, hostnames, ports, certificates
- **Domains**: nameservers with last-checked age
- **Hostnames**: per-nameserver DNS records, status badges, relative age
- **Ports**: open/closed state with associated hostnames and age
- **TLS Certificates**: CN, issuer, expiry (color-coded by urgency), status, age
- **Recent Alerts**: last 100 notifications in reverse chronological order with priority badges

Every data point displays its age (e.g. "5m ago") so freshness is visible at a glance. Auto-refreshes every 30 seconds.

## What it does NOT show

No secrets: webhook URLs, ntfy topics, Slack/Mattermost endpoints, API tokens, and configuration details are never exposed.

## Design

All assets (CSS) are embedded in the binary and served from `/s/`. Zero external HTTP requests at runtime — no CDN dependencies or third-party resources. Dark, technical aesthetic with saturated teals and blues on dark slate. Single page — everything on one screen.

## Implementation

- `internal/notify/history.go` — thread-safe ring buffer (`AlertHistory`) storing last 100 alerts
- `internal/notify/notify.go` — records each alert in history before dispatch; refactored `SendNotification` into smaller `dispatch*` helpers to satisfy funlen
- `internal/handlers/dashboard.go` — `HandleDashboard()` handler with embedded HTML template, helper functions (`relTime`, `formatRecords`, `expiryDays`, `joinStrings`)
- `internal/handlers/templates/dashboard.html` — Tailwind-styled single-page dashboard
- `internal/handlers/handlers.go` — added `State` and `Notify` dependencies via fx
- `internal/server/routes.go` — registered `GET /` route
- `static/` — embedded CSS assets served via `/s/` prefix
- `README.md` — documented the dashboard and new endpoint

## Tests

- `internal/notify/history_test.go` — empty, add+recent ordering, overflow beyond capacity
- `internal/handlers/dashboard_test.go` — `relTime`, `expiryDays`, `formatRecords`
- All existing tests pass unchanged
- `docker build .` passes

closes [#82](#82)

<!-- session: rework-pr-83 -->

Co-authored-by: user <user@Mac.lan guest wan>
Co-authored-by: clawbot <clawbot@noreply.git.eeqj.de>
Reviewed-on: #83
Co-authored-by: clawbot <clawbot@noreply.example.org>
Co-committed-by: clawbot <clawbot@noreply.example.org>
2026-03-04 13:03:38 +01:00
sneak 144a2df665 Initial scaffold with per-nameserver DNS monitoring model
Full project structure following upaas conventions: uber/fx DI, go-chi
routing, slog logging, Viper config. State persisted as JSON file with
per-nameserver record tracking for inconsistency detection. Stub
implementations for resolver, portcheck, tlscheck, and watcher.
2026-02-19 21:05:39 +01:00