feat: validate configuration on startup, fail fast on bad config (closes #52) #53

Merged
sneak merged 11 commits from feature/config-validation into main 2026-08-07 22:39:40 +02:00

11 Commits

Author SHA1 Message Date
22f19c849b style: use the config key error-message convention for signing_key
All checks were successful
check / check (push) Successful in 1m48s
The signing_key errors used bare phrasing while every other validation
error follows the 'config key %q' convention; align them. The secret
value itself is still never echoed.
2026-08-07 17:04:08 +00:00
83fa22871e fix: reject allowlist_hosts entries containing no hostname labels
Entries consisting only of dots (".", "..") are now a startup error
naming the key and entry. Previously a bare "." passed validation and
became a suffix pattern matching every trailing-dot FQDN upstream,
bypassing URL signing.
2026-08-07 17:03:50 +00:00
808356f142 test: allowlist_hosts must reject dot-only entries (PR #53 rework)
A bare "." entry becomes a HasSuffix suffix pattern that matches any
upstream written in FQDN trailing-dot form (evil.com.), effectively
disabling URL signing with one character. Failing test first, fix
follows.
2026-08-07 17:03:32 +00:00
5297e6033a fix: abort startup on explicitly empty db_url instead of deriving
The derived file:...state.sqlite3 URL is a default and defaults apply
only to omitted keys: db_url set to an empty string now aborts naming
the key, matching the existing behavior of state_dir: "".
2026-08-07 17:03:12 +00:00
813ff63153 test: explicitly empty db_url must abort startup (PR #53 rework)
db_url: "" currently silently derives the state_dir-based sqlite URL,
which is a default applied to a SET value; state_dir: "" already
aborts. Failing test first, fix follows.
2026-08-07 17:02:44 +00:00
c0d325156f fix: abort startup when a config key is explicitly set to null
An explicitly-null key (port: null, bare port:, debug: ~, metrics
subkeys, and every other known key) previously fell through the ok/nil
check in the strict getters and silently took the default, violating
the no-silent-fallback rule and contradicting metrics: null which
already aborted. validateKnownKeys now collects null-valued keys (top
level and metrics subkeys) and aborts naming each one, and the strict
getters and validateAllowlistHostsValue error on null instead of
defaulting as defense in depth. This also replaces the unhelpful
'value <nil> is not a map of metrics settings' rendering for
metrics: null with the null-specific message.
2026-08-07 17:02:16 +00:00
370545997f test: explicit null config values must abort startup (PR #53 rework)
An explicitly-null key (port: null, bare port:, debug: ~, and every
other config key including metrics subkeys) is a SET value under the
no-silent-fallback rule and must abort startup naming the key, instead
of silently taking the default as it does today. All 13 subtests fail
against the current behavior; the fix follows.
2026-08-07 17:01:16 +00:00
11e9206c21 fix: suppress gosec G703 false positive on state_dir probe removal
The pinned CI linter (golangci-lint v2.10.1) flags os.Remove(probePath)
in ensureStateDirWritable as G703 path traversal via taint analysis.
probePath comes from os.CreateTemp inside the StateDir that the probe
just validated, so the taint finding is a false positive; suppress it
with a justified nolint comment matching the existing precedent in
loadConfigFile. Verified against the pinned linter version via the
Dockerfile lint stage (0 issues).
2026-08-07 17:00:20 +00:00
745a461688 Merge origin/main into feature/config-validation (TODO.md bookkeeping) 2026-08-07 16:57:44 +00:00
2fb0801dc6 feat: validate configuration on startup, fail fast on bad config (closes #52)
Some checks failed
check / check (push) Failing after 42s
A config value that is set but unparseable or invalid now aborts
startup with an error naming the offending key and value; defaults
apply only to omitted keys. Unknown top-level config keys and unknown
metrics subkeys abort startup naming each unknown key, so typos like
whitelist_hosts fail immediately instead of being silently ignored. A
config file that exists at a standard location but fails to parse is
now a fatal error instead of being skipped with a warning. state_dir
is verified creatable and writable with a probe file before the
listener binds. Port must be in 1-65535 (fractional values are
rejected, not truncated), upstream_connections_per_host must be at
least 1, allowlist_hosts entries must be bare hostnames, sentry_dsn
must be a valid URL when set, and metrics credentials must be set
together. The stale signing_key comment in config.example.yml (keyless
mode was never implemented) now states the actual requirement.
TODO.md records the completed step per its Workflow section.
2026-08-07 16:37:30 +00:00
f19da2c02c test: add failing startup config validation tests (#52)
Encode the required fail-fast behavior as tests ahead of the
implementation: a config value that is SET but unparseable or invalid
must abort startup (defaults apply only to OMITTED keys), unknown
top-level keys and unknown metrics subkeys must abort naming the key,
a malformed config file at a standard location must abort instead of
being skipped with a warning, and state_dir must be creatable and
writable at startup. Mechanically extracts newFromSmartConfig from
config.New so the construction path is testable without fx; current
lenient behavior is unchanged, so the new enforcement tests fail.
2026-08-07 16:31:03 +00:00