fix(stability): fail CLOSED on feed-sanitize exception + cover bulk-SQL/flush (review round 1)
#1 [security] The final feed-sanitize try/except was FAIL-OPEN: since 4.4 removed the per-fragment passes, post['html'] / the concatenated feed html is now raw channel-controlled HTML, and this is its ONLY sanitize. If bleach itself throws (RecursionError/OOM on pathological nested HTML — a class already seen in this project), the except branch returned the RAW payload = stored XSS. Both branches (RSS per-post, HTML whole-feed) now fail CLOSED via html.escape, so the content survives as inert text and no live tag ever reaches the client. Added a test that forces bleach to raise and asserts no live <script>/<img>/<a> reaches the feed (adversarially validated: reverting to fail-open makes it fail). #2 [test] Direct test of the new upsert_media_file_ids_bulk_sync on a temp DB: empty no-op, multi-row insert, and re-upsert-updates-added (the real executemany + ON CONFLICT, previously only mocked). #3 [test] Test that media ids collected before a render exception are still flushed (the flush is in a finally) — removing the finally now turns a test red. #4 [cleanup] Removed the dead in rss_generator (the flush is delegated to post_parser._flush_pending_media_ids). #5 [doc] Corrected the sanitize-map comments: RSS sanitizes per-post, only HTML is the whole-feed pass. 233 passed (214 baseline + 19). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+5
-4
@@ -526,7 +526,8 @@ class PostParser:
|
||||
sanitize: when True, run the html body and footer through a single
|
||||
bleach pass each. Single-post HTML and JSON need this (there is no
|
||||
whole-feed pass on those paths). Feed generation passes False and
|
||||
relies on the final whole-feed sanitize in rss_generator, so no
|
||||
relies on the final sanitize in rss_generator (per-post for RSS,
|
||||
whole-feed for HTML), so no
|
||||
fragment is sanitized more than once.
|
||||
"""
|
||||
# Compute html body once — avoids triple _generate_html_body calls.
|
||||
@@ -715,8 +716,8 @@ class PostParser:
|
||||
content_body.append(f'</div><br>')
|
||||
|
||||
# NOTE: sanitize is NOT applied here. Sanitization happens exactly once per
|
||||
# output boundary (process_message for single-post/JSON, final whole-feed pass
|
||||
# in rss_generator for feeds). See the sanitize coverage map (4.4).
|
||||
# output boundary (process_message for single-post/JSON; in rss_generator the
|
||||
# per-post pass for RSS and the whole-feed pass for HTML). See the map (4.4).
|
||||
html_body = '\n'.join(content_body)
|
||||
return html_body
|
||||
|
||||
@@ -879,7 +880,7 @@ class PostParser:
|
||||
content_footer.append('<br>' + flags_html)
|
||||
|
||||
# Not sanitized here — sanitized once at the output boundary (4.4 coverage map):
|
||||
# process_message for single-post/JSON, final whole-feed pass for feeds.
|
||||
# process_message for single-post/JSON; per-post (RSS) / whole-feed (HTML) for feeds.
|
||||
html_footer = '\n'.join(content_footer)
|
||||
return html_footer
|
||||
|
||||
|
||||
Reference in New Issue
Block a user