Skip to content

feature: configurable trusted headers for proxy_ip_parser#120

Merged
rustatian merged 5 commits into
masterfrom
feature/configurable-trusted-headers
Jun 4, 2026
Merged

feature: configurable trusted headers for proxy_ip_parser#120
rustatian merged 5 commits into
masterfrom
feature/configurable-trusted-headers

Conversation

@rustatian

@rustatian rustatian commented Jun 4, 2026

Copy link
Copy Markdown
Member

Adds a configurable allowlist of IP-forwarding headers for resolving the real client IP.

  • New http.trusted_headers: an ordered allowlist, first non-empty match wins. Listing only X-Real-Ip ignores X-Forwarded-*; custom headers are supported (taken verbatim).
  • Unset → the previous default order (Forwarded, X-Forwarded-For, X-Real-Ip, True-Client-Ip, Cf-Connecting-Ip), so existing configs are unaffected.
  • An unparseable header (e.g. Forwarded without a for= directive) now falls through to the next header instead of short-circuiting.

Also includes a fix for the OTel middleware unit tests (they constructed Plugin without a propagator → nil panic; these main-module tests are not run in CI) and a bump of two transitive test-module deps.

The integration job is red for a pre-existing, org-wide reason (the PHP worker SDK predates pool/v2-beta / PHP 8.5), unrelated to this change; the feature is covered by unit tests.

closes roadrunner-server/roadrunner#1515

Summary by CodeRabbit

  • New Features

    • Added configurable trusted_headers setting to specify which headers the proxy IP parser middleware consults (and in what order) when resolving the real client IP. Defaults to built-in header priorities when unset.
  • Documentation

    • Updated middleware documentation to clarify IP resolution behavior with the configurable header allowlist.

rustatian added 3 commits June 4, 2026 08:19
Add the http.trusted_headers config key: an ordered allowlist of headers
consulted to resolve the real client IP, first non-empty match wins. Listing
only X-Real-Ip ignores X-Forwarded-* etc.; custom headers are supported. When
unset, the built-in default order is used, so existing configs are unaffected.
The otel middleware tests built Plugin without prop, so the OTel branch
nil-dereferenced p.prop.Inject. Init always sets it in production; set a
propagator in the tests too. CI runs only the tests/ module, so these
main-module tests were never exercised.
Copilot AI review requested due to automatic review settings June 4, 2026 06:20
@coderabbitai

coderabbitai Bot commented Jun 4, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@rustatian, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 48 minutes and 24 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6c09d7f8-3907-4232-aaf2-e87d2ee46e50

📥 Commits

Reviewing files that changed from the base of the PR and between 949ba04 and 70a7242.

📒 Files selected for processing (4)
  • doc.go
  • plugin.go
  • tests/proxy_ip_parser_test.go
  • trusted_test.go
📝 Walkthrough

Walkthrough

This PR introduces a configurable ordered header allowlist (TrustedHeaders) for the proxy IP parser middleware. The resolver-chain pattern replaces hardcoded header precedence, defaults to a built-in priority when unconfigured, and includes comprehensive unit and integration test coverage.

Changes

Trusted Headers Configuration

Layer / File(s) Summary
Configuration and documentation
config.go, doc.go
TrustedHeaders []string field added to Config with mapstructure tag; package documentation expanded to describe configurable ordered header allowlist via http.trusted_headers with default fallback, including corrected Cf-Connecting-Ip casing.
Resolver chain architecture and core logic
plugin.go
Configuration key constant headersKey added; Plugin struct extended with resolvers []resolver field; Init unmarshals http.trusted_headers and calls buildResolvers to initialize resolver chain; resolveIP refactored from hardcoded header sequence into loop over p.resolvers using header-specific parsers for Forwarded, X-Forwarded-For, and verbatim headers.
Unit tests for resolver logic
trusted_test.go
TestIP now uses resolvers: defaultResolvers(); helper functions header and resolverNames added; five new test cases validate allowlist behavior (unlisted headers ignored), resolver order precedence, custom header verbatim values, parse failure fallthrough, and buildResolvers normalization with default fallback.
Integration tests and test configuration
tests/configs/.rr-http-headers.yaml, tests/proxy_ip_parser_test.go, tests/php_test_files/http/ip.php
Test configuration yaml restricts trusted headers to X-Real-Ip only; new handleRequest function in ip.php test fixture reads and echoes REMOTE_ADDR; new TestTrustedHeadersAllowlist integration test verifies configured header is honored while unconfigured headers are ignored.
Existing test updates and dependency maintenance
plugin_otel_test.go, tests/go.mod
OpenTelemetry tests updated to explicitly initialize Plugin with prop: propagation.TraceContext{}; indirect dependencies bumped (go-colorable v0.1.14 → v0.1.15, prometheus/common v0.67.5 → v0.68.1); yaml/v2 indirect dependency removed.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 Hop, hop! Headers configured at last,
No more hardcoded chains to hold you fast.
Trust what you choose in ordered delight,
The resolver hops through, getting IP right! 🎯

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is incomplete—it lacks the 'Reason for This PR' section with issue number and omits the PR Checklist as required by the template. Add the issue number (#1515) to the 'Reason for This PR' section and include the PR Checklist from the template to confirm all requirements are met.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feature: configurable trusted headers for proxy_ip_parser' clearly and specifically describes the main change—adding configuration for trusted headers in the proxy_ip_parser middleware.
Linked Issues check ✅ Passed The code changes fully implement the requested feature: new configurable http.trusted_headers allowlist (#1515), support for custom headers, header-order priority matching, fallthrough on parse failure, and default behavior preservation.
Out of Scope Changes check ✅ Passed All changes are scoped to the core feature (config, plugin logic, tests, docs) and OTel test fix. go.mod updates are incidental transitive dependencies with no functional impact.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/configurable-trusted-headers

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds support for configuring which proxy IP-forwarding headers are trusted (and in what order) when resolving the real client IP, while preserving the previous default resolution chain when the new setting is unset. It also updates unit/integration tests (including an OTel test fix) and bumps a couple of transitive dependencies in the tests module.

Changes:

  • Add http.trusted_headers allowlist support, with ordered resolution and fall-through on parse failures.
  • Expand unit + integration test coverage for allowlist behavior; add a PHP worker that echoes REMOTE_ADDR for integration assertions.
  • Fix OTel middleware tests to initialize the propagator and update tests module dependencies.

Reviewed changes

Copilot reviewed 9 out of 10 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
trusted_test.go Adds unit tests for allowlist ordering, custom headers, and parse-failure fall-through.
tests/proxy_ip_parser_test.go Adds an integration test asserting allowlist behavior end-to-end via REMOTE_ADDR.
tests/php_test_files/http/ip.php Adds a PHP handler to echo REMOTE_ADDR for integration testing.
tests/go.sum Updates transitive dependency checksums for the tests module.
tests/go.mod Bumps two indirect deps and drops an unused indirect YAML v2 dep in the tests module.
tests/configs/.rr-http-headers.yaml Adds a dedicated RR config enabling http.trusted_headers for integration testing.
plugin.go Implements resolver chain abstraction and configurable trusted header allowlist.
plugin_otel_test.go Fixes OTel middleware tests by ensuring a non-nil propagator is set.
doc.go Documents the new http.trusted_headers configuration behavior.
config.go Adds TrustedHeaders config field mapped from trusted_headers.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread plugin.go

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@doc.go`:
- Around line 1-8: Doc default header order is inconsistent with the runtime
resolver in plugin.go where Forwarded is checked first; update the header list
in doc.go to mirror the actual default precedence used by the resolver (place
Forwarded first, then X-Forwarded-For, X-Real-Ip, True-Client-Ip,
Cf-Connecting-Ip) and verify the text still references http.trusted_headers as
the configurable allowlist.

In `@tests/proxy_ip_parser_test.go`:
- Around line 306-313: Replace non-fatal assertions that guard dereferencing the
HTTP response with fatal ones: change assert.NoError(t, err) to
require.NoError(t, err) for the http.DefaultClient.Do(req) call (the variables r
and err) so we don't access r.Body when r is nil, and likewise change the
assert.NoError(t, err) after io.ReadAll(r.Body) to require.NoError(t, err);
apply the same replacements in the similar block covering lines 322-329 to
harden those tests as well.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: fc10a97b-26bf-4734-8df6-6d647e813978

📥 Commits

Reviewing files that changed from the base of the PR and between 976af44 and 949ba04.

⛔ Files ignored due to path filters (1)
  • tests/go.sum is excluded by !**/*.sum
📒 Files selected for processing (9)
  • config.go
  • doc.go
  • plugin.go
  • plugin_otel_test.go
  • tests/configs/.rr-http-headers.yaml
  • tests/go.mod
  • tests/php_test_files/http/ip.php
  • tests/proxy_ip_parser_test.go
  • trusted_test.go

Comment thread doc.go
Comment thread tests/proxy_ip_parser_test.go
rustatian added 2 commits June 4, 2026 08:26
- range over values instead of indices (resolveIP, buildResolvers, test helper)
- derive the default chain via parserFor so the header->parser mapping has a
  single source of truth
- doc.go: list default headers in actual precedence (Forwarded first)
- tests: require.NoError before dereferencing the HTTP response
@rustatian rustatian self-assigned this Jun 4, 2026
@rustatian rustatian merged commit f57d23e into master Jun 4, 2026
6 of 7 checks passed
@rustatian rustatian deleted the feature/configurable-trusted-headers branch June 4, 2026 12:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[💡 FEATURE REQUEST]: Configuration for the proxy_ip_parser middleware

2 participants