Skip to content

chore: bump validators to 0.2.* and fix security vulnerabilities#219

Merged
loks0n merged 1 commit intomasterfrom
chore/bump-di-and-validators
Mar 3, 2026
Merged

chore: bump validators to 0.2.* and fix security vulnerabilities#219
loks0n merged 1 commit intomasterfrom
chore/bump-di-and-validators

Conversation

@loks0n
Copy link
Contributor

@loks0n loks0n commented Mar 3, 2026

Summary

  • Bump utopia-php/validators from 0.1.* to 0.2.*
  • Fix security vulnerabilities in dev dependencies:

Test plan

  • Unit tests pass
  • No security vulnerabilities reported by composer audit

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Chores
    • Updated validator package to improve compatibility and stability.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 3, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 048db7f and a7aa2e6.

⛔ Files ignored due to path filters (1)
  • composer.lock is excluded by !**/*.lock
📒 Files selected for processing (1)
  • composer.json

Walkthrough

The pull request updates the version constraint for the utopia-php/validators dependency in composer.json from 0.1.* to 0.2.* in the require section. This is a single-line change to the dependency specification.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~3 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly and concisely describes the primary changes: bumping the validators dependency to 0.2.* and fixing security vulnerabilities through dependency updates.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch chore/bump-di-and-validators

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.

Update utopia-php/validators from 0.1.* to 0.2.* and resolve security
advisories in dev dependencies by upgrading phpunit (9.6.31 → 9.6.34)
and symfony/process (8.0.3 → 8.0.5).

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@loks0n loks0n force-pushed the chore/bump-di-and-validators branch from 048db7f to a7aa2e6 Compare March 3, 2026 17:56
@loks0n loks0n closed this Mar 3, 2026
@loks0n loks0n reopened this Mar 3, 2026
Copy link
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: 3

🧹 Nitpick comments (1)
tests/ModelTest.php (1)

139-145: Prefer restoring $_SERVER by unsetting missing keys.

If REQUEST_METHOD/REQUEST_URI were absent before the test, Lines 141-142 currently reintroduce them with null. Unsetting preserves original global state more accurately.

Suggested patch
     protected function restoreRequest(): void
     {
-        $_SERVER['REQUEST_METHOD'] = $this->method;
-        $_SERVER['REQUEST_URI'] = $this->uri;
+        if ($this->method === null) {
+            unset($_SERVER['REQUEST_METHOD']);
+        } else {
+            $_SERVER['REQUEST_METHOD'] = $this->method;
+        }
+
+        if ($this->uri === null) {
+            unset($_SERVER['REQUEST_URI']);
+        } else {
+            $_SERVER['REQUEST_URI'] = $this->uri;
+        }
         $_GET = [];
         $_POST = [];
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/ModelTest.php` around lines 139 - 145, The restoreRequest method should
avoid reintroducing REQUEST_METHOD/REQUEST_URI when they were originally absent:
instead of unconditionally assigning $_SERVER['REQUEST_METHOD'] = $this->method
and $_SERVER['REQUEST_URI'] = $this->uri, check $this->method and $this->uri and
unset the corresponding $_SERVER keys when those properties are null (otherwise
restore their values); keep clearing $_GET and $_POST as-is. Update the
restoreRequest function to use conditional unset/assign logic referencing
restoreRequest, $_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI'],
$this->method and $this->uri.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@composer.json`:
- Line 31: Update the phpunit version constraint in composer.json to prevent
resolving vulnerable releases: replace the existing "phpunit/phpunit" constraint
(currently allowing 9.5.x or ^9.5.25) with "^9.6.33" so Composer will only allow
PHPUnit versions >=9.6.33; edit the "phpunit/phpunit" entry in composer.json
accordingly and run composer update or regenerate the lockfile to ensure the
lockfile reflects the new safe minimum.

In `@src/App.php`:
- Around line 720-722: The code checks $validator instanceof
\Utopia\Validator\ArrayList before resolving callable validators, so when
$param['validator'] is a callable (used by Hook::param) the instanceof test
fails; update the logic to first detect if $validator is callable and, if so,
invoke it to obtain the actual validator object (e.g. $validator = $validator()
or call_user_func($validator)), then perform the $validator instanceof
\Utopia\Validator\ArrayList check (affecting the isArrayList variable) so
model-list inputs are correctly recognized; ensure you reference and modify the
$validator variable before the isArrayList assignment in the same block.

In `@src/Request.php`:
- Around line 196-216: The code currently assigns $remoteAddr =
$this->getServer('REMOTE_ADDR') and returns it unvalidated; update the fallback
so $remoteAddr is validated with filter_var(..., FILTER_VALIDATE_IP) (supporting
IPv4/IPv6) and if invalid set it to '0.0.0.0' before returning; specifically,
after retrieving $remoteAddr from $this->getServer('REMOTE_ADDR') in the method
that iterates $this->trustedIpHeaders and uses $this->getHeader($header),
validate $remoteAddr the same way you validate $ip (use filter_var) and return
the validated value or '0.0.0.0'.

---

Nitpick comments:
In `@tests/ModelTest.php`:
- Around line 139-145: The restoreRequest method should avoid reintroducing
REQUEST_METHOD/REQUEST_URI when they were originally absent: instead of
unconditionally assigning $_SERVER['REQUEST_METHOD'] = $this->method and
$_SERVER['REQUEST_URI'] = $this->uri, check $this->method and $this->uri and
unset the corresponding $_SERVER keys when those properties are null (otherwise
restore their values); keep clearing $_GET and $_POST as-is. Update the
restoreRequest function to use conditional unset/assign logic referencing
restoreRequest, $_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI'],
$this->method and $this->uri.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a0acec5 and 048db7f.

⛔ Files ignored due to path filters (1)
  • composer.lock is excluded by !**/*.lock
📒 Files selected for processing (49)
  • Dockerfile
  • composer.json
  • docker-compose.yml
  • src/App.php
  • src/Hook.php
  • src/Model.php
  • src/Request.php
  • src/Validator.php
  • src/Validator/AnyOf.php
  • src/Validator/ArrayList.php
  • src/Validator/Assoc.php
  • src/Validator/Boolean.php
  • src/Validator/Domain.php
  • src/Validator/FloatValidator.php
  • src/Validator/HexColor.php
  • src/Validator/Host.php
  • src/Validator/Hostname.php
  • src/Validator/IP.php
  • src/Validator/Integer.php
  • src/Validator/JSON.php
  • src/Validator/Multiple.php
  • src/Validator/Nullable.php
  • src/Validator/Numeric.php
  • src/Validator/Range.php
  • src/Validator/Text.php
  • src/Validator/URL.php
  • src/Validator/WhiteList.php
  • src/Validator/Wildcard.php
  • tests/ModelTest.php
  • tests/Validator/ArrayListTest.php
  • tests/Validator/AssocTest.php
  • tests/Validator/BooleanTest.php
  • tests/Validator/DomainTest.php
  • tests/Validator/FloatValidatorTest.php
  • tests/Validator/HexColorTest.php
  • tests/Validator/HostTest.php
  • tests/Validator/HostnameTest.php
  • tests/Validator/IPTest.php
  • tests/Validator/IntegerTest.php
  • tests/Validator/JSONTest.php
  • tests/Validator/MultipleOfTest.php
  • tests/Validator/MultipleTest.php
  • tests/Validator/NullableTest.php
  • tests/Validator/NumericTest.php
  • tests/Validator/RangeTest.php
  • tests/Validator/TextTest.php
  • tests/Validator/URLTest.php
  • tests/Validator/WhiteListTest.php
  • tests/Validator/WildcardTest.php
💤 Files with no reviewable changes (43)
  • src/Validator/Nullable.php
  • tests/Validator/WildcardTest.php
  • src/Validator/IP.php
  • tests/Validator/MultipleOfTest.php
  • src/Validator/ArrayList.php
  • tests/Validator/DomainTest.php
  • src/Validator/Range.php
  • src/Validator/WhiteList.php
  • tests/Validator/IntegerTest.php
  • src/Validator/URL.php
  • src/Validator/HexColor.php
  • tests/Validator/NumericTest.php
  • src/Validator/Integer.php
  • Dockerfile
  • src/Validator/Text.php
  • tests/Validator/FloatValidatorTest.php
  • tests/Validator/AssocTest.php
  • tests/Validator/HexColorTest.php
  • src/Validator.php
  • src/Validator/AnyOf.php
  • tests/Validator/TextTest.php
  • tests/Validator/WhiteListTest.php
  • tests/Validator/ArrayListTest.php
  • tests/Validator/URLTest.php
  • tests/Validator/HostnameTest.php
  • src/Validator/Boolean.php
  • tests/Validator/HostTest.php
  • src/Validator/JSON.php
  • tests/Validator/NullableTest.php
  • src/Validator/Wildcard.php
  • tests/Validator/MultipleTest.php
  • tests/Validator/JSONTest.php
  • src/Validator/Domain.php
  • tests/Validator/BooleanTest.php
  • src/Validator/FloatValidator.php
  • src/Validator/Numeric.php
  • tests/Validator/RangeTest.php
  • docker-compose.yml
  • src/Validator/Host.php
  • src/Validator/Assoc.php
  • src/Validator/Hostname.php
  • tests/Validator/IPTest.php
  • src/Validator/Multiple.php

composer.json Outdated
"phpunit/phpunit": "^9.5.25",
"swoole/ide-helper": "4.8.3",
"laravel/pint": "^1.2",
"phpunit/phpunit": "9.*",
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n composer.json

Repository: utopia-php/http

Length of output: 1801


🏁 Script executed:

if [ -f composer.lock ]; then
  head -50 composer.lock
  echo "=== Checking for phpunit/phpunit ==="
  jq '.["packages-dev"][] | select(.name=="phpunit/phpunit") | {name, version, dist}' composer.lock 2>/dev/null || echo "PHPUnit not found in packages-dev or jq error"
else
  echo "composer.lock not found"
fi

Repository: utopia-php/http

Length of output: 2157


🌐 Web query:

PHPUnit 9.6.34 CVE security fix vulnerability

💡 Result:

PHPUnit 9.6.34 is relevant to CVE-2026-24765 (unsafe deserialization of PHPT code-coverage “.coverage” files that can lead to code execution if an attacker can pre-place a crafted file—commonly discussed as a CI/CD “poisoned pipeline” scenario). The upstream security fix landed in PHPUnit 9.6.33 (patched version), and 9.6.34 is a follow-up that fixes a regression introduced in 9.6.33—so 9.6.34 also contains the security fix. [1] [2] [3]

What to do

  • Upgrade to at least 9.6.33; 9.6.34 is the safer target for the 9.6.x line because it includes the regression fix. [1] [3]
  • If you can’t upgrade immediately, reduce risk by ensuring CI jobs don’t run with pre-existing/cached *.coverage files in the workspace (clean checkout / ephemeral runners). [1] [2]

Affected / patched (per advisory)

  • Affected: >= 9.0.0, < 9.6.33; Patched: 9.6.33 (and later, including 9.6.34). [1]

Sources:
[1] GitHub Advisory (GHSA-vvj3-c3rp-c85p / CVE-2026-24765) (github.com)
[2] NVD CVE-2026-24765 entry (nvd.nist.gov)
[3] PHPUnit 9.6.34 release notes (regression fix after 9.6.33) (github.com)

Citations:


Update PHPUnit constraint to ^9.6.33 to exclude vulnerable versions.

Line 40 declares "phpunit/phpunit": "^9.5.25", which allows versions down to 9.5.25 when dependencies are resolved. This includes vulnerable versions before 9.6.33 (affected by CVE-2026-24765 - unsafe deserialization in .coverage files). Although the lock file currently pins 9.6.34, the loose constraint risks resolution to vulnerable versions in fresh or lowest-constraint scenarios. Use ^9.6.33 instead.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@composer.json` at line 31, Update the phpunit version constraint in
composer.json to prevent resolving vulnerable releases: replace the existing
"phpunit/phpunit" constraint (currently allowing 9.5.x or ^9.5.25) with
"^9.6.33" so Composer will only allow PHPUnit versions >=9.6.33; edit the
"phpunit/phpunit" entry in composer.json accordingly and run composer update or
regenerate the lockfile to ensure the lockfile reflects the new safe minimum.

src/App.php Outdated
Comment on lines +720 to +722
$validator = $param['validator'];
$isArrayList = $validator instanceof \Utopia\Validator\ArrayList;

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Resolve callable validators before ArrayList detection.

Line 721 checks instanceof ArrayList on the raw validator field. When the validator is provided as a callable (supported by Hook::param), this is always false, and model-list inputs can be treated as a single model payload.

Suggested patch
-                    $validator = $param['validator'];
-                    $isArrayList = $validator instanceof \Utopia\Validator\ArrayList;
+                    $validator = $param['validator'];
+                    if (!\is_string($validator) && \is_callable($validator)) {
+                        $validator = \call_user_func_array($validator, $this->getResources($param['injections']));
+                    }
+                    $isArrayList = $validator instanceof \Utopia\Validator\ArrayList;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
$validator = $param['validator'];
$isArrayList = $validator instanceof \Utopia\Validator\ArrayList;
$validator = $param['validator'];
if (!\is_string($validator) && \is_callable($validator)) {
$validator = \call_user_func_array($validator, $this->getResources($param['injections']));
}
$isArrayList = $validator instanceof \Utopia\Validator\ArrayList;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/App.php` around lines 720 - 722, The code checks $validator instanceof
\Utopia\Validator\ArrayList before resolving callable validators, so when
$param['validator'] is a callable (used by Hook::param) the instanceof test
fails; update the logic to first detect if $validator is callable and, if so,
invoke it to obtain the actual validator object (e.g. $validator = $validator()
or call_user_func($validator)), then perform the $validator instanceof
\Utopia\Validator\ArrayList check (affecting the isArrayList variable) so
model-list inputs are correctly recognized; ensure you reference and modify the
$validator variable before the isArrayList assignment in the same block.

src/Request.php Outdated
Comment on lines +196 to +216
$remoteAddr = $this->getServer('REMOTE_ADDR') ?? '0.0.0.0';

foreach ($this->trustedIpHeaders as $header) {
$headerValue = $this->getHeader($header);

if (empty($headerValue)) {
continue;
}

// Leftmost IP address is the address of the originating client
$ips = explode(',', $headerValue);
$ip = trim($ips[0]);

// Validate IP format (supports both IPv4 and IPv6)
if (filter_var($ip, FILTER_VALIDATE_IP)) {
return $ip;
}
}

return $remoteAddr;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Validate REMOTE_ADDR before fallback return.

Line 196 assigns REMOTE_ADDR directly, and Line 215 returns it without validation. That contradicts the method contract (“validated client IP or 0.0.0.0”) and can leak invalid values downstream.

Suggested patch
-        $remoteAddr = $this->getServer('REMOTE_ADDR') ?? '0.0.0.0';
+        $remoteAddr = $this->getServer('REMOTE_ADDR');
+        $remoteAddr = (\is_string($remoteAddr) && \filter_var($remoteAddr, FILTER_VALIDATE_IP))
+            ? $remoteAddr
+            : '0.0.0.0';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
$remoteAddr = $this->getServer('REMOTE_ADDR') ?? '0.0.0.0';
foreach ($this->trustedIpHeaders as $header) {
$headerValue = $this->getHeader($header);
if (empty($headerValue)) {
continue;
}
// Leftmost IP address is the address of the originating client
$ips = explode(',', $headerValue);
$ip = trim($ips[0]);
// Validate IP format (supports both IPv4 and IPv6)
if (filter_var($ip, FILTER_VALIDATE_IP)) {
return $ip;
}
}
return $remoteAddr;
}
$remoteAddr = $this->getServer('REMOTE_ADDR');
$remoteAddr = (\is_string($remoteAddr) && \filter_var($remoteAddr, FILTER_VALIDATE_IP))
? $remoteAddr
: '0.0.0.0';
foreach ($this->trustedIpHeaders as $header) {
$headerValue = $this->getHeader($header);
if (empty($headerValue)) {
continue;
}
// Leftmost IP address is the address of the originating client
$ips = explode(',', $headerValue);
$ip = trim($ips[0]);
// Validate IP format (supports both IPv4 and IPv6)
if (filter_var($ip, FILTER_VALIDATE_IP)) {
return $ip;
}
}
return $remoteAddr;
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/Request.php` around lines 196 - 216, The code currently assigns
$remoteAddr = $this->getServer('REMOTE_ADDR') and returns it unvalidated; update
the fallback so $remoteAddr is validated with filter_var(...,
FILTER_VALIDATE_IP) (supporting IPv4/IPv6) and if invalid set it to '0.0.0.0'
before returning; specifically, after retrieving $remoteAddr from
$this->getServer('REMOTE_ADDR') in the method that iterates
$this->trustedIpHeaders and uses $this->getHeader($header), validate $remoteAddr
the same way you validate $ip (use filter_var) and return the validated value or
'0.0.0.0'.

@loks0n loks0n merged commit b704e80 into master Mar 3, 2026
8 of 9 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.

1 participant