Skip to content

fix(graphql): reject at query times before branch creation#9482

Draft
gmazoyer wants to merge 2 commits into
stablefrom
gma-20260605-4076
Draft

fix(graphql): reject at query times before branch creation#9482
gmazoyer wants to merge 2 commits into
stablefrom
gma-20260605-4076

Conversation

@gmazoyer

@gmazoyer gmazoyer commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Why

When a user picked a time-travel timestamp earlier than the Infrahub instance was created, the backend silently loaded an empty schema at that time and surfaced a generic, unactionable error (typically a deep schema-lookup failure from a resolver).

This PR makes the backend reject out-of-range at values at the request boundary with a clear, user-facing 422 that names the offending timestamp and the branch's effective lifetime.

Closes #4076

What changed

  • Requests with ?at=<time earlier than the branch's effective creation> now return HTTP 422 with a message like Requested time '2000-01-01T00:00:00.000000Z' is before branch 'main' was created at '2026-06-05T...'..
  • On a user branch, the floor is the origin branch's created_at, not the user branch's own branched_from, so legitimate historical-on-origin queries between origin.created_at and self.branched_from continue to work.
  • Mutations are unaffected: the existing override forces at = now before the validator can run.

Checklist

  • Tests added/updated
  • Changelog entry added (uv run towncrier create ...)
  • I have reviewed AI generated content

Summary by cubic

Rejects GraphQL and REST queries where at is earlier than the branch’s effective creation time, returning HTTP 422 with a clear message. Prevents confusing resolver errors caused by loading an empty schema.

  • Bug Fixes
    • Validate at at the request boundary (GraphQL and REST) and return 422 with a message that includes the requested time and the boundary branch’s creation time.
    • For user branches, use the origin branch’s created_at as the floor; historical queries on origin still work. Mutations unchanged (force at=now).
    • Added Branch.validate_query_time, integrated into REST dependency and GraphQL handler; tests cover REST and GraphQL; changelog entry.

Written for commit f1b2b7d. Summary will update on new commits.

Review in cubic

Validate the user-supplied `at` at the REST and GraphQL request
boundaries. Out-of-range timestamps now return a 422 with a clear,
user-facing message instead of a deep, generic resolver error caused
by `load_schema_from_db` returning an empty schema.
@github-actions github-actions Bot added the group/backend Issue related to the backend (API Server, Git Agent) label Jun 5, 2026

@cubic-dev-ai cubic-dev-ai Bot 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.

1 issue found across 5 files

Confidence score: 4/5

  • This PR looks safe to merge with minimal risk: the reported issue is low-to-moderate severity (4/10) and appears limited to HTTP status mapping behavior rather than core endpoint logic.
  • In backend/infrahub/api/dependencies.py, the new validation path may raise ValidationError expecting a 422, but the app-level handler currently translates it to 400, which can cause REST clients to receive the wrong error contract.
  • Pay close attention to backend/infrahub/api/dependencies.py - validation errors may return 400 instead of the intended 422 on REST endpoints.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="backend/infrahub/api/dependencies.py">

<violation number="1" location="backend/infrahub/api/dependencies.py:86">
P2: The new validation does not actually return the intended 422 on REST endpoints; the app-wide handler maps `ValidationError` to 400.</violation>
</file>

Shadow auto-approve: would not auto-approve because issues were found.

Re-trigger cubic

return BranchParams(branch=branch, at=Timestamp(at))
at_ts = Timestamp(at)
if at is not None:
branch.validate_query_time(at_ts)

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.

P2: The new validation does not actually return the intended 422 on REST endpoints; the app-wide handler maps ValidationError to 400.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At backend/infrahub/api/dependencies.py, line 86:

<comment>The new validation does not actually return the intended 422 on REST endpoints; the app-wide handler maps `ValidationError` to 400.</comment>

<file context>
@@ -81,7 +81,11 @@ async def get_branch_params(
-    return BranchParams(branch=branch, at=Timestamp(at))
+    at_ts = Timestamp(at)
+    if at is not None:
+        branch.validate_query_time(at_ts)
+
+    return BranchParams(branch=branch, at=at_ts)
</file context>

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The test_query_endpoint_at_before_branch_creation test covers this path and shows that a 422 is surfaced.

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.

Got it — thanks for the correction.

@codspeed-hq

codspeed-hq Bot commented Jun 5, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 12 untouched benchmarks


Comparing gma-20260605-4076 (f1b2b7d) with stable (2a1cff7)

Open in CodSpeed

@cubic-dev-ai cubic-dev-ai Bot 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.

0 issues found across 1 file (changes from recent commits).

Shadow auto-approve: would not auto-approve. Auto-approval blocked by 1 unresolved issue from previous reviews.

Re-trigger cubic

try:
branch.validate_query_time(at_ts)
except ValidationError as exc:
return JSONResponse(exc.api_response(), status_code=exc.HTTP_CODE)

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'm wondering if we need to raise a JSONResponse error here or if it would get managed automatically regardless?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

group/backend Issue related to the backend (API Server, Git Agent)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: Rewinding time to before an instance is spun up gives unactionable error message

2 participants