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:
parent
d1b6a19eb3
commit
09ea0a8b4f
3 changed files with 117 additions and 0 deletions
|
|
@ -237,6 +237,9 @@ class ArtifactDetailView(APIView):
|
|||
length_error = validate_field_lengths(data, ["title", "source_name", "source_id"])
|
||||
if length_error:
|
||||
return length_error
|
||||
string_error = validate_string_fields(data, ["source_name", "source_id", "source_prompt"])
|
||||
if string_error:
|
||||
return string_error
|
||||
if "title" in data:
|
||||
if not data["title"]:
|
||||
return Response({"detail": "title cannot be blank"}, status=400)
|
||||
|
|
@ -860,6 +863,19 @@ def validate_field_lengths(data, fields):
|
|||
return None
|
||||
|
||||
|
||||
def validate_string_fields(data, fields):
|
||||
"""Rejects non-string JSON types (object/array/number) instead of letting
|
||||
them reach save(), where Django's CharField/TextField silently coerce via
|
||||
str() - which for a dict/list produces Python repr() syntax, not JSON,
|
||||
and is irreversible.
|
||||
"""
|
||||
for field in fields:
|
||||
value = data.get(field)
|
||||
if value is not None and not isinstance(value, str):
|
||||
return Response({"detail": f"{field} must be a string"}, status=400)
|
||||
return None
|
||||
|
||||
|
||||
def validate_content_shape(kind, content):
|
||||
lower = (content or "").lower()
|
||||
if kind == Artifact.DECK and "<section" not in lower:
|
||||
|
|
@ -889,6 +905,9 @@ def validate_source_fields(data):
|
|||
length_error = validate_field_lengths(data, ["source", "title", "source_name", "source_id", "theme"])
|
||||
if length_error:
|
||||
return length_error
|
||||
string_error = validate_string_fields(data, ["source_name", "source_id", "source_prompt"])
|
||||
if string_error:
|
||||
return string_error
|
||||
if source_type := data.get("source_type"):
|
||||
if source_type not in {choice[0] for choice in Artifact.SOURCE_TYPE_CHOICES}:
|
||||
return Response({"detail": "source_type must be agent, person, or system"}, status=400)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue