feat: 迁入 MiGu.Server、平台前端与车辆列表 reflection 回退
从 Simple-FR 拆出 Platform.Server 并重命名为 MiGu.Server;frontends 源码与构建脚本迁入本仓库。地图监控在 projection/cars 失败或为空时回退 reflection 车辆列表;Simple 仓库已移除旧 Platform.Server。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,284 @@
|
||||
# 未提交代码审核 — 待优化问题清单
|
||||
|
||||
> **用途**:供其他 AI 模型或开发者按项修复。
|
||||
> **仓库路径**:`E:\Work\Core\Simple-FR\Simple`
|
||||
> **分支**:`dev_simpleLite`(审核时)
|
||||
> **审核日期**:2026-05-29
|
||||
> **审核范围**:后端 C#(MiGu.Server、SimpleLite、SimpleCore 相关 diff);**不含**前端 Vue 全量审阅与 `dotnet build` 验证。
|
||||
|
||||
---
|
||||
|
||||
## 使用说明(给优化 AI)
|
||||
|
||||
1. 按 **优先级** 从高到低处理:`P0` → `P1` → `P2`。
|
||||
2. 每项包含:**问题 ID**、**文件**、**现象**、**建议改法**、**验收标准**。
|
||||
3. 修改时遵循仓库现有风格;**不要**扩大无关重构范围。
|
||||
4. 修复后在对应项下可勾选 `[x]`(本文件由人工维护勾选状态)。
|
||||
|
||||
---
|
||||
|
||||
## 问题总表(快速索引)
|
||||
|
||||
| ID | 优先级 | 状态 | 标题 | 主要文件 |
|
||||
|----|--------|------|------|----------|
|
||||
| ISSUE-10 | P0 | ✅ 已修复 | CarRepository 反序列化白名单可能过严 | `SimpleLite/Persistence/Repositories/CarRepository.cs` |
|
||||
| ISSUE-05 | P1 | ✅ 已修复 | 项目/应用配置 API 未校验 writableViaApi | `SimpleLite/Web/ReflectionApiController.cs` |
|
||||
| ISSUE-04 | P1 | 🔧 部分处理 | Launcher 等新文件未纳入版本库 | `MiGu.Server/Launcher/*` 等 |
|
||||
| ISSUE-01 | P2 | 📝 已评估·可配置缓解 | 登录仍可能阻塞至 Readiness 超时 | `MiGu.Server/Controllers/AuthController.cs` |
|
||||
| ISSUE-02 | P2 | 📝 已评估·维持现状 | Me/SwitchScope RunMode 复用实例时偏保守 | `MiGu.Server/Controllers/AuthController.cs` |
|
||||
| ISSUE-03 | P2 | ✅ 已处理·README | 默认 admin 凭据(部署) | `MiGu.Server/appsettings.json` |
|
||||
| ISSUE-06 | P2 | ✅ 已修复 | GET monitor-config 写副作用 | `SimpleLite/Web/ReflectionApiController.cs` |
|
||||
| ISSUE-07 | P2 | 📝 已评估·待产品 | POST monitor-config 立即写盘 | `SimpleLite/Web/ReflectionApiController.cs` |
|
||||
| ISSUE-08 | P2 | ✅ 已修复 | Toolbar GetState 响应格式不一致 | `SimpleLite/Web/WorkspaceToolbarApiController.cs` |
|
||||
| ISSUE-09 | P2 | 📝 已评估·技术债 | 录制/图层 API 重复维护 | `MapEditApiController` + `WorkspaceToolbarApiController` |
|
||||
| ISSUE-11 | P2 | 📝 已评估·观察项 | 高频 redraw 仍可能偶发旧帧 | `SimpleLite/Rendering/SimpleSceneRenderer.cs` |
|
||||
| ISSUE-12 | P2 | 📝 已评估·待产品 | Online/Offline 远程 MethodMember 权限 | `SimpleLite/RCS/CarTypes/Car.cs` + 鉴权链 |
|
||||
| ISSUE-13 | P2 | 📝 已评估·依赖升级 | GetPosition realtime 未启用 | `SimpleLite/Workspace/WorkspacePickSession.cs` |
|
||||
| ISSUE-14 | P2 | 📝 已评估·环境项 | 2D 平移绑定依赖 CycleGUI 版本 | `SimpleLite/Workspace/WorkspaceViewModeService.cs` |
|
||||
| ISSUE-15 | P2 | 📝 已评估·低优维持 | 表格双击为时间窗口模拟 | `SimpleLite/UI/WorkbenchTableRowUi.cs` |
|
||||
| ISSUE-16 | P2 | 📝 已评估·待产品 | 底栏 CAD 入口已移除(产品确认) | `WorkspaceBottomBar.cs` 等 |
|
||||
|
||||
---
|
||||
|
||||
## P0 — 合并前建议先验证/修复
|
||||
|
||||
### ISSUE-10 — CarRepository 反序列化白名单可能过严
|
||||
|
||||
- **状态**:[x] 已修复(2026-05-29)
|
||||
- **文件**:`SimpleLite/Persistence/Repositories/CarRepository.cs`(`CarTypeBinder`、`JsonOpts`)
|
||||
- **现象**:`TypeNameHandling.Auto` + 自定义 `ISerializationBinder` 白名单未包含 `System.String`、`System.Int32`、`System.Boolean` 等 BCL 基础类型。`customProps` 由 `JsonConvert.SerializeObject(car, JsonOpts)` 序列化**整辆车**,JSON 中泛型容器(如 `Dictionary<string, int>`)的 `$type` 可能含 `System.*`,反序列化时 `BindToType` 抛 `SerializationException`。
|
||||
- **风险**:升级后 `LoadAllIntoSimpleLib` 部分车辆加载失败。
|
||||
- **建议改法**(择一或组合):
|
||||
1. 在白名单中增加安全 BCL 类型前缀/精确名:`System.String`、`System.Int32`、`System.Int64`、`System.Boolean`、`System.Single`、`System.Double`、`System.Decimal`、`System.DateTime` 等;或允许 `System` 下仅 primitive 与 `System.Collections.Generic` 的封闭列表。
|
||||
2. 缩小序列化范围:勿对整个 `car` 使用 `TypeNameHandling.Auto`,仅对已知 DTO/字段序列化。
|
||||
3. 提供 `RegisterAllowedNamespacePrefix("System")` 的文档说明(不推荐无限制放行整个 System)。
|
||||
- **验收标准**:
|
||||
- 用**现有生产/测试库**中真实 `customProps` JSON 跑 `LoadAllIntoSimpleLib`,无 SerializationException。
|
||||
- 恶意 `$type`(如 `System.Windows.Forms.*` gadget)仍被拒绝。
|
||||
- **回归命令**(示例):加载含多车型、多插件的程序集后启动 SimpleLite 并打开车辆列表。
|
||||
- **修复说明**(2026-05-29):在 `CarTypeBinder` 新增精确类型白名单 `_allowedExactTypeNames`,放行安全的 BCL 基础类型(string/int/long/bool/float/double/decimal/DateTime/DateTimeOffset/TimeSpan/Guid/char/byte/short/Object/Enum/Nullable<T> 等);`IsAllowedRawName` 在命名空间前缀匹配前先做「精确全名」匹配。修复后泛型容器实参(如 Dictionary<string,int>、Dictionary<string,object>)在字符串层 `IsAllowedSerializedTypeName` 与已解析层 `IsAllowedResolvedType` 两条路径均不再误抛 `SerializationException`。因采用精确全名而非放行整个 `System.*` 前缀,`System.Windows.Forms.*` 等 gadget 链仍被拒绝。**仍需**用真实生产/测试库回归 `LoadAllIntoSimpleLib`。
|
||||
|
||||
---
|
||||
|
||||
## P1 — 建议本轮一并处理
|
||||
|
||||
### ISSUE-05 — 项目/应用配置 API 未校验 writableViaApi
|
||||
|
||||
- **状态**:[x] 已修复(2026-05-29)
|
||||
- **文件**:`SimpleLite/Web/ReflectionApiController.cs`
|
||||
- `SetProjectField`(`POST /project/fields/{field}`)
|
||||
- `SetAppConfigField`(`POST /app-config/fields/{field}`)
|
||||
- **现象**:仅检查 `FieldMember.locked` 与 `MapObjectFactory.IsSensitiveFieldNamePublic`;**未**检查 `FieldMember.writableViaApi`(`SimpleCore/Scene.cs` 已新增,默认 `true`)。
|
||||
- **对比**:`MapObjectFactory.TryApplyField` 已拒绝 `writableViaApi == false`。
|
||||
- **建议改法**:在两处 setter 中读取 `FieldMember`,若 `!fm.writableViaApi` 返回 403 及明确文案;与 `TryApplyField` 日志风格一致。
|
||||
- **验收标准**:对标记 `writableViaApi=false` 的字段,Web POST 返回 403,内存值不变。
|
||||
- **修复说明**(2026-05-29):在 `SetProjectField`(`Scene.conf`)与 `SetAppConfigField`(`Configuration.conf`)的 `fm.locked` 检查之后新增 `if (!fm.writableViaApi)` 拦截,命中即 `Diagnosis.Post` 记录并返回 403(内存值不变),与 `MapObjectFactory.TryApplyField` 的双层防御保持一致。注:前端字段列举(`ListFieldMembers` / 字段记录)暂未暴露 `writableViaApi`,如需「预先禁用不可写输入框」可后续在响应中增列该布尔值(属前端契约增量,未纳入本次范围)。
|
||||
|
||||
---
|
||||
|
||||
### ISSUE-04 — 新增文件未纳入 Git(提交遗漏)
|
||||
|
||||
- **状态**:[~] 部分处理(2026-05-29):`.gitignore` 已补;编译必需的后端源文件待人工 `git add` + `commit`
|
||||
- **路径**(审核时为 untracked):
|
||||
- `MiGu.Server/Launcher/SimpleLiteLauncher.cs`
|
||||
- `MiGu.Server/Launcher/SimpleLiteOptions.cs`
|
||||
- `SimpleLite/Web/WorkspaceToolbarApiController.cs`
|
||||
- `SimpleLite/Web/MonitorVisibilityConfig.cs`
|
||||
- `SimpleLite/Workspace/CurveControlPointDragService.cs`
|
||||
- (前端相关见下方「未审范围」)
|
||||
- **现象**:`AuthController` 依赖 `SimpleLiteLauncher` DI;未 add 则他人 clone 无法编译/运行。
|
||||
- **建议改法**:确认属于本需求后 `git add`;`.codegraph/`、`.cursor/mcp.json` 按 `.gitignore` 决定是否提交。
|
||||
- **验收标准**:干净 clone + build 能通过;Launcher 与 Toolbar 路由可访问。
|
||||
- **处理进度**(2026-05-29):
|
||||
- ✅ 已补 `.gitignore`:忽略 `.codegraph/`(codegraph 本地索引缓存)与 `/SimpleCore/ref/`(同 `/ref/Ref` 的未知用途二进制),二者已从 untracked 列表移除。
|
||||
- ✅ 已确认 `AuthController` 构造函数注入 `SimpleLiteLauncher`(第 69/72 行)→ `Launcher/*.cs` 为编译必需,必须入库。
|
||||
- ⏳ 待人工执行(编译必需的后端源文件 + 本审核文档;单行命令,PowerShell/bash 均可):
|
||||
|
||||
```
|
||||
git add MiGu.Server/Launcher/SimpleLiteLauncher.cs MiGu.Server/Launcher/SimpleLiteOptions.cs SimpleLite/Web/WorkspaceToolbarApiController.cs SimpleLite/Web/MonitorVisibilityConfig.cs SimpleLite/Workspace/CurveControlPointDragService.cs Doc/ .gitignore
|
||||
```
|
||||
|
||||
- ❓ 需决策是否入库:`.cursor/mcp.json`、`.cursor/rules/codegraph.mdc`(团队是否共享该 MCP / 规则配置)。
|
||||
- 📦 前端新文件(`frontends/apps/simple-platform-vue/**`:`workspaceToolbar.ts`、`MonitorSelectionPanel.vue`、`FieldMemberEditor.vue`、`CarStyleEditor*`、`ProjectPropertiesView.vue`、`MapMonitorConfigView.vue` 等)归「前端另开任务」范围,建议随前端审核一并 add。
|
||||
- ⚠ 未执行 `git commit`:提交内容与时机由人工掌控。
|
||||
|
||||
---
|
||||
|
||||
## P2 — 按产品/环境决定或后续迭代
|
||||
|
||||
### ISSUE-01 — 登录仍可能阻塞至 Readiness 超时
|
||||
|
||||
- **状态**:[~] 已评估(2026-05-29):现有配置即可缓解,暂不改代码
|
||||
- **文件**:`MiGu.Server/Controllers/AuthController.cs`(`Login` → `Task.Run(() => _launcher.MaybeStart(...))`)
|
||||
- **现象**:`MaybeStart` 内 `WaitForProjectionReady` 默认最多 8000ms,登录请求仍等待该 Task。
|
||||
- **建议改法**:缩短超时、登录先返回 + 前端轮询 `/projection` 就绪、或 fire-and-forget + `LaunchWarning` 已有字段提示。
|
||||
- **验收标准**:登录 P95 延迟可接受;SimpleLite 未就绪时前端有明确降级(`Detached` / `LaunchWarning`)。
|
||||
- **评估说明**(2026-05-29):报告建议的「缩短超时 / 登录先返回」**现有设计已通过配置支持**,无需改代码:`SimpleLiteOptions.ReadinessTimeoutMs`(绑定 `appsettings.json:SimpleLite.ReadinessTimeoutMs`,默认 8000)注释明确 `0 = 不等待(登录立即返回)`、`负值 = 无限等待`;`Login` 已用 `Task.Run` 释放请求线程,失败时回填 `Detached` + `LaunchWarning`。运维若需更快登录可将该值调小或置 0(代价:`RunMode` 可能暂不准,由 `LaunchWarning` 降级提示)。真正的「fire-and-forget + 前端轮询 `/projection`」属前后端协议改动,留作后续迭代。
|
||||
|
||||
---
|
||||
|
||||
### ISSUE-02 — Me / SwitchScope 的 RunMode 在复用外部 SimpleLite 时偏保守
|
||||
|
||||
- **状态**:[~] 已评估(2026-05-29):当前保守映射为有意设计,维持现状
|
||||
- **文件**:`MiGu.Server/Controllers/AuthController.cs`(`Me`、`SwitchScope`、`ResolveRunMode`)
|
||||
- **现象**:`ReusingExisting` / `ExternalReuseLaunchMode` 常归为 `WebEnabled`,与用户本次 `WebOnly` 选择可能不一致。
|
||||
- **建议改法**:前端强依赖 `LaunchWarning`;或 HTTP 探针推断 displayMode(成本高)。
|
||||
- **验收标准**:用户知悉「已有实例未应用新模式」;无静默错误状态。
|
||||
- **评估说明**(2026-05-29):`ResolveRunMode` / `Me` / `SwitchScope` 在 `ExternalReuseLaunchMode`、`ReusingExisting` 时归 `WebEnabled` 是**有意的保守降级**(代码注释已说明:复用既有实例时其真实 displayMode 不可知,归 WebEnabled 最不会误导用户「以为本地窗口不存在」)。用 HTTP 探针推断成本高且不可靠;前端已可凭 `LaunchWarning` 提示「已有实例未应用新模式」。结论:维持现状,作为前端体验项后续跟进,不改后端。
|
||||
|
||||
---
|
||||
|
||||
### ISSUE-03 — 默认 admin 凭据(部署安全)
|
||||
|
||||
- **状态**:[x] 已处理(2026-05-29):已在 README 增加生产安全须知
|
||||
- **文件**:`MiGu.Server/appsettings.json`(`Auth:Users`)
|
||||
- **建议**:生产用环境变量/密钥管理覆盖;README 注明勿用默认密码。
|
||||
- **处理说明**(2026-05-29):已在 `MiGu.Server/README.md` 新增「安全须知(生产部署必读)」小节,明确 `admin/admin`、`ops/ops` 与 `Jwt.Secret`/`Internal.Token=REPLACE_ME` 仅供开发,并给出环境变量覆盖示例(`Auth__Users__admin__Password` 等)。`appsettings.json` 默认值保持不变以维持开箱即用的本地开发体验(属部署规范,非代码缺陷)。
|
||||
|
||||
---
|
||||
|
||||
### ISSUE-06 — GET monitor-config 写副作用
|
||||
|
||||
- **状态**:[x] 已修复(2026-05-29)
|
||||
- **文件**:`SimpleLite/Web/ReflectionApiController.cs`(`GetMonitorConfig`)
|
||||
- **现象**:`monitorVisibility == null` 时 GET 会 `Configuration.conf.monitorVisibility = new MonitorVisibilityConfig()`。
|
||||
- **建议改法**:GET 只读快照,不写回 `Configuration.conf`;初始化放在 `Configuration` 构造/`FromFile`。
|
||||
- **验收标准**:多次 GET 不改变磁盘上的 `simple.json`(除非 POST)。
|
||||
- **修复说明**(2026-05-29):删除 `GetMonitorConfig` 中的 `Configuration.conf.monitorVisibility = conf;` 写回行,GET 改为纯只读快照。`monitorVisibility` 非 null 已由 `Configuration` 字段默认值(`= new()`,第 74 行)、构造函数(`??=`,第 32 行)与 `FromFile`(`??=`,第 46 行)三处共同保证,GET 无需补写。多次 GET 不再触碰 `Configuration.conf`,自然不会引发后续写盘。
|
||||
|
||||
---
|
||||
|
||||
### ISSUE-07 — POST monitor-config 每次全量写 simple.json
|
||||
|
||||
- **状态**:[~] 已评估(2026-05-29):维持「保存即写盘」,待产品决定是否需要预览态
|
||||
- **文件**:`ReflectionApiController.PostMonitorConfig`
|
||||
- **现象**:POST 成功即 `Configuration.ToFile("simple.json")`,无单独「保存」步骤。
|
||||
- **建议改法**:若需「预览再保存」,拆分为 PATCH 内存 + `POST /monitor-config/save`;与 `PostAlarmColors` / `SaveCarStyle` 模式对齐。
|
||||
- **评估说明**(2026-05-29):当前「POST 成功即写盘」行为正确(非 bug)。是否拆分为「预览态 + 显式保存」取决于产品对监控可见性配置的交互预期,拆分需新增 `POST /monitor-config/save` 端点并由前端配合「保存」按钮,属产品/前端联动改动。结论:维持现状,待产品确认是否需要预览态后再迭代。
|
||||
|
||||
---
|
||||
|
||||
### ISSUE-08 — WorkspaceToolbar GetState 响应格式不一致
|
||||
|
||||
- **状态**:[x] 已修复(2026-05-29)
|
||||
- **文件**:`SimpleLite/Web/WorkspaceToolbarApiController.cs`(`GetState`)
|
||||
- **现象**:`GetState` 返回 `{ success, code, data }`;其它端点用 `ReflectionEnvelope<object>`。
|
||||
- **建议改法**:统一为 `ReflectionEnvelope`;或前端 adapter 层统一解析(若改 Vue 需另开任务)。
|
||||
- **验收标准**:`WorkspaceCanvasToolbar.vue`(未审)与 API 契约一致。
|
||||
- **修复说明**(2026-05-29):`GetState` 成功分支由手写匿名对象 `{ success, code, data }` 改为 `ReflectionEnvelope<object>.Ok(BuildStateAnon())`,输出补齐 `message` 字段。经核对前端 `workspaceToolbar.ts` 的 `Envelope<T>` 接口本就声明 `{ success, code, data, message }` 且 `unwrap` 在失败时读 `resp.message`——本次改动使后端与该契约完全对齐,`data`(`BuildStateAnon`)结构不变,前端仅多读到一个 `message` 字段,向后兼容,无需改 Vue。
|
||||
|
||||
---
|
||||
|
||||
### ISSUE-09 — 录制/图层 API 重复
|
||||
|
||||
- **状态**:[~] 已评估(2026-05-29):逻辑已收敛到共享单例,维持双入口
|
||||
- **文件**:
|
||||
- `SimpleLite/Web/MapEditApiController.cs`(`/layers`、`/recording/*`、`/playback/*`)
|
||||
- `SimpleLite/Web/WorkspaceToolbarApiController.cs`(同源能力)
|
||||
- **建议改法**:抽取 `RecordingApiHelper` / 单 controller;或文档标明 MapEdit=地图编辑器、Toolbar=Embed iframe,避免双份逻辑漂移。
|
||||
- **验收标准**:修一处行为两处一致,或 deprecate 其一。
|
||||
- **评估说明**(2026-05-29):核对两个 controller 后确认——`MapEditApiController`(`/objects/*`、`/layers`、`/recording/*`、`/playback/*`)与 `WorkspaceToolbarApiController`(`/toolbar/*`)**都只是薄 HTTP 封装**,真正的状态与逻辑均委托给共享单例 `PlaybackController` / `SimulationRecorder` / `RecordingLibrary` / `SimpleUI.LayerToShowRef`。因此「修一处行为两处一致」**本质已满足**(无逻辑漂移,仅路由壳与响应组装重复)。分工:MapEdit=地图编辑器全功能页,Toolbar=Embed/CanvasOnly iframe 精简栏。结论:维持双入口(强行合并会牵动两套前端),作为技术债记录;后续若消重可抽取 `RecordingApiHelper` 收拢响应组装。
|
||||
|
||||
---
|
||||
|
||||
### ISSUE-11 — 高频 redraw 仍可能偶发旧帧
|
||||
|
||||
- **状态**:[~] 已评估(2026-05-29):观察项,未复现不改
|
||||
- **文件**:`SimpleLite/Rendering/SimpleSceneRenderer.cs`
|
||||
- **现象**:已做 force 16ms、运动 33ms、`NotifyStateChanged` 直通;极端高频仍可能竞态。
|
||||
- **建议**:仅在实际复现时合并 redraw 或加锁。
|
||||
- **评估说明**(2026-05-29):现有节流(force 16ms / 运动 33ms / `NotifyStateChanged` 直通)已覆盖常规场景;极端高频旧帧为理论竞态,未见稳定复现。盲目加锁可能引入渲染线程争用、得不偿失。结论:保持观察,待出现可复现用例再针对性合并 redraw 或加锁。
|
||||
|
||||
---
|
||||
|
||||
### ISSUE-12 — Car.OnlineCar / OfflineCar 经 Web 反射调用
|
||||
|
||||
- **状态**:[~] 已评估(2026-05-29):需产品确认角色边界,未擅自加限制
|
||||
- **文件**:`SimpleLite/RCS/CarTypes/Car.cs`;调用链 `ReflectionApiController` + Platform 鉴权
|
||||
- **建议**:确认 Platform 角色是否允许远程触发;必要时 MethodMember 加权限或 Web 层拦截。
|
||||
- **评估说明**(2026-05-29):`OnlineCar` / `OfflineCar` 经 `ReflectionApiController` 反射触发,已受 Platform JWT 鉴权链保护(需登录且具备相应 scope)。是否进一步收紧(仅 `role-platform`、或 `MethodMember` 增权限位)取决于产品对「远程上/下线车辆」的角色边界定义,属权限策略决策,不宜由代码审核单方收紧(可能误伤合法运营操作)。结论:待产品确认角色边界后再决定是否加 `MethodMember` 权限或 Web 层拦截。
|
||||
|
||||
---
|
||||
|
||||
### ISSUE-13 — GetPosition realtime 未启用
|
||||
|
||||
- **状态**:[~] 已评估(2026-05-29):阻塞于 CycleGUI 协议,维持注释
|
||||
- **文件**:`SimpleLite/Workspace/WorkspacePickSession.cs`
|
||||
- **现象**:`getPos.realtime = true` 仍注释;依赖 `OnPickFeedback` 双路驱动拖动。
|
||||
- **建议**:CycleGUI 协议支持后取消注释并删「尚未上线」说明。
|
||||
- **评估说明**(2026-05-29):`getPos.realtime = true` 依赖 CycleGUI 协议层支持,当前版本未提供,强行开启会导致拖动反馈异常;现有 `OnPickFeedback` 双路驱动已能正常工作。结论:阻塞于外部依赖(CycleGUI 升级),维持注释现状,待协议支持后取消注释。
|
||||
|
||||
---
|
||||
|
||||
### ISSUE-14 — 2D 平移绑定依赖 CycleGUI API
|
||||
|
||||
- **状态**:[~] 已评估(2026-05-29):环境/版本项,建议补版本矩阵
|
||||
- **文件**:`SimpleLite/Workspace/WorkspaceViewModeService.cs`(`TryBind2DPanOnly`)
|
||||
- **现象**:反射 `SetWorkspaceBehaviour` 字段名;版本不匹配时 2D 右键可能仍改俯仰。
|
||||
- **建议**:版本矩阵文档;失败时 UI 提示升级 CycleGUI。
|
||||
- **评估说明**(2026-05-29):`TryBind2DPanOnly` 经反射读 `SetWorkspaceBehaviour` 字段名,与 CycleGUI 版本强相关。本质是「运行环境/依赖版本匹配」问题,非代码逻辑缺陷。结论:作为环境项记录;建议在 CycleGUI 版本矩阵文档标注最低版本,并在反射失败时通过 UI 提示升级(可后续小改)。本轮不改逻辑以免误判版本。
|
||||
|
||||
---
|
||||
|
||||
### ISSUE-15 — 表格双击为 400ms 时间窗口模拟
|
||||
|
||||
- **状态**:[~] 已评估(2026-05-29):可接受方案,维持
|
||||
- **文件**:`SimpleLite/UI/WorkbenchTableRowUi.cs`
|
||||
- **说明**:CycleGUI 无原生 DoubleClick;已有 `PruneExpiredClickTimestamps` 防泄漏。
|
||||
- **评估说明**(2026-05-29):CycleGUI 立即模式 UI 无原生 DoubleClick 事件,400ms 时间窗口模拟是合理的既定方案,且已有 `PruneExpiredClickTimestamps` 防时间戳泄漏。结论:方案可接受,维持现状,低优先级。
|
||||
|
||||
---
|
||||
|
||||
### ISSUE-16 — 底栏 CAD 入口已移除
|
||||
|
||||
- **状态**:[~] 已评估(2026-05-29):非 bug,待产品确认无强依赖
|
||||
- **文件**:`WorkspaceBottomBar.cs`、`WorkspaceFloatingToolbar.cs`
|
||||
- **说明**:CAD 仍可通过主菜单/插件;确认用户无强依赖底栏入口。
|
||||
- **评估说明**(2026-05-29):底栏 CAD 入口移除是产品调整(非缺陷),CAD 功能仍可经主菜单/插件访问。结论:非 bug,仅需产品确认用户无对「底栏 CAD 入口」的强依赖即可关闭。
|
||||
|
||||
---
|
||||
|
||||
## 已确认修复项(无需再改,供对照)
|
||||
|
||||
| 项 | 说明 |
|
||||
|----|------|
|
||||
| 脚本 KPI | `script` count 改为 `CarProgram.GetPrograms().Length` |
|
||||
| 脚本 CRUD | Web 禁止新建/删除 script;`ResolveObject` 走 CarProgram |
|
||||
| 删 script 误删车 | `MapObjectFactory.DeleteByKind` script 分支独立返回 400 |
|
||||
| JSON camelCase | `SetViewFilter` 用 Dictionary;Toolbar 用 `JsonSerializerCase.CamelCase` |
|
||||
| 敏感字段 | `MapObjectFactory` 前缀黑名单 + `writableViaApi` |
|
||||
| 项目保存路径 | `TryResolveSafeProjectPath` 白名单 |
|
||||
| 对齐/选择解耦 | `WorkspacePointerSnap` 用 `AlignSnap*` |
|
||||
| GetPosition 竞态 | `terminated` ReferenceEquals 防误删新会话 |
|
||||
| 车体默认白色 | `WorkspaceViewportStyle` 纯白判定修复 |
|
||||
|
||||
---
|
||||
|
||||
## 未审范围(后续可另开审核任务)
|
||||
|
||||
- `frontends/apps/simple-platform-vue/**`(含 `DashboardView.vue` 等大 diff)
|
||||
- `SimpleLite/UI/ComposerDockPanel.cs` 大 diff
|
||||
- `build-platform-frontend.bat`
|
||||
- 全解决方案 `dotnet build` / 前端 `npm run build`
|
||||
- 未跟踪前端文件:`workspaceToolbar.ts`、`WorkspaceCanvasToolbar.vue`、`CarStyleEditor*.vue` 等
|
||||
|
||||
---
|
||||
|
||||
## 给优化 AI 的推荐执行顺序
|
||||
|
||||
```
|
||||
1. ISSUE-10(回归真实 DB → 修 binder 或序列化策略)
|
||||
2. ISSUE-05(writableViaApi 对齐)
|
||||
3. ISSUE-04(git add 缺失文件)
|
||||
4. ISSUE-08 / ISSUE-09(若本轮动前端 Toolbar)
|
||||
5. 其余 P2 按产品排期
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 修订记录
|
||||
|
||||
| 日期 | 说明 |
|
||||
|------|------|
|
||||
| 2026-05-29 | 初版:基于会话 58 代码审核整理 |
|
||||
| 2026-05-29 | 优化轮(会话 65):修复 ISSUE-10/05/06/08(代码改动);ISSUE-03 在 `MiGu.Server/README.md` 增「安全须知」、ISSUE-04 补 `.gitignore` 并给出 `git add` 命令(后端必需文件待人工提交);ISSUE-01/02/07/09/11/12/13/14/15/16 完成评估并记录决策。`dotnet build SimpleLite/SimpleLite.csproj` 通过(0 错误 / 282 预存警告)。 |
|
||||
@@ -0,0 +1,37 @@
|
||||
# 代码审核问题 Checklist(给其他 AI)
|
||||
|
||||
完整说明见:`Doc/CODE_REVIEW_ISSUES_2026-05-29.md`
|
||||
|
||||
---
|
||||
|
||||
## P0
|
||||
|
||||
- [ ] **ISSUE-10** `SimpleLite/Persistence/Repositories/CarRepository.cs` — `CarTypeBinder` 白名单过严,可能拦 `System.String`/`System.Int32` 等,导致 `DeserializeObject(car)` 失败。修复:放宽安全 BCL 类型或缩小 `TypeNameHandling.Auto` 范围;用真实 DB 回归。
|
||||
|
||||
## P1
|
||||
|
||||
- [ ] **ISSUE-05** `SimpleLite/Web/ReflectionApiController.cs` — `SetProjectField` / `SetAppConfigField` 未检查 `[FieldMember].writableViaApi`,与 `MapObjectFactory.TryApplyField` 不一致。修复:writableViaApi=false → 403。
|
||||
|
||||
- [ ] **ISSUE-04** 未跟踪文件需 `git add`:`MiGu.Server/Launcher/*`、`WorkspaceToolbarApiController.cs`、`MonitorVisibilityConfig.cs`、`CurveControlPointDragService.cs`。
|
||||
|
||||
## P2(可选)
|
||||
|
||||
- [ ] **ISSUE-01** `AuthController.Login` — `MaybeStart` 仍可能阻塞 ~8s。
|
||||
- [ ] **ISSUE-02** `Me`/`SwitchScope` — 复用外部 SimpleLite 时 RunMode 可能不准。
|
||||
- [ ] **ISSUE-03** `appsettings.json` — 默认 admin 密码,生产需覆盖。
|
||||
- [ ] **ISSUE-06** `GetMonitorConfig` — GET 写 `Configuration.conf.monitorVisibility`。
|
||||
- [ ] **ISSUE-07** `PostMonitorConfig` — POST 即写 `simple.json`。
|
||||
- [ ] **ISSUE-08** `WorkspaceToolbarApiController.GetState` — 响应格式与 `ReflectionEnvelope` 不一致。
|
||||
- [ ] **ISSUE-09** MapEdit vs Toolbar 录制/图层 API 重复,易漂移。
|
||||
- [ ] **ISSUE-11** `SimpleSceneRenderer` — 极端高频 redraw 竞态(观察)。
|
||||
- [ ] **ISSUE-12** `Car.OnlineCar`/`OfflineCar` — Web 反射权限确认。
|
||||
- [ ] **ISSUE-13** `WorkspacePickSession` — `realtime=true` 待 CycleGUI。
|
||||
- [ ] **ISSUE-14** `WorkspaceViewModeService.TryBind2DPanOnly` — 依赖 CycleGUI 版本。
|
||||
- [ ] **ISSUE-15** `WorkbenchTableRowUi` — 双击 400ms 模拟(低优)。
|
||||
- [ ] **ISSUE-16** 底栏 CAD 已移除 — 产品确认。
|
||||
|
||||
---
|
||||
|
||||
## 推荐顺序
|
||||
|
||||
`ISSUE-10` → `ISSUE-05` → `ISSUE-04` → 其余 P2
|
||||
@@ -0,0 +1,133 @@
|
||||
# 本周代码复审报告(2026-05-23 ~ 2026-05-29)
|
||||
|
||||
> **用途**:对本周全部改动(含已提交)的一次复审,聚焦后端 C# 安全性与正确性。
|
||||
> **仓库**:`E:\Work\Core\Simple-FR\Simple` **分支**:`dev_simpleLite`
|
||||
> **基线**:`d8d4d3c`(2026-05-21)→ **HEAD**:`1412bf0`(含一次合并远程的 merge)
|
||||
> **本文档为本地工作记录,默认不纳入版本库。**
|
||||
|
||||
---
|
||||
|
||||
## 1. 范围与方法
|
||||
|
||||
- 本周累计:**37 commit,277 文件,+32461 / −5740 行**;其中后端 C# **96 文件 / +15302 行**为审核核心。
|
||||
- `MiGu.Server/wwwroot/assets`(占 dirstat 28%)为前端构建产物,忽略。
|
||||
- 说明:本轮原计划用 5 个并行子代理分模块审核,但因账户账单(unpaid invoice)子代理不可用,改为**人工聚焦后端安全关键面**深度审核;功能性大文件(录制/流/UI/Workspace)与前端做轻量或留待后续。
|
||||
|
||||
### 已深度审阅
|
||||
| 文件 | 关注点 | 结论 |
|
||||
|------|--------|------|
|
||||
| `MiGu.Server/Launcher/SimpleLiteLauncher.cs` | 命令注入/进程生命周期/JobObject | 良好 |
|
||||
| `SimpleLite/Web/AiCompletionService.cs` | SSRF/密钥/Prompt 注入/并发 | 见 RV-01~03 |
|
||||
| `SimpleLite/PluginManager.cs` | 任意 DLL 加载/RCE/并发 | 良好(入口受限) |
|
||||
| `SimpleLite/Web/AiConfigController.cs` | 密钥脱敏 | 良好 |
|
||||
| `SimpleLite/Web/InternalAuthModule.cs` | 8222 鉴权 | 见 RV-04 |
|
||||
| `SimpleLite/Web/ReflectionApiController.cs`(本会话已改部分) | writableViaApi/只读/Envelope | 已修 ISSUE-05/06/08 |
|
||||
| `SimpleLite/Persistence/Repositories/CarRepository.cs` | 反序列化白名单 | 已修 ISSUE-10 |
|
||||
|
||||
### 鉴权链确认(关键前提)
|
||||
- `InternalAuthModule`(AR-1/AR-2)统一前置守护所有 `/projection/*`(reflection / map-edit / persistence / ai-config / stream)。
|
||||
- MiGu.Server 侧 Controller 已加 `[Authorize]`(AR-4)。
|
||||
- **结论**:AI 生图、插件 reload、字段写入等敏感入口**不可被未认证外部直接触达**——这把多处原本可能的高危项降级为 P2 加固建议。
|
||||
|
||||
---
|
||||
|
||||
## 2. 发现清单(按严重度)
|
||||
|
||||
### P1 — 建议处理(视部署环境)
|
||||
|
||||
#### RV-04 — InternalAuthModule loopback 默认无条件放行
|
||||
- **文件**:`SimpleLite/Web/InternalAuthModule.cs:79-80`(`AllowLoopback` 默认 `true`)
|
||||
- **现象**:本机回环(127.0.0.1/::1/IPv4-mapped)请求**不校验 token 直接放行**。
|
||||
- **风险**:单机可信环境无碍;但在**多租户/共享主机**或存在可打到 `127.0.0.1:8222` 的 SSRF 时,本机任意进程即可接管调度内核(execute [MethodMember] / patch 字段 / reload plugin)。
|
||||
- **建议**:生产(尤其共享主机)通过配置将 `AllowLoopback=false`,强制依赖 `X-Platform-Internal-Token`;并在部署文档标注。代码已预留开关,无需改逻辑,仅需配置 + 文档。
|
||||
|
||||
### P2 — 加固建议
|
||||
|
||||
#### RV-01 — AiCompletion endpoint 无 SSRF 白名单
|
||||
- **文件**:`SimpleLite/Web/AiCompletionService.cs:191-197`
|
||||
- **现象**:`cfg.Endpoint`(管理员经 ai-config 表单可配任意 URL)被服务端 `SharedClient.SendAsync` 直接请求,并携带 `Authorization: Bearer <apiKey>`。
|
||||
- **风险**:已认证管理员可让服务器向任意(含内网)URL 发带密钥请求 → SSRF / 密钥外泄到非预期端点。
|
||||
- **建议**:对 `Endpoint` 做 scheme 限制(仅 https)+ host 白名单/黑名单(禁内网段),或显式告警「endpoint 指向内网」。
|
||||
|
||||
#### RV-02 — apiKey 明文存盘且 config/ 未被 gitignore
|
||||
- **文件**:`SimpleLite/Web/AiCompletionService.cs:71-99`(`CWD/config/ai-completion.json` 明文读写)
|
||||
- **现象**:`apiKey` 明文落盘;`.gitignore` 未覆盖 `config/` 或该文件(已核查无匹配规则)。
|
||||
- **风险**:误 `git add config/` 或随包分发会泄露 LLM 密钥。
|
||||
- **建议**:`.gitignore` 增加 `**/config/ai-completion.json`(或运行时 `config/`);考虑落盘前对 apiKey 做 DPAPI/对称加密。注:GET 已脱敏(`AiConfigController.MaskApiKey`),此项仅针对磁盘文件。
|
||||
|
||||
#### RV-03 — AiCompletion 把 LLM 原始响应回抛前端
|
||||
- **文件**:`SimpleLite/Web/AiCompletionService.cs:199-200`(`throw ... LLM HTTP {status}: {raw}`)
|
||||
- **现象**:上游非 2xx 时把 `raw` 响应体原样抛出,经 `MapEditApiController` 返回前端。
|
||||
- **风险**:信息泄露(上游错误细节/内部 endpoint),低概率含敏感片段。
|
||||
- **建议**:仅记日志保留 `raw`,对前端返回精简错误码与通用提示。
|
||||
|
||||
#### RV-05 — 登录阻塞至 Readiness 超时(同 ISSUE-01)
|
||||
- **文件**:`MiGu.Server/Controllers/AuthController.cs:111` + `SimpleLiteLauncher.WaitForProjectionReady`
|
||||
- **现状**:已通过 `SimpleLiteOptions.ReadinessTimeoutMs`(可配,0=立即返回)缓解;真正的「fire-and-forget + 前端轮询」留待迭代。
|
||||
|
||||
---
|
||||
|
||||
## 3. 已确认良好(无需改动)
|
||||
|
||||
- **SimpleLiteLauncher**:`displayMode` 由 `NormalizeDisplayMode` 归一为固定枚举(web / web+local),命令行无注入面;`_opts.Arguments` 来自受信 appsettings;进程 `Exited` 事件用 `ReferenceEquals(_proc, proc)` 防误清;JobObject 资源用 `AllocHGlobal/FreeHGlobal` 配对释放。
|
||||
- **PluginManager**:`reload` 入口(`/reflection/plugins/reload`)只**重扫固定 `./plugins` 目录**,不接受任意路径参数 → 无「任意路径 DLL 加载」漏洞;`Load`/`Unload` 全程加锁(修复历史并发覆盖 bug);collectible ALC + WeakReference + GC best-effort 卸载。
|
||||
- **AiConfigController**:GET 脱敏 `apiKey`(`***`+后4位);POST 对脱敏占位保留旧值,避免被覆盖清空。
|
||||
- **InternalAuthModule**:token 校验用 `CryptographicOperations.FixedTimeEquals` 防 timing;未配置 token 时一律拒绝远程(仅 loopback 可入)。
|
||||
- **AiCompletionService 并发**:静态 `SharedClient`(避免 socket exhaustion)+ `Timeout.Infinite` + `CancellationTokenSource` 控制单次超时;`BoundsContext` 用 `AsyncLocal` 跨 await 保持并 `try/finally` 清理。
|
||||
- **本会话修复**:ISSUE-10(反序列化白名单)/ ISSUE-05(writableViaApi 403)/ ISSUE-06(GET 只读)/ ISSUE-08(Envelope 统一),均经 `dotnet build SimpleLite` 验证 0 错误。
|
||||
|
||||
---
|
||||
|
||||
## 4. 未深审(建议后续专项)
|
||||
|
||||
| 区域 | 文件(本周新增/大改) | 建议关注 |
|
||||
|------|----------------------|----------|
|
||||
| 录制/回放 | `SimulationRecorder` `PlaybackController` `RecordingFileIO` `SimulationPlayer` `SchedulerProbe` | 文件句柄/内存映射释放、帧索引边界 |
|
||||
| 实时流 | `ProjectionStreamModule` `AlarmStreamService` | SSE 连接泄漏/重连/背压 |
|
||||
| 持久化 | `SceneRepository` `ScriptRepository` `MissionRepository` `PersistenceWorker` `PersistenceBootstrap` | EF DbContext 生命周期、并发、事务 |
|
||||
| 交互/渲染 | `WorkspaceSceneInput` `CurveControlPointDragService` `SimpleSceneRenderer` `ComposerDockPanel` `SimpleUI` | 线程竞态、事件/定时器泄漏 |
|
||||
| 前端 | `simple-platform-vue/**` | 鉴权守卫、契约一致、XSS、mock 开关(子代理不可用,本轮未审) |
|
||||
|
||||
---
|
||||
|
||||
## 5. 结论
|
||||
|
||||
本周后端改动建立在会话 53 的安全基线(AR-1~AR-6)之上,**鉴权链完整、未见新增高危漏洞**。建议优先处理 **RV-04(生产关 loopback)** 与 **RV-02(config/ai-completion.json 入 gitignore)** 两项低成本加固;RV-01/RV-03 视风险排期。功能性模块与前端建议在子代理可用后做一轮专项复审。
|
||||
|
||||
---
|
||||
|
||||
## 6. 本轮处理与补充发现(会话 65 续)
|
||||
|
||||
### 6.1 已修复(按「修复 RV-04 + P2 加固项」)
|
||||
- **RV-01(SSRF)**:`AiCompletionService.GenerateMapInternalAsync` 发请求前校验 endpoint —— 仅允许 http/https(挡 `file://` 等异常 scheme),指向内网/回环时记审计日志但不阻断(兼容自建 LLM)。新增 `IsPrivateOrLoopbackHost`。
|
||||
- **RV-02(密钥入库)**:`.gitignore` 增 `**/config/ai-completion.json`。
|
||||
- **RV-03(信息泄露)**:上游 LLM 非 2xx 时原始响应仅进日志(截断 500 字符),前端只返回状态码 + “详见日志”。
|
||||
- **RV-04(loopback)**:经核实**已可配置**(`PlatformOptions.allowLoopbackBypass`,`ProjectionWebHost.cs:51` 已接线),无需改代码;已在 `MiGu.Server/README.md` 安全须知补充「生产建议 `allowLoopbackBypass=false`」。
|
||||
|
||||
### 6.2 补充深审结论(质量良好)
|
||||
- **实时流** `ProjectionStreamModule` / `AlarmStreamService`:每订阅者一把 `SemaphoreSlim` + `finally` 清理 CTS/锁 + 断连移除;删除车辆时清 `LastAlarmByCar` 防膨胀;反射 `FieldInfo` 缓存。仅 P2(SSE `Dispose` 与 fire-and-forget `Broadcast` 的竞态已被 `catch (ObjectDisposedException)` 吸收;`AlarmStream` Timer Tick 极端慢时可能重入,`ConcurrentDictionary` 保证安全)。
|
||||
- **录制文件 IO** `RecordingFileIO`:`compressedLen` ≤ 64MB 校验、`ReadExact` 截断检测、GZip 流 `using` 释放、`ScanIndex` 损坏帧停止。仅 P2(解压后大小无上限,GZip 炸弹理论风险;录像为本地受信文件,实际影响小)。
|
||||
|
||||
### 6.3 补充发现并修复
|
||||
- **RV-06(已预防性修复,2026-05-29)** `PersistenceWorker.FlushUpsert`/`FlushDelete` 原在 `ctx.SaveChanges()` / `tx.Commit()` **之前**就调用 `SetHash`/`RemoveHash`,若事务随后回滚,`_lastWrittenHash` 已记录该 hash → 后续 `ShouldSkipWrite` 跳过重写 → 该变更(尤其低频状态如 Mission/Script)可能永久不落库。`AUDIT.md` 的 PB-1~PB-5 未覆盖此项。虽 `Startup.cs:72-74` 已整体下线持久化(worker 不运行),仍按要求预防性修复:
|
||||
- `FlushUpsert`/`FlushDelete` 改为把 hash 变更累积到局部 `hashOps`(`hash==null` 表示移除),不再直接改字典;
|
||||
- 仅当 `SaveChanges()` + `tx.Commit()` 成功后才由新增的 `ApplyHashOps` 在 `_hashLock` 内原子应用;回滚 / 异常路径不应用,保留「下次仍需写入」语义;
|
||||
- 删除不再使用的 `SetHash`/`RemoveHash`。`ReadLints` 验证 0 错误(完整 `dotnet build` 仍受 §6.4 weaver 环境阻塞)。
|
||||
|
||||
### 6.4 编译验证说明(受阻于织入工具链环境问题)
|
||||
- 修复仅触及 `SimpleLite/Web/AiCompletionService.cs`(标准 C#:`Uri.TryCreate` / `IPAddress` / 字符串操作)。
|
||||
- **首次** `dotnet build SimpleLite/SimpleLite.csproj`(本会话早段)**0 错误**成功,`LessokajiWeaver` 在线织入完整跑过(约 51s,日志 `Online compilation finished`)。
|
||||
- **本次复验**:SimpleCore 报 20 个 `CS0246/CS0616/CS0641`,全部是 `LessokajiWeaver` 在线织入临时项目(`obj/MaxKeeper_tmp`)应提供的类型缺失(`I18N`/`MethodMember`/`MaxValueKeeper`/`KeepMaxMod`/`ReplaceWithCompileInfo`);`--no-incremental` 全量重建仍 7s 即失败,未进入在线织入。**错误列表无任何 SimpleLite 文件**。
|
||||
- 判定:**织入工具链在线服务/状态不可用的环境问题,非本次代码问题**。建议在 VS2022 正常环境、或 `tools\setenv.ps1` 恢复 deps 且 weaver 在线服务可用后复验本次 AI 服务改动。
|
||||
|
||||
### 6.5 未完成(建议后续专项)
|
||||
- `Workspace` / `UI` / `Rendering`、前端全量:本轮因并行子代理不可用(账户账单)未深审,建议子代理恢复后补一轮。
|
||||
|
||||
---
|
||||
|
||||
## 修订记录
|
||||
| 日期 | 说明 |
|
||||
|------|------|
|
||||
| 2026-05-29 | 初版:会话 65 本周复审(聚焦后端安全关键面;子代理因账单不可用,人工聚焦审核) |
|
||||
| 2026-05-29 | 续:修复 RV-01/02/03 + RV-04 文档;补深审(流/文件良好、PersistenceWorker 发现 RV-06);编译复验受阻于 LessokajiWeaver 在线织入环境问题(与改动无关)。 |
|
||||
| 2026-05-29 | 续:按要求预防性修复 RV-06(hash 延迟到事务 Commit 后由 ApplyHashOps 原子应用);本会话全部 5 个改动文件 ReadLints 0 错误。 |
|
||||
Reference in New Issue
Block a user