Skip to content

feat: improved reference client ip through _APP_TRUSTED_HEADERS#10941

Merged
levivannoort merged 8 commits into1.8.xfrom
CLO-3704-utopia-request-extend
Dec 15, 2025
Merged

feat: improved reference client ip through _APP_TRUSTED_HEADERS#10941
levivannoort merged 8 commits into1.8.xfrom
CLO-3704-utopia-request-extend

Conversation

@levivannoort
Copy link
Copy Markdown
Member

@levivannoort levivannoort commented Dec 12, 2025

What does this PR do?

As not to default on the x-forwarded-for header, this pull-request introduces the option to set trusted headers. Which are checked from left to right on request presence wise, where the left most address will be used for as the client reference. With a default set to x-forwarded-for.

To-do:

Test Plan

Add a test that should validate from not diverting from the original behaviour, while allowing the overwrite of the to be trusted headers through the variable.

Related PRs and Issues

Checklist

  • Have you read the Contributing Guidelines on issues?
  • If the PR includes a change to an API's metadata (desc, label, params, etc.), does it also include updated API specs and example docs?

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Dec 12, 2025

📝 Walkthrough

Walkthrough

This PR adds a new trusted-headers configuration option: _APP_TRUSTED_HEADERS (default x-forwarded-for) to .env, docker-compose.yml, and app/config/variables.php. src/Appwrite/Utopia/Request.php reads that comma-separated list at initialization and calls setTrustedIpHeaders() to apply it. An end-to-end test (tests/e2e/Services/Account/AccountBase.php) was added to verify IP capture when x-forwarded-for is supplied. No existing public signatures or other control flow were changed.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Review Request.php: parsing logic, trimming/case handling, and interaction with System::getEnv / setTrustedIpHeaders.
  • Ensure defaults and empty-value behavior are safe (no accidental trusting of all headers).
  • Confirm app/config/variables.php entry matches project conventions (description, introduced version, default).
  • Check docker-compose.yml and .env placement/formatting for consistency.
  • Review the new e2e test for deterministic behavior and any environment assumptions.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: adding a new _APP_TRUSTED_HEADERS configuration option to improve client IP reference detection.
Description check ✅ Passed The description is directly related to the changeset, explaining the motivation for the new trusted headers feature, test plan, and completed to-dos.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch CLO-3704-utopia-request-extend

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8a35762 and 03a19cc.

📒 Files selected for processing (1)
  • .env (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-07-08T01:20:14.364Z
Learnt from: stnguyen90
Repo: appwrite/appwrite PR: 10119
File: app/controllers/api/account.php:1226-1232
Timestamp: 2025-07-08T01:20:14.364Z
Learning: In Appwrite, `_APP_DOMAIN` is a required environment variable that must always be set for the system to function properly.

Applied to files:

  • .env
🪛 dotenv-linter (4.0.0)
.env

[warning] 128-128: [EndingBlankLine] No blank line at the end of the file

(EndingBlankLine)


[warning] 128-128: [UnorderedKey] The _APP_TRUSTED_HEADERS key should go before the _APP_USAGE_AGGREGATION_INTERVAL key

(UnorderedKey)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (20)
  • GitHub Check: E2E Service Test (FunctionsSchedule)
  • GitHub Check: E2E Service Test (Locale)
  • GitHub Check: E2E Service Test (Sites)
  • GitHub Check: E2E Service Test (Webhooks)
  • GitHub Check: E2E Service Test (Migrations)
  • GitHub Check: E2E Service Test (Projects)
  • GitHub Check: E2E Service Test (Storage)
  • GitHub Check: E2E Service Test (Messaging)
  • GitHub Check: E2E Service Test (Console)
  • GitHub Check: E2E Service Test (GraphQL)
  • GitHub Check: E2E Service Test (Proxy)
  • GitHub Check: E2E Service Test (Account)
  • GitHub Check: E2E Service Test (Databases/Legacy)
  • GitHub Check: E2E Service Test (Avatars)
  • GitHub Check: E2E Service Test (Site Screenshots)
  • GitHub Check: E2E Service Test (Dev Keys)
  • GitHub Check: Unit Test
  • GitHub Check: E2E General Test
  • GitHub Check: Benchmark
  • GitHub Check: scan

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.

@levivannoort levivannoort changed the title Add teamId to project array in e2e test feat: improved reference client ip through _APP_TRUSTED_HEADERS Dec 12, 2025
@github-actions
Copy link
Copy Markdown

github-actions bot commented Dec 12, 2025

Security Scan Results for PR

Docker Image Scan Results

Package Version Vulnerability Severity
libpng 1.6.51-r0 CVE-2025-66293 HIGH
libpng-dev 1.6.51-r0 CVE-2025-66293 HIGH

Source Code Scan Results

🎉 No vulnerabilities found!

@github-actions
Copy link
Copy Markdown

github-actions bot commented Dec 12, 2025

✨ Benchmark results

  • Requests per second: 1,173
  • Requests with 200 status code: 211,148
  • P99 latency: 0.168105124

⚡ Benchmark Comparison

Metric This PR Latest version
RPS 1,173 1,232
200 211,148 221,789
P99 0.168105124 0.169220669

@levivannoort levivannoort marked this pull request as ready for review December 15, 2025 14:32
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
docker-compose.yml (1)

223-223: Wiring of _APP_TRUSTED_HEADERS into the API container looks good

Exposing _APP_TRUSTED_HEADERS on the main appwrite service matches where Appwrite\Utopia\Request is typically used. If other HTTP-facing services (for example appwrite-realtime) also rely on the same Request wrapper and should honor the same trusted headers, consider adding this env there as well for consistency.

tests/e2e/Services/Account/AccountBase.php (1)

330-365: Good end‑to‑end coverage of the trusted IP fallback, with a couple of optional refinements

This test does a good job validating that x-forwarded-for is honored as the client IP when talking directly to the API container.

Two optional tweaks you might consider:

  • Also assert the IP on the /account creation response if that endpoint surfaces a clientIp/ip field, to cover both write and auth flows.
  • Use one of the RFC 5737 documentation ranges (for example 203.0.113.x) instead of 191.0.113.195 to make it clear the address is non‑production.

Both are non‑blocking; the current test meaningfully exercises the new behavior.

app/config/variables.php (1)

361-368: Config entry for _APP_TRUSTED_HEADERS is clear and aligned with implementation

The new variable definition matches the runtime behavior (default 'x-forwarded-for', comma‑separated list, left‑to‑right evaluation) and gives operators enough context to configure multiple headers.

If you end up distinguishing between “unset” (use default) and “empty string” (disable trusted headers), it might be worth adding a brief note to the description later; otherwise this looks good as‑is.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e9d9aa6 and 8a35762.

⛔ Files ignored due to path filters (1)
  • composer.lock is excluded by !**/*.lock
📒 Files selected for processing (5)
  • .env (1 hunks)
  • app/config/variables.php (1 hunks)
  • docker-compose.yml (1 hunks)
  • src/Appwrite/Utopia/Request.php (2 hunks)
  • tests/e2e/Services/Account/AccountBase.php (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-07-08T01:20:14.364Z
Learnt from: stnguyen90
Repo: appwrite/appwrite PR: 10119
File: app/controllers/api/account.php:1226-1232
Timestamp: 2025-07-08T01:20:14.364Z
Learning: In Appwrite, `_APP_DOMAIN` is a required environment variable that must always be set for the system to function properly.

Applied to files:

  • .env
🧬 Code graph analysis (1)
tests/e2e/Services/Account/AccountBase.php (1)
tests/e2e/Client.php (2)
  • setEndpoint (140-145)
  • Client (8-342)
🪛 dotenv-linter (4.0.0)
.env

[warning] 128-128: [EndingBlankLine] No blank line at the end of the file

(EndingBlankLine)


[warning] 128-128: [UnorderedKey] The _APP_TRUSTED_HEADERS key should go before the _APP_USAGE_AGGREGATION_INTERVAL key

(UnorderedKey)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Setup & Build Appwrite Image
  • GitHub Check: Setup & Build Appwrite Image
  • GitHub Check: scan
🔇 Additional comments (1)
src/Appwrite/Utopia/Request.php (1)

12-27: No changes needed. The current implementation is correct and robust.

The parent class Utopia\Swoole\Request::__construct() does not initialize or overwrite the trustedIpHeaders property—it only sets $this->swoole. The call order in your code (setting trusted headers before parent::__construct()) is safe and works as intended.

Additionally, the setTrustedIpHeaders() method already normalizes headers to lowercase, trims whitespace, and filters empty values via array_map('strtolower', ...), array_map('trim', ...), and array_filter(). The comma-separated env var parsing is handled correctly without needing extra trimming in the constructor.

@levivannoort levivannoort merged commit f4bca74 into 1.8.x Dec 15, 2025
39 of 41 checks passed
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.

2 participants