Skip to content

Allow computing query complexity without variable values - #1970

Open
ruudk wants to merge 1 commit into
masterfrom
fix-graphql-php-issue-1968
Open

Allow computing query complexity without variable values#1970
ruudk wants to merge 1 commit into
masterfrom
fix-graphql-php-issue-1968

Conversation

@ruudk

@ruudk ruudk commented Aug 25, 2026

Copy link
Copy Markdown
Collaborator

Fixes #1968.

QueryComplexity coerces the operation's variable definitions to evaluate @include/@skip and to build the arguments of fields with a complexity function, which fails for every operation that declares a required variable — so validating operation text alone, such as a manifest of Apollo persisted operations checked in CI, was only possible by subclassing the rule and overriding the protected directiveExcludesField().

Setting the new QueryComplexity::$assumeWorstCaseForUnprovidedVariables treats variables without a value as unknown instead of coercing them: conditional fields count as included, so only literal @include(if: false)/@skip(if: true) are dropped, and arguments that depend on such a variable (including ones nested in list or input object literals) are left out of what is passed to complexity functions, which can then pick their own fallback.

Variables that were provided a value are still used as given, invalid values still error out, and the default behaviour is unchanged. Along the way buildFieldArguments() now reuses the cached coerced variable values instead of re-coercing every variable definition per field.

@ruudk
ruudk force-pushed the fix-graphql-php-issue-1968 branch from 335870e to 94e4717 Compare August 25, 2026 12:49
@ruudk
ruudk requested a lite review from Copilot August 25, 2026 12:50

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 a supported way to compute QueryComplexity for operations when runtime variable values are not available (e.g., validating Apollo persisted operation manifests in CI), by introducing a “worst-case” mode for unprovided variables while keeping default behavior unchanged.

Changes:

  • Add QueryComplexity::$assumeWorstCaseForUnprovidedVariables to treat unprovided variables as “unknown” (include variable-conditional fields; omit variable-dependent field arguments passed to complexity functions).
  • Reuse cached coerced variable values (avoid re-coercing per field) and adjust coercion to skip non-coercible variable definitions in worst-case mode.
  • Add test coverage and documentation for the new behavior, plus changelog entry.

Reviewed changes

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

Show a summary per file
File Description
src/Validator/Rules/QueryComplexity.php Implements worst-case mode for unprovided variables, updates directive and argument handling, and reuses cached variable coercion.
tests/Validator/QuerySecuritySchema.php Extends test schema arguments/input types to exercise variable-dependent argument omission scenarios.
tests/Validator/QueryComplexityTest.php Adds tests covering worst-case behavior for @include/@skip and variable-dependent arguments.
docs/security.md Documents how to enable and reason about complexity computation without variable values.
CHANGELOG.md Records the new QueryComplexity capability for the next release.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +389 to +395
// Arguments that depend on a variable without a value can not be coerced,
// so they are left out and complexity functions get to decide what to make
// of their absence.
$argumentValueMap = [];
foreach ($node->arguments as $argumentNode) {
if ($this->dependsOnUnprovidedVariable($argumentNode->value)) {
continue;
Validating operations for which no variable values exist yet - such as a
manifest of Apollo persisted operations checked in CI - was impossible with
QueryComplexity: coercing the variable definitions to evaluate @include/@Skip
and the arguments of fields with a complexity function fails for every
operation that declares a required variable. The only way out was to subclass
the rule and override the protected directiveExcludesField().

QueryComplexity::$assumeWorstCaseForUnprovidedVariables makes that a supported
use case by treating variables without a value as unknown instead of coercing
them: conditional fields count as included, so only literal
@include(if: false)/@Skip(if: true) are dropped, and arguments that depend on
such a variable are left out of what is passed to complexity functions.
Variables that were provided a value keep working as before, and invalid
values still error out.
@ruudk
ruudk force-pushed the fix-graphql-php-issue-1968 branch from 94e4717 to d1e1b98 Compare August 25, 2026 13:05
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.

Allow computing query complexity without variable values

2 participants