Files
config/doc/audit.md
T
2026-09-28 16:55:58 -04:00

5.3 KiB

Config audit and TOML migration

This branch updates only lixenwraith/config. It uses Go 1.27.1 and the user's merged TOML main commit b59d068ff6a48b86365a65e1121343f672f77a67, pinned as v0.0.0-20260928180512-b59d068ff6a4 because no version tag existed at integration. Logwisp adoption and other TOML consumers are separate follow-up work.

Confirmed defects and fixes

Finding Result Regression evidence
Fractions/overflow could pass through weak numeric conversion Checked TOML conversion and explicit destination-width parsing TestCheckedConversionsAndRollback, FuzzConfigNumericConversions
Options, input containers and returned values could alias caller state Owned options/values and detached reads/clones TestOptionsAreOwned, TestOwnedValuesAndSnapshots
Updating the cached target changed old AsStruct results Immutable cached result and a fresh snapshot per call TestOwnedValuesAndSnapshots
ExportEnv compared uncomparable slices/maps directly Deep equality, with callbacks outside Config locks TestExportEnvContainerValues
Invalid sources could be published before decoding failed Whole-source validation before mutation TestSourceReplacementIsTransactional
Removed env/CLI values survived subsequent loads Successful loads replace their complete source TestSourceReplacementIsTransactional
A timed-out reload kept running and could publish after stop Context, watcher identity, path and generation checked at commit TestReloadCannotPublishAfterStopTimeoutOrNewLoad
A timeout could suppress retries of unchanged content Retry timeouts while deduplicating their notifications TestWatcherRetriesTimedOutUnchangedContent
Debounce did not cover errors from partial in-place writes Errors and successful updates wait for a quiet interval TestWatcherDebouncesErrorsAndRecovers
Metadata-only polling missed some replacements/edits Content fingerprints on every poll; deletion/recreation recovery TestWatcherSameMetadataReplacementAndRecreation
Source saving lost comments and widened permissions Comment preamble, existing modes retained, new files 0600 TestSaveCommentsPermissionsAndFailure
Atomic types were inconsistently registered/serialized Exact type matching for duration/time/IP/CIDR/URL and pointer forms TestAtomicValuesAndFileRoundTrip
A missing file could hide a joined invalid CLI/environment error Missing-file fallback only when other sources succeed TestBuilderDoesNotHideInvalidSourceBehindMissingFile
Required registration was a no-op; overlapping/duplicate fields were ambiguous Required paths validated at Build; staged registration rejects conflicts TestRegistrationAndRequiredContracts
Default source selection and narrow target schemas could be inconsistent Default precedence honored; explicit defaults must match the typed target TestRegistrationAndRequiredContracts

Reproduction against original main ccd280b: fractional-to-integer conversion silently produced 1 from 1.5; modifying an input slice changed its registered default; an out-of-range CLI batch returned success; and requesting a refreshed AsStruct changed an earlier result under its reader. All four were reproduced with public-API probes; committed regressions cover the corrected behavior.

Dependency and scope decision

Mapstructure is replaceable for the package's actual object model. The replacement supports TOML field names, ordinary containers, pointers and the existing standard atomic types. It does not reproduce mapstructure's broad weak coercions or add a custom hook API. Numeric correctness is shared with lixenwraith/toml.

go list -deps ./... reports only the standard library, lixenwraith/toml and this module. BurntSushi TOML, mapstructure and YAML are removed from runtime code. Testify remains test-only, so its transitive YAML dependency still appears in go.mod and go.sum. JSON/YAML files and tags are unsupported, with explicit rejection tests.

No global reflection cache or lock was introduced. Known container sizes are used for allocation. Stored values are immutable after admission. One watcher worker owns observation/debounce state, and subscription cleanup has no per-subscriber goroutine. File I/O and environment callbacks execute outside Config locks.

Verification and limits

The full unit and race suites and go vet pass with Go 1.27.1. Numeric fuzzing ran for 10 seconds and passed 234,155 executions, covering full uint64 preservation, signed boundaries and narrowing. The 386 and Windows test binaries cross-compile locally. This host cannot execute 386 binaries; CI executes that suite and also runs race tests, vet, fuzzing and Windows compilation. Final checks are on the PR.

TOML's supported subset is unchanged. Native datetime syntax is not added; time.Time is represented by a quoted RFC3339Nano string. Full uint64 works in memory but values above MaxInt64 cannot be saved as TOML integers. Comment text survives as a preamble; locations and formatting do not. Unknown file keys are not saved. Depth is bounded at 128 for configuration graphs. Live application validators remain an application responsibility; Builder validators run only during initialization. Notifications are best effort, and file timeouts prevent late publication without forcibly interrupting kernel I/O. See the linked topic guides for migration details.