From 1ab5f63ab01a56aed5c4d0551b463a82fff0b062 Mon Sep 17 00:00:00 2001 From: Charlie Tonneslan Date: Sun, 17 May 2026 13:58:17 -0400 Subject: [PATCH] Validate event document URLs as URIs The event documents schema treated url as a plain non-empty string and put it at the top level of each document, which didn't match what add_document actually writes (note + classification + a links array of {url, media_type}). The result was that a relative path like '/whatever/124.html' would pass validation silently, and the real URL never got the format: uri check at all. Restructure the documents item schema to mirror bill versions and the existing event media schema: classification + nested links with uri-validated urls. Added a regression test that asserts e.add_document(url='/relative.html') now fails validation. Closes openstates/issues#1298. Signed-off-by: Charlie Tonneslan --- openstates/scrape/schemas/event.py | 13 +++++++++++-- openstates/scrape/tests/test_event_scrape.py | 18 ++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/openstates/scrape/schemas/event.py b/openstates/scrape/schemas/event.py index e0f941395..6858811ba 100644 --- a/openstates/scrape/schemas/event.py +++ b/openstates/scrape/schemas/event.py @@ -67,9 +67,18 @@ "items": { "properties": { "note": {"type": "string", "minLength": 1}, - "url": {"type": "string", "minLength": 1}, - "media_type": {"type": "string", "minLength": 1}, "date": fuzzy_date_blank, + "classification": {"type": "string"}, + "links": { + "items": { + "properties": { + "media_type": {"type": "string"}, + "url": {"type": "string", "format": "uri"}, + }, + "type": "object", + }, + "type": "array", + }, }, "type": "object", }, diff --git a/openstates/scrape/tests/test_event_scrape.py b/openstates/scrape/tests/test_event_scrape.py index 8ff5abe4c..3038358b5 100644 --- a/openstates/scrape/tests/test_event_scrape.py +++ b/openstates/scrape/tests/test_event_scrape.py @@ -125,6 +125,24 @@ def test_add_document(): e.validate() +def test_add_document_rejects_bad_url(): + # Regression for openstates/issues#1298: the schema treated document + # urls as plain strings, so a relative path like "/whatever/124.html" + # silently passed validation. The url should now have to be a real URI. + import pytest + + from openstates.exceptions import ScrapeValueError + + e = event_obj() + e.add_document( + note="hello", + url="/whatever/124.html", + media_type="text/html", + ) + with pytest.raises(ScrapeValueError): + e.validate() + + def test_participants(): e = event_obj() e.add_participant("Committee of the Whole", type="committee", note="everyone")