Skip to content

spp_api_v2: paging and logging follow-ups from #554 (/_search paging, prev links, Program cursor, error logs, PII) #574

Description

@gonzalesedwin1123

Items

  1. POST /Individual/_search (routers/filter.py:228) has the paging defects fix(api_v2): REST API v2 defects found by the OpenFn adaptor (#554) #555 fixed in the GET searches:

    • next is dropped on a short page
    • the id > last_record_id cursor combined with an arbitrary sort skips rows
  2. prev links on consent-filtered pages are approximate (offset - count doesn't invert the scanned offset).

  3. GET /Program pages with _lastId, a raw database id (against api-design.md), and its total is counted after
    the cursor, so it shrinks from page to page. The Program list also includes archived programs that
    GET /Program/{id} can't read.

  4. After fix(api_v2): REST API v2 defects found by the OpenFn adaptor (#554) #555, D10 lets a consent client with _count=1 over many hidden rows follow many empty pages (the 3×count
    scan cap). Consider scanning up to the per-query maximum on short consent pages.

  5. D10 signal: walking next offsets on a consent-filtered search reveals how many hidden rows match a filter
    (final offset − visible). It is accepted under D10; revisit with security(spp_api_v2): "exists but no consent" 403 has no timing jitter, unlike "not found" [Severity: Low] #559/security(spp_api_v2_programs): POST /ProgramMembership "Beneficiary not found: <ref>" 422 reveals registrant existence [Severity: Low] #560.

  6. odoo.http logs every handled HTTPException (any 4xx) at ERROR ("Exception during request handling"):
    144 such lines in the spp_api_v2 suite, and the same noise in production logs.

  7. Identifier values (e.g. national IDs) in INFO logs:

    • ProgramMembership create/update
    • group_service add/update/remove member

    Same class as spp_api_v2: GroupService._create_members logs identifier values (PII in logs) #566.

  8. Unbounded deep _offset scans on the searches (bounded to bigint in fix(api_v2): REST API v2 defects found by the OpenFn adaptor (#554) #555, but not for cost).

  9. 409/404 detection in the member endpoints matches English substrings of translated messages ("already a member",
    "not a member"). A translation would turn them into 422. Use dedicated exception classes.

  10. group=none loads every active membership into an id not in [...] list on each batch. Use a not any domain.

  11. A savepoint rollback clears the cursor's precommit hooks (Odoo 19 _FlushingSavepoint). No impact today (no
    precommit use in spp_api_v2*); note it for when audit logging moves to precommit.

  12. spp_api_v2_change_request:

  13. Search timing: a hidden match costs serialization + consent queries per row, an unknown identifier costs nothing;
    the search path has no jitter (the read path does). Run the cheap consent check before to_api_schema.

  14. routers/group.py:

    • membership-history self/next/prev links (:1012) and the Location headers (:332, :949) carry a raw #
    • membership-history _offset (:966) has no le=MAX_OFFSET (huge value gives a 500)
  15. Role lookups accept a code from any vocabulary ($add-member with urn:iso:std:iso:5218|1 links "Male" as a role).
    Restricting to urn:openspp:vocab:group-membership-type needs an owner decision; the existing tests use a test
    vocabulary.

  16. Read endpoints decide consent/jitter from is_require_consent, while search and filter_response use
    legal_basis. A client with legal_basis="consent" and is_require_consent=False is consent-filtered in search
    but unchecked on read.

  17. Three copies of the non-consent legal-basis list:

    • ConsentService.NON_CONSENT_BASES
    • AuthenticatedClient.has_legal_basis_bypass
    • spp_dci_server/services/consent_adapter.py
  18. $add-member and $split catch-alls still return str(e) when the text contains "already a member", "not a
    member" or "head".

  19. Nits:


Found while checking OpenSPP2 REST API v2 against the OpenFn @openfn/language-openspp v4 adaptor (#554, PR #555); not fixed in #555.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions