No test coverage for rss.py's feed parsing or app.py's ssrf_check #20

Closed
opened 2026-08-13 19:33:31 +00:00 by paulloth1 · 1 comment
paulloth1 commented 2026-08-13 19:33:31 +00:00 (Migrated from github.com)

Problem

tests/ currently covers backend/rotation.py (test_rotation.py) and backend/db.py (test_db.py) reasonably well, but two significant pieces of pure, easily-unit-testable logic added recently have zero automated test coverage:

  1. backend/slides/rss.py's feed parsing pipeline — _parse_items, _pick_headline, _html_to_lines, _join_lines, _guess_author, _first_image_url, _strip_html. This is the most logic-dense file in backend/slides/ (handles RSS 2.0, Atom, GoToSocial's truncated-title-with-ellipsis quirk, Mastodon tag RSS with no <title>/<author> at all, markdown bold stripping, media:content image extraction, per-instance username derivation from post links) and has been manually verified via ad-hoc scratch scripts during development, but none of that got committed as real tests. A future change to any of these functions has no safety net.

  2. backend/app.py's ssrf_check() (added in #16) — the entire SSRF protection for /proxy lives in this one pure function (ssrf_check, _resolve_hostname_ips, _is_internal_address), which was manually verified during development (private IPs, loopback, link-local, multicast, file:// scheme, public hosts) but again isn't captured as a real test. This is a security-critical function — a regression here silently reopens the SSRF hole from #16 with no test to catch it.

Suggested fix

Add tests/test_rss.py covering _parse_items/_pick_headline/_html_to_lines/_join_lines/_guess_author/_first_image_url against small inline RSS/Atom XML fixtures representing: a normal RSS feed with <title>+<description>, a GoToSocial-style feed with a truncated <title> (trailing ...) and full <content:encoded>, a Mastodon tag RSS feed with no <title>/<author> and <p>-separated <description>, an Atom feed, and a feed with <media:content> images.

Add tests/test_app.py (or extend an existing file) covering ssrf_check against: loopback (127.0.0.1), RFC1918 ranges (10/8, 172.16/12, 192.168/16), link-local (169.254.0.0/16), a file:// URL, and a normal public hostname — mirroring the manual test matrix used when #16 was fixed.

Where

New: tests/test_rss.py, tests/test_app.py (or similar). Follow the existing tests/test_rotation.py style (plain pytest, no fixtures needed beyond maybe small XML string constants).

## Problem `tests/` currently covers `backend/rotation.py` (`test_rotation.py`) and `backend/db.py` (`test_db.py`) reasonably well, but two significant pieces of pure, easily-unit-testable logic added recently have zero automated test coverage: 1. **`backend/slides/rss.py`**'s feed parsing pipeline — `_parse_items`, `_pick_headline`, `_html_to_lines`, `_join_lines`, `_guess_author`, `_first_image_url`, `_strip_html`. This is the most logic-dense file in `backend/slides/` (handles RSS 2.0, Atom, GoToSocial's truncated-title-with-ellipsis quirk, Mastodon tag RSS with no `<title>`/`<author>` at all, markdown bold stripping, media:content image extraction, per-instance username derivation from post links) and has been manually verified via ad-hoc scratch scripts during development, but none of that got committed as real tests. A future change to any of these functions has no safety net. 2. **`backend/app.py`'s `ssrf_check()`** (added in #16) — the entire SSRF protection for `/proxy` lives in this one pure function (`ssrf_check`, `_resolve_hostname_ips`, `_is_internal_address`), which was manually verified during development (private IPs, loopback, link-local, multicast, `file://` scheme, public hosts) but again isn't captured as a real test. This is a security-critical function — a regression here silently reopens the SSRF hole from #16 with no test to catch it. ## Suggested fix Add `tests/test_rss.py` covering `_parse_items`/`_pick_headline`/`_html_to_lines`/`_join_lines`/`_guess_author`/`_first_image_url` against small inline RSS/Atom XML fixtures representing: a normal RSS feed with `<title>`+`<description>`, a GoToSocial-style feed with a truncated `<title>` (trailing `...`) and full `<content:encoded>`, a Mastodon tag RSS feed with no `<title>`/`<author>` and `<p>`-separated `<description>`, an Atom feed, and a feed with `<media:content>` images. Add `tests/test_app.py` (or extend an existing file) covering `ssrf_check` against: loopback (127.0.0.1), RFC1918 ranges (10/8, 172.16/12, 192.168/16), link-local (169.254.0.0/16), a `file://` URL, and a normal public hostname — mirroring the manual test matrix used when #16 was fixed. ## Where New: `tests/test_rss.py`, `tests/test_app.py` (or similar). Follow the existing `tests/test_rotation.py` style (plain `pytest`, no fixtures needed beyond maybe small XML string constants).
paulloth1 commented 2026-08-13 19:39:07 +00:00 (Migrated from github.com)

Fixed and deployed. Added tests/test_rss.py (40 tests) and tests/test_app.py (9 tests) covering rss.py's feed-parsing quirks and app.py's ssrf_check. Full suite: 71/71 passing, verified independently in this session as well as by the implementing agent.

Fixed and deployed. Added tests/test_rss.py (40 tests) and tests/test_app.py (9 tests) covering rss.py's feed-parsing quirks and app.py's ssrf_check. Full suite: 71/71 passing, verified independently in this session as well as by the implementing agent.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
paul_loth/krautspaceTV#20
No description provided.