Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions tests/api/test_graphql_authenticated.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,55 @@ def test_audits_without_sort_options_returns_well_formed_response(
assert "totalItemsCount" in wrapper


AUDITS_BY_UPDATED_AT = """
query($limit: Int, $filters: [FilterSpec!], $sortOptions: [SortSpec!]) {
audits(limit: $limit, filters: $filters, sortOptions: $sortOptions) {
data { id updatedAt }
totalItemsCount
}
}
"""


class TestAuditsUpdatedAt:
"""`updated_at` is in the audits sort and filter allowlists (ParakhAI-Backend#130, #133)."""

def _audits(self, client, **variables):
result = client(AUDITS_BY_UPDATED_AT, variables={"limit": 20, **variables})
assert not result.get("errors"), f"audits query errored: {result.get('errors')}"
return result["data"]["audits"]

def test_audits_sorted_by_updated_at_asc_is_non_decreasing(self, authenticated_graphql_client):
# Ascending, because the default order (created_at desc) would fail it.
rows = self._audits(
authenticated_graphql_client,
sortOptions=[{"field": "updated_at", "direction": "asc"}],
)["data"]
values = [r["updatedAt"] for r in rows]
if len(values) < 2:
pytest.skip("Fewer than 2 audits — not enough data to prove ordering")
assert values == sorted(values), f"updatedAt is not ascending: {values}"

def test_audits_filtered_by_updated_at_narrows_the_result(self, authenticated_graphql_client):
everything = self._audits(
authenticated_graphql_client,
sortOptions=[{"field": "updated_at", "direction": "desc"}],
)
if everything["totalItemsCount"] < 11:
pytest.skip("Too few audits to pick a cutoff that narrows the result")
cutoff = everything["data"][9]["updatedAt"]

filtered = self._audits(
authenticated_graphql_client,
filters=[{"field": "updated_at", "condition": "gte", "value": cutoff}],
)
assert 0 < filtered["totalItemsCount"] < everything["totalItemsCount"], (
f"Filtering on updated_at >= {cutoff} returned {filtered['totalItemsCount']} "
f"of {everything['totalItemsCount']} audits; the filter was not applied"
)
assert all(r["updatedAt"] >= cutoff for r in filtered["data"])


# ── Audit tests pagination (new — Jun 2026) ───────────────────────────────────


Expand Down
4 changes: 2 additions & 2 deletions tests/api/test_security.py
Original file line number Diff line number Diff line change
Expand Up @@ -649,7 +649,7 @@ def test_audits_sort_by_non_allowlisted_field_is_rejected(
"""A sort field outside the server allowlist must fail closed.

Allowed sort fields for `audits` are name/status/model_snapshot__display_name/
passed_tests/evaluation_mode/audit_type/completed_at/created_at. Anything else
passed_tests/evaluation_mode/audit_type/completed_at/created_at/updated_at. Anything else
must be rejected — not silently ignored (falling back to default ordering while
looking successful) and not passed through to the ORM.
"""
Expand Down Expand Up @@ -681,7 +681,7 @@ def test_audits_filter_by_non_allowlisted_field_is_rejected(
"""A filter field outside the server allowlist must fail closed.

Allowed filter fields for `audits` are name/model_snapshot__display_name/
audit_type/evaluation_mode/model_id/status/completed_at — notably `requested_by`
audit_type/evaluation_mode/model_id/status/completed_at/updated_at — notably `requested_by`
(the owning user FK) is NOT allowed, so a client can't filter by arbitrary
internal fields even though the underlying ORM call would otherwise accept them.
"""
Expand Down
Loading