Skip to content

fix: validate negative offset and limit in graphql resolver#9203

Merged
ogenstad merged 3 commits into
opsmill:stablefrom
DharmaBytesX:fix/negative-offset-limit-validation
May 13, 2026
Merged

fix: validate negative offset and limit in graphql resolver#9203
ogenstad merged 3 commits into
opsmill:stablefrom
DharmaBytesX:fix/negative-offset-limit-validation

Conversation

@DharmaBytesX

Copy link
Copy Markdown
Contributor

Closes #7474

What

Adds input validation in default_paginated_list_resolver to reject negative limit and offset values with a user-friendly GraphQLError before reaching the database layer.

Before

Negative values were passed through to Neo4j, resulting in a CypherSyntaxError with an unhelpful stack trace in the server logs.

After

The resolver immediately raises a GraphQLError with a clear message (limit must be a non-negative integer / offset must be a non-negative integer).

Tests

Added unit tests in backend/tests/unit/graphql/resolvers/test_resolver.py covering both limit and offset validation.

@DharmaBytesX DharmaBytesX requested a review from a team as a code owner May 10, 2026 13:26
@codspeed-hq

codspeed-hq Bot commented May 10, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 12 untouched benchmarks


Comparing DharmaBytesX:fix/negative-offset-limit-validation (24001a4) with stable (7c1fe93)

Open in CodSpeed

@dgarros dgarros left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@DharmaBytesX

Copy link
Copy Markdown
Contributor Author

Hey, I added the changelog entry in changelog/7474.fixed.md.

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.

I suppose other resolvers would be affected by this too, the first coming to my mind is backend/infrahub/graphql/resolvers/ipam.py. Considering that, I would extract that tiny logic into a function that resolvers could call. That would also make the logic itself easier to test.

from infrahub.graphql.resolvers.resolver import default_paginated_list_resolver


@pytest.mark.anyio

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.

No need for those pytest.mark.anyio.


@pytest.mark.anyio
async def test_negative_limit_raises() -> None:
info = MagicMock()

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.

We tend to avoid mocks but that seems about right here in a unit test.

if limit is not None and limit < 0:
raise GraphQLError("limit must be a non-negative integer")
if offset is not None and offset < 0:
raise GraphQLError("offset must be a non-negative integer")

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.

If we look at the rest of the function this check comes a bit to late. For instance on line 208 we start a new database session and on line 226 there's a query to the database regarding permissions. So a check like this should be at the start of this function and fail early.

await default_paginated_list_resolver(root=None, info=info, limit=-1)


@pytest.mark.anyio

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.

These pytest markers should not be needed.


@pytest.mark.anyio
async def test_negative_limit_raises() -> None:
info = MagicMock()

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.

While we have mocking in this repo we're trying to phase it out, the reason being that it becomes quite muddy with regards to what is actually being testing when some interfaces doesn't behave as you would expect and with future changes bugs might be introduced when we thought that we had tests to cover a given scenario. If we move the check up as described above we can send in anything to the info parameter. If it's just about making the type checker happy a cast() of None into the correct type could do the trick here. Ideally we should not use cast() within the code either, however in this case it could be fine short of creating a dummy object.

After the change the main problem with having a MagicMock for something like this is that AI agents looking at other tests to figure out the structure can think that it's ok to continue using mocking.

Comment thread changelog/7474.fixed.md Outdated
@@ -0,0 +1 @@
Fixed GraphQL resolver returning an unhelpful database error when negative values were provided for limit or offset query arguments.

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.

Unfortunately this doesn't fix all of the resolvers, could you please update this to say that it fixes the standard resolver for schema based objects?

@ogenstad

Copy link
Copy Markdown
Contributor

Ah see that both me and @gmazoyer was reviewing at the same type. 😅

@DharmaBytesX

Copy link
Copy Markdown
Contributor Author

Thx for the input. I've refacto the logic into a tiny validation function, moved the check earlier, cleaned up the tests, and updated the changelog.

@DharmaBytesX

Copy link
Copy Markdown
Contributor Author

The CI issue is not code related

@ogenstad ogenstad 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.

Thank you for your contribution and the changes!

Approving, but also as an internal note as the release notes for Infrahub 1.9.4 has already been generated we should wait for that version to be released before merging this PR so that it gets included in Infrahub 1.9.5 instead.

@ogenstad ogenstad merged commit f44cfc2 into opsmill:stable May 13, 2026
90 of 91 checks passed
@DharmaBytesX DharmaBytesX deleted the fix/negative-offset-limit-validation branch May 13, 2026 11:46
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.

bug: Late errors for negative offset or limit query parameters

4 participants