From a36a5504fa82f2b4b9cdc55b020cf740952fc329 Mon Sep 17 00:00:00 2001 From: Daniel Carrillo Date: Tue, 21 Jul 2026 18:40:56 +0200 Subject: [PATCH] chore: Add AGENTS.md --- AGENTS.md | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..15cf002 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,67 @@ +# whatismyip + +Single-binary Go service: HTTP/TLS/QUIC server that returns the client's IP, geolocation, ASN, headers, TCP port scan, and DNS discovery. Uses [gin](https://github.com/gin-gonic/gin) + [httprouter](https://github.com/julienschmidt/httprouter). Requires Go >= 1.25. + +## Commands + +```sh +make build # CGO_ENABLED=0 build -ldflags "-s -w" -> ./whatismyip +make unit-test # go test -count=1 -race -short -cover ./... +make integration-test # requires Docker; runs separate module (integration-tests/) +make test # unit-test + integration-test +make lint # gofmt -l + golangci-lint + shadow (auto-installs tools) +make docker-run # builds & runs container exposing :8080 :8081 :9100 +make docker-push VERSION=x.y.z # tagged release push (blocks devel builds) +``` + +**Order**: `lint -> unit-test -> integration-test`. Integration tests depend on testcontainers-go (needs Docker running). Integration tests are a separate Go module with its own `go.mod` — run from the `integration-tests/` directory. + +## Architecture + +``` +cmd/whatismyip.go # entrypoint: parses flags, wires servers, runs +├── server/server.go # Manager: Start/Stop/SIGHUP-reload for all server types +├── server/tcp.go # plain HTTP +├── server/tls.go # TLS/HTTP2 +├── server/quic.go # HTTP/3 (requires TLS server) +├── server/dns.go # micro-DNS server for discovery +├── server/prometheus.go # separate metrics endpoint +├── router/setup.go # Gin route registration +│ ├── router/generic.go # /, /client-port, /all, /json +│ ├── router/geo.go # /geo/*, /asn/* +│ ├── router/headers.go # /headers, /:header +│ ├── router/dns.go # DNS discovery HTTP handler +│ ├── router/port_scanner.go # /scan/tcp/:port +│ └── router/templates.go # embedded HTML template +├── service/geo.go # GeoIP lookup service (MaxMind MMDB) +├── service/port_scanner.go +├── resolver/setup.go # authoritative micro-DNS server (miekg/dns) +├── internal/setting/ # flag parsing + resolver YAML config +├── internal/httputils/ # header filtering and formatting +├── internal/metrics/ # Prometheus counters/histograms (opt-in) +├── internal/validator/uuid/ +├── internal/core/version.go +└── models/geo.go # GeoDB wrapper around oschwald/maxminddb-golang +``` + +## Key facts + +- **DNS discovery**: enabled via `-resolver test/resolver.yml`. The resolver is an authoritative DNS server answering for a subdomain. Clients prove their DNS provider by resolving `.dns.`. +- **Geo**: both `-geoip2-city` and `-geoip2-asn` required together (or omitted). Uses test DBs in `test/`. +- **Trusted headers**: `-trusted-header X-Real-IP` for proxy mode. When set without `-trusted-port-header`, client port shows "unknown". +- **SIGHUP**: reloads GeoIP databases and restarts all servers without full stop. +- **HTTP/3**: requires `-tls-bind`; reuses its port for UDP. +- **Prometheus**: separate process/port via `-metrics-bind`. Metrics prefixed `whatismyip_*`. +- **Port scan**: enabled by default; disable with `-disable-scan`. +- **Embedded template**: `router/templates.go` has the default `home` template. `-template` overrides. +- **Version**: injected at build via `-ldflags="-X 'github.com/dcarrillo/whatismyip/internal/core.Version=${VERSION}'"`. + +## Testing quirks + +- Integration tests need Docker (testcontainers-go) and will take longer. They run against a real containerized build. +- Unit tests in `internal/setting/`, `internal/httputils/`, `internal/metrics/`, `internal/validator/uuid/`, `models/`, `router/`, and `service/` use test DBs from `test/`. +- The router test reads `test/` resources by relative path — run from repo root. + +## Lint + +Uses `golangci-lint` v2 config (`.golangci.yaml`) with strict `revive` rules and `goimports` as formatter. One exception: `internal/metrics/` gets a pass on `var-naming` (package name conflicts with stdlib `metrics`). Also runs `shadow` and `gofmt -l -d`.