Break down findings from review #002 into dependency-ordered fix tasks: Critical/High: - fix/acme-contact-and-challenge (C1+C2): Add acme_contact field, wire to ACME, remove unused challenge_config, add validation rule 19 - fix/remove-health-and-hardcode-https (W5+W14+ADR-022): Remove /health from main listener, hardcode X-Forwarded-Proto to https - fix/config-reload-static-drift (C4): Use ArcSwap<StaticConfig> so reload diffs against last config, not startup config - fix/access-logging (W13): Wire up log_request! macro for every proxied request with client_ip, host, method, path, status, upstream, duration_ms Medium: - fix/graceful-shutdown (W1+W7): Join HTTPS tasks with timeout instead of abort, add shutdown signal to admin socket and eviction task - fix/connect-timeout (W4): Wire upstream_connect_timeout_secs to enforce separate connect timeout Low/Independent: - fix/token-bucket-nanosecond (W6): Use as_nanos() instead of as_millis() - fix/normalize-host-ipv6 (S3): Handle IPv6 bracket notation in normalize_host - fix/http-port-validation (S1): Validate http_port in range 0 or 1-65535 - fix/integration-test-toml (S10): Fix double-nested listeners.listeners.sites - fix/logging-test-global-subscriber (W9): Use try_init() to avoid test conflicts - fix/fragile-error-detection (W3): Add typed error matching or documented string match - fix/add-code-comments (C3,W8,W10,W11,S9): Document correct-but-non-obvious behaviors - fix/request-timeout-scope (S8): Document full-request timeout scope - fix/clean-dead-code (S4+S2): Remove dead_code annotations, add #[non_exhaustive] Review gate: - review/post-fix-review: Verify all fixes against architecture spec
3.6 KiB
id, name, status, depends_on, scope, risk, impact, level, review_findings
| id | name | status | depends_on | scope | risk | impact | level | review_findings | ||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| fix/add-code-comments | Add clarifying code comments for correct-but-non-obvious behaviors | pending |
|
narrow | trivial | component | implementation |
|
Description
Several review findings identified behaviors that are correct but need clarifying comments to prevent future "fixes" that would change correct behavior. This task adds documentation comments to these code locations.
Comments to Add
C3 — X-Forwarded-For replace semantics (src/proxy/headers.rs):
Add a comment above headers.insert(HeaderName::from_static("x-forwarded-for"), ip_value):
// X-Forwarded-For is SET (not appended) because this proxy is the outermost
// edge proxy. Any existing X-Forwarded-For from the client is untrusted and
// must be replaced with the actual client IP from ConnectInfo.
// See ADR-021 for the edge proxy model rationale.
W8 — Server header removal (src/proxy/handler.rs):
Add a comment above parts.headers.remove("server"):
// The upstream Server header is intentionally removed. As a security-focused
// reverse proxy, we hide upstream server identity as a defense-in-depth measure.
// The proxy does not add its own Server header either. See W8 in review #002.
W10 — Body limit two-layer defense (src/proxy/body_limit.rs):
Add a comment above the Content-Length check:
// Early rejection: if Content-Length is present and exceeds the limit, reject
// immediately without reading the body. For requests without Content-Length
// (chunked, HTTP/2), the Limited body wrapper below enforces the limit during
// streaming. This is a two-layer defense.
W11 — Health check port conflict conservatism (src/config/validation.rs):
Add a comment above the health check port conflict check:
// Health check always binds to 127.0.0.1 (hardcoded in src/health.rs), so this
// conflict check is conservative — it warns even when the health check port
// wouldn't actually conflict (e.g., health check on 127.0.0.1:80 vs listener
// on 203.0.113.10:80). This is acceptable for Phase 1.
S9 — Rate limit bypass when no IP (src/rate_limit/mod.rs):
Add a comment above the return next.run(req).await in the None branch:
// If no client IP can be identified, the request passes through without rate
// limiting. In practice, ConnectInfo is always set by the server's
// ConnectInfoService, so this branch is unreachable. If the proxy were ever
// deployed without ConnectInfo propagation, rate limiting would silently become
// a no-op. Consider adding a warning log or returning 429 in a future phase.
Acceptance Criteria
- All five comments are added at the specified locations
- Comments reference the relevant ADRs or review findings where applicable
- Code behavior is unchanged (comments only)
cargo clippypasses with no warnings
References
- docs/reviews/002-implementation-review.md — C3, W8, W10, W11, S9 findings
- docs/architecture/decisions/021-x-forwarded-for-edge-proxy.md — ADR-021
- src/proxy/headers.rs — X-Forwarded-For insert
- src/proxy/handler.rs — Server header removal
- src/proxy/body_limit.rs — Content-Length check
- src/config/validation.rs — Health check port conflict
- src/rate_limit/mod.rs — No IP fallback
Notes
This task depends on fix/remove-health-and-hardcode-https because the X-Forwarded-Proto comment (W14) is being addressed in that task. The remaining comments here are independent.
Summary
To be filled on completion