fix: add shared API pagination and failure handling (#67) #83

Merged
sysadmin merged 1 commits from fix/issue-67-api-pagination-failures into master 2026-07-02 12:42:10 -05:00
Owner

Implements #67. Narrow API-reliability improvement with unit coverage — no mcp_server.py modular refactor (#65).

Reliability gap

gitea_auth.api_request had no request timeout, let URLError/timeouts/DNS failures propagate raw (uncaught), gave 502/503 no clarity, raised bare JSONDecodeError on malformed success bodies, echoed raw upstream error bodies unredacted, and did no pagination (one page only — gitea_list_issues even crashed on a None body).

Changes

gitea_auth.py

  • api_request hardened: per-request timeout (env GITEA_HTTP_TIMEOUT, default 30s); (URLError, TimeoutError) → clear RuntimeError("network error contacting Gitea: …"); 502/503/504 → explicit "Gitea upstream unavailable"; malformed success JSON → RuntimeError("malformed JSON response…"); all error text redacted via the audit redactor. Success path and 429 retry/backoff preserved.
  • New shared api_get_all(url, auth, *, limit=None, page_size=50, max_pages=100): page-based pagination that relies on page length (tolerates missing/malformed X-Total-Count/Link metadata), honors an optional overall limit, and caps pages. Reuses api_request (inherits failure handling).

mcp_server.py — wired api_get_all into read-only list tools gitea_list_issues, gitea_list_prs, gitea_list_labels. Return shapes unchanged; list_issues still honors limit as an overall max, now across pages. Internal ?limit=100 label-id lookups left unchanged (out of scope; noted follow-up).

Tests

  • New tests/test_api_reliability.py — 18 cases: single/multi-page, missing metadata, malformed (non-list) metadata, limit cap, max-pages cap, query preservation; timeout, DNS/network, 502/503, malformed error payload, malformed success JSON, no-secret leakage, auth-header-never-in-error, success + 429 preserved.
  • Updated the 3 list-tool tests in test_mcp_server.py to the new call path.

Checks

  • py_compile mcp_server.py / manage_labels.py (+gitea_auth.py) — OK
  • bash -n scripts/clear-provenance — OK
  • git diff --check — clean
  • pytest tests/ -q345 passed (327 → +18)
  • Secret sweep (no repo scanner; staged-diff sweep) — clean

Scope

No auth/profile/merge/review/tracker behavior changed. No Jenkins/GlitchTip/release/worktree changes. No #65 refactor.

🤖 Generated with Claude Code

Implements #67. Narrow API-reliability improvement with unit coverage — **no** `mcp_server.py` modular refactor (#65). ## Reliability gap `gitea_auth.api_request` had no request timeout, let `URLError`/timeouts/DNS failures propagate raw (uncaught), gave 502/503 no clarity, raised bare `JSONDecodeError` on malformed success bodies, echoed raw upstream error bodies unredacted, and did no pagination (one page only — `gitea_list_issues` even crashed on a `None` body). ## Changes **`gitea_auth.py`** - `api_request` hardened: per-request `timeout` (env `GITEA_HTTP_TIMEOUT`, default 30s); `(URLError, TimeoutError)` → clear `RuntimeError("network error contacting Gitea: …")`; 502/503/504 → explicit "Gitea upstream unavailable"; malformed success JSON → `RuntimeError("malformed JSON response…")`; all error text redacted via the audit redactor. **Success path and 429 retry/backoff preserved.** - New shared `api_get_all(url, auth, *, limit=None, page_size=50, max_pages=100)`: page-based pagination that relies on page length (tolerates missing/malformed `X-Total-Count`/`Link` metadata), honors an optional overall `limit`, and caps pages. Reuses `api_request` (inherits failure handling). **`mcp_server.py`** — wired `api_get_all` into read-only list tools `gitea_list_issues`, `gitea_list_prs`, `gitea_list_labels`. Return shapes unchanged; `list_issues` still honors `limit` as an overall max, now across pages. Internal `?limit=100` label-id lookups left unchanged (out of scope; noted follow-up). ## Tests - New `tests/test_api_reliability.py` — 18 cases: single/multi-page, missing metadata, malformed (non-list) metadata, limit cap, max-pages cap, query preservation; timeout, DNS/network, 502/503, malformed error payload, malformed success JSON, no-secret leakage, auth-header-never-in-error, success + 429 preserved. - Updated the 3 list-tool tests in `test_mcp_server.py` to the new call path. ## Checks - `py_compile mcp_server.py` / `manage_labels.py` (+`gitea_auth.py`) — OK - `bash -n scripts/clear-provenance` — OK - `git diff --check` — clean - `pytest tests/ -q` — **345 passed** (327 → +18) - Secret sweep (no repo scanner; staged-diff sweep) — clean ## Scope No auth/profile/merge/review/tracker behavior changed. No Jenkins/GlitchTip/release/worktree changes. No #65 refactor. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
jcwalker3 added 1 commit 2026-07-02 12:27:31 -05:00
Harden gitea_auth.api_request: add a per-request timeout (env
GITEA_HTTP_TIMEOUT), convert timeouts and DNS/network failures
(URLError/TimeoutError) into clear RuntimeErrors, give 502/503/504 an
explicit 'upstream unavailable' message, convert malformed success JSON
into a clean error, and redact credential-like substrings from all error
text. Preserves the success path and existing 429 retry/backoff.

Add shared gitea_auth.api_get_all: page-based pagination that tolerates
missing/malformed metadata (relies on page length, not Link/X-Total-Count
headers), honors an optional overall limit, and caps pages. Wire it into
the read-only list tools gitea_list_issues, gitea_list_prs, and
gitea_list_labels (return shape unchanged).

Add tests/test_api_reliability.py (18 cases) and update the three list-tool
tests to the new call path. No auth/profile/merge/review/tracker behavior
changed. No modular #65 refactor.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
sysadmin reviewed 2026-07-02 12:41:43 -05:00
sysadmin left a comment
Owner

Reviewed PR #83 at cfe3ff6755. Scope is limited to shared Gitea API reliability/pagination handling and tests. Changed files match expected, pagination is wired only into list PRs/issues/labels, targeted and full test suites pass, and no auth/profile/merge/review/tracker behavior or Jenkins/GlitchTip work is included.

Reviewed PR #83 at cfe3ff67556a159d54c9f02da3ff94928ea3b385. Scope is limited to shared Gitea API reliability/pagination handling and tests. Changed files match expected, pagination is wired only into list PRs/issues/labels, targeted and full test suites pass, and no auth/profile/merge/review/tracker behavior or Jenkins/GlitchTip work is included.
sysadmin merged commit 53e061bafd into master 2026-07-02 12:42:10 -05:00
Sign in to join this conversation.