Skip to content
5 changes: 2 additions & 3 deletions app/code/Magento/GraphQl/etc/di.xml
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,8 @@
<type name="Magento\Framework\GraphQl\Query\Resolver\Argument\Validator\CompositeValidator">
<arguments>
<argument name="validators" xsi:type="array">
<item name="backpressureValidator" xsi:type="object">
Magento\GraphQl\Model\Backpressure\BackpressureFieldValidator
</item>
<item name="searchCriteriaValidator" xsi:type="object">Magento\Framework\GraphQl\Query\Resolver\Argument\Validator\SearchCriteriaValidator</item>
<item name="backpressureValidator" xsi:type="object">Magento\GraphQl\Model\Backpressure\BackpressureFieldValidator</item>
</argument>
</arguments>
</type>
Expand Down
7 changes: 0 additions & 7 deletions app/etc/di.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1990,13 +1990,6 @@
</arguments>
</type>
<preference for="Magento\Framework\GraphQl\Query\Resolver\Argument\ValidatorInterface" type="Magento\Framework\GraphQl\Query\Resolver\Argument\Validator\CompositeValidator"/>
<type name="Magento\Framework\GraphQl\Query\Resolver\Argument\Validator\CompositeValidator">
<arguments>
<argument name="validators" xsi:type="array">
<item name="searchCriteriaValidator" xsi:type="object">Magento\Framework\GraphQl\Query\Resolver\Argument\Validator\SearchCriteriaValidator</item>
</argument>
</arguments>
</type>
<type name="Magento\Framework\GraphQl\Query\Resolver\Argument\Validator\SearchCriteriaValidator">
<arguments>
<argument name="maxPageSize" xsi:type="number">300</argument>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<?php
/**
* Copyright 2026 Adobe
* All Rights Reserved.
*/
declare(strict_types=1);

namespace Magento\GraphQl\Query;

use Magento\TestFramework\Fixture\Config;
use Magento\TestFramework\TestCase\GraphQlAbstract;
use Magento\TestFramework\TestCase\GraphQl\ResponseContainsErrorsException;

/**
* Verify that SearchCriteriaValidator enforces the pageSize limit in GraphQL queries.
*
* Regression: Magento_GraphQl module-level di.xml was overriding the global di.xml array argument
* for CompositeValidator, silently dropping SearchCriteriaValidator from the composite.
*/
class SearchCriteriaValidatorTest extends GraphQlAbstract
{
/**
* Verify that a pageSize argument exceeding the configured maximum returns an error.
*/
#[
Config('graphql/validation/input_limit_enabled', 1),
Config('graphql/validation/maximum_page_size', 5)
]
public function testProductsQueryExceedingPageSizeReturnsError()
{
$query = <<<QUERY
{
products(pageSize: 6, filter: {sku: {eq: "test"}}) {
total_count
}
}
QUERY;

$this->expectException(ResponseContainsErrorsException::class);
$this->expectExceptionMessage('Maximum pageSize is 5');
$this->graphQlQuery($query);
}

/**
* Verify that a pageSize argument within the configured maximum succeeds.
*/
#[
Config('graphql/validation/input_limit_enabled', 1),
Config('graphql/validation/maximum_page_size', 5)
]
public function testProductsQueryWithinPageSizeLimitSucceeds()
{
$query = <<<QUERY
{
products(pageSize: 5, filter: {sku: {eq: "test"}}) {
total_count
}
}
QUERY;

$response = $this->graphQlQuery($query);
$this->assertArrayHasKey('products', $response);
}

/**
* Verify that pageSize is not enforced when input limiting is disabled.
*/
#[
Config('graphql/validation/input_limit_enabled', 0),
Config('graphql/validation/maximum_page_size', 5)
]
public function testProductsQueryPageSizeNotEnforcedWhenLimitingDisabled()
{
$query = <<<QUERY
{
products(pageSize: 100, filter: {sku: {eq: "test"}}) {
total_count
}
}
QUERY;

$response = $this->graphQlQuery($query);
$this->assertArrayHasKey('products', $response);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
<?php
/**
* Copyright 2026 Adobe
* All Rights Reserved.
*/
declare(strict_types=1);

namespace Magento\GraphQl\Query;

use Magento\Framework\App\Area;
use Magento\Framework\GraphQl\Config\Element\Field;
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
use Magento\Framework\GraphQl\Query\Resolver\Argument\Validator\CompositeValidator;
use Magento\Store\Model\ScopeInterface;
use Magento\TestFramework\Fixture\AppArea;
use Magento\TestFramework\Fixture\Config;
use Magento\TestFramework\Fixture\DbIsolation;
use Magento\TestFramework\Helper\Bootstrap;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\TestCase;

/**
* Verify that CompositeValidator correctly delegates to all registered validators.
*
* Integration test for composites per DoD: ensures SearchCriteriaValidator and
* BackpressureFieldValidator are loaded and functional within the composite.
*
* Regression: module-level di.xml array arguments replace global di.xml entries,
* so SearchCriteriaValidator was silently dropped from CompositeValidator.
*/
#[
CoversClass(CompositeValidator::class),
AppArea(Area::AREA_GRAPHQL),
DbIsolation(false),
]
class CompositeValidatorTest extends TestCase
{
/**
* @var CompositeValidator
*/
private CompositeValidator $compositeValidator;

/**
* @inheritDoc
*/
protected function setUp(): void
{
$this->compositeValidator = Bootstrap::getObjectManager()->get(CompositeValidator::class);
}

/**
* Verify SearchCriteriaValidator in composite enforces pageSize when limiting is enabled.
*/
#[
Config('graphql/validation/input_limit_enabled', 1, ScopeInterface::SCOPE_STORE, 'default'),
Config('graphql/validation/maximum_page_size', 5, ScopeInterface::SCOPE_STORE, 'default')
]
public function testSearchCriteriaValidatorEnforcesPageSizeLimit(): void
{
$field = $this->createMock(Field::class);

$this->expectException(GraphQlInputException::class);
$this->expectExceptionMessage('Maximum pageSize is 5');
$this->compositeValidator->validate($field, ['pageSize' => 6]);
}

/**
* Verify composite does not throw when pageSize is within the configured limit.
*
* @doesNotPerformAssertions
*/
#[
Config('graphql/validation/input_limit_enabled', 1, ScopeInterface::SCOPE_STORE, 'default'),
Config('graphql/validation/maximum_page_size', 5, ScopeInterface::SCOPE_STORE, 'default')
]
public function testCompositeAllowsPageSizeWithinLimit(): void
{
$field = $this->createMock(Field::class);

$this->compositeValidator->validate($field, ['pageSize' => 5]);
}

/**
* Verify composite does not throw when input limiting is disabled.
*
* @doesNotPerformAssertions
*/
#[
Config('graphql/validation/input_limit_enabled', 0, ScopeInterface::SCOPE_STORE, 'default'),
Config('graphql/validation/maximum_page_size', 5, ScopeInterface::SCOPE_STORE, 'default')
]
public function testSearchCriteriaValidatorSkipsEnforcementWhenDisabled(): void
{
$field = $this->createMock(Field::class);

$this->compositeValidator->validate($field, ['pageSize' => 100]);
}
}