Skip to content

fix(conversation): guard invalid create type#1936

Merged
piorpua merged 2 commits intoiOfficeAI:mainfrom
cdxiaodong:fix/1920-create-conversation-type-guard
Mar 31, 2026
Merged

fix(conversation): guard invalid create type#1936
piorpua merged 2 commits intoiOfficeAI:mainfrom
cdxiaodong:fix/1920-create-conversation-type-guard

Conversation

@cdxiaodong
Copy link
Copy Markdown
Member

Summary

  • add a runtime whitelist for conversation.create requests before they reach ConversationServiceImpl
  • return a safe empty result for missing or unknown conversation types so the bridge does not surface an unhandled rejection
  • add regression tests for missing and invalid type payloads

Test plan

  • bun run lint
  • bun run format
  • bunx tsc --noEmit
  • bun run test

Fixes #1920

@sentry
Copy link
Copy Markdown

sentry bot commented Mar 30, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@piorpua piorpua added the bot:reviewing Review in progress (mutex) label Mar 30, 2026
@piorpua
Copy link
Copy Markdown
Contributor

piorpua commented Mar 30, 2026

Code Review:fix(conversation): guard invalid create type (#1936)

变更概述

本 PR 在 conversationBridge.tsconversation.create 处理器中新增了运行时类型白名单校验(VALID_CONVERSATION_TYPES),将原来仅检查 type 是否缺失改为检查 type 是否在允许列表内。对于不合法的类型,不再抛出异常,而是静默返回 undefined。同时新增了两个单元测试覆盖缺失和未知类型的场景。


方案评估

结论⚠️ 方案有缺陷

白名单校验的方向正确,能有效拦截非法的 type 值。但将错误处理方式从抛出异常改为 return undefined as unknown as TChatConversation 存在类型安全问题:部分调用方(如 ConversationTabs.tsx:242ModelModalContent.tsx:210)未对返回值做 null/undefined 检查,会在访问 .id 时抛出 TypeError。建议保持抛出异常的行为(调用方已有 try/catch),或者将返回类型改为允许 undefined 并修复所有调用点。


问题清单

🟠 HIGH — return undefined as unknown as TChatConversation 绕过类型安全

文件src/process/bridge/conversationBridge.ts,第 117 行

问题代码

return undefined as unknown as TChatConversation;

问题说明:通过双重类型断言将 undefined 伪装成 TChatConversation,绕过了 TypeScript 的类型检查。部分调用方(ConversationTabs.tsx:242openTab(newConversation)navigate(\/conversation/${newConversation.id}`)ModelModalContent.tsx:210conversation.id)没有对返回值做空值检查,会在运行时因访问 undefined.id抛出TypeError`。

虽然目前这些调用方传入的都是合法类型,不会触发此分支,但这种类型欺骗模式会掩盖未来的错误。原始代码抛出异常的方式更安全——调用方已有 try/catch 处理。

修复建议

保持抛出异常的行为,同时扩展校验范围:

if (!VALID_CONVERSATION_TYPES.has(params?.type as TChatConversation['type'])) {
  console.warn('[conversationBridge] Rejecting create request with invalid conversation type:', params?.type);
  throw new Error(`Invalid conversation type: ${params?.type ?? 'missing'}`);
}

🟡 MEDIUM — 白名单与 TChatConversation 联合类型存在维护耦合

文件src/process/bridge/conversationBridge.ts,第 33–40 行

问题代码

const VALID_CONVERSATION_TYPES = new Set<TChatConversation['type']>([
  'gemini',
  'acp',
  'codex',
  'openclaw-gateway',
  'nanobot',
  'remote',
]);

问题说明VALID_CONVERSATION_TYPES 的值与 TChatConversation 联合类型中的所有 type 字面量完全重复。当新增会话类型时(如在 storage.ts 中新增一个变体),需要同步更新此 Set,否则新类型会被静默拒绝。TypeScript 不会对遗漏发出警告,因为 Set<TChatConversation['type']> 只约束元素类型,不要求穷尽。

修复建议

添加一个编译期穷尽检查辅助,确保类型变更时不会遗漏:

// Exhaustiveness helper — if TChatConversation adds a new type,
// TypeScript will error here until the array is updated.
const VALID_CONVERSATION_TYPES_ARRAY = [
  'gemini',
  'acp',
  'codex',
  'openclaw-gateway',
  'nanobot',
  'remote',
] as const satisfies readonly TChatConversation['type'][];

const VALID_CONVERSATION_TYPES = new Set<TChatConversation['type']>(VALID_CONVERSATION_TYPES_ARRAY);

使用 satisfies 可以确保数组中每个元素都是 TChatConversation['type'] 的成员(虽然无法强制穷尽,但至少能保证不会写入非法值)。或者在 storage.ts 中导出一个运行时类型列表常量。


汇总

# 严重级别 文件 问题
1 🟠 HIGH conversationBridge.ts:117 return undefined as unknown as TChatConversation 绕过类型安全,部分调用方无空值检查
2 🟡 MEDIUM conversationBridge.ts:33-40 白名单与联合类型手动同步,缺乏编译期穷尽保障

结论

⚠️ 有条件批准 — HIGH 问题建议修复(改回抛出异常或修复所有调用方),MEDIUM 问题建议跟进但不阻塞。


本报告由本地 pr-review skill 生成,包含完整项目上下文,无截断限制。

CONCLUSION: CONDITIONAL
IS_CRITICAL_PATH: false
PR_NUMBER: 1936

@piorpua piorpua added bot:needs-human-review Blocking issues — human must intervene and removed bot:reviewing Review in progress (mutex) labels Mar 30, 2026
@cdxiaodong
Copy link
Copy Markdown
Member Author

Merged the latest upstream/main into this branch and kept the bridge-side invalid-type guard.

Local validation before pushing:

  • bun run lint
  • bun run format
  • bunx tsc --noEmit
  • bun run test

CI has been retriggered on commit 761553d.

@piorpua piorpua added bot:reviewing Review in progress (mutex) bot:ready-to-fix CONDITIONAL review done, waiting for bot fix bot:fixing Fix in progress (mutex) and removed bot:needs-human-review Blocking issues — human must intervene bot:reviewing Review in progress (mutex) bot:ready-to-fix CONDITIONAL review done, waiting for bot fix bot:fixing Fix in progress (mutex) labels Mar 31, 2026
@piorpua piorpua added bot:reviewing Review in progress (mutex) bot:ready-to-fix CONDITIONAL review done, waiting for bot fix bot:fixing Fix in progress (mutex) and removed bot:reviewing Review in progress (mutex) bot:ready-to-fix CONDITIONAL review done, waiting for bot fix bot:fixing Fix in progress (mutex) labels Mar 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix: unhandled rejection when conversation type is undefined (ELECTRON-FP)

2 participants