# ZCLAW 代码质量与安全全面检查计划 > **类型**: 代码审查 / 安全审计 > **优先级**: P0 (阻塞发布) > **预计工时**: 25 人天 > **创建日期**: 2026-03-16 ## 一、背景与目标 ### 1.1 问题背景 ZCLAW 项目在进行代码审查时发现多个安全漏洞和代码质量问题,需要系统性修复以确保: 1. **安全性**: 敏感数据存储、通信加密、输入验证 2. **代码质量**: 文件大小、类型安全、错误处理 3. **测试覆盖**: 当前约 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` **修改内容**: ```typescript // 当 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` (新建) **关键类型定义**: ```typescript 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天] **命令**: ```bash cd desktop && pnpm add uuid && pnpm add -D @types/uuid ``` **验证**: - [ ] `pnpm install` 无错误 - [ ] `pnpm tsc --noEmit` 通过 #### 1.6 修复静默错误吞噬 [1天] **修改模式**: ```typescript // 错误模式 catch { } // 正确模式 catch (err: unknown) { if (import.meta.env.DEV) { console.warn('[模块名] 操作失败:', err); } // 预期: 某些场景下 localStorage 可能不可用 } ``` **涉及文件**: - `secure-storage.ts` - `gateway-client.ts` - `connectionStore.ts` - `chatStore.ts` - `RightPanel.tsx` - `App.tsx` **验证**: - [ ] 搜索 `catch\s*\([^)]*\)\s*\{[\s\n]*\}` 返回空 --- ### Phase 2: P1 重要修复 (预计 6.5 天) #### 2.1 ReDoS 防护 [1天] **文件**: `desktop/src/components/CreateTriggerModal.tsx` **修改内容**: ```typescript 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` **修改**: ```typescript 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` **修改**: ```typescript 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` **修改**: ```typescript // 生产环境默认 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 修改**: ```json { "compilerOptions": { "useUnknownInCatchVariables": true } } ``` **修复所有 catch 块**: ```typescript catch (err: unknown) { const message = err instanceof Error ? err.message : String(err); } ``` #### 2.6 提取错误处理工具 [1天] **新建文件**: `desktop/src/lib/error-utils.ts` ```typescript 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.tsx` - `src/components/ui/ErrorAlert.tsx` - `src/components/ui/ErrorBoundary.tsx` - `src/store/activeLearningStore.ts` - `src/store/skillMarketStore.ts` - `src/types/active-learning.ts` - `src/types/skill-market.ts` **操作**: 逐个修复类型错误后从排除列表移除 --- ### Phase 3: P2 质量改进 (预计 7.5 天) #### 3.1 屏蔽控制台 Token [0.5天] **文件**: `desktop/src/store/connectionStore.ts` ```typescript // 修改前 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` ```typescript 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. **立即执行** (无依赖): - 1.5 添加 uuid 依赖 - 1.6 修复静默错误吞噬 - 2.1 ReDoS 防护 - 2.2 清理 API 错误 - 2.3 限制堆栈跟踪 - 2.4 默认 WSS - 2.5 类型化 catch - 2.6 错误处理工具 - 3.1 屏蔽 Token 2. **第二批** (有依赖): - 1.2 拆分 gateway-client - 1.3 拆分 gatewayStore - 1.4 替换 any 类型 3. **最后执行**: - 1.1 安全存储加密 (需要设计确认) - 2.7 移除 tsconfig 排除 - 3.2 提升测试覆盖率 - 3.3 结构化日志