feat: fail fast when no monitoring targets configured #75

Merged
sneak merged 1 commits from fix/issue-69-empty-targets-validation into main 2026-03-02 01:26:56 +01:00
Collaborator

Summary

When DNSWATCHER_TARGETS is empty (the default), dnswatcher previously started successfully and ran indefinitely monitoring nothing. This is a common misconfiguration — forgetting to set the variable or making a typo in its name — and gave no indication anything was wrong.

Changes

  • Added ErrNoTargets sentinel error in internal/config/config.go
  • Extracted parseAndValidateTargets() helper to validate that at least one domain or hostname is configured after target classification
  • If no targets are configured, dnswatcher now exits with a clear error: "no monitoring targets configured: set DNSWATCHER_TARGETS environment variable"
  • Updated README.md to document that DNSWATCHER_TARGETS is required and dnswatcher will refuse to start without it

How it works

The validation runs during config construction (via uber/fx), before the watcher or any other component starts. If DNSWATCHER_TARGETS is empty or contains only whitespace/empty entries, buildConfig() returns ErrNoTargets, which causes fx to fail startup with a clear error message.

This is fail-fast behavior: a monitoring daemon with nothing to monitor is a misconfiguration and should not silently run.

Closes #69

## Summary When `DNSWATCHER_TARGETS` is empty (the default), dnswatcher previously started successfully and ran indefinitely monitoring nothing. This is a common misconfiguration — forgetting to set the variable or making a typo in its name — and gave no indication anything was wrong. ## Changes - Added `ErrNoTargets` sentinel error in `internal/config/config.go` - Extracted `parseAndValidateTargets()` helper to validate that at least one domain or hostname is configured after target classification - If no targets are configured, dnswatcher now exits with a clear error: `"no monitoring targets configured: set DNSWATCHER_TARGETS environment variable"` - Updated README.md to document that `DNSWATCHER_TARGETS` is required and dnswatcher will refuse to start without it ## How it works The validation runs during config construction (via uber/fx), before the watcher or any other component starts. If `DNSWATCHER_TARGETS` is empty or contains only whitespace/empty entries, `buildConfig()` returns `ErrNoTargets`, which causes fx to fail startup with a clear error message. This is fail-fast behavior: a monitoring daemon with nothing to monitor is a misconfiguration and should not silently run. Closes https://git.eeqj.de/sneak/dnswatcher/issues/69
clawbot added 1 commit 2026-03-02 01:00:37 +01:00
feat: fail fast when no monitoring targets configured
All checks were successful
check / check (push) Successful in 45s
792304e1e4
clawbot added the botneeds-review labels 2026-03-02 01:00:45 +01:00
clawbot self-assigned this 2026-03-02 01:01:51 +01:00
clawbot added merge-ready and removed botneeds-review labels 2026-03-02 01:03:59 +01:00
clawbot removed their assignment 2026-03-02 01:03:59 +01:00
sneak was assigned by clawbot 2026-03-02 01:04:00 +01:00
sneak merged commit e882e7d237 into main 2026-03-02 01:26:56 +01:00
sneak deleted branch fix/issue-69-empty-targets-validation 2026-03-02 01:26:56 +01:00
Author
Collaborator

Review: PASS

Summary

Clean, minimal implementation of fail-fast validation when DNSWATCHER_TARGETS is empty. Correctly addresses issue #69.

Code Review

internal/config/config.go (+26/-4)

  • ErrNoTargets sentinel error: exported, descriptive message, good practice
  • parseAndValidateTargets() helper: cleanly extracted from buildConfig(), preserves the existing ClassifyTargets error wrapping, adds len(domains) == 0 && len(hostnames) == 0 check
  • Validation runs during config construction (via uber/fx) before watcher starts — true fail-fast
  • Edge cases handled: empty string, whitespace-only, and empty CSV entries are all stripped by parseCSV() before reaching validation

README.md (+6/-0)

  • Documents that DNSWATCHER_TARGETS is required and dnswatcher will refuse to start without it

Verification

  • docker build .PASS (all tests green)
  • No test files modified — no test weakening
  • Existing behavior unchanged when targets ARE configured
  • One clean commit, properly scoped

Notes

  • No unit test added for parseAndValidateTargets(), but acceptable: it is unexported, the validation is a trivial length check, and ClassifyTargets is already well-tested in classify_test.go.
  • Observed a transient flake in TestQueryNameserver_TXT (live DNS — google.com TXT returned empty from one nameserver). Unrelated to this PR; passed on retry. Pre-existing issue tracked separately.
## Review: ✅ PASS ### Summary Clean, minimal implementation of fail-fast validation when `DNSWATCHER_TARGETS` is empty. Correctly addresses issue #69. ### Code Review **`internal/config/config.go`** (+26/-4) - `ErrNoTargets` sentinel error: exported, descriptive message, good practice ✅ - `parseAndValidateTargets()` helper: cleanly extracted from `buildConfig()`, preserves the existing `ClassifyTargets` error wrapping, adds `len(domains) == 0 && len(hostnames) == 0` check ✅ - Validation runs during config construction (via uber/fx) before watcher starts — true fail-fast ✅ - Edge cases handled: empty string, whitespace-only, and empty CSV entries are all stripped by `parseCSV()` before reaching validation ✅ **`README.md`** (+6/-0) - Documents that `DNSWATCHER_TARGETS` is required and dnswatcher will refuse to start without it ✅ ### Verification - `docker build .` — **PASS** (all tests green) - No test files modified — no test weakening ✅ - Existing behavior unchanged when targets ARE configured ✅ - One clean commit, properly scoped ### Notes - No unit test added for `parseAndValidateTargets()`, but acceptable: it is unexported, the validation is a trivial length check, and `ClassifyTargets` is already well-tested in `classify_test.go`. - Observed a transient flake in `TestQueryNameserver_TXT` (live DNS — google.com TXT returned empty from one nameserver). Unrelated to this PR; passed on retry. Pre-existing issue tracked separately.
Sign in to join this conversation.