Skip to content

fix(types): expose page/limit/totalPages on the paginated indicator surfaces - #5

Merged
batuhanisildak-malwation merged 1 commit into
mainfrom
fix/paginated-response-envelope
Aug 2, 2026
Merged

batuhanisildak-malwation merged 1 commit into
mainfrom
fix/paginated-response-envelope

Conversation

@batuhanisildak-malwation

Copy link
Copy Markdown
Contributor

Found while integrating the Public API from an external client, verified against the live service with a real submission.

The gap

IoCsResponse, IndicatorsResponse and YaraRulesResponse model only items and total. The API returns the full envelope on all three:

GET /submissions/{uuid}/iocs?page=1&limit=5
-> {"items": [...], "total": 35, "page": 1, "limit": 5, "totalPages": 7}

Pydantic silently drops the three extra keys, so a caller cannot page these endpoints without recomputing from total what the service already sent — and has no way to discover totalPages exists at all.

BehavioursResponse (types/behaviours.py:42) has exposed page, limit and total_pages all along, so the SDK was inconsistent with itself.

Why no test caught it

The in-memory fake had the same hole. build_iocs_response and friends returned {items, total}, so the fixtures agreed with the incomplete models rather than with the API they stand in for — a fake that reproduces the bug it should expose.

The builders now apply the documented defaults (page 1, limit 20), slice accordingly, and emit the whole envelope, so the fake pages like the real service.

Changes

  • types/indicators.py — the three models gain page, limit, total_pages (aliased totalPages), matching BehavioursResponse exactly.
  • testing/_responses.py — the three builders emit the full envelope and paginate.
  • tests/conftest.py — the shared fixtures carry the fields the API actually sends.
  • tests/test_types.py — asserts all three surfaces expose the envelope.

Required rather than optional, matching the service DTOs (indicators.response.dto.ts:126,211,259), which declare them non-optional, and matching the existing BehavioursResponse precedent.

Verification

607 tests pass, ruff check clean, mypy clean on 33 source files.

Related

Companion to Malwation/threatzone-services#1455 — the guides for these same three endpoints omitted the same three fields, so the docs and the SDK were wrong in the same place.

…urfaces

IoCsResponse, IndicatorsResponse and YaraRulesResponse modelled only items and
total. The API returns page, limit and totalPages on all three -- verified
against app.threat.zone, where /iocs?page=1&limit=5 answers
{items, total: 35, page: 1, limit: 5, totalPages: 7} -- and BehavioursResponse
has exposed the full envelope all along. Pydantic silently dropped the three
extra keys, so a caller could not page these endpoints without recomputing from
total what the service had already sent, and had no way to learn totalPages
existed.

The fake server had the same hole, which is why no test caught it: its builders
returned {items, total} and therefore agreed with the incomplete models rather
than with the API they stand in for. They now apply the documented defaults
(page 1, limit 20), slice accordingly and emit the whole envelope, so the
in-memory server pages like the real one.

Companion to the public-api docs fix: the guides for these three endpoints
omitted the same three fields.
@batuhanisildak-malwation
batuhanisildak-malwation merged commit a92c642 into main Aug 2, 2026
7 checks passed
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.

1 participant