a2ui-project / a2ui-project/a2ui

Component schema validation silently ignores primitive type mismatches

未关闭
#1,899 1 条评论 0 个 reaction 已指派 1 人 已被 @andrewkolos 认领 在 GitHub 查看
component: genui P2 status: first-line-handled type: bug
主要语言
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

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。