Address 4 critical, 8 warning, and 5 suggestion findings from the security and bug review by creating atomic, dependency-ordered tasks: Critical fixes (C1-C4): rate limiter IP source (ADR-025), InFlightCounter increment + drain interval, connector timeout ceiling (ADR-026), JSON format without log file. Validation tightening (W1, W2): upstream host validation, ACME contact email validation. Robustness (W3, W4, W5, W12): upstream URI error handling (502 not silent drop), admin socket resource limits (ADR-027), TlsMode wildcard mismatch, http_port u32→u16. Code quality (W6, W10, W11, S1, S3, W8/W9): config type consolidation, TokenBucket field visibility, reload_mutex #[cfg(test)], dead code removal, root cert count logging, misleading test names. Test coverage (S10): rate limiter ConnectInfo tests (depends on C1 fix). Review: post-security-fix-review checkpoint covering all critical fixes and sensitive config consolidation path.
3.3 KiB
id, name, status, depends_on, scope, risk, impact, level, review_findings
| id | name | status | depends_on | scope | risk | impact | level | review_findings | ||
|---|---|---|---|---|---|---|---|---|---|---|
| fix/consolidate-config-types | Delete RawConfig and use FullConfig in load_config (W6, S5) | pending | narrow | medium | component | implementation |
|
Description
RawConfig (in src/cli.rs) and FullConfig (in src/config/mod.rs) have
identical fields and identical serde attributes. They exist because the initial
load path manually constructs StaticConfig + SerializableDynamicConfig,
while the reload path uses FullConfig::into_static_and_dynamic(). Any new
config field must be added in two places.
The fix is to delete RawConfig and use FullConfig in load_config. The
collect_sites helper can also be removed since into_static_and_dynamic
already collects sites from all listeners.
Changes Required
src/cli.rs:
- Delete the
RawConfigstruct (lines 49-65) - Rewrite
load_configto useFullConfig:pub fn load_config(cli: &Cli) -> Result<LoadedConfig> { let config_path = Path::new(&cli.config); let config_content = std::fs::read_to_string(config_path) .with_context(|| format!("failed to read config file: {}", cli.config))?; let full_config = crate::config::FullConfig::parse(&config_content) .with_context(|| format!("failed to parse config file: {}", cli.config))?; let (static_config, dynamic_config) = full_config.into_static_and_dynamic(); let allow_wildcard_bind = static_config.allow_wildcard_bind || cli.allow_wildcard_bind; validate(&static_config, &dynamic_config, cli.allow_wildcard_bind).map_err(|errors| { anyhow::anyhow!( "config validation failed:\n{}", errors.iter() .map(|e| format!(" - {}", e)) .collect::<Vec<_>>() .join("\n") ) })?; Ok(LoadedConfig { static_config, dynamic_config, allow_wildcard_bind, }) } - Delete the
collect_siteshelper function (lines 112-118) - Remove the now-unused imports:
SerializableDynamicConfig,BodyConfig,RateLimitConfig(if they're only used viaRawConfig)
src/config/mod.rs:
- No changes needed —
FullConfigalready hasinto_static_and_dynamic() - Verify
FullConfig::parseandinto_static_and_dynamicproduce identical results to the oldRawConfigpath
Acceptance Criteria
RawConfigstruct deleted fromsrc/cli.rscollect_sitesfunction deleted fromsrc/cli.rsload_configusesFullConfig::parse+into_static_and_dynamic- Startup config loading produces same results as before
- Config validation still runs on both startup and reload
- All existing
cli.rstests pass cargo testpassescargo clippypasses with no warnings
References
- docs/architecture/config.md — config reload, FullConfig
- docs/reviews/003-security-and-bug-review.md — W6, S5 findings
- src/cli.rs — RawConfig, load_config, collect_sites
- src/config/mod.rs — FullConfig, into_static_and_dynamic
Notes
This changes the startup config parsing path. While the behavior should be identical (same fields, same serde attributes), this is a sensitive area. A review task follows the code quality generation.
Summary
To be filled on completion