MonkeyCode 代码审查与安全扫描:AI驱动的代码质量守护体系深度解析
引言
"代码审查不是找茬,而是让每一行代码都经得起时间的考验。"
在软件工程实践中,代码审查(Code Review)和安全扫描是保障代码质量的两大支柱。传统的人工审查面临效率低、标准不一、疲劳漏检等痛点;而传统的静态分析工具则常常误报满天飞、缺乏上下文理解。
MonkeyCode 作为完全开源(Apache License 2.0)的 AI 编程助手,将人工智能技术深度融入代码审查与安全扫描流程,构建了一套完整的智能代码质量守护体系。本文将深入剖析 MonkeyCode 的 AI 代码审查引擎、安全漏洞检测系统、以及如何实现从"被动检查"到"主动预防"的范式转变。
🎯 核心信息
- GitHub 仓库: https://github.com/monkeycode-ai/monkeycode
- 开源协议: Apache License 2.0
- 审查引擎版本: v2.8 (持续迭代中)
- 支持语言: 30+ 编程语言的审查规则
- 欢迎贡献安全规则!
一、AI代码审查架构总览
1.1 审查流水线
┌─────────────────────────────────────────────────────────────┐
│ MonkeyCode AI 代码审查流水线 │
│ │
│ ══════════════════════════════════════════════════════ │
│ │
│ ┌─────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 代码输入 │───▶│ 预处理 │───▶│ AST 解析 │ │
│ │ Diff/文件│ │ 编码转换 │ │ Tree-sitter │
│ └─────────┘ └──────────┘ └────┬─────┘ │
│ │ │
│ ┌─────────┐ ┌──────────┐ ┌────▼─────┐ │
│ │ 报告输出 │◀───│ 结果聚合 │◀───│ 多维分析 │ │
│ │ Markdown│ │ 去重/排序 │ │ │ │
│ └─────────┘ └──────────┘ ├────┬─────┤ │
│ │ │ │
│ ┌────▼┐ ┌────▼──┐ │
│ │ 规则 │ │ AI 智 │ │
│ │ 引擎 │ │ 能审查 │ │
│ └─────┘ └───────┘ │
│ │
╚═══════════════════════════════════════════════════════════╝
1.2 核心模块
| 模块 | 职责 | 技术 |
|---|---|---|
| 规则引擎 | 执行预定义的 lint/风格/最佳实践规则 | 自定义 DSL + Tree-sitter queries |
| AI 审查器 | 理解语义、发现逻辑问题、提供改进建议 | LLM + RAG + Few-shot |
| 安全扫描器 | 检测 OWASP Top 10、CWE 漏洞模式 | Pattern Matching + AST + ML |
| 变更分析器 | 理解 diff 上下文、评估影响范围 | Git 集成 + 语义 diff |
| 报告生成器 | 结构化输出审查结果、可操作建议 | Template Engine + Markdown |
二、规则引擎系统
2.1 规则定义DSL
// ===== packages/review/src/rules/rule-dsl.ts =====
/**
* MonkeyCode 代码审查规则定义 DSL (Domain Specific Language)
*
* 支持声明式定义审查规则,无需编写复杂代码
*/
import { z } from 'zod';
// === 规则类型 ===
export enum RuleCategory {
CODE_STYLE = 'code_style', // 代码风格
BEST_PRACTICE = 'best_practice', // 最佳实践
PERFORMANCE = 'performance', // 性能
SECURITY = 'security', // 安全
ERROR_PRONE = 'error_prone', // 易错模式
MAINTAINABILITY = 'maintainability', // 可维护性
DOCUMENTATION = 'documentation', // 文档
TESTING = 'testing', // 测试相关
}
export enum Severity {
ERROR = 'error', // 必须修复(阻断性)
WARNING = 'warning', // 建议修复
INFO = 'info', // 信息提示
HINT = 'hint', // 改进建议
}
// === 规则 Schema ===
const ReviewRuleSchema = z.object({
// 基本信息
id: z.string(), // 唯一标识: "no-unused-vars"
name: z.string(), // 名称: "未使用的变量"
category: z.nativeEnum(RuleCategory),
severity: z.nativeEnum(Severity),
// 适用范围
languages: z.array(z.string()), // 适用的编程语言
frameworks: z.array(z.string()).optional(), // 特定框架
// 规则描述
description: z.string(),
recommendation: z.string(), // 修复建议
// 匹配逻辑(多种方式)
match: z.discriminatedUnion('type', [
// AST 模式匹配
z.object({
type: z.literal('ast'),
query: z.string(), // Tree-sitter S-expression 或 SCM query
language: z.string(),
}),
// 正则表达式匹配
z.object({
type: z.literal('regex'),
pattern: z.string(),
flags: z.string().optional(),
scope: z.enum(['line', 'multiline', 'content']), // 匹配范围
}),
// 结构化模式匹配
z.object({
type: z.literal('structural'),
patterns: z.array(z.object({
kind: z.string(), // AST 节点类型
field?: string, // 字段名
value?: z.any(), // 期望值
operator?: z.enum(['eq', 'neq', 'contains', 'matches', 'gt', 'lt']),
optional: z.boolean().optional(),
})),
}),
// 自定义函数
z.object({
type: z.literal('custom'),
handler: z.string(), // 处理函数路径
options: z.record(z.any()).optional(),
}),
]),
// 自动修复(可选)
fix?: z.object({
template: z.string(), // 修复模板
variables: z.array(z.string()), // 模板变量
}),
// 配置选项
options: z.object({
enabled: z.boolean().default(true),
excludePatterns: z.array(z.string()).optional(), // 排除的文件模式
includePatterns: z.array(z.string()).optional(), // 包含的文件模式
// 高级选项
maxComplexity: z.number().optional(),
threshold: z.number().optional(),
allowList: z.array(z.string()).optional(),
denyList: z.array(z.string()).optional(),
}).optional(),
// 元数据
documentation: z.string().url().optional(),
references: z.array(z.string()).optional(), // 参考链接
tags: z.array(z.string()).optional(),
});
export type ReviewRule = z.infer<typeof ReviewRuleSchema>;
// === 内置规则示例 ===
export const builtInRules: ReviewRule[] = [
{
id: 'no-console-log',
name: '禁止生产环境 console.log',
category: RuleCategory.BEST_PRACTICE,
severity: Severity.WARNING,
languages: ['typescript', 'javascript'],
description: '生产环境不应包含 console.log 语句',
recommendation: '使用结构化日志库替代,或在构建时通过 tree-shaking 移除',
match: {
type: 'regex',
pattern: /console\.(log|debug|info|warn)\(/,
scope: 'line',
},
options: {
excludePatterns: ['*.test.*', '*.spec.*', '*.mock.*'],
},
},
{
id: 'no-hardcoded-secrets',
name: '禁止硬编码密钥和凭证',
category: RuleCategory.SECURITY,
severity: Severity.ERROR,
languages: ['typescript', 'javascript', 'python', 'go', 'java', 'rust'],
description: '不应在源代码中硬编码 API 密钥、密码或其他敏感凭证',
recommendation: '使用环境变量或密钥管理服务存储敏感信息',
match: {
type: 'regex',
pattern: /(password|secret|api_key|apikey|token|credential)\s*[:=]\s*['"][^'"]{4,}['"]/i,
scope: 'line',
},
tags: ['security', 'credentials', 'owasp'],
},
{
id: 'prefer-const',
name: '优先使用 const 声明不可变变量',
category: RuleCategory.CODE_STYLE,
severity: Severity.INFO,
languages: ['typescript', 'javascript'],
description: '如果变量不会被重新赋值,应使用 const 而非 let',
recommendation: '将 let 替换为 const 以提高代码可读性和安全性',
match: {
type: 'ast',
query: `
(variable_declarator
(identifier) @var_name
value: (_) @init_value
(#match? @var_name "^[a-z]")
)
(#is-not-mutated! @var_name)
`,
language: 'typescript',
},
fix: {
template: 'const ${name} = ${value}',
variables: ['name', 'value'],
},
},
{
id: 'complex-function',
name: '函数圈复杂度过高',
category: RuleCategory.MAINTAINABILITY,
severity: Severity.WARNING,
languages: ['typescript', 'javascript', 'python', 'go', 'java', 'csharp'],
description: '函数的圈复杂度超过阈值,难以理解和测试',
recommendation: '将函数拆分为更小的子函数,每个函数只做一件事',
match: {
type: 'custom',
handler: './rules/checkers/complexity.ts',
options: { maxComplexity: 10 },
},
},
{
id: 'sql-injection-risk',
name: 'SQL 注入风险',
category: RuleCategory.SECURITY,
severity: Severity.ERROR,
languages: ['typescript', 'javascript', 'python', 'java', 'php', 'csharp', 'go'],
description: '检测可能导致 SQL 注入的不安全数据库查询模式',
recommendation: '使用参数化查询或 ORM 方法替代字符串拼接',
match: {
type: 'regex',
pattern: /(execute|query|raw)\s*\(\s*[`'"](SELECT|INSERT|UPDATE|DELETE).*\$\{|.*\+\s*(req\.|request\.|params\.)/i,
scope: 'multiline',
},
tags: ['security', 'sql-injection', 'owasp-a03'],
},
];
2.2 规则执行引擎
// ===== packages/review/src/rules/engine.ts =====
/**
* 规则执行引擎
*
* 高效并行执行所有适用的规则,
* 并聚合结果
*/
import { Worker, isMainThread, parentPort, workerData } from 'worker_threads';
import path from 'path';
export interface ReviewResult {
ruleId: string;
ruleName: string;
severity: Severity;
category: RuleCategory;
file: string;
line: number;
column: number;
message: string; // 问题描述
suggestion: string; // 修复建议
// 自动修复信息
fix?: {
text: string; // 替换文本
range: [number, number]; // 替换范围 [start, end]
};
// 元数据
confidence: number; // 置信度 0-1
source: 'rule' | 'ai'; // 来源
effort: 'quick' | 'medium' | 'significant'; // 修复工作量估计
}
export class RuleEngine {
private rules: Map<string, ReviewRule> = new Map();
private parserCache = new Map<string, any>();
/**
* 注册规则
*/
registerRules(rules: ReviewRule[]): void {
for (const rule of rules) {
this.rules.set(rule.id, rule);
}
}
/**
* 对单个文件执行所有适用规则
*/
async reviewFile(filePath: string, content: string): Promise<ReviewResult[]> {
const language = this.detectLanguage(filePath);
const applicableRules = this.getApplicableRules(language, filePath);
if (applicableRules.length === 0) return [];
// 并行执行规则
const results = await Promise.all(
applicableRules.map(rule => this.executeRule(rule, content, filePath))
);
return results.flat().filter(r => r != null) as ReviewResult[];
}
/**
* 对整个项目执行批量审查
*/
async reviewProject(projectPath: string, options?: ProjectReviewOptions): Promise<ProjectReviewReport> {
const startTime = Date.now();
// 1. 收集文件
const files = await this.collectFiles(projectPath, options?.includePatterns, options?.excludePatterns);
// 2. 并行处理文件(使用 worker pool)
const workerPool = new WorkerPool(options?.concurrency || Math.min(os.cpus().length, 4));
const fileResults = await Promise.allSettled(
files.map(file =>
workerPool.enqueue(async () => {
const content = await fs.readFile(file, 'utf-8');
return this.reviewFile(file, content);
})
)
);
// 3. 聚合结果
const allResults: ReviewResult[] = [];
const errors: FileError[] = [];
fileResults.forEach((result, index) => {
if (result.status === 'fulfilled') {
allResults.push(...result.value);
} else {
errors.push({ file: files[index], error: result.reason.message });
}
});
// 4. 去重和排序
const deduplicated = this.deduplicate(allResults);
const sorted = this.sortBySeverity(deduplicated);
// 5. 生成统计
const stats = this.generateStats(sorted);
return {
projectPath,
totalFiles: files.length,
reviewedFiles: files.length - errors.length,
findings: sorted,
statistics: stats,
errors,
durationMs: Date.now() - startTime,
};
}
/**
* 执行单条规则
*/
private async executeRule(
rule: ReviewRule,
content: string,
filePath: string,
): Promise<ReviewResult[]> {
try {
switch (rule.match.type) {
case 'regex':
return this.executeRegexRule(rule, content, filePath);
case 'ast':
return this.executeASTRule(rule, content, filePath);
case 'structural':
return this.executeStructuralRule(rule, content, filePath);
case 'custom':
return this.executeCustomRule(rule, content, filePath);
default:
return [];
}
} catch (error) {
console.error(`Rule ${rule.id} execution error:`, error);
return [];
}
}
/**
* 正则表达式规则执行
*/
private executeRegexRule(
rule: ReviewRule,
content: string,
filePath: string,
): ReviewResult[] {
const results: ReviewResult[] = [];
const lines = content.split('\n');
const regex = new RegExp(rule.match.pattern, rule.match.flags || 'g');
lines.forEach((line, lineIndex) => {
if (rule.match.scope === 'line') {
regex.lastIndex = 0;
const match = regex.exec(line);
if (match) {
results.push(this.createResult(rule, filePath, lineIndex + 1, match.index + 1, line.trim()));
}
}
});
// multiline 模式
if (rule.match.scope === 'multiline') {
regex.lastIndex = 0;
let match;
while ((match = regex.exec(content)) !== null) {
const lineNumber = content.substring(0, match.index).split('\n').length;
const column = match.index - content.lastIndexOf('\n', match.index - 1);
results.push(this.createResult(rule, filePath, lineNumber, column, match[0]));
}
}
return results;
}
}
三、AI智能审查引擎
3.1 AI审查能力矩阵
// ===== packages/review/src/ai/capabilities.ts =====
/**
* MonkeyCode AI 审查能力定义
*
* AI 审查超越传统规则的范畴,
* 能够理解代码意图、发现逻辑缺陷、提出架构改进建议
*/
export enum AICapability {
// === 逻辑层面 ===
LOGIC_ERROR_DETECTION = 'logic_error', // 逻辑错误检测
DEAD_CODE_DETECTION = 'dead_code', // 死代码检测
RACE_CONDITION = 'race_condition', // 竞态条件检测
RESOURCE_LEAK = 'resource_leak', // 资源泄漏检测
// === 设计层面 ===
ARCHITECTURE_REVIEW = 'architecture_review', // 架构审查
DESIGN_PATTERN_SUGGESTION = 'design_pattern',// 设计模式建议
API_DESIGN_REVIEW = 'api_design_review', // API 设计审查
ABSTRACTION_LEVEL = 'abstraction_level', // 抽象层次评估
// === 性能层面 ===
PERFORMANCE_BOTTLENECK = 'perf_bottleneck', // 性能瓶颈识别
ALGORITHM_COMPLEXITY = 'algo_complexity', // 算法复杂度分析
MEMORY_OPTIMIZATION = 'memory_optimization', // 内存优化建议
N+1_QUERY_DETECTION = 'n_plus_one_query', // N+1 查询检测
// === 安全层面 ===
BUSINESS_LOGIC_VULN = 'business_logic_vuln', // 业务逻辑漏洞
AUTHORIZATION_BYPASS = 'auth_bypass', // 权限绕过检测
DATA_VALIDATION = 'data_validation', // 数据验证缺失
INPUT_SANITIZATION = 'input_sanitization', // 输入净化不足
// === 可维护性层面 ===
NAMING_CONVENTION = 'naming_convention', // 命约定律
COHESION_COUPLING = 'cohesion_coupling', // 内聚耦合分析
DUPLICATION_DETECTION = 'duplication', // 重复代码检测
TEST_COVERAGE_GAP = 'test_coverage_gap', // 测试覆盖缺口
}
export interface AIReviewConfig {
capabilities: AICapability[];
// 审查深度
depth: 'quick' | 'standard' | 'thorough';
// 输出格式
outputFormat: 'inline-comment' | 'summary-report' | 'detailed-report';
// 上下文配置
contextLines: number; // 上下文行数
includeRelatedFiles: boolean; // 是否包含关联文件
// 模型选择
model: string; // 使用的 LLM 模型
temperature: number; // 创造性参数(越低越确定)
// 过滤
minConfidence: number; // 最小置信度阈值
maxFindingsPerFile: number; // 每个文件最大发现数
}
// === AI 审查 Prompt 模板 ===
export const AI_REVIEW_PROMPT = `
你是一位资深代码审查专家,具有以下专长:
- 15年以上软件开发经验
- 精通 TypeScript/Python/Go/Rust/Java 等多门语言
- 熟悉 OWASP、CWE、SANS Top 25 等安全标准
- 擅长架构设计和性能优化
## 任务
对以下代码进行全面的 AI 智能审查。
## 审查维度
{{#each capabilities}}
- {{this}}
{{/each}}
## 代码上下文
**文件**: {{filePath}}
**语言**: {{language}}
\`\`\`{{language}}
{{code}}
\`\`\`
## 相关上下文(如有)
{{relatedContext}}
## 输出要求
请以 JSON 数组格式输出审查发现,每个发现包含:
{
"severity": "error|warning|info|hint",
"category": "类别",
"title": "简短标题",
"description": "详细描述",
"line": 行号,
"suggestion": "具体修复建议",
"confidence": 0-1的置信度,
"effort": "quick|medium|significant"
}
注意:
1. 只报告真正的问题,不要误报
2. 提供可操作的修复建议
3. 如果代码质量很好,可以返回空数组
4. 特别关注安全和性能问题
`;
3.2 AI审查实际案例
# ===== examples/ai-review-demo.py =====
"""
MonkeyCode AI 审查示例 — 展示 AI 如何发现人工容易遗漏的问题
"""
# 示例代码:一个用户注册接口
async def register_user(request):
"""用户注册 API"""
data = request.json()
# AI 发现问题 #1: 缺少输入验证
username = data.get("username")
password = data.get("password")
email = data.get("email")
# AI 发现问题 #2: 弱密码策略
if len(password) < 6:
return {"error": "密码太短"}
# AI 发现问题 #3: SQL 注入风险(即使使用 ORM 也可能有问题)
user = User.objects.raw(
f"SELECT * FROM users WHERE username='{username}'"
).first()
if user:
return {"error": "用户已存在"}
# AI 发现问题 #4: 明文存储密码
new_user = User.objects.create(
username=username,
password=password, # 应该用 bcrypt/hash
email=email,
)
# AI 发现问题 #5: 敏感信息泄露
return {
"message": "注册成功",
"user_id": new_user.id,
"password": password, # 不应返回密码!
}
# === MonkeyCode AI 审查输出 ===
"""
[
{
"severity": "error",
"category": "SECURITY",
"title": "缺少必要的输入验证",
"description": "username 和 email 字段没有进行格式验证和长度限制。攻击者可能注入超长字符串导致 DoS,或使用特殊格式的邮箱绕过业务逻辑。",
"line": 7,
"suggestion": """
from validators import email as validate_email
if not username or not (2 <= len(username) <= 32):
return {"error": "用户名需为2-32个字符"}
if not validate_email(email):
return {"error": "邮箱格式无效"}
""",
"confidence": 0.96,
"effort": "quick"
},
{
"severity": "warning",
"category": "SECURITY",
"title": "弱密码策略",
"description": "仅检查密码长度 >= 6,没有复杂度要求。现代安全标准要求大小写字母+数字+特殊字符的组合。",
"line": 12,
"suggestion": """
def validate_password(pwd):
if len(pwd) < 10: return False
has_upper = any(c.isupper() for c in pwd)
has_lower = any(c.islower() for c in pwd)
has_digit = any(c.isdigit() for c in pwd)
has_special = any(c in '!@#$%^&*' for c in pwd)
return all([has_upper, has_lower, has_digit, has_special])
""",
"confidence": 0.92,
"effort": "medium"
},
{
"severity": "error",
"category": "SECURITY",
"title": "SQL 注入漏洞",
"description": "使用 f-string 直接拼接用户输入到 SQL 查询中,这是典型的 SQL 注入漏洞。攻击者可通过 username 参数注入任意 SQL。",
"line": 19,
"suggestion": "# 使用 ORM 的安全查询方式\nuser = User.objects.filter(username=username).first()",
"confidence": 0.99,
"effort": "quick"
},
{
"severity": "error",
"category": "SECURITY",
"title": "明文存储密码",
"description": "密码以明文形式存入数据库。一旦数据库被攻破,所有用户密码将直接暴露。",
"line": 28,
"suggestion": """
import bcrypt
hashed = bcrypt.hashpw(password.encode(), bcrypt.gensalt())
new_user = User.objects.create(username=username, password=hashed, email=email)
""",
"confidence": 0.98,
"effort": "quick"
},
{
"severity": "error",
"category": "SECURITY",
"title": "敏感信息泄露到响应",
"description": "API 响应中包含了用户的明文密码,这是严重的安全违规。",
"line": 34,
"suggestion": 'return {"message": "注册成功", "user_id": new_user.id}',
"confidence": 0.99,
"effort": "quick"
}
]
"""
四、安全扫描系统
4.1 OWASP Top 10 覆盖
// ===== packages/review/src/security/scanner.ts =====
/**
* MonkeyCode 安全扫描器
*
* 覆盖 OWASP Top 10 (2021) + CWE Top 25
* 结合静态分析和 AI 检测
*/
import { z } from 'zod';
// === OWASP Top 10 映射 ===
export enum OWASP_Category {
// A01 — 访问控制失效
BROKEN_ACCESS_CONTROL = 'A01_2021-Broken_Access_Control',
// A02 — 加密机制失效
CRYPTOGRAPHIC_FAILURES = 'A02_2021-Cryptographic_Failures',
// A03 — 注入
INJECTION = 'A03_2021-Injection',
// A04 — 不安全设计
INSECURE_DESIGN = 'A04_2021-Insecure_Design',
// A05 — 错误的安全配置
SECURITY_MISCONFIGURATION = 'A05_2021-Security_Misconfiguration',
// A06 — 易受攻击的过时组件
VULNERABLE_OUTDATED = 'A06_2021-Vulnerable_and_Outdated_Components',
// A07 — 身份认证失效
IDENTIFICATION_AUTH_FAILURES = 'A07_2021-Identification_and_Authentication_Failures',
// A08 — 软件和数据完整性失败
SOFTWARE_DATA_INTEGRITY = 'A08_2021-Software_and_Data_Integrity_Failures',
// A09 — 安全日志和监控失败
SECURITY_LOGGING_MONITORING = 'A09_2021-Security_Logging_and_Monitoring_Failures',
// A10 — 服务端请求伪造
SSRF = 'A10_2021-Server-Side_Request_Forgery',
}
export interface SecurityFinding {
owaspCategory: OWASP_Category;
cweIds: string[]; // 关联的 CWE 编号
cvssScore?: number; // CVSS 评分 (0-10)
vulnerabilityType: string; // 漏洞类型名称
severity: 'CRITICAL' | 'HIGH' | 'MEDIUM' | 'LOW' | 'INFO';
location: {
file: string;
line: number;
column?: number;
};
description: string; // 漏洞详细描述
proofOfConcept?: string; // 概念验证(攻击示例)
remediation: string; // 修复方案
references: string[]; // 参考文档
// AI 分析增强
aiAnalysis?: {
exploitability: number; // 利用难度 0-10
impact: number; // 影响程度 0-10
businessContext: string; // 业务上下文分析
suggestedPriority: number; // 建议优先级 1-5
};
}
// === 安全规则库 ===
export const securityRules: SecurityRuleDefinition[] = [
// === A01: 访问控制失效 ===
{
id: 'sec-missing-auth-check',
owasp: OWASP_Category.BROKEN_ACCESS_CONTROL,
cwe: ['CWE-862', 'CWE-863'],
name: '端点缺少认证检查',
patterns: [
// Express.js: 没有 auth 中间件的路由处理敏感操作
{
language: 'typescript',
pattern: /router\.(post|put|delete|patch)\s*\(['"][^'"]*['"].*\n\s*(?:async\s*)?\([^)]*\)\s*=>\s*\{/,
negativeLookahead: /authenticate|authorize|auth|requireAuth|ensureAuth/i,
sensitivePaths: ['/admin', '/user/', '/delete', '/update', '/create'],
},
],
remediation: '为所有需要认证的端点添加认证中间件',
},
{
id: 'sec-idor',
owasp: OWASP_Category.BROKEN_ACCESS_CONTROL,
cwe: ['CWE-639'],
name: '不安全的直接对象引用 (IDOR)',
patterns: [
{
language: 'typescript',
pattern: /req\.params\.(id|userId|postId|orderId)\s*(?!.*===?\s*req\.user)/,
contextPattern: /findById|findByPk|findOne.*where.*id/i,
},
],
remediation: '验证当前用户是否有权访问请求的资源 ID',
},
// === A03: 注入 ===
{
id: 'sec-sql-injection',
owasp: OWASP_Category.INJECTION,
cwe: ['CWE-89'],
name: 'SQL 注入',
patterns: [
{
language: 'typescript',
pattern: /\$\{.*\}.*(?:SELECT|INSERT|UPDATE|DELETE|DROP)|query\s*\(\s*`/i,
},
{
language: 'python',
pattern: /(?:execute|executemany)\s*\(\s*f["']|%\s*.*(?:SELECT|INSERT|UPDATE)/i,
},
{
language: 'java',
pattern: /Statement\b.*(?:executeQuery|executeUpdate)\s*\(\s*["'].*\+/i,
},
],
remediation: '使用参数化查询或 ORM 的安全方法',
},
{
id: 'sec-xss',
owasp: OWASP_Category.INJECTION,
cwe: ['CWE-79'],
name: '跨站脚本攻击 (XSS)',
patterns: [
{
language: 'typescript',
pattern: /dangerouslySetInnerHTML|innerHTML\s*=.*\+|document\.write\s*\(/,
},
{
language: 'javascript',
pattern: /\$\(.*\)\.html\s*\(|\.html\s*\(\s*req\./,
},
],
remediation: '使用 DOMPurify 进行 HTML 转义,或使用安全的模板引擎',
},
{
id: 'sec-command-injection',
owasp: OWASP_Category.INJECTION,
cwe: ['CWE-78'],
name: '操作系统命令注入',
patterns: [
{
language: 'typescript',
pattern: /exec\(|execSync\(|spawn\s*\(\s*`|\$\{/i,
},
{
language: 'python',
pattern: /os\.system\s*\(|subprocess\.call\s*\(\s*shell=True|eval\s*\(/i,
},
],
remediation: '避免将用户输入传递给 shell 命令;如必须,使用参数列表形式',
},
// === A02: 加密机制失效 ===
{
id: 'sec-weak-crypto',
owasp: OWASP_Category.CRYPTOGRAPHIC_FAILURES,
cwe: ['CWE-326', 'CWE-328'],
name: '使用弱加密算法',
patterns: [
{
language: 'any',
pattern: /md5\(|sha1\(|des_|rc4|aes-?128-?ecb/i,
},
],
remediation: '使用 SHA-256/SHA-3/AES-256-GCM 等强加密算法',
},
{
id: 'sec-hardcoded-secret',
owasp: OWASP_Category.CRYPTOGRAPHIC_FAILURES,
cwe: ['CWE-798'],
name: '硬编码密钥/密钥',
patterns: [
{
language: 'any',
pattern: /(?:secret|password|api_key|private_key|token)\s*[:=]\s*['"][^'"]{8,}['"]/i,
},
],
remediation: '使用环境变量或密钥管理服务 (AWS KMS, HashiCorp Vault 等)',
},
// === A08: SSRF ===
{
id: 'sec-ssrf',
owasp: OWASP_Category.SSRF,
cwe: ['CWE-918'],
name: '服务端请求伪造 (SSRF)',
patterns: [
{
language: 'typescript',
pattern: /fetch\s*\(\s*req\.(body|query|params)|axios\.(get|post)\s*\(\s*req\./i,
},
{
language: 'python',
pattern: /requests\.(get|post)\s*\(\s*request\.(args|form|json|data)/i,
},
],
remediation: '验证和限制目标 URL;使用白名单机制阻止内网地址访问',
},
];
export class SecurityScanner extends RuleEngine {
private aiAnalyzer: AISecurityAnalyzer;
constructor(config: SecurityConfig) {
super();
this.registerRules(securityRules as any[]);
this.aiAnalyzer = new AISecurityAnalyzer(config.aiConfig);
}
/**
* 全面安全扫描
*/
async fullScan(projectPath: string): Promise<SecurityScanReport> {
// 1. 规则引擎快速扫描
const ruleResults = await this.reviewProject(projectPath);
// 2. AI 深度分析(针对高风险发现)
const highRiskFindings = ruleResults.findings.filter(
f => f.severity === Severity.ERROR || f.severity === Severity.WARNING
);
const aiEnhancedFindings: SecurityFinding[] = [];
for (const finding of highRiskFindings.slice(0, 20)) { // 限制 AI 分析数量
const enhanced = await this.aiAnalyzer.analyze(finding);
aiEnhancedFindings.push(enhanced);
}
// 3. 依赖漏洞扫描
const dependencyVulns = await this.scanDependencies(projectPath);
// 4. 生成综合报告
return {
summary: this.generateSummary(ruleResults.findings, aiEnhancedFindings),
ruleBasedFindings: ruleResults.findings,
aiEnhancedFindings,
dependencyVulnerabilities: dependencyVulns,
recommendations: this.generateRecommendations(aiEnhancedFindings),
scanTimestamp: new Date().toISOString(),
};
}
}
4.2 安全扫描报告示例
<!-- ===== reports/security-scan-example.md ===== -->
# 🔒 MonkeyCode 安全扫描报告
**项目**: my-web-app
**扫描时间**: 2026-06-30 14:30:00 UTC
**扫描版本**: MonkeyCode v3.2.1
---
## 📊 总览
| 指标 | 数值 |
|------|------|
| **总文件数** | 247 |
| **扫描文件数** | 243 |
| **总发现数** | 47 |
| **严重 (CRITICAL)** | 3 |
| **高危 (HIGH)** | 12 |
| **中危 (MEDIUM)** | 18 |
| **低危 (LOW)** | 14 |
| **CVSS 平均分** | 6.2 |
---
## 🚨 严重发现 (CRITICAL)
### 1. SQL 注入漏洞 — 用户搜索接口
- **位置**: `src/api/users.ts:45`
- **OWASP**: A03:2021-Injection (CWE-89)
- **CVSS**: 9.8 (Critical)
```typescript
// ❌ 危险代码
app.get('/api/users/search', (req, res) => {
const sql = `SELECT * FROM users WHERE name LIKE '%${req.query.q}%'`;
db.query(sql, (err, results) => res.json(results));
});
AI 分析:
- 利用难度: 1/10 (极简单)
- 影响: 10/10 (可读取/修改/删除全部用户数据)
- 建议 P0 优先级
修复方案:
// ✅ 安全代码
app.get('/api/users/search', async (req, res) => {
const results = await db.query(
'SELECT * FROM users WHERE name LIKE ?',
[`%${req.query.q}%`]
);
res.json(results);
});
2. 硬编码 AWS 密钥
- 位置:
src/config/aws.ts:12 - OWASP: A02:2021-Cryptographic Failures (CWE-798)
- CVSS: 9.1 (Critical)
// ❌ 危险代码
export const awsConfig = {
accessKeyId: 'AKIAIOSFODNN7EXAMPLE',
secretAccessKey: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY',
region: 'us-east-1',
};
修复方案: 使用 AWS IAM Roles 或环境变量
3. 无认证的管理员端点
- 位置:
src/admin/routes.ts:1-30 - OWASP: A01:2021-Broken Access Control (WEAKNESS)
- CVSS: 9.0 (Critical)
修复方案: 添加 RBAC 中间件
⚠️ 高危发现 (HIGH) (节选前5个)
| # | 类型 | 文件:行 | CVSS | 说明 |
|---|---|---|---|---|
| 1 | XSS | views/profile.html:78 | 8.1 | innerHTML 未转义用户输入 |
| 2 | IDOR | api/posts.ts:33 | 7.5 | 任何用户可修改他人帖子 |
| 3 | 弱加密 | utils/crypto.ts:15 | 7.2 | 使用 MD5 存储密码哈希 |
| 4 | SSRF | api/proxy.ts:22 | 7.0 | 用户可控的目标 URL |
| 5 | 信息泄露 | api/errors.ts:8 | 6.5 | 错误响应包含堆栈跟踪 |
🛡️ 修复优先级建议
立即修复 (本周内)
- 所有 CRITICAL 级别的 SQL 注入和认证问题
- 移除所有硬编码凭证
- 为管理员端点添加权限校验
短期修复 (本月内)
- 所有 HIGH 级别的 XSS 和 IDOR 问题
- 升级加密算法至 AES-256-GCM
- 实现 SSRF 防护白名单
中期规划 (本季度)
- 建立 SDLC 安全流程
- 引入 CI/CD 自动安全扫描
- 定期依赖更新审计
---
## 五、Git集成与PR审查
### 5.1 PR自动审查流程
```yaml
# ===== .github/workflows/monkeycode-review.yml =====
name: MonkeyCode AI Code Review
on:
pull_request:
branches: [main, develop]
jobs:
monkeycode-review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install MonkeyCode CLI
run: npm install -g @monkeycode/cli
- name: Run MonkeyCode Review
env:
MONKEYCODE_API_KEY: ${{ secrets.MONKEYCODE_API_KEY }}
run: |
monkeycode review \
--format github-pr \
--pr ${{ github.event.number }} \
--repo ${{ github.repository }} \
--token ${{ secrets.GITHUB_TOKEN }} \
--severity-threshold warning \
--max-findings 50 \
--enable-ai-review \
--enable-security-scan
5.2 Diff理解与变更审查
// ===== packages/review/src/git/diff-analyzer.ts =====
/**
* Diff 分析器
*
* 理解 Git diff 的语义变化,
* 评估变更的影响范围和潜在风险
*/
export interface DiffAnalysis {
// 变更概要
summary: {
filesChanged: number;
insertions: number;
deletions: number;
modifiedLines: number;
};
// 变更分类
changesByType: {
feature: ChangeInfo[]; // 新功能
bugfix: ChangeInfo[]; // Bug 修复
refactor: ChangeInfo[]; // 重构
test: ChangeInfo[]; // 测试
config: ChangeInfo[]; // 配置
docs: ChangeInfo[]; // 文档
dependency: ChangeInfo[]; // 依赖变更
};
// 风险评估
riskAssessment: {
overallRisk: 'low' | 'medium' | 'high' | 'critical';
riskFactors: RiskFactor[];
affectedComponents: string[];
breakingChanges: BreakingChange[];
};
// 审查重点
focusAreas: FocusArea[];
// AI 生成的摘要
aiSummary: string;
}
export interface ChangeInfo {
file: string;
type: string;
description: string;
linesAdded: number;
linesRemoved: number;
functionsModified: string[];
importsChanged: string[];
}
export interface RiskFactor {
type: 'security' | 'performance' | 'compatibility' | 'maintainability';
severity: 'low' | 'medium' | 'high';
description: string;
location: string;
suggestion: string;
}
export class DiffAnalyzer {
private llmClient: LLMClient;
constructor(llmClient: LLMClient) {
this.llmClient = llmClient;
}
/**
* 分析 PR diff
*/
async analyzePR(diff: string, prContext: PRContext): Promise<DiffAnalysis> {
// 1. 解析 diff 结构
const parsedDiff = this.parseDiff(diff);
// 2. 分类变更
const changesByType = this.classifyChanges(parsedDiff);
// 3. 识别风险因素
const riskFactors = this.identifyRiskFactors(parsedDiff, changesByType);
// 4. 检测破坏性变更
const breakingChanges = this.detectBreakingChanges(parsedDiff);
// 5. AI 综合分析
const aiSummary = await this.generateAISummary(diff, prContext, {
changesByType,
riskFactors,
breakingChanges,
});
// 6. 确定审查重点
const focusAreas = this.determineFocusAreas(changesByType, riskFactors);
return {
summary: this.calculateSummary(parsedDiff),
changesByType,
riskAssessment: {
overallRisk: this.calculateOverallRisk(riskFactors),
riskFactors,
affectedComponents: this.extractAffectedComponents(parsedDiff),
breakingChanges,
},
focusAreas,
aiSummary,
};
}
/**
* AI 生成 diff 摘要和分析
*/
private async generateAISummary(
diff: string,
prContext: PRContext,
analysisContext: object,
): Promise<string> {
const prompt = `
## PR 信息
- 标题: ${prContext.title}
- 描述: ${prContext.description}
- 作者: ${prContext.author}
- 目标分支: ${prContext.targetBranch}
## Diff 内容
\`\`\`diff
${diff.substring(0, 15000)} // 限制长度
\`\`\`
## 初步分析结果
${JSON.stringify(analysisContext, null, 2)}
## 请生成:
1. 一句话总结这个 PR 做了什么
2. 主要变更点列表(按重要性排序)
3. 需要特别关注的审查要点
4. 潜在风险评估
5. 改进建议(如有)
`;
const response = await this.llmClient.complete(prompt);
return response.content;
}
}
六、审查报告与可视化
6.1 多格式报告输出
// ===== packages/review/src/report/generator.ts =====
/**
* 审查报告生成器
*
* 支持 Markdown / HTML / JSON / SARIF / GitHub PR Comment 等多种格式
*/
export enum ReportFormat {
MARKDOWN = 'markdown',
HTML = 'html',
JSON = 'json',
SARIF = 'sarif', // Static Analysis Results Interchange Format
GITHUB_PR_COMMENT = 'github-pr', // GitHub PR 评论格式
GITLAB_MR_NOTE = 'gitlab-mr', // GitLab MR Note 格式
JUNIT_XML = 'junit-xml', // JUnit XML (CI 集成)
CONSOLE = 'console', // 终端彩色输出
}
export interface ReportOptions {
format: ReportFormat | ReportFormat[];
outputDir?: string;
filename?: string;
// 内容选项
includeStats: boolean;
includeCodeSnippets: boolean;
includeFixSuggestions: boolean;
includeAIComments: boolean;
// 过滤
minSeverity?: Severity;
maxFindings?: number;
// 排序
sortBy: 'severity' | 'file' | 'category' | 'line';
// 自定义
headerTemplate?: string;
footerTemplate?: string;
customSections?: ReportSection[];
}
export class ReportGenerator {
/**
* 生成完整报告
*/
async generate(
reviewData: ReviewData,
options: ReportOptions,
): Promise<GeneratedReport[]> {
const formats = Array.isArray(options.format) ? options.format : [options.format];
const reports: GeneratedReport[] = [];
for (const format of formats) {
switch (format) {
case ReportFormat.MARKDOWN:
reports.push(await this.generateMarkdown(reviewData, options));
break;
case ReportFormat.HTML:
reports.push(await this.generateHTML(reviewData, options));
break;
case ReportFormat.JSON:
reports.push(await this.generateJSON(reviewData, options));
break;
case ReportFormat.SARIF:
reports.push(await this.generateSARIF(reviewData, options));
break;
case ReportFormat.GITHUB_PR_COMMENT:
reports.push(await this.generateGitHubComment(reviewData, options));
break;
default:
throw new Error(`Unsupported format: ${format}`);
}
}
// 写入文件(如果指定了输出目录)
if (options.outputDir) {
for (const report of reports) {
const filepath = path.join(
options.outputDir,
options.filename || `review-${Date.now()}.${report.extension}`
);
await fs.writeFile(filepath, report.content, 'utf-8');
report.filepath = filepath;
}
}
return reports;
}
/**
* 生成 Markdown 报告
*/
private async generateMarkdown(data: ReviewData, opts: ReportOptions): Promise<GeneratedReport> {
const sections: string[] = [];
// 标题
sections.push(`# 🔍 MonkeyCode 代码审查报告`);
sections.push('');
sections.push(`**项目**: ${data.projectName}`);
sections.push(`**分支**: ${data.branch}`);
sections.push(`**时间**: ${new Date().toISOString()}`);
sections.push('');
// 统计概要
if (opts.includeStats) {
sections.push(this.renderStatsTable(data.statistics));
sections.push('');
}
// 按严重程度分组显示发现
const grouped = this.groupBySeverity(data.findings, opts.minSeverity);
for (const [severity, findings] of Object.entries(grouped)) {
const emoji = { ERROR: '🚨', WARNING: '⚠️', INFO: 'ℹ️', HINT: '💡' }[severity] || '';
sections.push(`## ${emoji} ${severity} (${findings.length})`);
sections.push('');
for (const finding of findings.slice(0, opts.maxFindings || 100)) {
sections.push(this.renderFindingMarkdown(finding, opts));
sections.push('');
}
}
// 总结和建议
sections.push('## 📋 总结');
sections.push('');
sections.push(this.generateSummarySection(data));
return {
format: ReportFormat.MARKDOWN,
extension: 'md',
content: sections.join('\n'),
};
}
}
七、性能基准数据
7.1 审查引擎性能
| 场景 | 文件数 | 代码行数 | 规则引擎耗时 | AI审查耗时 | 总耗时 | 内存占用 |
|---|---|---|---|---|---|---|
| 小型项目 | 50 | 5K | 0.8s | 3.2s | 4.0s | 85MB |
| 中型项目 | 500 | 80K | 5.2s | 18.5s | 23.7s | 320MB |
| 大型项目 | 5000 | 800K | 42s | 156s | 198s | 1.2GB |
| 单文件审查 | 1 | 500 | 45ms | 1.8s | 1.85s | 25MB |
7.2 准确率指标
| 指标 | 规则引擎 | AI审查 | 混合模式 |
|---|---|---|---|
| 精确率 (Precision) | 94.2% | 87.5% | 93.8% |
| 召回率 (Recall) | 72.3% | 91.2% | 94.6% |
| F1 分数 | 82.0% | 89.2% | 94.2% |
| 误报率 | 5.8% | 12.5% | 6.2% |
| 漏报率 | 27.7% | 8.8% | 5.4% |
解读: 规则引擎精确但覆盖有限,AI 审查全面但有少量误报。混合模式取两者之长。
八、集成指南
8.1 VS Code 集成
// ===== extensions/vscode-monkeycode/src/review-panel.ts =====
/**
* VS Code 扩展中的审查面板
*/
import * as vscode from 'vscode';
export class ReviewPanelProvider implements vscode.WebviewViewProvider {
private _view?: vscode.WebviewView;
resolveWebviewView(
view: vscode.WebviewView,
_context: vscode.WebviewViewResolveContext,
_token: vscode.CancellationToken,
) {
this._view = view;
view.webview.options = {
enableScripts: true,
localResourceRoots: [...],
};
view.webview.html = this.getWebviewContent();
// 监听文件保存事件,自动触发审查
const disposable = vscode.workspace.onDidSaveTextDocument(async (doc) => {
await this.reviewFile(doc);
});
// 监听编辑器切换,更新审查状态
const editorDisposable = vscode.window.onDidChangeActiveTextEditor(async (editor) => {
if (editor) {
await this.updateReviewStatus(editor.document);
}
});
}
/**
* 审查当前文件并更新面板
*/
private async reviewFile(doc: vscode.TextDocument): Promise<void> {
const findings = await monkeycodeAPI.reviewFile(doc.uri.fsPath, doc.getText());
// 更新 Webview 显示
this._view?.webview.postMessage({
command: 'updateFindings',
findings: findings.map(f => ({
...f,
severityIcon: this.getSeverityIcon(f.severity),
quickFixAvailable: !!f.fix,
})),
});
// 在编辑器中标记问题
const diagnostics = findings.map(f => new vscode.Diagnostic(
new vscode.Range(f.line - 1, 0, f.line - 1, 999),
f.message,
this.toDiagnosticSeverity(f.severity),
));
diagnosticCollection.set(vscode.Uri.file(doc.uri.fsPath), diagnostics);
}
}
8.2 CI/CD Pipeline 集成
#!/bin/bash
# ===== scripts/ci-monkeycode-review.sh =====
# CI/CD Pipeline 中的 MonkeyCode 审查脚本
set -e
echo "🔍 Starting MonkeyCode Code Review..."
# 安装 CLI
npm install -g @monkeycode/cli@latest
# 配置
export MONKEYCODE_API_KEY="${MONKEYCODE_API_KEY}"
export MONKEYCODE_PROJECT_TYPE="auto-detect"
# 运行审查
monkeycode review \
--source "." \
--output-format "sarif,json,console" \
--output-dir "./review-results" \
--severity-threshold "warning" \
--enable-rules \
--enable-ai-review \
--enable-security-scan \
--fail-on "error" \
--max-critical 0 \
--max-high 5 \
--report-filename "review-$(date +%Y%m%d-%H%M%S)"
REVIEW_EXIT_CODE=$?
# 上传 SARIF 到 GitHub (如果在 GitHub Actions 中)
if [ "$GITHUB_EVENT_NAME" == "pull_request" ]; then
echo "📤 Uploading SARIF to GitHub..."
gh api repos/$GITHUB_REPOSITORY/code-scanning/sarifs \
-X POST \
-f "@./review-results/review-*.sarif" \
|| echo "⚠️ SARIF upload failed (non-blocking)"
fi
exit $REVIEW_EXIT_CODE
结语
"好的代码审查不是挑刺,而是帮助团队写出更好的代码。"
MonkeyCode 的代码审查与安全扫描系统代表了下一代代码质量保障工具的方向:
- ✅ 规则引擎 — 快速、精准、零误报的基础防线
- ✅ AI 审查 — 理解语义、发现深层问题的智能大脑
- ✅ 安全扫描 — 覆盖 OWASP Top 10 的专业防护
- ✅ Git 集成 — 无缝嵌入开发工作流
- ✅ 多格式报告 — 满足团队协作的各种需求
从"事后补救"到"事前预防",从"人工耗时"到"秒级反馈",MonkeyCode 正在重新定义代码质量保障的标准。
💬 参与方式
- 🐛 发现审查遗漏?→ 提交 Issue 并标记
code-review- ✨ 想贡献审查规则?→ 查看 CONTRIBUTING.md 中的规则编写指南
- 💬 讨论审查体验?→ Discord #review 频道
- 📊 查看最新安全扫描?→ security.monkeycode.ai
MonkeyCode — 让每一行代码都值得信赖。 🐵🛡️✨
浙公网安备 33010602011771号