fix: narrow source reference validation

This commit is contained in:
lda
2026-08-13 18:10:25 +07:00 Verified
parent 03150a5cf8
commit 0eeb6079d4
3 changed files with 118 additions and 5 deletions
+2 -2
View File
@@ -61,7 +61,7 @@ from .drafts import (
)
from .input_expressions import (
validate_and_project_input_expression,
validate_supported_input_schema,
validate_schema_references,
)
from .models import DraftWorkspaceResult, JsonProjector
from .operation_context import WorkflowOperationContext
@@ -684,7 +684,7 @@ class WorkflowDraftAuthoringApi:
source.parts,
label=f"{source.root} source schema",
)
validate_supported_input_schema(
validate_schema_references(
source_fragment,
label=f"{source.root} source schema",
)
+75 -3
View File
@@ -588,9 +588,81 @@ def _ensure_supported_schema(schema: Mapping[str, Any], *, label: str) -> None:
_canonical_schema(schema, label=label)
def validate_supported_input_schema(schema: Mapping[str, Any], *, label: str) -> None:
"""Reject schema fragments outside the bounded input-schema subset."""
_ensure_supported_schema(schema, label=label)
def validate_schema_references(schema: Mapping[str, Any], *, label: str) -> None:
"""Resolve schema references without imposing expression-keyword limits."""
_validate_schema_references(
schema,
root_schema=schema,
label=label,
context=_SchemaNormalizationContext(),
)
def _validate_schema_references(
schema: Mapping[str, Any],
*,
root_schema: Mapping[str, Any],
label: str,
context: _SchemaNormalizationContext,
) -> None:
context.visit(label)
reference = schema.get("$ref")
if isinstance(reference, str):
if reference in context.active_refs:
raise ValueError(f"cyclic local schema reference {reference!r} at {label}")
context.active_refs.add(reference)
try:
resolved = _resolved_schema(schema, label=label, root_schema=root_schema)
_validate_schema_references(
resolved,
root_schema=root_schema,
label=label,
context=context,
)
finally:
context.active_refs.remove(reference)
return
properties = schema.get("properties")
if isinstance(properties, Mapping):
for name, child in properties.items():
if isinstance(name, str) and isinstance(child, Mapping):
_validate_schema_references(
child,
root_schema=root_schema,
label=f"{label}.{name}",
context=context,
)
for key in ("items", "additionalProperties"):
child = schema.get(key)
if isinstance(child, Mapping):
_validate_schema_references(
child,
root_schema=root_schema,
label=f"{label}.{key}",
context=context,
)
prefix_items = schema.get("prefixItems")
if isinstance(prefix_items, list):
for index, child in enumerate(prefix_items):
if isinstance(child, Mapping):
_validate_schema_references(
child,
root_schema=root_schema,
label=f"{label}.prefixItems[{index}]",
context=context,
)
for key in ("$defs", "definitions"):
definitions = schema.get(key)
if isinstance(definitions, Mapping):
for name, child in definitions.items():
if isinstance(name, str) and isinstance(child, Mapping):
_validate_schema_references(
child,
root_schema=root_schema,
label=f"{label}.{key}.{name}",
context=context,
)
def _resolved_schema(