a2ui-project / a2ui-project/a2ui
Component schema validation silently ignores primitive type mismatches
- Ngôn ngữ chính
- TypeScript
- Star
- 16.4k
- Fork
- 1.3k
- Merge trung bình
- 2 ngày 13 giờ
- Pull request đã merge (30 ngày)
- 134
Mô tả
_↴ Ported from [flutter/genui#954](https://github.com/flutter/genui/issues/954) — originally opened by [andrewkolos](https://github.com/andrewkolos) on 2026-06-03._
_Original labels: front-line-handled_
_Original assignees: [andrewkolos](https://github.com/andrewkolos)_
---
Currently, GenUI uses a bespoke JSON Schema walker ([`_validateInstance`](https://github.com/flutter/genui/blob/c79062b7094eacc6e849ed97b8b507aa50237f02/packages/genui/lib/src/model/ui_models.dart#L235-L300) inside [`SurfaceDefinition.validate`](https://github.com/flutter/genui/blob/c79062b7094eacc6e849ed97b8b507aa50237f02/packages/genui/lib/src/model/ui_models.dart#L155)) to validate incoming components.
While this custom validator correctly enforces structural keywords like `const`, `enum`, `required`, and `properties`, it doesn't consider `type`.Because `type` is not validated, per-property primitive-type mismatches silently pass the validation layer.
Example: suppose a `MyButton` component expects a `label` of type `string` and a `width` of type `integer`, the following malformed component will successfully pass validation:
```json
{"id": "btn", "component": "Button", "label": 42, "width": "two"}
```
This bad data lands in [`ComponentModel.properties`](https://github.com/flutter/genui/blob/c79062b7094eacc6e849ed97b8b507aa50237f02/packages/a2ui_core/lib/src/core/component_model.dart#L22) with the wrong types, silently corrupting the data model and eventually causing a crash at render time when the Flutter widget expects a `String` but finds an `int`.
Also, here's a failing test that captures the issue:
```dart
// in ui_models_test.dart
test('validate enforces primitive types (this will fail due to the bug)', () {
final component = const Component(
id: 'test',
type: 'Text',
// oopsies, text is a number
properties: {'text': 42},
);
final surfaceDefinition = SurfaceDefinition(
surfaceId: 's1',
components: {'test': component},
);
final schema = S.object(
properties: {
'components': S.list(
items: S.object(
properties: {
'component': S.string(constValue: 'Text'),
'text': S.string(), // Validator should enforce this.
},
),
),
},
);
expect(
() => surfaceDefinition.validate(schema),
throwsA(isA()),
);
});
});
```
Initially, I was confused as to why we aren't using the `json_schema_builder` package to validate these components. However, I there are a few reasons:
1. `Schema.validate()` is async. [`SurfaceController.handleMessage`](https://github.com/flutter/genui/blob/c79062b7094eacc6e849ed97b8b507aa50237f02/packages/genui/lib/src/engine/surface_controller.dart#L101) is a synchronous `void` function responding to `Stream.listen(...)`. Going async would ripple through callers and could involve a good amount of refactoring.
2. The global catalog schema defines many things (`{components, styles, functions}`). If we feed a component payload directly to the package, it will fail because `styles` and `functions` are missing. The hand-rolled implementation in `SurfaceDefinition.validate` drills down into the `oneOf` branch and validates the component against *only* its specific sub-schema.
3. The current implementation throws an [`A2uiValidationException`](https://github.com/flutter/genui/blob/c79062b7094eacc6e849ed97b8b507aa50237f02/packages/genui/lib/src/model/ui_models.dart#L366) containing a formatted `path` on the first failure, which is optimized for relaying over our protocol back to the server.
## Fixes
Band-aid fix: extend the `_validateInstance` method to explicitly check the `type` keyword (and ideally `additionalProperties`).
Proper fix (maybe): Delegate entirely to `json_schema_builder` to close all spec gaps. This will require:
- Make `SurfaceController.handleMessage` async.
- Writing an adapter to translate `ValidationError` lists into `A2uiValidationException`s.
Hướng dẫn đóng góp
Hướng nghiên cứu
The validation logic is in packages/genui/lib/src/model/ui_models.dart, specifically the _validateInstance function. Start by examining how it currently walks the schema and where the 'type' keyword is ignored. The failing test in ui_models_test.dart shows the expected behavior. To fix, extend _validateInstance to check primitive types, or research integrating the json_schema_builder package, considering the async and error translation challenges outlined.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Đánh giá
- Công nghệ
- dart, json, typescript
- Lĩnh vực
- backend-api-design
- Loại issue
- Lỗi
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức độ hoạt động
- Ít trao đổi
- Độ rõ ràng
- Đặc tả rõ ràng
- Mức phù hợp với người mới
- 40/100