Files
reverse-proxy/tasks/fix/add-code-comments.md
glm-5.1 f9d7b8112b Decompose implementation review fixes into 14 atomic tasks with post-fix review
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
2026-06-12 04:08:45 +00:00

87 lines
3.6 KiB
Markdown

---
id: fix/add-code-comments
name: Add clarifying code comments for correct-but-non-obvious behaviors
status: pending
depends_on: [fix/remove-health-and-hardcode-https]
scope: narrow
risk: trivial
impact: component
level: implementation
review_findings: [C3, W8, W10, W11, S9]
---
## 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)`:
```rust
// 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")`:
```rust
// 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:
```rust
// 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:
```rust
// 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:
```rust
// 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 clippy` passes 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