Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion core/wren/src/wren/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -1155,7 +1155,18 @@ def validate_project(project_path: Path) -> list[ValidationError]:
)
continue
rel_name = rel.get("name", f"relationships[{i}]")
ref_models = rel.get("models") or []
ref_models = rel.get("models")
if ref_models is None:
ref_models = []
if not isinstance(ref_models, list):
errors.append(
ValidationError(
"error",
f"relationships > {rel_name}",
f"'models' must be a list, got {type(ref_models).__name__}",
)
)
ref_models = []
for m in ref_models:
if m not in all_entity_names:
Comment on lines +1161 to 1171

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

Validate each relationship model entry before set membership.

A value such as models: [{}] passes the list check, then m not in all_entity_names raises TypeError: unhashable type: 'dict' instead of returning validation errors. Reject non-string entries with an indexed path and continue validation.

Proposed fix
-        for m in ref_models:
+        for j, m in enumerate(ref_models):
+            if not isinstance(m, str):
+                errors.append(
+                    ValidationError(
+                        "error",
+                        f"relationships > {rel_name} > models[{j}]",
+                        "'models' entries must be strings",
+                    )
+                )
+                continue
             if m not in all_entity_names:
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if not isinstance(ref_models, list):
errors.append(
ValidationError(
"error",
f"relationships > {rel_name}",
f"'models' must be a list, got {type(ref_models).__name__}",
)
)
ref_models = []
for m in ref_models:
if m not in all_entity_names:
if not isinstance(ref_models, list):
errors.append(
ValidationError(
"error",
f"relationships > {rel_name}",
f"'models' must be a list, got {type(ref_models).__name__}",
)
)
ref_models = []
for j, m in enumerate(ref_models):
if not isinstance(m, str):
errors.append(
ValidationError(
"error",
f"relationships > {rel_name} > models[{j}]",
"'models' entries must be strings",
)
)
continue
if m not in all_entity_names:
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@core/wren/src/wren/context.py` around lines 1161 - 1171, Update the
relationship-model validation loop in the context validation logic to verify
each entry is a string before checking membership in all_entity_names. For
non-string entries, append a ValidationError using the indexed models path
(including the relationship name and entry index), then continue validating
subsequent entries without performing set membership on the invalid value.

errors.append(
Expand Down
15 changes: 15 additions & 0 deletions core/wren/tests/unit/test_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -1628,3 +1628,18 @@ def test_validate_manifest_invalid_datasource():
manifest = {**_SEM_BASE_MANIFEST, "views": [_VALID_VIEW]}
result = validate_manifest(_b64(manifest), "not-a-datasource")
assert len(result["errors"]) == 1


def test_validate_relationship_models_must_be_list(tmp_path):
"""Non-list relationship models is a structural error, not iterated as chars."""
_make_valid_project(tmp_path)
(tmp_path / "relationships.yml").write_text(
"relationships:\n"
" - name: bad\n"
" models: orders\n"
" condition: a.id = b.id\n"
" join_type: MANY_TO_ONE\n"
)
errors = validate_project(tmp_path)
hard = [e for e in errors if e.level == "error"]
assert any("must be a list" in e.message for e in hard)
Loading