fix(protocol): reject unknown root named types

This commit is contained in:
2026-09-28 22:47:46 +09:00
parent 742442f174
commit 6b6e96c303
2 changed files with 46 additions and 1 deletions
+8 -1
View File
@@ -315,6 +315,8 @@ pub(crate) fn validate_root_value(
) -> Result<(), ValidationError> {
descriptor.validate()?;
let declarations = declaration_map(descriptor)?;
validate_type_expr(ty, &declarations)
.map_err(|error| error.prepend(PathSegment::Interface(descriptor.name.clone())))?;
validate_value(ty, value, &declarations)
.map_err(|error| error.prepend(PathSegment::Interface(descriptor.name.clone())))
}
@@ -369,7 +371,12 @@ fn validate_value(
_ => expect_kind(value, ValueKind::Json),
},
TypeExpr::Named(name) => {
validate_declared_value(declarations[name.as_str()], value, declarations)
let Some(declaration) = declarations.get(name.as_str()) else {
return Err(ValidationError::new(ValidationErrorKind::UnknownType {
name: name.clone(),
}));
};
validate_declared_value(declaration, value, declarations)
}
}
}
+38
View File
@@ -233,6 +233,44 @@ fn named_references_must_exist_and_must_not_cycle() {
]
);
let valid = descriptor("catalog");
let error = valid
.validate_value(&TypeExpr::Named("Elsewhere".into()), &Value::Record(vec![]))
.unwrap_err();
assert_eq!(
error.kind,
ValidationErrorKind::UnknownType {
name: "Elsewhere".into()
}
);
assert_eq!(error.path, vec![PathSegment::Interface("catalog".into())]);
let error = valid
.validate_value(
&TypeExpr::Entry {
key: Box::new(TypeExpr::String),
value: Box::new(TypeExpr::List(Box::new(TypeExpr::Named("Nested".into())))),
},
&Value::Entry {
key: Box::new(Value::String("key".into())),
value: Box::new(Value::List(vec![])),
},
)
.unwrap_err();
assert_eq!(
error.kind,
ValidationErrorKind::UnknownType {
name: "Nested".into()
}
);
assert_eq!(
error.path,
vec![
PathSegment::Interface("catalog".into()),
PathSegment::EntryValue,
]
);
let cyclic = InterfaceDescriptor {
name: "cyclic".into(),
documentation: None,