Changelog
New Features
- 8f1fd72: feat(config): add case-insensitive YAML key normalizer with fuzzy suggestions (@almeidapaulopt)
- c00a0ce: feat(config): add provider-level validation guardrails (@almeidapaulopt)
- 4922499: feat(docker): integrate SSH tunnel into Docker target provider (@almeidapaulopt)
- dbaff21: feat(lifecycle): add internal/lifecycle package with Status and StateTracker (@almeidapaulopt)
- 8fb3f86: feat(model): add mode-aware proxy config validation (@almeidapaulopt)
- f5bf9ad: feat(sshtunnel): add SSH tunnel package for remote Docker daemon access (@almeidapaulopt)
- 36ed6d4: feat: add X-Real-IP header forwarding with anti-spoofing (@almeidapaulopt)
Bug fixes
- e4ba716: fix(config): preserve AuthKey in ClearSecrets for runtime per-proxy resolution (@almeidapaulopt)
- 963f9d3: fix(dashboard): trust Tailscale CGNAT addresses in IsTrustedSource (@almeidapaulopt)
- 030c3ac: fix(lint): resolve 23 golangci-lint warnings and fix test failures (@almeidapaulopt)
- e7259e4: fix(lint): resolve cyclop and mnd warnings in keynormalizer (@almeidapaulopt)
- e355621: fix(lint): resolve goconst and gosec warnings in config tests (@almeidapaulopt)
- 00b664c: fix(proxymanager): handle localhost hostname in isManagementTarget (@almeidapaulopt)
- 084668c: fix(proxymanager): route TCP ports through RawTCPListener interface (@almeidapaulopt)
- ed287fd: fix(proxymanager): show proxies in dashboard during Tailscale auth (@almeidapaulopt)
- de20510: fix(security): reject null bytes and absolute paths in validateDatadir (@almeidapaulopt)
- d4658b0: fix(security): skip online devices in VIP service conflict resolution (@almeidapaulopt)
- 434819b: fix(security): stop leaking auth token to proxied backends (@almeidapaulopt)
- e8200b7: fix(security): strip spoofed X-Forwarded-For in reverse proxy (GHSA-pqg7-v6wh-3pfp) (@almeidapaulopt)
- 2bb6334: fix(tailscale): deduplicate concurrent TLS cert IPC with singleflight (@almeidapaulopt)
- 3caebe5: fix(tailscale): defend cert helpers against typed-nil interface panics (@almeidapaulopt)
- 3f93a53: fix(tailscale): defend whoisFromAddr against typed-nil interface panics (@almeidapaulopt)
- 15456ae: fix(tailscale): defer release reply until VIP service cleanup completes (@almeidapaulopt)
- 1ecb6de: fix(tailscale): force-clean online devices when local state is missing (@almeidapaulopt)
- 85ed9c7: fix(tailscale): serialize ListenService calls to prevent etag mismatch race (@almeidapaulopt)
- 4511205: fix(tailscale): trigger lazy init before accessing client.BaseURL in service device approval (@almeidapaulopt)
- e126e8c: fix(targetproviders): add ErrTargetNotFound sentinel (@almeidapaulopt)
Documentation updates
- 0c562e8: docs(agents): add config and tlsproviders AGENTS.md, update root structure (@almeidapaulopt)
- 2fcdb82: docs: add SSH tunnel configuration to v3 docs (@almeidapaulopt)
- 2e6fdcc: docs: add v2.3.1 and v2.3.2 changelog entries (@almeidapaulopt)
Build process updates
- 9c37be4: build(deps): bump codeberg.org/miekg/dns from 0.6.79 to 0.6.80 (#471) (@dependabot[bot])
- b5e8597: build(deps): bump tailscale.com from 1.98.5 to 1.100.0 (#469) (@dependabot[bot])
Other work
- d9e078b: fix(targetproviders/docker): remove stale ctx, signal disconnect, normalize hostname (@almeidapaulopt)
- 2218664: fix(targetproviders/docker): sort legacy ports numerically (@almeidapaulopt)
- 402dd66: fix(targetproviders/list): fix missing return, data race, and event dropping (@almeidapaulopt)
- 4552e25: refactor(config): add debounce to config file watcher (@almeidapaulopt)
- 26422da: refactor(config): wire keynormalizer into File.Load (@almeidapaulopt)
- d87beec: refactor(core): move FormatDuration to core/format.go (@almeidapaulopt)
- ef0ab8e: refactor(dashboard): improve SSE stream with resync and client prefs (@almeidapaulopt)
- 33f46a6: refactor(dns,tls): consolidate status types to lifecycle.Status (@almeidapaulopt)
- 6724147: refactor(docker): propagate context in target provider (@almeidapaulopt)
- 04adf37: refactor(tailscale): add isNilInterface helper for typed-nil defense (@almeidapaulopt)
- 277dd3d: refactor(tailscale): improve shared server state machine and idle handling (@almeidapaulopt)
- 6aeec75: refactor(tailscale): reduce cyclomatic complexity to satisfy cyclop linter (@almeidapaulopt)
- 80c7348: refactor(tailscale): reorder SharedSNIExposure struct fields (@almeidapaulopt)
- 01b4b59: refactor(tailscale): use consts.HeaderXForwardedFor in services_server (@almeidapaulopt)
- d4c57c9: refactor(tls): enhance Tailscale TLS provider with DataDir and MaxCertConcurrency (@almeidapaulopt)
- 9be34b9: refactor(webhook): simplify Sender close state to mutex-only (@almeidapaulopt)
- 1064d66: refactor: deduplicate identity header strip lists into shared constants (@almeidapaulopt)
- e46059b: style: reorder struct fields, use errors.New for static strings, fix indentation (@almeidapaulopt)
- 8f77d04: test(api): add REST API unit tests (@almeidapaulopt)
- ce811dc: test(config): add unit tests for File load, save, watch lifecycle (@almeidapaulopt)
- 5075a3a: test(config): add unit tests for secrets and provider generation (@almeidapaulopt)
- 4f59842: test(core): add unit tests for HTTP server, logging, health, and format (@almeidapaulopt)
- a0869c4: test(core): add unit tests for SecretString leak prevention (@almeidapaulopt)
- cffd1b4: test(core): harden admin tests with subtest isolation and IP coverage (@almeidapaulopt)
- 4e4bb89: test(core/metrics): add metrics middleware unit tests (@almeidapaulopt)
- 8415ac3: test(dashboard): add dashboard preferences and SSE unit tests (@almeidapaulopt)
- 58945a8: test(docker): add unit tests for label parsing and proxy config helpers (@almeidapaulopt)
- 582e617: test(e2e): add REST API, dashboard actions, and metrics tests (@almeidapaulopt)
- a278aee: test(e2e): add SSE, webhook, health config, and verbose control tests (@almeidapaulopt)
- 54eb5b0: test(e2e): add SSH Docker host e2e test (@almeidapaulopt)
- 1118821: test(e2e): add Tailscale device and VIP service cleanup via OAuth API (@almeidapaulopt)
- 35f49c7: test(e2e): add auth, identity, and access control tests (@almeidapaulopt)
- de364f1: test(e2e): add ephemeral label to httpLabels helper (@almeidapaulopt)
- 53e7471: test(e2e): add port range, UDP, and concurrent stress tests (@almeidapaulopt)
- 76b511e: test(e2e): add services mode and shared Tailscale FQDN tests (@almeidapaulopt)
- c157e5f: test(e2e): prevent env leakage, fix tag mismatch, and harden flaky tests (@almeidapaulopt)
- c97b802: test(lifecycle): add StatusTracker unit tests (@almeidapaulopt)
- a0b6570: test(proxymanager): add comprehensive proxy manager, health, and port unit tests (@almeidapaulopt)
- 061e2de: test(tailscale): add exposure, retry policy, and services server unit tests (@almeidapaulopt)
- 83223ae: test(targetproviders): add Docker and list target provider unit tests (@almeidapaulopt)
- 4dea479: typo (@almeidapaulopt)