a2ui-project / a2ui-project/a2ui
Component schema validation silently ignores primitive type mismatches
- 主要语言
- TypeScript
- 星标
- 16.4k
- 派生
- 1.3k
- 平均合并
- 2 天 13 小时
- 30 天内合并 PR
- 134
描述
_↴ 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.
贡献指南
调研方向
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.
由索引模型根据 Issue 内容生成。
评估
- 技术栈
- dart, json, typescript
- 领域
- backend-api-design
- Issue 类型
- 缺陷
- 难度
- 4/5
- 预计耗时
- 3-5 天
- 活跃度
- 冷清
- 描述清晰度
- 描述清楚
- 新手友好度
- 40/100