fix(graphql): reject at query times before branch creation#9482
fix(graphql): reject at query times before branch creation#9482gmazoyer wants to merge 2 commits into
at query times before branch creation#9482Conversation
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.
There was a problem hiding this comment.
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 raiseValidationErrorexpecting 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) |
There was a problem hiding this comment.
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>
There was a problem hiding this comment.
The test_query_endpoint_at_before_branch_creation test covers this path and shows that a 422 is surfaced.
There was a problem hiding this comment.
Got it — thanks for the correction.
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
I'm wondering if we need to raise a JSONResponse error here or if it would get managed automatically regardless?
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
atvalues 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
?at=<time earlier than the branch's effective creation>now return HTTP 422 with a message likeRequested time '2000-01-01T00:00:00.000000Z' is before branch 'main' was created at '2026-06-05T...'..created_at, not the user branch's ownbranched_from, so legitimate historical-on-origin queries betweenorigin.created_atandself.branched_fromcontinue to work.at = nowbefore the validator can run.Checklist
uv run towncrier create ...)Summary by cubic
Rejects GraphQL and REST queries where
atis 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.atat the request boundary (GraphQL and REST) and return 422 with a message that includes the requested time and the boundary branch’s creation time.created_atas the floor; historical queries on origin still work. Mutations unchanged (forceat=now).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.