Skip to content

Conversation

@ysmolski
Copy link
Contributor

@ysmolski ysmolski commented Oct 23, 2025

Introspection queries are not considered when calculating complexity limits.

Summary by CodeRabbit

  • New Features

    • Added a configuration option to skip complexity limits for introspection queries.
  • Bug Fixes

    • Introspection queries now respect the new skip option and behave correctly when depth/complexity limits are configured.
  • Tests

    • Added tests validating complexity limit behavior with introspection enabled and when skipping limits.
  • Chores

    • Updated dependency versions.

Introspection queries are not considered when calculating complexity
limits.
@coderabbitai
Copy link

coderabbitai bot commented Oct 23, 2025

Walkthrough

Added tests and configuration to control skipping complexity checks for GraphQL introspection; refactored complexity-check plumbing to use a local limits variable; added SkipIntrospection config field and schema/testdata entry; adjusted a deprecation warning; bumped graphql-go-tools dependency versions in both modules.

Changes

Cohort / File(s) Change Summary
Tests
router-tests/complexity_limits_test.go
Added two subtests that enable router introspection and validate complexity-limits behavior: one verifies introspection queries are checked by default and fail when depth limit exceeded; the other sets SkipIntrospection: true and verifies introspection queries bypass complexity limits. Added import github.com/wundergraph/cosmo/router/core.
Core router logic
router/core/operation_processor.go, router/core/router.go
operation_processor.go: use a local limits variable (from o.operationProcessor.complexityLimits), short-circuit when nil, initialize estimator with limits.SkipIntrospection, update cache and comparisons to use globalComplexity fields and pass limits into comparisons. router.go: updated deprecation warning text to reference security.complexity_limits.depth.
Configuration
router/pkg/config/config.go, router/pkg/config/config.schema.json, router/pkg/config/testdata/config_full.json
Added SkipIntrospection bool to ComplexityLimits (yaml/env tags) and schema entry; adjusted ApplyLimit persistence condition; added SkipIntrospection to testdata full config JSON.
Dependency bumps
router-tests/go.mod, router/go.mod
Bumped github.com/wundergraph/graphql-go-tools/v2 to v2.0.0-rc.237.0.20251111144341-5d93cce1da45 in both modules.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Potential attention points:

  • router/core/operation_processor.go changes to complexity estimator usage, cache entry shape (Depth/NodeCount), and passing limits into comparisons.
  • Interaction of SkipIntrospection with estimator initialization and existing complexity limit logic.
  • New tests in router-tests/complexity_limits_test.go for determinism and correctness under introspection-enabled configurations.
  • Build/test after dependency bump.

Possibly related PRs

  • fix: enforce parser limits #2068: Modifies operation_processor complexity validation flow and is likely directly related to these complexity-limit plumbing changes.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding the ability to omit introspection queries from complexity limit calculations, which is the primary purpose of this PR.
✨ Finishing touches
  • 📝 Generate docstrings

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bcc0222 and 78213a4.

📒 Files selected for processing (1)
  • router/core/operation_processor.go (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • router/core/operation_processor.go
⏰ 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). (11)
  • GitHub Check: image_scan (nonroot)
  • GitHub Check: image_scan
  • GitHub Check: build_push_image (nonroot)
  • GitHub Check: build_push_image
  • GitHub Check: integration_test (./telemetry)
  • GitHub Check: integration_test (./. ./fuzzquery ./lifecycle ./modules)
  • GitHub Check: integration_test (./events)
  • GitHub Check: build_test
  • GitHub Check: build_test
  • GitHub Check: Analyze (go)
  • GitHub Check: Analyze (javascript-typescript)

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

@github-actions
Copy link

github-actions bot commented Oct 23, 2025

Router-nonroot image scan passed

✅ No security vulnerabilities found in image:

ghcr.io/wundergraph/cosmo/router:sha-6301bf512ba9c49d2768d8ae254ae424e0e84def-nonroot

Copy link

@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: 0

🧹 Nitpick comments (1)
router-tests/complexity_limits_test.go (1)

59-133: Excellent test coverage for introspection bypass.

This test effectively validates that introspection queries bypass complexity limits. The test uses a depth limit of 1 but runs an introspection query with 7+ levels of nesting, clearly demonstrating the bypass behavior.

Consider adding a companion assertion within this test to verify that regular queries still respect the depth limit when introspection is enabled:

// After the introspection query succeeds, verify regular queries still blocked
res2, _ := xEnv.MakeGraphQLRequest(testenv.GraphQLRequest{
    Query: `{ employee(id:1) { id details { forename } } }`,
})
require.Equal(t, 400, res2.Response.StatusCode)
require.Contains(t, res2.Body, "exceeds the max query depth allowed")

This would provide more confidence that the introspection bypass doesn't accidentally disable depth limits for all queries.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 609cf13 and b5e7743.

⛔ Files ignored due to path filters (2)
  • router-tests/go.sum is excluded by !**/*.sum
  • router/go.sum is excluded by !**/*.sum
📒 Files selected for processing (3)
  • router-tests/complexity_limits_test.go (2 hunks)
  • router-tests/go.mod (1 hunks)
  • router/go.mod (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-08-20T22:13:25.222Z
Learnt from: StarpTech
PR: wundergraph/cosmo#2157
File: router-tests/go.mod:16-16
Timestamp: 2025-08-20T22:13:25.222Z
Learning: github.com/mark3labs/mcp-go v0.38.0 has regressions and should not be used in the wundergraph/cosmo project. v0.36.0 is the stable version that should be used across router-tests and other modules.

Applied to files:

  • router-tests/go.mod
🧬 Code graph analysis (1)
router-tests/complexity_limits_test.go (3)
router-tests/testenv/testenv.go (4)
  • Run (105-122)
  • Config (284-341)
  • Environment (1729-1765)
  • GraphQLRequest (1905-1913)
router/pkg/config/config.go (3)
  • Config (1000-1074)
  • SecurityConfiguration (410-420)
  • QueryDepthConfiguration (427-432)
router/core/router.go (2)
  • Option (172-172)
  • WithIntrospection (1539-1543)
⏰ 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). (11)
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: image_scan
  • GitHub Check: Analyze (go)
  • GitHub Check: build_push_image
  • GitHub Check: build_push_image (nonroot)
  • GitHub Check: integration_test (./telemetry)
  • GitHub Check: image_scan (nonroot)
  • GitHub Check: integration_test (./. ./fuzzquery ./lifecycle ./modules)
  • GitHub Check: integration_test (./events)
  • GitHub Check: build_test
  • GitHub Check: build_test
🔇 Additional comments (3)
router/go.mod (1)

34-34: LGTM! Dependency version consistent with router-tests.

The version bump matches the update in router-tests/go.mod, maintaining consistency across modules.

router-tests/complexity_limits_test.go (1)

10-10: LGTM! Import necessary for introspection option.

The core package import is required to use core.WithIntrospection(true) in the new test case.

router-tests/go.mod (1)

30-30: Feature is implemented and tested; however, note RC pre-release status.

The version rc.233 was released today (2025-10-23) and includes the implementation for excluding introspection queries from complexity limits, as confirmed by the git history showing the commit "fix: omit introspection queries for complexity limits" as the most recent go.mod change. The test "allows introspection queries without limits" in complexity_limits_test.go validates this functionality by setting a depth limit of 1 and confirming an introspection query succeeds despite the constraint.

That said, rc.233 is a pre-release (RC status), not a stable release. Consider whether a pre-release version is appropriate for your deployment environment, or plan to upgrade to a stable version (e.g., v2.0.0) once available.

@github-actions
Copy link

github-actions bot commented Nov 8, 2025

This PR was marked stale due to lack of activity. It will be closed in 14 days.

@github-actions github-actions bot added the Stale label Nov 8, 2025
Copy link

@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: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
router/core/operation_processor.go (1)

1162-1191: Don’t reuse complexity cache entries across SkipIntrospection flips

When SkipIntrospection is true we now drop the complexity for introspection documents, but we still cache that zeroed ComplexityCacheEntry. If an operator later disables SkipIntrospection, the cached entry (still keyed only by InternalID) is returned here and we never recompute, so the introspection operation keeps sailing through the limits despite the config change. That violates the expected guard until the cache is manually flushed or evicted, effectively disabling the limit.

Please include the skip flag in the cache identity (or bypass caching altogether while skipping) so toggling the option forces a fresh computation. For example:

-type ComplexityCacheEntry struct {
-	Depth            int
-	TotalFields      int
-	RootFields       int
-	RootFieldAliases int
-}
+type ComplexityCacheEntry struct {
+	Depth             int
+	TotalFields       int
+	RootFields        int
+	RootFieldAliases  int
+	SkipIntrospection bool
+}
@@
-	if o.cache != nil && o.cache.complexityCache != nil {
-		if cachedComplexity, found := o.cache.complexityCache.Get(o.parsedOperation.InternalID); found {
-			return true, cachedComplexity, o.runComplexityComparisons(limits, cachedComplexity, o.parsedOperation.IsPersistedOperation)
-		}
-	}
+	if o.cache != nil && o.cache.complexityCache != nil {
+		if cachedComplexity, found := o.cache.complexityCache.Get(o.parsedOperation.InternalID); found && cachedComplexity.SkipIntrospection == limits.SkipIntrospection {
+			return true, cachedComplexity, o.runComplexityComparisons(limits, cachedComplexity, o.parsedOperation.IsPersistedOperation)
+		}
+	}
@@
-	cacheResult := ComplexityCacheEntry{
-		Depth:       globalComplexityResult.Depth,
-		TotalFields: globalComplexityResult.NodeCount,
-	}
+	cacheResult := ComplexityCacheEntry{
+		Depth:             globalComplexityResult.Depth,
+		TotalFields:       globalComplexityResult.NodeCount,
+		SkipIntrospection: limits.SkipIntrospection,
+	}
🧹 Nitpick comments (2)
router/pkg/config/config.schema.json (1)

2599-2604: Good placement; fix tiny description typo.

Property is correctly added under security.complexity_limits. Tweak wording.

Apply:

-              "description": "Set to to true to skip introspection queries when calculating complexity limits."
+              "description": "Set to true to skip introspection queries when calculating complexity limits."
router/pkg/config/config.go (1)

440-445: Field addition aligns with schema; consider a brief doc comment.

Add a short comment to clarify scope (applies to all complexity checks).

 type ComplexityLimits struct {
-	Depth             *ComplexityLimit `yaml:"depth"`
-	TotalFields       *ComplexityLimit `yaml:"total_fields"`
-	RootFields        *ComplexityLimit `yaml:"root_fields"`
-	RootFieldAliases  *ComplexityLimit `yaml:"root_field_aliases"`
-	SkipIntrospection bool             `yaml:"skip_introspection" envDefault:"false"`
+	Depth             *ComplexityLimit `yaml:"depth"`
+	TotalFields       *ComplexityLimit `yaml:"total_fields"`
+	RootFields        *ComplexityLimit `yaml:"root_fields"`
+	RootFieldAliases  *ComplexityLimit `yaml:"root_field_aliases"`
+	// When true, introspection operations are excluded from all complexity checks.
+	SkipIntrospection bool `yaml:"skip_introspection" envDefault:"false"`
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b5e7743 and bcc0222.

⛔ Files ignored due to path filters (2)
  • router-tests/go.sum is excluded by !**/*.sum
  • router/go.sum is excluded by !**/*.sum
📒 Files selected for processing (8)
  • router-tests/complexity_limits_test.go (2 hunks)
  • router-tests/go.mod (1 hunks)
  • router/core/operation_processor.go (2 hunks)
  • router/core/router.go (1 hunks)
  • router/go.mod (1 hunks)
  • router/pkg/config/config.go (2 hunks)
  • router/pkg/config/config.schema.json (1 hunks)
  • router/pkg/config/testdata/config_full.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • router/go.mod
🧰 Additional context used
🧠 Learnings (14)
📓 Common learnings
Learnt from: SkArchon
Repo: wundergraph/cosmo PR: 2252
File: router-tests/telemetry/telemetry_test.go:9684-9693
Timestamp: 2025-10-01T20:39:16.113Z
Learning: Repo preference: In router-tests/telemetry/telemetry_test.go, keep strict > 0 assertions for request.operation.*Time (parsingTime, normalizationTime, validationTime, planningTime) in telemetry-related tests; do not relax to >= 0 unless CI flakiness is observed.
📚 Learning: 2025-09-29T10:28:07.122Z
Learnt from: dkorittki
Repo: wundergraph/cosmo PR: 2192
File: router/pkg/config/config.go:1028-1029
Timestamp: 2025-09-29T10:28:07.122Z
Learning: The deprecation strategy for IntrospectionEnabled field in router/pkg/config/config.go is to first mark it as deprecated, then migrate all call sites to use IntrospectionConfig.Enabled, and finally remove the deprecated field. The envDefault tag should be kept during the deprecation period for backward compatibility.

Applied to files:

  • router/pkg/config/config.go
  • router/core/router.go
📚 Learning: 2025-08-28T09:59:19.999Z
Learnt from: SkArchon
Repo: wundergraph/cosmo PR: 2167
File: router/core/supervisor_instance.go:196-204
Timestamp: 2025-08-28T09:59:19.999Z
Learning: In router/pkg/config/config.go, the BackoffJitterRetry struct uses envDefault tags to provide default values for Algorithm ("backoff_jitter") and Expression ("IsRetryableStatusCode() || IsConnectionError() || IsTimeout()"), ensuring that even when YAML configs omit these fields, valid defaults are applied automatically, preventing ProcessRetryOptions from rejecting empty values.

Applied to files:

  • router/pkg/config/config.go
📚 Learning: 2025-07-30T09:29:46.660Z
Learnt from: SkArchon
Repo: wundergraph/cosmo PR: 2090
File: router/pkg/config/config.schema.json:0-0
Timestamp: 2025-07-30T09:29:46.660Z
Learning: The "operation_name_trim_limit" configuration property in router/pkg/config/config.schema.json should be placed at the security level as a sibling to complexity_limits, not inside the complexity_limits object.

Applied to files:

  • router/pkg/config/config.go
  • router/core/router.go
  • router/core/operation_processor.go
  • router/pkg/config/config.schema.json
  • router/pkg/config/testdata/config_full.json
📚 Learning: 2025-07-21T15:06:36.664Z
Learnt from: SkArchon
Repo: wundergraph/cosmo PR: 2067
File: router/pkg/config/config.schema.json:1637-1644
Timestamp: 2025-07-21T15:06:36.664Z
Learning: In the Cosmo router project, when extending JSON schema validation for security-sensitive fields like JWKS secrets, backwards compatibility is maintained by implementing warnings in the Go code rather than hard validation constraints in the schema. This allows existing configurations to continue working while alerting users to potential security issues.

Applied to files:

  • router/core/router.go
  • router/pkg/config/config.schema.json
  • router/pkg/config/testdata/config_full.json
📚 Learning: 2025-08-20T22:13:25.222Z
Learnt from: StarpTech
Repo: wundergraph/cosmo PR: 2157
File: router-tests/go.mod:16-16
Timestamp: 2025-08-20T22:13:25.222Z
Learning: github.com/mark3labs/mcp-go v0.38.0 has regressions and should not be used in the wundergraph/cosmo project. v0.36.0 is the stable version that should be used across router-tests and other modules.

Applied to files:

  • router-tests/go.mod
  • router-tests/complexity_limits_test.go
📚 Learning: 2025-10-01T20:39:16.113Z
Learnt from: SkArchon
Repo: wundergraph/cosmo PR: 2252
File: router-tests/telemetry/telemetry_test.go:9684-9693
Timestamp: 2025-10-01T20:39:16.113Z
Learning: Repo preference: In router-tests/telemetry/telemetry_test.go, keep strict > 0 assertions for request.operation.*Time (parsingTime, normalizationTime, validationTime, planningTime) in telemetry-related tests; do not relax to >= 0 unless CI flakiness is observed.

Applied to files:

  • router-tests/go.mod
  • router-tests/complexity_limits_test.go
📚 Learning: 2025-09-24T12:54:00.765Z
Learnt from: endigma
Repo: wundergraph/cosmo PR: 2222
File: router-tests/websocket_test.go:2238-2302
Timestamp: 2025-09-24T12:54:00.765Z
Learning: The wundergraph/cosmo project uses Go 1.25 (Go 1.23+ minimum), so fmt.Appendf and other newer Go standard library functions are available and can be used without compatibility concerns.

Applied to files:

  • router-tests/go.mod
📚 Learning: 2025-09-24T12:54:00.765Z
Learnt from: endigma
Repo: wundergraph/cosmo PR: 2222
File: router-tests/websocket_test.go:2238-2302
Timestamp: 2025-09-24T12:54:00.765Z
Learning: The wundergraph/cosmo project uses Go 1.25 (Go 1.25 minimum), so fmt.Appendf and other newer Go standard library functions are available and can be used without compatibility concerns.

Applied to files:

  • router-tests/go.mod
📚 Learning: 2025-08-15T10:21:45.838Z
Learnt from: StarpTech
Repo: wundergraph/cosmo PR: 2142
File: helm/cosmo/Chart.yaml:0-0
Timestamp: 2025-08-15T10:21:45.838Z
Learning: In the WunderGraph Cosmo project, helm chart version upgrades and README badge synchronization are handled in separate helm release PRs, not in the initial version bump PRs.

Applied to files:

  • router-tests/go.mod
📚 Learning: 2025-08-20T10:08:17.857Z
Learnt from: endigma
Repo: wundergraph/cosmo PR: 2155
File: router/core/router.go:1857-1866
Timestamp: 2025-08-20T10:08:17.857Z
Learning: router/pkg/config/config.schema.json forbids null values for traffic_shaping.subgraphs: additionalProperties references $defs.traffic_shaping_subgraph_request_rule with type "object". Therefore, in core.NewSubgraphTransportOptions, dereferencing each subgraph rule pointer is safe under schema-validated configs, and a nil-check is unnecessary.

Applied to files:

  • router/pkg/config/config.schema.json
📚 Learning: 2025-08-20T10:08:17.857Z
Learnt from: endigma
Repo: wundergraph/cosmo PR: 2155
File: router/core/router.go:1857-1866
Timestamp: 2025-08-20T10:08:17.857Z
Learning: In the Cosmo router codebase, JSON schema validation prevents null values in TrafficShapingRules subgraph configurations, making nil checks unnecessary when dereferencing subgraph rule pointers in NewSubgraphTransportOptions.

Applied to files:

  • router/pkg/config/config.schema.json
📚 Learning: 2025-08-28T09:17:49.477Z
Learnt from: endigma
Repo: wundergraph/cosmo PR: 2141
File: router-tests/http_subscriptions_test.go:17-55
Timestamp: 2025-08-28T09:17:49.477Z
Learning: The Cosmo router uses a custom, intentionally rigid multipart implementation for GraphQL subscriptions. The multipart parsing in test files should remain strict and not be made more tolerant, as this rigidity is by design.

Applied to files:

  • router-tests/complexity_limits_test.go
📚 Learning: 2025-07-21T14:46:34.879Z
Learnt from: SkArchon
Repo: wundergraph/cosmo PR: 2067
File: router/pkg/authentication/jwks_token_decoder.go:80-106
Timestamp: 2025-07-21T14:46:34.879Z
Learning: In the Cosmo router project, required field validation for JWKS configuration (Secret, Algorithm, KeyId) is handled at the JSON schema level in config.schema.json rather than through runtime validation in the Go code at router/pkg/authentication/jwks_token_decoder.go.

Applied to files:

  • router/pkg/config/testdata/config_full.json
🧬 Code graph analysis (1)
router-tests/complexity_limits_test.go (3)
router-tests/testenv/testenv.go (4)
  • Run (105-122)
  • Config (284-341)
  • Environment (1731-1767)
  • GraphQLRequest (1907-1915)
router/pkg/config/config.go (5)
  • Config (1007-1082)
  • IntrospectionConfiguration (1002-1005)
  • SecurityConfiguration (410-420)
  • ComplexityLimits (439-445)
  • ComplexityLimit (447-451)
router/core/router.go (2)
  • Option (172-172)
  • WithIntrospection (1548-1553)
⏰ 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). (11)
  • GitHub Check: Analyze (go)
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: build_test
  • GitHub Check: build_push_image (nonroot)
  • GitHub Check: image_scan (nonroot)
  • GitHub Check: integration_test (./. ./fuzzquery ./lifecycle ./modules)
  • GitHub Check: integration_test (./events)
  • GitHub Check: build_test
  • GitHub Check: build_push_image
  • GitHub Check: integration_test (./telemetry)
  • GitHub Check: image_scan
🔇 Additional comments (3)
router/pkg/config/testdata/config_full.json (1)

712-714: Config sample update matches new field.

The sample adds SkipIntrospection at the correct location and casing. LGTM.

router/pkg/config/config.go (1)

453-455: ApplyLimit logic is correct.

Condition simplifies to “enabled and not (persistent AND ignorePersisted)”. No issues.

router-tests/go.mod (1)

30-30: Dependency bump verified and cross-module alignment confirmed.

Both router/go.mod and router-tests/go.mod point to the same graphql-go-tools/v2 version (v2.0.0-rc.237.0.20251111144341-5d93cce1da45), ensuring consistent planner/parser behavior across modules.

@github-actions github-actions bot removed the Stale label Nov 12, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants