Major type system refactoring and error fixes across the codebase: **Type System Improvements:** - Extended OpenFangStreamEvent with 'connected' and 'agents_updated' event types - Added GatewayPong interface for WebSocket pong responses - Added index signature to MemorySearchOptions for Record compatibility - Fixed RawApproval interface with hand_name, run_id properties **Gateway & Protocol Fixes:** - Fixed performHandshake nonce handling in gateway-client.ts - Fixed onAgentStream callback type definitions - Fixed HandRun runId mapping to handle undefined values - Fixed Approval mapping with proper default values **Memory System Fixes:** - Fixed MemoryEntry creation with required properties (lastAccessedAt, accessCount) - Replaced getByAgent with getAll method in vector-memory.ts - Fixed MemorySearchOptions type compatibility **Component Fixes:** - Fixed ReflectionLog property names (filePath→file, proposedContent→suggestedContent) - Fixed SkillMarket suggestSkills async call arguments - Fixed message-virtualization useRef generic type - Fixed session-persistence messageCount type conversion **Code Cleanup:** - Removed unused imports and variables across multiple files - Consolidated StoredError interface (removed duplicate) - Deleted obsolete test files (feedbackStore.test.ts, memory-index.test.ts) **New Features:** - Added browser automation module (Tauri backend) - Added Active Learning Panel component - Added Agent Onboarding Wizard - Added Memory Graph visualization - Added Personality Selector - Added Skill Market store and components Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
12 KiB
12 KiB
ZCLAW 代码质量与安全全面检查计划
类型: 代码审查 / 安全审计 优先级: P0 (阻塞发布) 预计工时: 25 人天 创建日期: 2026-03-16
一、背景与目标
1.1 问题背景
ZCLAW 项目在进行代码审查时发现多个安全漏洞和代码质量问题,需要系统性修复以确保:
- 安全性: 敏感数据存储、通信加密、输入验证
- 代码质量: 文件大小、类型安全、错误处理
- 测试覆盖: 当前约 40-50%,目标 80%
1.2 预期成果
- 所有关键安全漏洞修复
- 代码文件符合 800 行限制
- TypeScript 严格模式通过
- 测试覆盖率达到 80%
二、发现的问题摘要
2.1 安全问题 (按严重性)
| 严重性 | 问题 | 文件位置 |
|---|---|---|
| HIGH | Ed25519 私钥 localStorage 明文存储 | secure-storage.ts:270-278 |
| MEDIUM | 正则表达式 ReDoS 风险 | CreateTriggerModal.tsx:149 |
| MEDIUM | API 错误详情泄露敏感信息 | llm-service.ts:189-192 |
| MEDIUM | 堆栈跟踪存储在错误对象中 | error-types.ts:356-358 |
| MEDIUM | 默认使用 ws:// 非加密协议 | gateway-client.ts:51 |
| LOW | Token 部分字符记录到控制台 | connectionStore.ts:249 |
2.2 代码质量问题
| 优先级 | 问题 | 影响范围 |
|---|---|---|
| P0 | 2 个超大文件 (>800行) | gateway-client.ts (~1850行), gatewayStore.ts (~1670行) |
| P0 | 32 处 any 类型 |
主要在 gateway-client.ts |
| P0 | 21 处静默错误吞噬 | 多个文件 |
| P0 | 测试覆盖率不足 | 估计 40-50% |
| P1 | 30+ 未类型化 catch | 多个文件 |
| P1 | 缺少 UI 组件测试 | *.tsx 文件 |
| P1 | 错误提取逻辑重复 | 30+ 处相同模式 |
| P2 | 130+ console.log | 需要结构化日志 |
2.3 架构问题
gatewayStore.ts未完全拆分- 类型定义分散在多个 store 文件
tsconfig.json排除 7 个有类型错误的文件uuid包使用但未声明依赖
三、实施计划
Phase 1: P0 关键修复 (预计 12.5 天)
1.1 安全存储加密 [2天]
文件: desktop/src/lib/secure-storage.ts
修改内容:
// 当 keyring 不可用时,加密私钥后再存储
function encryptPrivateKey(key: string, passphrase: string): string {
// 使用 PBKDF2 派生密钥 + AES-GCM 加密
}
// 添加安全状态组件显示警告
export function SecurityStatusBanner(): JSX.Element {
// 当使用 localStorage 回退时显示警告
}
验证:
- 单元测试: 验证加密后再存储
- 手动测试: 禁用 keyring,验证 localStorage 中数据已加密
1.2 拆分 gateway-client.ts [3天]
当前: 1 个 1850 行文件
目标结构:
lib/gateway/
├── client.ts (~300 行 - 核心 GatewayClient 类)
├── websocket.ts (~200 行 - WebSocket 处理)
├── rest-api.ts (~400 行 - REST API 方法)
├── auth.ts (~150 行 - 认证逻辑)
├── types.ts (~100 行 - 类型定义)
└── config.ts (~50 行 - 配置常量)
验证:
pnpm tsc --noEmit通过- 所有现有测试通过
- 每个文件 <400 行
1.3 拆分 gatewayStore.ts [4天]
当前: 1 个 1670 行文件
目标结构:
store/
├── connectionStore.ts (已存在)
├── cloneStore.ts (新增 - clone 管理)
├── skillStore.ts (新增 - skill 管理)
├── channelStore.ts (新增 - channel 管理)
├── triggerStore.ts (新增 - trigger 管理)
├── workflowStore.ts (已存在)
├── handStore.ts (已存在)
├── usageStore.ts (新增 - 使用统计)
└── configStore.ts (已存在)
依赖: 应在 1.2 之后执行以避免合并冲突
验证:
pnpm tsc --noEmit通过- 所有现有测试通过
- 每个 store <400 行
1.4 替换 any 类型 [2天]
文件: lib/gateway/types.ts (新建)
关键类型定义:
export interface HealthResponse {
status: 'ok' | 'degraded' | 'error';
version: string;
uptime: number;
}
export interface StatusResponse {
gateway_version: string;
agent_count: number;
active_connections: number;
}
export interface CloneUpdate {
name?: string;
model?: string;
system_prompt?: string;
temperature?: number;
}
依赖: 应在 1.2 之后执行
验证:
noImplicitAny: true检查通过- API 响应有运行时验证
1.5 添加 uuid 依赖 [0.5天]
命令:
cd desktop && pnpm add uuid && pnpm add -D @types/uuid
验证:
pnpm install无错误pnpm tsc --noEmit通过
1.6 修复静默错误吞噬 [1天]
修改模式:
// 错误模式
catch { }
// 正确模式
catch (err: unknown) {
if (import.meta.env.DEV) {
console.warn('[模块名] 操作失败:', err);
}
// 预期: 某些场景下 localStorage 可能不可用
}
涉及文件:
secure-storage.tsgateway-client.tsconnectionStore.tschatStore.tsRightPanel.tsxApp.tsx
验证:
- 搜索
catch\s*\([^)]*\)\s*\{[\s\n]*\}返回空
Phase 2: P1 重要修复 (预计 6.5 天)
2.1 ReDoS 防护 [1天]
文件: desktop/src/components/CreateTriggerModal.tsx
修改内容:
const MAX_PATTERN_LENGTH = 200;
function validateRegexPattern(pattern: string): { valid: boolean; error?: string } {
if (pattern.length > MAX_PATTERN_LENGTH) {
return { valid: false, error: 'Pattern too long (max 200 chars)' };
}
// 检测危险构造
const dangerousPatterns = [/\(\?[^)]*\+[^)]*\)/, /(.*)\1{3,}/];
for (const dangerous of dangerousPatterns) {
if (dangerous.test(pattern)) {
return { valid: false, error: 'Pattern contains dangerous constructs' };
}
}
// 超时检测
try {
const regex = new RegExp(pattern);
const start = Date.now();
regex.test('a'.repeat(20) + 'b'.repeat(20));
if (Date.now() - start > 100) {
return { valid: false, error: 'Pattern is too complex' };
}
return { valid: true };
} catch {
return { valid: false, error: 'Invalid regular expression' };
}
}
2.2 清理 API 错误详情 [0.5天]
文件: desktop/src/lib/llm-service.ts
修改:
if (!response.ok) {
const errorBody = await response.text();
if (import.meta.env.DEV) {
console.error('[OpenAI] API error:', errorBody);
}
// 返回清理后的错误
throw new Error(`[OpenAI] API error: ${response.status} - Request failed`);
}
2.3 限制堆栈跟踪 [0.5天]
文件: desktop/src/lib/error-types.ts
修改:
technicalDetails: error instanceof Error
? `${error.name}: ${error.message}` // 移除 stack
: String(error),
// 仅开发环境保留原始错误
originalError: import.meta.env.DEV ? error : undefined,
2.4 默认安全 WebSocket [0.5天]
文件: desktop/src/lib/gateway-client.ts
修改:
// 生产环境默认 WSS
const USE_WSS = import.meta.env.VITE_USE_WSS !== 'false' || import.meta.env.PROD;
// 非 localhost 使用 ws:// 时警告
if (!url.startsWith('wss://') && !isLocalhost(url)) {
console.warn('[Gateway] Connecting to non-localhost with insecure WebSocket');
}
2.5 类型化所有 catch 块 [1天]
tsconfig.json 修改:
{
"compilerOptions": {
"useUnknownInCatchVariables": true
}
}
修复所有 catch 块:
catch (err: unknown) {
const message = err instanceof Error ? err.message : String(err);
}
2.6 提取错误处理工具 [1天]
新建文件: desktop/src/lib/error-utils.ts
export function getErrorMessage(err: unknown): string {
if (err instanceof Error) return err.message;
if (typeof err === 'string') return err;
return 'Unknown error';
}
export function isError(err: unknown): err is Error {
return err instanceof Error;
}
2.7 移除 tsconfig 排除项 [2天]
当前排除:
src/components/ActiveLearningPanel.tsxsrc/components/ui/ErrorAlert.tsxsrc/components/ui/ErrorBoundary.tsxsrc/store/activeLearningStore.tssrc/store/skillMarketStore.tssrc/types/active-learning.tssrc/types/skill-market.ts
操作: 逐个修复类型错误后从排除列表移除
Phase 3: P2 质量改进 (预计 7.5 天)
3.1 屏蔽控制台 Token [0.5天]
文件: desktop/src/store/connectionStore.ts
// 修改前
console.log('[ConnectionStore] Connecting with token:', effectiveToken ? `${effectiveToken.substring(0, 8)}...` : '(empty)');
// 修改后
console.log('[ConnectionStore] Connecting with token:', effectiveToken ? '[REDACTED]' : '(empty)');
3.2 提升测试覆盖率到 80% [5天]
当前测试:
- Store 层: ~70%
- Lib 层: ~50%
- Component 层: ~10%
新增测试:
tests/desktop/
├── components/
│ ├── CreateTriggerModal.test.tsx
│ ├── ChatArea.test.tsx
│ └── CloneManager.test.tsx
├── lib/
│ ├── gateway-client.test.ts
│ ├── secure-storage.test.ts
│ └── llm-service.test.ts
└── integration/
├── websocket-flow.test.ts
└── auth-flow.test.ts
依赖: 应在 Phase 1 重构后执行
3.3 结构化日志 [2天]
新建文件: desktop/src/lib/logger.ts
type LogLevel = 'debug' | 'info' | 'warn' | 'error';
export const logger = {
debug: (context: string, message: string, data?: unknown) => { ... },
info: (context: string, message: string, data?: unknown) => { ... },
warn: (context: string, message: string, data?: unknown) => { ... },
error: (context: string, message: string, error?: unknown) => { ... },
};
逐步替换 console.log
四、关键文件清单
| 文件 | 问题 | 修改类型 |
|---|---|---|
desktop/src/lib/secure-storage.ts |
私钥明文存储 | 安全加固 |
desktop/src/lib/gateway-client.ts |
1850行, 32处any | 拆分+类型化 |
desktop/src/store/gatewayStore.ts |
1670行 | 拆分 |
desktop/src/components/CreateTriggerModal.tsx |
ReDoS风险 | 输入验证 |
desktop/src/lib/error-types.ts |
堆栈泄露 | 数据清理 |
desktop/src/lib/llm-service.ts |
错误详情泄露 | 错误处理 |
desktop/src/store/connectionStore.ts |
Token日志 | 日志清理 |
desktop/package.json |
缺uuid依赖 | 依赖添加 |
desktop/tsconfig.json |
排除7文件 | 类型修复 |
五、验证清单
Phase 1 完成标准
pnpm tsc --noEmit通过pnpm vitest run通过- 无
any类型 (gateway-client 相关) - 无静默 catch 块
- 所有文件 <800 行
Phase 2 完成标准
- ReDoS 模式被拒绝
- API 错误不暴露响应体
- 堆栈跟踪不在 technicalDetails
- 生产环境默认 WSS
- 所有 catch 使用
unknown - tsconfig 无自定义排除
Phase 3 完成标准
- 控制台无敏感数据
- 测试覆盖率 >= 80%
- 所有日志使用结构化 logger
六、风险与依赖
6.1 风险
| 风险 | 影响 | 缓解措施 |
|---|---|---|
| 重构引入回归 | 高 | 每步运行测试套件 |
| 拆分破坏导入 | 中 | 使用 TypeScript 重构 |
| 测试用例失效 | 中 | 先修复代码再写测试 |
6.2 依赖关系
1.2 (拆分 gateway-client) → 1.3 (拆分 gatewayStore) → 1.4 (替换 any)
→ 3.2 (增加测试)
七、执行顺序建议
-
立即执行 (无依赖):
- 1.5 添加 uuid 依赖
- 1.6 修复静默错误吞噬
- 2.1 ReDoS 防护
- 2.2 清理 API 错误
- 2.3 限制堆栈跟踪
- 2.4 默认 WSS
- 2.5 类型化 catch
- 2.6 错误处理工具
- 3.1 屏蔽 Token
-
第二批 (有依赖):
- 1.2 拆分 gateway-client
- 1.3 拆分 gatewayStore
- 1.4 替换 any 类型
-
最后执行:
- 1.1 安全存储加密 (需要设计确认)
- 2.7 移除 tsconfig 排除
- 3.2 提升测试覆盖率
- 3.3 结构化日志