Reject non-string source_name/source_id/source_prompt (issue #008)

These accepted any JSON type on both POST and PATCH, silently mangled
into Python repr() strings at save time (a dict became the literal text
"{'a': 1}", unparseable as JSON) - and the immediate response echoed the
raw pre-save value, while a later GET returned the mangled one, an
internally inconsistent API.

Added validate_string_fields(), rejecting non-string values with 400
before they reach save(), matching #005's approach for tags. Verified live
and with new tests.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
peter 2026-09-02 15:27:07 +01:00
parent d1b6a19eb3
commit 09ea0a8b4f
3 changed files with 117 additions and 0 deletions

View file

@ -427,3 +427,31 @@ class ArtifactAPITestCase(APITestCase):
def test_create_csv_artifact_with_header_only(self):
response = self.create_artifact(kind="csv", content="name,score")
self.assertEqual(response.status_code, 201)
# -- source_name/source_id/source_prompt type checks (issue #008) -------
def test_create_rejects_non_string_source_name(self):
response = self.create_artifact(source_name=12345)
self.assertEqual(response.status_code, 400)
self.assertIn("source_name", response.data["detail"])
def test_create_rejects_non_string_source_id(self):
response = self.create_artifact(source_id=["a", "b"])
self.assertEqual(response.status_code, 400)
def test_create_rejects_non_string_source_prompt(self):
response = self.create_artifact(source_prompt={"nested": "object"})
self.assertEqual(response.status_code, 400)
def test_patch_rejects_non_string_source_name(self):
artifact_id = self.create_artifact().data["id"]
response = self.client.patch(
reverse("artifact-detail-api", args=[artifact_id]),
{"source_name": 12345},
format="json",
**self.auth_headers(self.token),
)
self.assertEqual(response.status_code, 400)
artifact = Artifact.objects.get(pk=artifact_id)
self.assertEqual(artifact.source_name, "test-agent") # unchanged, not mangled