mirror of
https://gitee.com/mateos/mateclaw.git
synced 2026-09-14 19:45:08 +08:00
fix(guard): align tool guard rule names with runtime @Tool method names and add audit config
This commit is contained in:
parent
e14759638e
commit
bcf37d95fe
@ -42,7 +42,7 @@ public class ShellExecuteTool {
|
|||||||
|
|
||||||
@Tool(description = "在本地服务器上执行 Shell 命令。用于执行系统命令、查看文件、运行脚本等操作。"
|
@Tool(description = "在本地服务器上执行 Shell 命令。用于执行系统命令、查看文件、运行脚本等操作。"
|
||||||
+ "Windows 下使用 cmd.exe,Linux/macOS 下使用 /bin/sh。"
|
+ "Windows 下使用 cmd.exe,Linux/macOS 下使用 /bin/sh。"
|
||||||
+ "注意:每次执行都需要用户审批确认。返回包含 exitCode、stdout、stderr、timedOut 的结构化结果。")
|
+ "危险操作(如 rm -rf、格式化磁盘等)会触发安全审批。返回包含 exitCode、stdout、stderr、timedOut 的结构化结果。")
|
||||||
public String execute_shell_command(
|
public String execute_shell_command(
|
||||||
@ToolParam(description = "要执行的 Shell 命令") String command,
|
@ToolParam(description = "要执行的 Shell 命令") String command,
|
||||||
@ToolParam(description = "超时秒数,默认 60 秒", required = false) Integer timeoutSeconds) {
|
@ToolParam(description = "超时秒数,默认 60 秒", required = false) Integer timeoutSeconds) {
|
||||||
|
|||||||
@ -24,6 +24,7 @@ public class ToolGuardSchemaMigration implements ApplicationRunner {
|
|||||||
createGuardRuleTable();
|
createGuardRuleTable();
|
||||||
createGuardConfigTable();
|
createGuardConfigTable();
|
||||||
createAuditLogTable();
|
createAuditLogTable();
|
||||||
|
migrateGuardConfigAuditColumns();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createGuardRuleTable() {
|
private void createGuardRuleTable() {
|
||||||
@ -108,6 +109,16 @@ public class ToolGuardSchemaMigration implements ApplicationRunner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 为 mate_tool_guard_config 补充审计配置列(向已有表兼容迁移)
|
||||||
|
*/
|
||||||
|
private void migrateGuardConfigAuditColumns() {
|
||||||
|
safeExecute("ALTER TABLE mate_tool_guard_config ADD COLUMN audit_enabled BOOLEAN NOT NULL DEFAULT TRUE");
|
||||||
|
safeExecute("ALTER TABLE mate_tool_guard_config ADD COLUMN audit_min_severity VARCHAR(16) NOT NULL DEFAULT 'INFO'");
|
||||||
|
safeExecute("ALTER TABLE mate_tool_guard_config ADD COLUMN audit_retention_days INT NOT NULL DEFAULT 90");
|
||||||
|
log.info("[ToolGuardSchemaMigration] audit columns migration done");
|
||||||
|
}
|
||||||
|
|
||||||
private void safeExecute(String sql) {
|
private void safeExecute(String sql) {
|
||||||
try {
|
try {
|
||||||
jdbcTemplate.execute(sql);
|
jdbcTemplate.execute(sql);
|
||||||
|
|||||||
@ -186,6 +186,13 @@ public class ShellCommandGuardian implements ToolGuardGuardian {
|
|||||||
"此命令可能被用于远程控制,请勿执行"));
|
"此命令可能被用于远程控制,请勿执行"));
|
||||||
|
|
||||||
// === 高风险(HIGH)===
|
// === 高风险(HIGH)===
|
||||||
|
list.add(new ShellRule("SHELL_RM",
|
||||||
|
"(^|[;&|]|\\s)rm\\s",
|
||||||
|
GuardSeverity.HIGH, GuardCategory.COMMAND_INJECTION,
|
||||||
|
"rm 删除命令",
|
||||||
|
"检测到 rm 删除操作,可能导致文件永久丢失",
|
||||||
|
"请确认要删除的文件列表,考虑使用 trash 替代 rm"));
|
||||||
|
|
||||||
list.add(new ShellRule("SHELL_RM_RF",
|
list.add(new ShellRule("SHELL_RM_RF",
|
||||||
"rm\\s+-(rf|fr)",
|
"rm\\s+-(rf|fr)",
|
||||||
GuardSeverity.HIGH, GuardCategory.COMMAND_INJECTION,
|
GuardSeverity.HIGH, GuardCategory.COMMAND_INJECTION,
|
||||||
|
|||||||
@ -22,6 +22,13 @@ public class ToolGuardConfigEntity {
|
|||||||
private Boolean fileGuardEnabled;
|
private Boolean fileGuardEnabled;
|
||||||
private String sensitivePathsJson;
|
private String sensitivePathsJson;
|
||||||
|
|
||||||
|
/** 审计日志总开关 */
|
||||||
|
private Boolean auditEnabled;
|
||||||
|
/** 最低记录等级(INFO/LOW/MEDIUM/HIGH/CRITICAL) */
|
||||||
|
private String auditMinSeverity;
|
||||||
|
/** 审计日志保留天数(0=永不清理) */
|
||||||
|
private Integer auditRetentionDays;
|
||||||
|
|
||||||
@TableField(fill = FieldFill.INSERT)
|
@TableField(fill = FieldFill.INSERT)
|
||||||
private LocalDateTime createTime;
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
|||||||
@ -8,16 +8,20 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.scheduling.annotation.Async;
|
import org.springframework.scheduling.annotation.Async;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import vip.mate.tool.guard.model.*;
|
import vip.mate.tool.guard.model.*;
|
||||||
import vip.mate.tool.guard.repository.ToolGuardAuditLogMapper;
|
import vip.mate.tool.guard.repository.ToolGuardAuditLogMapper;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 工具安全审计服务
|
* 工具安全审计服务
|
||||||
|
* <p>
|
||||||
|
* 支持审计开关、最低记录等级过滤、过期日志自动清理。
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@ -26,13 +30,33 @@ public class ToolGuardAuditService {
|
|||||||
|
|
||||||
private final ToolGuardAuditLogMapper auditMapper;
|
private final ToolGuardAuditLogMapper auditMapper;
|
||||||
private final ObjectMapper objectMapper;
|
private final ObjectMapper objectMapper;
|
||||||
|
private final ToolGuardConfigService configService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 异步记录审计日志
|
* 异步记录审计日志
|
||||||
|
* <p>
|
||||||
|
* 受审计开关和最低等级过滤控制:
|
||||||
|
* <ul>
|
||||||
|
* <li>auditEnabled=false → 不记录</li>
|
||||||
|
* <li>maxSeverity 低于 auditMinSeverity → 不记录</li>
|
||||||
|
* </ul>
|
||||||
*/
|
*/
|
||||||
@Async
|
@Async
|
||||||
public void record(ToolInvocationContext context, GuardEvaluation evaluation, String pendingId) {
|
public void record(ToolInvocationContext context, GuardEvaluation evaluation, String pendingId) {
|
||||||
try {
|
try {
|
||||||
|
// 审计开关检查
|
||||||
|
if (!configService.isAuditEnabled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 等级过滤:无 finding 时 maxSeverity 为 null,视为 INFO 级
|
||||||
|
GuardSeverity minSeverity = configService.getAuditMinSeverity();
|
||||||
|
GuardSeverity actualSeverity = evaluation.maxSeverity() != null
|
||||||
|
? evaluation.maxSeverity() : GuardSeverity.INFO;
|
||||||
|
if (!actualSeverity.isAtLeast(minSeverity)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ToolGuardAuditLogEntity entity = new ToolGuardAuditLogEntity();
|
ToolGuardAuditLogEntity entity = new ToolGuardAuditLogEntity();
|
||||||
entity.setConversationId(context.conversationId());
|
entity.setConversationId(context.conversationId());
|
||||||
entity.setAgentId(context.agentId());
|
entity.setAgentId(context.agentId());
|
||||||
@ -99,6 +123,27 @@ public class ToolGuardAuditService {
|
|||||||
return stats;
|
return stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 定时清理过期审计日志(每天凌晨 3 点)
|
||||||
|
*/
|
||||||
|
@Scheduled(cron = "0 0 3 * * ?")
|
||||||
|
public void cleanExpiredAuditLogs() {
|
||||||
|
try {
|
||||||
|
int days = configService.getAuditRetentionDays();
|
||||||
|
if (days <= 0) return;
|
||||||
|
|
||||||
|
LocalDateTime cutoff = LocalDateTime.now().minusDays(days);
|
||||||
|
int deleted = auditMapper.delete(
|
||||||
|
new LambdaQueryWrapper<ToolGuardAuditLogEntity>()
|
||||||
|
.lt(ToolGuardAuditLogEntity::getCreateTime, cutoff));
|
||||||
|
if (deleted > 0) {
|
||||||
|
log.info("[ToolGuardAudit] Cleaned {} expired records (older than {} days)", deleted, days);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("[ToolGuardAudit] Failed to clean expired logs: {}", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private String serializeFindings(GuardEvaluation evaluation) {
|
private String serializeFindings(GuardEvaluation evaluation) {
|
||||||
try {
|
try {
|
||||||
return objectMapper.writeValueAsString(evaluation.findingsToMapList());
|
return objectMapper.writeValueAsString(evaluation.findingsToMapList());
|
||||||
|
|||||||
@ -11,6 +11,8 @@ import org.springframework.stereotype.Service;
|
|||||||
import vip.mate.tool.guard.model.ToolGuardConfigEntity;
|
import vip.mate.tool.guard.model.ToolGuardConfigEntity;
|
||||||
import vip.mate.tool.guard.repository.ToolGuardConfigMapper;
|
import vip.mate.tool.guard.repository.ToolGuardConfigMapper;
|
||||||
|
|
||||||
|
import vip.mate.tool.guard.model.GuardSeverity;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@ -51,6 +53,9 @@ public class ToolGuardConfigService {
|
|||||||
if (config.getDeniedToolsJson() != null) existing.setDeniedToolsJson(config.getDeniedToolsJson());
|
if (config.getDeniedToolsJson() != null) existing.setDeniedToolsJson(config.getDeniedToolsJson());
|
||||||
if (config.getFileGuardEnabled() != null) existing.setFileGuardEnabled(config.getFileGuardEnabled());
|
if (config.getFileGuardEnabled() != null) existing.setFileGuardEnabled(config.getFileGuardEnabled());
|
||||||
if (config.getSensitivePathsJson() != null) existing.setSensitivePathsJson(config.getSensitivePathsJson());
|
if (config.getSensitivePathsJson() != null) existing.setSensitivePathsJson(config.getSensitivePathsJson());
|
||||||
|
if (config.getAuditEnabled() != null) existing.setAuditEnabled(config.getAuditEnabled());
|
||||||
|
if (config.getAuditMinSeverity() != null) existing.setAuditMinSeverity(config.getAuditMinSeverity());
|
||||||
|
if (config.getAuditRetentionDays() != null) existing.setAuditRetentionDays(config.getAuditRetentionDays());
|
||||||
configMapper.updateById(existing);
|
configMapper.updateById(existing);
|
||||||
// 通知 AgentService 刷新缓存(denied 工具列表变更需要重建 agent 的工具集)
|
// 通知 AgentService 刷新缓存(denied 工具列表变更需要重建 agent 的工具集)
|
||||||
eventPublisher.publishEvent(new ToolGuardConfigChangedEvent(this));
|
eventPublisher.publishEvent(new ToolGuardConfigChangedEvent(this));
|
||||||
@ -90,6 +95,27 @@ public class ToolGuardConfigService {
|
|||||||
return parseJsonList(json);
|
return parseJsonList(json);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==================== 审计配置 ====================
|
||||||
|
|
||||||
|
public boolean isAuditEnabled() {
|
||||||
|
return Boolean.TRUE.equals(getConfig().getAuditEnabled());
|
||||||
|
}
|
||||||
|
|
||||||
|
public GuardSeverity getAuditMinSeverity() {
|
||||||
|
String s = getConfig().getAuditMinSeverity();
|
||||||
|
if (s == null || s.isBlank()) return GuardSeverity.INFO;
|
||||||
|
try {
|
||||||
|
return GuardSeverity.valueOf(s);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
return GuardSeverity.INFO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getAuditRetentionDays() {
|
||||||
|
Integer days = getConfig().getAuditRetentionDays();
|
||||||
|
return days != null ? days : 90;
|
||||||
|
}
|
||||||
|
|
||||||
// ==================== 内部方法 ====================
|
// ==================== 内部方法 ====================
|
||||||
|
|
||||||
private ToolGuardConfigEntity createDefaultConfig() {
|
private ToolGuardConfigEntity createDefaultConfig() {
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package vip.mate.tool.guard.service;
|
package vip.mate.tool.guard.service;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.boot.ApplicationArguments;
|
import org.springframework.boot.ApplicationArguments;
|
||||||
@ -9,17 +10,23 @@ import org.springframework.core.annotation.Order;
|
|||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import vip.mate.tool.guard.model.GuardCategory;
|
import vip.mate.tool.guard.model.GuardCategory;
|
||||||
import vip.mate.tool.guard.model.GuardSeverity;
|
import vip.mate.tool.guard.model.GuardSeverity;
|
||||||
|
import vip.mate.tool.guard.model.ToolGuardConfigEntity;
|
||||||
import vip.mate.tool.guard.model.ToolGuardRuleEntity;
|
import vip.mate.tool.guard.model.ToolGuardRuleEntity;
|
||||||
|
import vip.mate.tool.guard.repository.ToolGuardConfigMapper;
|
||||||
import vip.mate.tool.guard.repository.ToolGuardRuleMapper;
|
import vip.mate.tool.guard.repository.ToolGuardRuleMapper;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.List;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 规则种子服务
|
* 规则种子服务
|
||||||
* <p>
|
* <p>
|
||||||
* 首次启动时将内置规则写入 DB。
|
* 启动时完成三项工作:
|
||||||
* 已存在则跳过(通过 rule_id UNIQUE 约束)。
|
* <ol>
|
||||||
|
* <li>迁移旧版工具名(类名 → @Tool 方法名)+ 清理旧 legacy 规则</li>
|
||||||
|
* <li>按 rule_id 逐条 upsert 内置规则(不存在则插入,已存在则同步更新)</li>
|
||||||
|
* <li>迁移 guardedToolsJson 中的旧工具名</li>
|
||||||
|
* </ol>
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Component
|
@Component
|
||||||
@ -28,38 +35,176 @@ import java.util.List;
|
|||||||
public class ToolGuardRuleSeedService implements ApplicationRunner {
|
public class ToolGuardRuleSeedService implements ApplicationRunner {
|
||||||
|
|
||||||
private final ToolGuardRuleMapper ruleMapper;
|
private final ToolGuardRuleMapper ruleMapper;
|
||||||
|
private final ToolGuardConfigMapper configMapper;
|
||||||
|
|
||||||
|
/** 旧类名 → 新 @Tool 方法名 */
|
||||||
|
private static final Map<String, String> TOOL_NAME_RENAMES = Map.of(
|
||||||
|
"ShellExecuteTool", "execute_shell_command",
|
||||||
|
"WriteFileTool", "write_file",
|
||||||
|
"EditFileTool", "edit_file"
|
||||||
|
);
|
||||||
|
|
||||||
|
/** 旧 SQL 种子中的 legacy rule_id,已被 Java 种子的新规则完全覆盖 */
|
||||||
|
private static final Set<String> LEGACY_RULE_IDS = Set.of(
|
||||||
|
"write_file_any",
|
||||||
|
"edit_file_any",
|
||||||
|
"shell_rm_approval",
|
||||||
|
"shell_rm_rf_block",
|
||||||
|
"shell_write_system_file",
|
||||||
|
"shell_chmod_777"
|
||||||
|
);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run(ApplicationArguments args) {
|
public void run(ApplicationArguments args) {
|
||||||
|
migrateOldData();
|
||||||
seedBuiltinRules();
|
seedBuiltinRules();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==================== 旧数据迁移 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 DB 中旧版数据统一迁移:
|
||||||
|
* <ul>
|
||||||
|
* <li>rule 表旧工具名(类名 → @Tool 方法名)</li>
|
||||||
|
* <li>清理 legacy rule_id(旧 SQL 种子残留)</li>
|
||||||
|
* <li>config 表 guardedToolsJson 中的旧工具名</li>
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
|
private void migrateOldData() {
|
||||||
|
try {
|
||||||
|
// 1. 迁移 rule 表旧工具名
|
||||||
|
for (var entry : TOOL_NAME_RENAMES.entrySet()) {
|
||||||
|
int updated = ruleMapper.update(null,
|
||||||
|
new LambdaUpdateWrapper<ToolGuardRuleEntity>()
|
||||||
|
.eq(ToolGuardRuleEntity::getToolName, entry.getKey())
|
||||||
|
.set(ToolGuardRuleEntity::getToolName, entry.getValue()));
|
||||||
|
if (updated > 0) {
|
||||||
|
log.info("[RuleSeed] Migrated {} rules: {} -> {}", updated, entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 清理旧 SQL 种子残留的 legacy 规则
|
||||||
|
cleanupLegacyRules();
|
||||||
|
|
||||||
|
// 3. 迁移 config 表 guardedToolsJson
|
||||||
|
migrateGuardedToolsJson();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("[RuleSeed] Migration failed (table may not exist): {}", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除旧 SQL 种子中残留的 legacy builtin 规则。
|
||||||
|
* 这些规则的 rule_id 与新 Java 种子不重叠,增量升级后会形成冗余重复。
|
||||||
|
*/
|
||||||
|
private void cleanupLegacyRules() {
|
||||||
|
for (String legacyId : LEGACY_RULE_IDS) {
|
||||||
|
int deleted = ruleMapper.delete(
|
||||||
|
new LambdaQueryWrapper<ToolGuardRuleEntity>()
|
||||||
|
.eq(ToolGuardRuleEntity::getRuleId, legacyId)
|
||||||
|
.eq(ToolGuardRuleEntity::getBuiltin, true));
|
||||||
|
if (deleted > 0) {
|
||||||
|
log.info("[RuleSeed] Removed legacy rule: {}", legacyId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void migrateGuardedToolsJson() {
|
||||||
|
try {
|
||||||
|
List<ToolGuardConfigEntity> configs = configMapper.selectList(null);
|
||||||
|
for (ToolGuardConfigEntity config : configs) {
|
||||||
|
String json = config.getGuardedToolsJson();
|
||||||
|
if (json == null || json.isBlank()) continue;
|
||||||
|
|
||||||
|
String updated = json;
|
||||||
|
for (var entry : TOOL_NAME_RENAMES.entrySet()) {
|
||||||
|
updated = updated.replace("\"" + entry.getKey() + "\"", "\"" + entry.getValue() + "\"");
|
||||||
|
}
|
||||||
|
if (!updated.equals(json)) {
|
||||||
|
config.setGuardedToolsJson(updated);
|
||||||
|
configMapper.updateById(config);
|
||||||
|
log.info("[RuleSeed] Migrated guardedToolsJson: {} -> {}", json, updated);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.debug("[RuleSeed] guardedToolsJson migration skipped: {}", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 规则种子 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按 rule_id 逐条 upsert 内置规则:
|
||||||
|
* <ul>
|
||||||
|
* <li>不存在 → 插入</li>
|
||||||
|
* <li>已存在 → 同步更新 pattern / severity / decision / priority / toolName 等字段</li>
|
||||||
|
* </ul>
|
||||||
|
* 这样后续版本修正了 regex 或 severity,已有部署也能在重启时自动拿到更新。
|
||||||
|
*/
|
||||||
void seedBuiltinRules() {
|
void seedBuiltinRules() {
|
||||||
try {
|
try {
|
||||||
Long existingCount = ruleMapper.selectCount(
|
// 加载已有 builtin 规则(按 rule_id 索引)
|
||||||
|
List<ToolGuardRuleEntity> existingList = ruleMapper.selectList(
|
||||||
new LambdaQueryWrapper<ToolGuardRuleEntity>()
|
new LambdaQueryWrapper<ToolGuardRuleEntity>()
|
||||||
.eq(ToolGuardRuleEntity::getBuiltin, true));
|
.eq(ToolGuardRuleEntity::getBuiltin, true));
|
||||||
if (existingCount > 0) {
|
Map<String, ToolGuardRuleEntity> existingMap = existingList.stream()
|
||||||
log.info("[RuleSeed] {} builtin rules already exist, skipping seed", existingCount);
|
.collect(Collectors.toMap(ToolGuardRuleEntity::getRuleId, e -> e, (a, b) -> a));
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<ToolGuardRuleEntity> rules = buildBuiltinRules();
|
List<ToolGuardRuleEntity> rules = buildBuiltinRules();
|
||||||
int inserted = 0;
|
int inserted = 0;
|
||||||
|
int updated = 0;
|
||||||
|
int unchanged = 0;
|
||||||
|
|
||||||
for (ToolGuardRuleEntity rule : rules) {
|
for (ToolGuardRuleEntity rule : rules) {
|
||||||
try {
|
ToolGuardRuleEntity existing = existingMap.get(rule.getRuleId());
|
||||||
ruleMapper.insert(rule);
|
if (existing == null) {
|
||||||
inserted++;
|
// 新规则 → 插入
|
||||||
} catch (Exception e) {
|
try {
|
||||||
log.debug("[RuleSeed] Rule {} already exists", rule.getRuleId());
|
ruleMapper.insert(rule);
|
||||||
|
inserted++;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.debug("[RuleSeed] Rule {} insert failed: {}", rule.getRuleId(), e.getMessage());
|
||||||
|
}
|
||||||
|
} else if (needsUpdate(existing, rule)) {
|
||||||
|
// 已存在但内容有变化 → 更新
|
||||||
|
ruleMapper.update(null,
|
||||||
|
new LambdaUpdateWrapper<ToolGuardRuleEntity>()
|
||||||
|
.eq(ToolGuardRuleEntity::getRuleId, rule.getRuleId())
|
||||||
|
.set(ToolGuardRuleEntity::getName, rule.getName())
|
||||||
|
.set(ToolGuardRuleEntity::getDescription, rule.getDescription())
|
||||||
|
.set(ToolGuardRuleEntity::getPattern, rule.getPattern())
|
||||||
|
.set(ToolGuardRuleEntity::getSeverity, rule.getSeverity())
|
||||||
|
.set(ToolGuardRuleEntity::getCategory, rule.getCategory())
|
||||||
|
.set(ToolGuardRuleEntity::getDecision, rule.getDecision())
|
||||||
|
.set(ToolGuardRuleEntity::getToolName, rule.getToolName())
|
||||||
|
.set(ToolGuardRuleEntity::getRemediation, rule.getRemediation())
|
||||||
|
.set(ToolGuardRuleEntity::getPriority, rule.getPriority()));
|
||||||
|
updated++;
|
||||||
|
} else {
|
||||||
|
unchanged++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.info("[RuleSeed] Seeded {} builtin rules", inserted);
|
log.info("[RuleSeed] Builtin rules: {} inserted, {} updated, {} unchanged",
|
||||||
|
inserted, updated, unchanged);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn("[RuleSeed] Failed to seed rules (table may not exist): {}", e.getMessage());
|
log.warn("[RuleSeed] Failed to seed rules (table may not exist): {}", e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断已有 builtin 规则是否需要更新(任一核心字段有变化即需要)
|
||||||
|
*/
|
||||||
|
private boolean needsUpdate(ToolGuardRuleEntity existing, ToolGuardRuleEntity expected) {
|
||||||
|
return !Objects.equals(existing.getPattern(), expected.getPattern())
|
||||||
|
|| !Objects.equals(existing.getSeverity(), expected.getSeverity())
|
||||||
|
|| !Objects.equals(existing.getCategory(), expected.getCategory())
|
||||||
|
|| !Objects.equals(existing.getDecision(), expected.getDecision())
|
||||||
|
|| !Objects.equals(existing.getToolName(), expected.getToolName())
|
||||||
|
|| !Objects.equals(existing.getPriority(), expected.getPriority())
|
||||||
|
|| !Objects.equals(existing.getName(), expected.getName())
|
||||||
|
|| !Objects.equals(existing.getRemediation(), expected.getRemediation());
|
||||||
|
}
|
||||||
|
|
||||||
private List<ToolGuardRuleEntity> buildBuiltinRules() {
|
private List<ToolGuardRuleEntity> buildBuiltinRules() {
|
||||||
List<ToolGuardRuleEntity> rules = new ArrayList<>();
|
List<ToolGuardRuleEntity> rules = new ArrayList<>();
|
||||||
|
|
||||||
@ -97,6 +242,10 @@ public class ToolGuardRuleSeedService implements ApplicationRunner {
|
|||||||
"execute_shell_command", "此命令可能被用于远程控制", 200));
|
"execute_shell_command", "此命令可能被用于远程控制", 200));
|
||||||
|
|
||||||
// === HIGH Shell Rules ===
|
// === HIGH Shell Rules ===
|
||||||
|
rules.add(rule("SHELL_RM", "rm 删除命令", "(^|[;&|]|\\s)rm\\s",
|
||||||
|
GuardSeverity.HIGH, GuardCategory.COMMAND_INJECTION, "NEEDS_APPROVAL",
|
||||||
|
"execute_shell_command", "请确认要删除的文件列表,考虑使用 trash 替代 rm", 150));
|
||||||
|
|
||||||
rules.add(rule("SHELL_RM_RF", "递归强制删除", "rm\\s+-(rf|fr)",
|
rules.add(rule("SHELL_RM_RF", "递归强制删除", "rm\\s+-(rf|fr)",
|
||||||
GuardSeverity.HIGH, GuardCategory.COMMAND_INJECTION, "NEEDS_APPROVAL",
|
GuardSeverity.HIGH, GuardCategory.COMMAND_INJECTION, "NEEDS_APPROVAL",
|
||||||
"execute_shell_command", "使用 rm -ri 或指定具体文件", 150));
|
"execute_shell_command", "使用 rm -ri 或指定具体文件", 150));
|
||||||
|
|||||||
@ -1720,149 +1720,26 @@ VALUES (
|
|||||||
|
|
||||||
-- ==================== ToolGuard Default Config & Rule Seed Data ====================
|
-- ==================== ToolGuard Default Config & Rule Seed Data ====================
|
||||||
|
|
||||||
-- Global security config (single row)
|
-- Global security config (single row, insert only if not exists)
|
||||||
MERGE INTO mate_tool_guard_config (id, enabled, guard_scope, guarded_tools_json, denied_tools_json,
|
-- Note: tool names in guarded_tools_json must match @Tool method names (execute_shell_command / write_file / edit_file)
|
||||||
file_guard_enabled, sensitive_paths_json, create_time, update_time)
|
-- Use SELECT + INSERT to avoid overwriting user-modified config on restart (H2 MERGE would overwrite all columns)
|
||||||
KEY (id)
|
INSERT INTO mate_tool_guard_config (id, enabled, guard_scope, guarded_tools_json, denied_tools_json,
|
||||||
VALUES (
|
file_guard_enabled, sensitive_paths_json, audit_enabled, audit_min_severity, audit_retention_days,
|
||||||
|
create_time, update_time)
|
||||||
|
SELECT
|
||||||
1000000001,
|
1000000001,
|
||||||
TRUE,
|
TRUE,
|
||||||
'all',
|
'all',
|
||||||
'["WriteFileTool","EditFileTool","ShellExecuteTool"]',
|
'["write_file","edit_file","execute_shell_command"]',
|
||||||
'[]',
|
'[]',
|
||||||
TRUE,
|
TRUE,
|
||||||
'["/etc","/usr","/bin","/sbin","/boot","/sys","/proc","/dev"]',
|
'["/etc","/usr","/bin","/sbin","/boot","/sys","/proc","/dev"]',
|
||||||
|
TRUE, 'INFO', 90,
|
||||||
NOW(), NOW()
|
NOW(), NOW()
|
||||||
);
|
FROM DUAL
|
||||||
|
WHERE NOT EXISTS (SELECT 1 FROM mate_tool_guard_config WHERE id = 1000000001);
|
||||||
|
|
||||||
-- Security rule: WriteFileTool — any path write requires approval (HIGH)
|
-- Security rules are managed by ToolGuardRuleSeedService (Java) as single source of truth.
|
||||||
MERGE INTO mate_tool_guard_rule (id, rule_id, name, description, tool_name, param_name,
|
-- Removed 6 legacy SQL rules (rule_id: write_file_any, edit_file_any, shell_rm_approval,
|
||||||
category, severity, decision, pattern, exclude_pattern, remediation,
|
-- shell_rm_rf_block, shell_write_system_file, shell_chmod_777).
|
||||||
builtin, enabled, priority, create_time, update_time, deleted)
|
-- Their superset is registered in ToolGuardRuleSeedService.buildBuiltinRules() with correct tool names.
|
||||||
KEY (id)
|
|
||||||
VALUES (
|
|
||||||
1000300001,
|
|
||||||
'write_file_any',
|
|
||||||
'File write requires approval',
|
|
||||||
'Any file write operation requires user confirmation to prevent accidental overwrite of important files',
|
|
||||||
'WriteFileTool',
|
|
||||||
'path',
|
|
||||||
'file_write',
|
|
||||||
'HIGH',
|
|
||||||
'NEEDS_APPROVAL',
|
|
||||||
'.+',
|
|
||||||
NULL,
|
|
||||||
'Please confirm write path and content are correct before allowing execution',
|
|
||||||
TRUE, TRUE, 10,
|
|
||||||
NOW(), NOW(), 0
|
|
||||||
);
|
|
||||||
|
|
||||||
-- Security rule: EditFileTool — any file edit requires approval (HIGH)
|
|
||||||
MERGE INTO mate_tool_guard_rule (id, rule_id, name, description, tool_name, param_name,
|
|
||||||
category, severity, decision, pattern, exclude_pattern, remediation,
|
|
||||||
builtin, enabled, priority, create_time, update_time, deleted)
|
|
||||||
KEY (id)
|
|
||||||
VALUES (
|
|
||||||
1000300002,
|
|
||||||
'edit_file_any',
|
|
||||||
'File edit requires approval',
|
|
||||||
'Any file content replacement operation requires user confirmation',
|
|
||||||
'EditFileTool',
|
|
||||||
'path',
|
|
||||||
'file_write',
|
|
||||||
'HIGH',
|
|
||||||
'NEEDS_APPROVAL',
|
|
||||||
'.+',
|
|
||||||
NULL,
|
|
||||||
'Please confirm edit path and replacement content are correct before allowing execution',
|
|
||||||
TRUE, TRUE, 10,
|
|
||||||
NOW(), NOW(), 0
|
|
||||||
);
|
|
||||||
|
|
||||||
-- Security rule: ShellExecuteTool — delete commands require approval (HIGH)
|
|
||||||
MERGE INTO mate_tool_guard_rule (id, rule_id, name, description, tool_name, param_name,
|
|
||||||
category, severity, decision, pattern, exclude_pattern, remediation,
|
|
||||||
builtin, enabled, priority, create_time, update_time, deleted)
|
|
||||||
KEY (id)
|
|
||||||
VALUES (
|
|
||||||
1000300003,
|
|
||||||
'shell_rm_approval',
|
|
||||||
'rm command requires approval',
|
|
||||||
'rm / rmdir commands may cause permanent file loss, requires user confirmation',
|
|
||||||
'ShellExecuteTool',
|
|
||||||
'command',
|
|
||||||
'shell_execution',
|
|
||||||
'HIGH',
|
|
||||||
'NEEDS_APPROVAL',
|
|
||||||
'(?i)(^|[;&|]|\s)rm\s',
|
|
||||||
NULL,
|
|
||||||
'Consider using trash command instead of rm, or confirm file list before allowing execution',
|
|
||||||
TRUE, TRUE, 20,
|
|
||||||
NOW(), NOW(), 0
|
|
||||||
);
|
|
||||||
|
|
||||||
-- Security rule: ShellExecuteTool — forced recursive delete blocked (CRITICAL)
|
|
||||||
MERGE INTO mate_tool_guard_rule (id, rule_id, name, description, tool_name, param_name,
|
|
||||||
category, severity, decision, pattern, exclude_pattern, remediation,
|
|
||||||
builtin, enabled, priority, create_time, update_time, deleted)
|
|
||||||
KEY (id)
|
|
||||||
VALUES (
|
|
||||||
1000300004,
|
|
||||||
'shell_rm_rf_block',
|
|
||||||
'rm -rf blocked',
|
|
||||||
'rm -rf forced recursive delete is extremely dangerous, blocked directly',
|
|
||||||
'ShellExecuteTool',
|
|
||||||
'command',
|
|
||||||
'shell_execution',
|
|
||||||
'CRITICAL',
|
|
||||||
'BLOCK',
|
|
||||||
'(?i)rm\s+(-[a-z]*r[a-z]*f[a-z]*|-[a-z]*f[a-z]*r[a-z]*)\s+(/|~|\$HOME|\*|\.\s*$)',
|
|
||||||
NULL,
|
|
||||||
'Absolutely forbidden to execute rm -rf on root directory, Home directory, or wildcards',
|
|
||||||
TRUE, TRUE, 5,
|
|
||||||
NOW(), NOW(), 0
|
|
||||||
);
|
|
||||||
|
|
||||||
-- Security rule: ShellExecuteTool — writing system config files requires approval (HIGH)
|
|
||||||
MERGE INTO mate_tool_guard_rule (id, rule_id, name, description, tool_name, param_name,
|
|
||||||
category, severity, decision, pattern, exclude_pattern, remediation,
|
|
||||||
builtin, enabled, priority, create_time, update_time, deleted)
|
|
||||||
KEY (id)
|
|
||||||
VALUES (
|
|
||||||
1000300005,
|
|
||||||
'shell_write_system_file',
|
|
||||||
'System file write requires approval',
|
|
||||||
'Writing to system directories like /etc or /usr via Shell requires user confirmation',
|
|
||||||
'ShellExecuteTool',
|
|
||||||
'command',
|
|
||||||
'shell_execution',
|
|
||||||
'HIGH',
|
|
||||||
'NEEDS_APPROVAL',
|
|
||||||
'(?i)(>\s*|tee\s+|cp\s+.*\s+)(/etc/|/usr/|/bin/|/sbin/|/boot/)',
|
|
||||||
NULL,
|
|
||||||
'Please confirm the system file and content to modify before allowing execution',
|
|
||||||
TRUE, TRUE, 15,
|
|
||||||
NOW(), NOW(), 0
|
|
||||||
);
|
|
||||||
|
|
||||||
-- Security rule: ShellExecuteTool — chmod 777 requires approval (MEDIUM)
|
|
||||||
MERGE INTO mate_tool_guard_rule (id, rule_id, name, description, tool_name, param_name,
|
|
||||||
category, severity, decision, pattern, exclude_pattern, remediation,
|
|
||||||
builtin, enabled, priority, create_time, update_time, deleted)
|
|
||||||
KEY (id)
|
|
||||||
VALUES (
|
|
||||||
1000300006,
|
|
||||||
'shell_chmod_777',
|
|
||||||
'chmod 777 requires approval',
|
|
||||||
'chmod 777 grants full permissions to all users, security risk',
|
|
||||||
'ShellExecuteTool',
|
|
||||||
'command',
|
|
||||||
'shell_execution',
|
|
||||||
'MEDIUM',
|
|
||||||
'NEEDS_APPROVAL',
|
|
||||||
'(?i)chmod\s+(777|a\+rwx|o\+rwx)',
|
|
||||||
NULL,
|
|
||||||
'Please confirm if full permissions for all users are truly needed',
|
|
||||||
TRUE, TRUE, 30,
|
|
||||||
NOW(), NOW(), 0
|
|
||||||
);
|
|
||||||
|
|||||||
@ -1719,149 +1719,22 @@ ON DUPLICATE KEY UPDATE agent_id=VALUES(agent_id), filename=VALUES(filename), co
|
|||||||
|
|
||||||
-- ==================== ToolGuard Default Config & Rule Seed Data ====================
|
-- ==================== ToolGuard Default Config & Rule Seed Data ====================
|
||||||
|
|
||||||
-- Global security config (single row)
|
-- Global security config (single row, insert only if not exists, never overwrite user config)
|
||||||
INSERT INTO mate_tool_guard_config (id, enabled, guard_scope, guarded_tools_json, denied_tools_json,
|
-- Note: tool names in guarded_tools_json must match @Tool method names (execute_shell_command / write_file / edit_file)
|
||||||
file_guard_enabled, sensitive_paths_json, create_time, update_time)
|
INSERT IGNORE INTO mate_tool_guard_config (id, enabled, guard_scope, guarded_tools_json, denied_tools_json,
|
||||||
|
file_guard_enabled, sensitive_paths_json, audit_enabled, audit_min_severity, audit_retention_days,
|
||||||
|
create_time, update_time)
|
||||||
VALUES (
|
VALUES (
|
||||||
1000000001,
|
1000000001,
|
||||||
TRUE,
|
TRUE,
|
||||||
'all',
|
'all',
|
||||||
'["WriteFileTool","EditFileTool","ShellExecuteTool"]',
|
'["write_file","edit_file","execute_shell_command"]',
|
||||||
'[]',
|
'[]',
|
||||||
TRUE,
|
TRUE,
|
||||||
'["/etc","/usr","/bin","/sbin","/boot","/sys","/proc","/dev"]',
|
'["/etc","/usr","/bin","/sbin","/boot","/sys","/proc","/dev"]',
|
||||||
|
TRUE, 'INFO', 90,
|
||||||
NOW(), NOW()
|
NOW(), NOW()
|
||||||
)
|
);
|
||||||
ON DUPLICATE KEY UPDATE enabled=VALUES(enabled), guard_scope=VALUES(guard_scope), guarded_tools_json=VALUES(guarded_tools_json), denied_tools_json=VALUES(denied_tools_json), file_guard_enabled=VALUES(file_guard_enabled), sensitive_paths_json=VALUES(sensitive_paths_json), update_time=VALUES(update_time);
|
|
||||||
|
|
||||||
-- Security rule: WriteFileTool — any path write requires approval (HIGH)
|
-- Security rules are managed by ToolGuardRuleSeedService (Java) as single source of truth.
|
||||||
INSERT INTO mate_tool_guard_rule (id, rule_id, name, description, tool_name, param_name,
|
-- Removed 6 legacy SQL rules. Their superset is registered in ToolGuardRuleSeedService.buildBuiltinRules() with correct tool names.
|
||||||
category, severity, decision, pattern, exclude_pattern, remediation,
|
|
||||||
builtin, enabled, priority, create_time, update_time, deleted)
|
|
||||||
VALUES (
|
|
||||||
1000300001,
|
|
||||||
'write_file_any',
|
|
||||||
'File write requires approval',
|
|
||||||
'Any file write operation requires user confirmation to prevent accidental overwrite of important files',
|
|
||||||
'WriteFileTool',
|
|
||||||
'path',
|
|
||||||
'file_write',
|
|
||||||
'HIGH',
|
|
||||||
'NEEDS_APPROVAL',
|
|
||||||
'.+',
|
|
||||||
NULL,
|
|
||||||
'Please confirm write path and content are correct before allowing execution',
|
|
||||||
TRUE, TRUE, 10,
|
|
||||||
NOW(), NOW(), 0
|
|
||||||
)
|
|
||||||
ON DUPLICATE KEY UPDATE rule_id=VALUES(rule_id), name=VALUES(name), description=VALUES(description), tool_name=VALUES(tool_name), param_name=VALUES(param_name), category=VALUES(category), severity=VALUES(severity), decision=VALUES(decision), pattern=VALUES(pattern), exclude_pattern=VALUES(exclude_pattern), remediation=VALUES(remediation), builtin=VALUES(builtin), enabled=VALUES(enabled), priority=VALUES(priority), update_time=VALUES(update_time), deleted=VALUES(deleted);
|
|
||||||
|
|
||||||
-- Security rule: EditFileTool — any file edit requires approval (HIGH)
|
|
||||||
INSERT INTO mate_tool_guard_rule (id, rule_id, name, description, tool_name, param_name,
|
|
||||||
category, severity, decision, pattern, exclude_pattern, remediation,
|
|
||||||
builtin, enabled, priority, create_time, update_time, deleted)
|
|
||||||
VALUES (
|
|
||||||
1000300002,
|
|
||||||
'edit_file_any',
|
|
||||||
'File edit requires approval',
|
|
||||||
'Any file content replacement operation requires user confirmation',
|
|
||||||
'EditFileTool',
|
|
||||||
'path',
|
|
||||||
'file_write',
|
|
||||||
'HIGH',
|
|
||||||
'NEEDS_APPROVAL',
|
|
||||||
'.+',
|
|
||||||
NULL,
|
|
||||||
'Please confirm edit path and replacement content are correct before allowing execution',
|
|
||||||
TRUE, TRUE, 10,
|
|
||||||
NOW(), NOW(), 0
|
|
||||||
)
|
|
||||||
ON DUPLICATE KEY UPDATE rule_id=VALUES(rule_id), name=VALUES(name), description=VALUES(description), tool_name=VALUES(tool_name), param_name=VALUES(param_name), category=VALUES(category), severity=VALUES(severity), decision=VALUES(decision), pattern=VALUES(pattern), exclude_pattern=VALUES(exclude_pattern), remediation=VALUES(remediation), builtin=VALUES(builtin), enabled=VALUES(enabled), priority=VALUES(priority), update_time=VALUES(update_time), deleted=VALUES(deleted);
|
|
||||||
|
|
||||||
-- Security rule: ShellExecuteTool — delete commands require approval (HIGH)
|
|
||||||
INSERT INTO mate_tool_guard_rule (id, rule_id, name, description, tool_name, param_name,
|
|
||||||
category, severity, decision, pattern, exclude_pattern, remediation,
|
|
||||||
builtin, enabled, priority, create_time, update_time, deleted)
|
|
||||||
VALUES (
|
|
||||||
1000300003,
|
|
||||||
'shell_rm_approval',
|
|
||||||
'rm command requires approval',
|
|
||||||
'rm / rmdir commands may cause permanent file loss, requires user confirmation',
|
|
||||||
'ShellExecuteTool',
|
|
||||||
'command',
|
|
||||||
'shell_execution',
|
|
||||||
'HIGH',
|
|
||||||
'NEEDS_APPROVAL',
|
|
||||||
'(?i)(^|[;&|]|\s)rm\s',
|
|
||||||
NULL,
|
|
||||||
'Consider using trash command instead of rm, or confirm file list before allowing execution',
|
|
||||||
TRUE, TRUE, 20,
|
|
||||||
NOW(), NOW(), 0
|
|
||||||
)
|
|
||||||
ON DUPLICATE KEY UPDATE rule_id=VALUES(rule_id), name=VALUES(name), description=VALUES(description), tool_name=VALUES(tool_name), param_name=VALUES(param_name), category=VALUES(category), severity=VALUES(severity), decision=VALUES(decision), pattern=VALUES(pattern), exclude_pattern=VALUES(exclude_pattern), remediation=VALUES(remediation), builtin=VALUES(builtin), enabled=VALUES(enabled), priority=VALUES(priority), update_time=VALUES(update_time), deleted=VALUES(deleted);
|
|
||||||
|
|
||||||
-- Security rule: ShellExecuteTool — forced recursive delete blocked (CRITICAL)
|
|
||||||
INSERT INTO mate_tool_guard_rule (id, rule_id, name, description, tool_name, param_name,
|
|
||||||
category, severity, decision, pattern, exclude_pattern, remediation,
|
|
||||||
builtin, enabled, priority, create_time, update_time, deleted)
|
|
||||||
VALUES (
|
|
||||||
1000300004,
|
|
||||||
'shell_rm_rf_block',
|
|
||||||
'rm -rf blocked',
|
|
||||||
'rm -rf forced recursive delete is extremely dangerous, blocked directly',
|
|
||||||
'ShellExecuteTool',
|
|
||||||
'command',
|
|
||||||
'shell_execution',
|
|
||||||
'CRITICAL',
|
|
||||||
'BLOCK',
|
|
||||||
'(?i)rm\s+(-[a-z]*r[a-z]*f[a-z]*|-[a-z]*f[a-z]*r[a-z]*)\s+(/|~|\$HOME|\*|\.\s*$)',
|
|
||||||
NULL,
|
|
||||||
'Absolutely forbidden to execute rm -rf on root directory, Home directory, or wildcards',
|
|
||||||
TRUE, TRUE, 5,
|
|
||||||
NOW(), NOW(), 0
|
|
||||||
)
|
|
||||||
ON DUPLICATE KEY UPDATE rule_id=VALUES(rule_id), name=VALUES(name), description=VALUES(description), tool_name=VALUES(tool_name), param_name=VALUES(param_name), category=VALUES(category), severity=VALUES(severity), decision=VALUES(decision), pattern=VALUES(pattern), exclude_pattern=VALUES(exclude_pattern), remediation=VALUES(remediation), builtin=VALUES(builtin), enabled=VALUES(enabled), priority=VALUES(priority), update_time=VALUES(update_time), deleted=VALUES(deleted);
|
|
||||||
|
|
||||||
-- Security rule: ShellExecuteTool — writing system config files requires approval (HIGH)
|
|
||||||
INSERT INTO mate_tool_guard_rule (id, rule_id, name, description, tool_name, param_name,
|
|
||||||
category, severity, decision, pattern, exclude_pattern, remediation,
|
|
||||||
builtin, enabled, priority, create_time, update_time, deleted)
|
|
||||||
VALUES (
|
|
||||||
1000300005,
|
|
||||||
'shell_write_system_file',
|
|
||||||
'System file write requires approval',
|
|
||||||
'Writing to system directories like /etc or /usr via Shell requires user confirmation',
|
|
||||||
'ShellExecuteTool',
|
|
||||||
'command',
|
|
||||||
'shell_execution',
|
|
||||||
'HIGH',
|
|
||||||
'NEEDS_APPROVAL',
|
|
||||||
'(?i)(>\s*|tee\s+|cp\s+.*\s+)(/etc/|/usr/|/bin/|/sbin/|/boot/)',
|
|
||||||
NULL,
|
|
||||||
'Please confirm the system file and content to modify before allowing execution',
|
|
||||||
TRUE, TRUE, 15,
|
|
||||||
NOW(), NOW(), 0
|
|
||||||
)
|
|
||||||
ON DUPLICATE KEY UPDATE rule_id=VALUES(rule_id), name=VALUES(name), description=VALUES(description), tool_name=VALUES(tool_name), param_name=VALUES(param_name), category=VALUES(category), severity=VALUES(severity), decision=VALUES(decision), pattern=VALUES(pattern), exclude_pattern=VALUES(exclude_pattern), remediation=VALUES(remediation), builtin=VALUES(builtin), enabled=VALUES(enabled), priority=VALUES(priority), update_time=VALUES(update_time), deleted=VALUES(deleted);
|
|
||||||
|
|
||||||
-- Security rule: ShellExecuteTool — chmod 777 requires approval (MEDIUM)
|
|
||||||
INSERT INTO mate_tool_guard_rule (id, rule_id, name, description, tool_name, param_name,
|
|
||||||
category, severity, decision, pattern, exclude_pattern, remediation,
|
|
||||||
builtin, enabled, priority, create_time, update_time, deleted)
|
|
||||||
VALUES (
|
|
||||||
1000300006,
|
|
||||||
'shell_chmod_777',
|
|
||||||
'chmod 777 requires approval',
|
|
||||||
'chmod 777 grants full permissions to all users, security risk',
|
|
||||||
'ShellExecuteTool',
|
|
||||||
'command',
|
|
||||||
'shell_execution',
|
|
||||||
'MEDIUM',
|
|
||||||
'NEEDS_APPROVAL',
|
|
||||||
'(?i)chmod\s+(777|a\+rwx|o\+rwx)',
|
|
||||||
NULL,
|
|
||||||
'Please confirm if full permissions for all users are truly needed',
|
|
||||||
TRUE, TRUE, 30,
|
|
||||||
NOW(), NOW(), 0
|
|
||||||
)
|
|
||||||
ON DUPLICATE KEY UPDATE rule_id=VALUES(rule_id), name=VALUES(name), description=VALUES(description), tool_name=VALUES(tool_name), param_name=VALUES(param_name), category=VALUES(category), severity=VALUES(severity), decision=VALUES(decision), pattern=VALUES(pattern), exclude_pattern=VALUES(exclude_pattern), remediation=VALUES(remediation), builtin=VALUES(builtin), enabled=VALUES(enabled), priority=VALUES(priority), update_time=VALUES(update_time), deleted=VALUES(deleted);
|
|
||||||
|
|||||||
@ -1721,149 +1721,22 @@ ON DUPLICATE KEY UPDATE agent_id=VALUES(agent_id), filename=VALUES(filename), co
|
|||||||
|
|
||||||
-- ==================== ToolGuard 默认配置与规则种子数据 ====================
|
-- ==================== ToolGuard 默认配置与规则种子数据 ====================
|
||||||
|
|
||||||
-- 全局安全配置(只有一行)
|
-- 全局安全配置(只有一行,仅首次初始化时插入,不覆盖用户修改)
|
||||||
INSERT INTO mate_tool_guard_config (id, enabled, guard_scope, guarded_tools_json, denied_tools_json,
|
-- 注意:guarded_tools_json 中的工具名必须与 @Tool 方法名一致(execute_shell_command / write_file / edit_file)
|
||||||
file_guard_enabled, sensitive_paths_json, create_time, update_time)
|
INSERT IGNORE INTO mate_tool_guard_config (id, enabled, guard_scope, guarded_tools_json, denied_tools_json,
|
||||||
|
file_guard_enabled, sensitive_paths_json, audit_enabled, audit_min_severity, audit_retention_days,
|
||||||
|
create_time, update_time)
|
||||||
VALUES (
|
VALUES (
|
||||||
1000000001,
|
1000000001,
|
||||||
TRUE,
|
TRUE,
|
||||||
'all',
|
'all',
|
||||||
'["WriteFileTool","EditFileTool","ShellExecuteTool"]',
|
'["write_file","edit_file","execute_shell_command"]',
|
||||||
'[]',
|
'[]',
|
||||||
TRUE,
|
TRUE,
|
||||||
'["/etc","/usr","/bin","/sbin","/boot","/sys","/proc","/dev"]',
|
'["/etc","/usr","/bin","/sbin","/boot","/sys","/proc","/dev"]',
|
||||||
|
TRUE, 'INFO', 90,
|
||||||
NOW(), NOW()
|
NOW(), NOW()
|
||||||
)
|
);
|
||||||
ON DUPLICATE KEY UPDATE enabled=VALUES(enabled), guard_scope=VALUES(guard_scope), guarded_tools_json=VALUES(guarded_tools_json), denied_tools_json=VALUES(denied_tools_json), file_guard_enabled=VALUES(file_guard_enabled), sensitive_paths_json=VALUES(sensitive_paths_json), update_time=VALUES(update_time);
|
|
||||||
|
|
||||||
-- 安全规则:WriteFileTool — 任意路径写入需要审批(HIGH)
|
-- 安全规则由 ToolGuardRuleSeedService (Java) 统一种子化,不在 SQL 中重复维护
|
||||||
INSERT INTO mate_tool_guard_rule (id, rule_id, name, description, tool_name, param_name,
|
-- 已移除旧的 6 条 SQL 规则,其超集已在 ToolGuardRuleSeedService.buildBuiltinRules() 中以正确的工具名注册。
|
||||||
category, severity, decision, pattern, exclude_pattern, remediation,
|
|
||||||
builtin, enabled, priority, create_time, update_time, deleted)
|
|
||||||
VALUES (
|
|
||||||
1000300001,
|
|
||||||
'write_file_any',
|
|
||||||
'文件写入需审批',
|
|
||||||
'任何文件写入操作都需要用户确认,防止意外覆盖重要文件',
|
|
||||||
'WriteFileTool',
|
|
||||||
'path',
|
|
||||||
'file_write',
|
|
||||||
'HIGH',
|
|
||||||
'NEEDS_APPROVAL',
|
|
||||||
'.+',
|
|
||||||
NULL,
|
|
||||||
'请确认写入路径和内容正确后再允许执行',
|
|
||||||
TRUE, TRUE, 10,
|
|
||||||
NOW(), NOW(), 0
|
|
||||||
)
|
|
||||||
ON DUPLICATE KEY UPDATE rule_id=VALUES(rule_id), name=VALUES(name), description=VALUES(description), tool_name=VALUES(tool_name), param_name=VALUES(param_name), category=VALUES(category), severity=VALUES(severity), decision=VALUES(decision), pattern=VALUES(pattern), exclude_pattern=VALUES(exclude_pattern), remediation=VALUES(remediation), builtin=VALUES(builtin), enabled=VALUES(enabled), priority=VALUES(priority), update_time=VALUES(update_time), deleted=VALUES(deleted);
|
|
||||||
|
|
||||||
-- 安全规则:EditFileTool — 任意文件编辑需要审批(HIGH)
|
|
||||||
INSERT INTO mate_tool_guard_rule (id, rule_id, name, description, tool_name, param_name,
|
|
||||||
category, severity, decision, pattern, exclude_pattern, remediation,
|
|
||||||
builtin, enabled, priority, create_time, update_time, deleted)
|
|
||||||
VALUES (
|
|
||||||
1000300002,
|
|
||||||
'edit_file_any',
|
|
||||||
'文件编辑需审批',
|
|
||||||
'任何文件内容替换操作都需要用户确认',
|
|
||||||
'EditFileTool',
|
|
||||||
'path',
|
|
||||||
'file_write',
|
|
||||||
'HIGH',
|
|
||||||
'NEEDS_APPROVAL',
|
|
||||||
'.+',
|
|
||||||
NULL,
|
|
||||||
'请确认编辑路径和替换内容正确后再允许执行',
|
|
||||||
TRUE, TRUE, 10,
|
|
||||||
NOW(), NOW(), 0
|
|
||||||
)
|
|
||||||
ON DUPLICATE KEY UPDATE rule_id=VALUES(rule_id), name=VALUES(name), description=VALUES(description), tool_name=VALUES(tool_name), param_name=VALUES(param_name), category=VALUES(category), severity=VALUES(severity), decision=VALUES(decision), pattern=VALUES(pattern), exclude_pattern=VALUES(exclude_pattern), remediation=VALUES(remediation), builtin=VALUES(builtin), enabled=VALUES(enabled), priority=VALUES(priority), update_time=VALUES(update_time), deleted=VALUES(deleted);
|
|
||||||
|
|
||||||
-- 安全规则:ShellExecuteTool — 删除命令需审批(HIGH)
|
|
||||||
INSERT INTO mate_tool_guard_rule (id, rule_id, name, description, tool_name, param_name,
|
|
||||||
category, severity, decision, pattern, exclude_pattern, remediation,
|
|
||||||
builtin, enabled, priority, create_time, update_time, deleted)
|
|
||||||
VALUES (
|
|
||||||
1000300003,
|
|
||||||
'shell_rm_approval',
|
|
||||||
'rm 命令需审批',
|
|
||||||
'rm / rmdir 命令可能导致文件永久丢失,需要用户确认',
|
|
||||||
'ShellExecuteTool',
|
|
||||||
'command',
|
|
||||||
'shell_execution',
|
|
||||||
'HIGH',
|
|
||||||
'NEEDS_APPROVAL',
|
|
||||||
'(?i)(^|[;&|]|\s)rm\s',
|
|
||||||
NULL,
|
|
||||||
'考虑使用 trash 命令替代 rm,或确认要删除的文件列表后再允许执行',
|
|
||||||
TRUE, TRUE, 20,
|
|
||||||
NOW(), NOW(), 0
|
|
||||||
)
|
|
||||||
ON DUPLICATE KEY UPDATE rule_id=VALUES(rule_id), name=VALUES(name), description=VALUES(description), tool_name=VALUES(tool_name), param_name=VALUES(param_name), category=VALUES(category), severity=VALUES(severity), decision=VALUES(decision), pattern=VALUES(pattern), exclude_pattern=VALUES(exclude_pattern), remediation=VALUES(remediation), builtin=VALUES(builtin), enabled=VALUES(enabled), priority=VALUES(priority), update_time=VALUES(update_time), deleted=VALUES(deleted);
|
|
||||||
|
|
||||||
-- 安全规则:ShellExecuteTool — 强制递归删除直接拦截(CRITICAL)
|
|
||||||
INSERT INTO mate_tool_guard_rule (id, rule_id, name, description, tool_name, param_name,
|
|
||||||
category, severity, decision, pattern, exclude_pattern, remediation,
|
|
||||||
builtin, enabled, priority, create_time, update_time, deleted)
|
|
||||||
VALUES (
|
|
||||||
1000300004,
|
|
||||||
'shell_rm_rf_block',
|
|
||||||
'rm -rf 直接拦截',
|
|
||||||
'rm -rf 强制递归删除极度危险,直接拦截',
|
|
||||||
'ShellExecuteTool',
|
|
||||||
'command',
|
|
||||||
'shell_execution',
|
|
||||||
'CRITICAL',
|
|
||||||
'BLOCK',
|
|
||||||
'(?i)rm\s+(-[a-z]*r[a-z]*f[a-z]*|-[a-z]*f[a-z]*r[a-z]*)\s+(/|~|\$HOME|\*|\.\s*$)',
|
|
||||||
NULL,
|
|
||||||
'绝对禁止对根目录、Home 目录或通配符执行 rm -rf',
|
|
||||||
TRUE, TRUE, 5,
|
|
||||||
NOW(), NOW(), 0
|
|
||||||
)
|
|
||||||
ON DUPLICATE KEY UPDATE rule_id=VALUES(rule_id), name=VALUES(name), description=VALUES(description), tool_name=VALUES(tool_name), param_name=VALUES(param_name), category=VALUES(category), severity=VALUES(severity), decision=VALUES(decision), pattern=VALUES(pattern), exclude_pattern=VALUES(exclude_pattern), remediation=VALUES(remediation), builtin=VALUES(builtin), enabled=VALUES(enabled), priority=VALUES(priority), update_time=VALUES(update_time), deleted=VALUES(deleted);
|
|
||||||
|
|
||||||
-- 安全规则:ShellExecuteTool — 写入系统配置文件需审批(HIGH)
|
|
||||||
INSERT INTO mate_tool_guard_rule (id, rule_id, name, description, tool_name, param_name,
|
|
||||||
category, severity, decision, pattern, exclude_pattern, remediation,
|
|
||||||
builtin, enabled, priority, create_time, update_time, deleted)
|
|
||||||
VALUES (
|
|
||||||
1000300005,
|
|
||||||
'shell_write_system_file',
|
|
||||||
'写入系统文件需审批',
|
|
||||||
'通过 Shell 向 /etc / /usr 等系统目录写入内容需要用户确认',
|
|
||||||
'ShellExecuteTool',
|
|
||||||
'command',
|
|
||||||
'shell_execution',
|
|
||||||
'HIGH',
|
|
||||||
'NEEDS_APPROVAL',
|
|
||||||
'(?i)(>\s*|tee\s+|cp\s+.*\s+)(/etc/|/usr/|/bin/|/sbin/|/boot/)',
|
|
||||||
NULL,
|
|
||||||
'请确认要修改的系统文件和内容后再允许执行',
|
|
||||||
TRUE, TRUE, 15,
|
|
||||||
NOW(), NOW(), 0
|
|
||||||
)
|
|
||||||
ON DUPLICATE KEY UPDATE rule_id=VALUES(rule_id), name=VALUES(name), description=VALUES(description), tool_name=VALUES(tool_name), param_name=VALUES(param_name), category=VALUES(category), severity=VALUES(severity), decision=VALUES(decision), pattern=VALUES(pattern), exclude_pattern=VALUES(exclude_pattern), remediation=VALUES(remediation), builtin=VALUES(builtin), enabled=VALUES(enabled), priority=VALUES(priority), update_time=VALUES(update_time), deleted=VALUES(deleted);
|
|
||||||
|
|
||||||
-- 安全规则:ShellExecuteTool — chmod 777 需审批(MEDIUM)
|
|
||||||
INSERT INTO mate_tool_guard_rule (id, rule_id, name, description, tool_name, param_name,
|
|
||||||
category, severity, decision, pattern, exclude_pattern, remediation,
|
|
||||||
builtin, enabled, priority, create_time, update_time, deleted)
|
|
||||||
VALUES (
|
|
||||||
1000300006,
|
|
||||||
'shell_chmod_777',
|
|
||||||
'chmod 777 需审批',
|
|
||||||
'chmod 777 给予所有用户完全权限,存在安全风险',
|
|
||||||
'ShellExecuteTool',
|
|
||||||
'command',
|
|
||||||
'shell_execution',
|
|
||||||
'MEDIUM',
|
|
||||||
'NEEDS_APPROVAL',
|
|
||||||
'(?i)chmod\s+(777|a\+rwx|o\+rwx)',
|
|
||||||
NULL,
|
|
||||||
'请确认是否真的需要给予所有用户完全权限',
|
|
||||||
TRUE, TRUE, 30,
|
|
||||||
NOW(), NOW(), 0
|
|
||||||
)
|
|
||||||
ON DUPLICATE KEY UPDATE rule_id=VALUES(rule_id), name=VALUES(name), description=VALUES(description), tool_name=VALUES(tool_name), param_name=VALUES(param_name), category=VALUES(category), severity=VALUES(severity), decision=VALUES(decision), pattern=VALUES(pattern), exclude_pattern=VALUES(exclude_pattern), remediation=VALUES(remediation), builtin=VALUES(builtin), enabled=VALUES(enabled), priority=VALUES(priority), update_time=VALUES(update_time), deleted=VALUES(deleted);
|
|
||||||
|
|||||||
@ -1724,149 +1724,26 @@ VALUES (
|
|||||||
|
|
||||||
-- ==================== ToolGuard 默认配置与规则种子数据 ====================
|
-- ==================== ToolGuard 默认配置与规则种子数据 ====================
|
||||||
|
|
||||||
-- 全局安全配置(只有一行)
|
-- 全局安全配置(只有一行,仅首次初始化时插入)
|
||||||
MERGE INTO mate_tool_guard_config (id, enabled, guard_scope, guarded_tools_json, denied_tools_json,
|
-- 注意:guarded_tools_json 中的工具名必须与 @Tool 方法名一致(execute_shell_command / write_file / edit_file)
|
||||||
file_guard_enabled, sensitive_paths_json, create_time, update_time)
|
-- 使用 SELECT + INSERT 确保已存在时不覆盖(H2 的 MERGE 会覆盖所有列,会重置用户修改的配置)
|
||||||
KEY (id)
|
INSERT INTO mate_tool_guard_config (id, enabled, guard_scope, guarded_tools_json, denied_tools_json,
|
||||||
VALUES (
|
file_guard_enabled, sensitive_paths_json, audit_enabled, audit_min_severity, audit_retention_days,
|
||||||
|
create_time, update_time)
|
||||||
|
SELECT
|
||||||
1000000001,
|
1000000001,
|
||||||
TRUE,
|
TRUE,
|
||||||
'all',
|
'all',
|
||||||
'["WriteFileTool","EditFileTool","ShellExecuteTool"]',
|
'["write_file","edit_file","execute_shell_command"]',
|
||||||
'[]',
|
'[]',
|
||||||
TRUE,
|
TRUE,
|
||||||
'["/etc","/usr","/bin","/sbin","/boot","/sys","/proc","/dev"]',
|
'["/etc","/usr","/bin","/sbin","/boot","/sys","/proc","/dev"]',
|
||||||
|
TRUE, 'INFO', 90,
|
||||||
NOW(), NOW()
|
NOW(), NOW()
|
||||||
);
|
FROM DUAL
|
||||||
|
WHERE NOT EXISTS (SELECT 1 FROM mate_tool_guard_config WHERE id = 1000000001);
|
||||||
|
|
||||||
-- 安全规则:WriteFileTool — 任意路径写入需要审批(HIGH)
|
-- 安全规则由 ToolGuardRuleSeedService (Java) 统一种子化,不在 SQL 中重复维护
|
||||||
MERGE INTO mate_tool_guard_rule (id, rule_id, name, description, tool_name, param_name,
|
-- 已移除旧的 6 条 SQL 规则(rule_id: write_file_any, edit_file_any, shell_rm_approval,
|
||||||
category, severity, decision, pattern, exclude_pattern, remediation,
|
-- shell_rm_rf_block, shell_write_system_file, shell_chmod_777),
|
||||||
builtin, enabled, priority, create_time, update_time, deleted)
|
-- 它们的超集已在 ToolGuardRuleSeedService.buildBuiltinRules() 中以正确的工具名注册。
|
||||||
KEY (id)
|
|
||||||
VALUES (
|
|
||||||
1000300001,
|
|
||||||
'write_file_any',
|
|
||||||
'文件写入需审批',
|
|
||||||
'任何文件写入操作都需要用户确认,防止意外覆盖重要文件',
|
|
||||||
'WriteFileTool',
|
|
||||||
'path',
|
|
||||||
'file_write',
|
|
||||||
'HIGH',
|
|
||||||
'NEEDS_APPROVAL',
|
|
||||||
'.+',
|
|
||||||
NULL,
|
|
||||||
'请确认写入路径和内容正确后再允许执行',
|
|
||||||
TRUE, TRUE, 10,
|
|
||||||
NOW(), NOW(), 0
|
|
||||||
);
|
|
||||||
|
|
||||||
-- 安全规则:EditFileTool — 任意文件编辑需要审批(HIGH)
|
|
||||||
MERGE INTO mate_tool_guard_rule (id, rule_id, name, description, tool_name, param_name,
|
|
||||||
category, severity, decision, pattern, exclude_pattern, remediation,
|
|
||||||
builtin, enabled, priority, create_time, update_time, deleted)
|
|
||||||
KEY (id)
|
|
||||||
VALUES (
|
|
||||||
1000300002,
|
|
||||||
'edit_file_any',
|
|
||||||
'文件编辑需审批',
|
|
||||||
'任何文件内容替换操作都需要用户确认',
|
|
||||||
'EditFileTool',
|
|
||||||
'path',
|
|
||||||
'file_write',
|
|
||||||
'HIGH',
|
|
||||||
'NEEDS_APPROVAL',
|
|
||||||
'.+',
|
|
||||||
NULL,
|
|
||||||
'请确认编辑路径和替换内容正确后再允许执行',
|
|
||||||
TRUE, TRUE, 10,
|
|
||||||
NOW(), NOW(), 0
|
|
||||||
);
|
|
||||||
|
|
||||||
-- 安全规则:ShellExecuteTool — 删除命令需审批(HIGH)
|
|
||||||
MERGE INTO mate_tool_guard_rule (id, rule_id, name, description, tool_name, param_name,
|
|
||||||
category, severity, decision, pattern, exclude_pattern, remediation,
|
|
||||||
builtin, enabled, priority, create_time, update_time, deleted)
|
|
||||||
KEY (id)
|
|
||||||
VALUES (
|
|
||||||
1000300003,
|
|
||||||
'shell_rm_approval',
|
|
||||||
'rm 命令需审批',
|
|
||||||
'rm / rmdir 命令可能导致文件永久丢失,需要用户确认',
|
|
||||||
'ShellExecuteTool',
|
|
||||||
'command',
|
|
||||||
'shell_execution',
|
|
||||||
'HIGH',
|
|
||||||
'NEEDS_APPROVAL',
|
|
||||||
'(?i)(^|[;&|]|\s)rm\s',
|
|
||||||
NULL,
|
|
||||||
'考虑使用 trash 命令替代 rm,或确认要删除的文件列表后再允许执行',
|
|
||||||
TRUE, TRUE, 20,
|
|
||||||
NOW(), NOW(), 0
|
|
||||||
);
|
|
||||||
|
|
||||||
-- 安全规则:ShellExecuteTool — 强制递归删除直接拦截(CRITICAL)
|
|
||||||
MERGE INTO mate_tool_guard_rule (id, rule_id, name, description, tool_name, param_name,
|
|
||||||
category, severity, decision, pattern, exclude_pattern, remediation,
|
|
||||||
builtin, enabled, priority, create_time, update_time, deleted)
|
|
||||||
KEY (id)
|
|
||||||
VALUES (
|
|
||||||
1000300004,
|
|
||||||
'shell_rm_rf_block',
|
|
||||||
'rm -rf 直接拦截',
|
|
||||||
'rm -rf 强制递归删除极度危险,直接拦截',
|
|
||||||
'ShellExecuteTool',
|
|
||||||
'command',
|
|
||||||
'shell_execution',
|
|
||||||
'CRITICAL',
|
|
||||||
'BLOCK',
|
|
||||||
'(?i)rm\s+(-[a-z]*r[a-z]*f[a-z]*|-[a-z]*f[a-z]*r[a-z]*)\s+(/|~|\$HOME|\*|\.\s*$)',
|
|
||||||
NULL,
|
|
||||||
'绝对禁止对根目录、Home 目录或通配符执行 rm -rf',
|
|
||||||
TRUE, TRUE, 5,
|
|
||||||
NOW(), NOW(), 0
|
|
||||||
);
|
|
||||||
|
|
||||||
-- 安全规则:ShellExecuteTool — 写入系统配置文件需审批(HIGH)
|
|
||||||
MERGE INTO mate_tool_guard_rule (id, rule_id, name, description, tool_name, param_name,
|
|
||||||
category, severity, decision, pattern, exclude_pattern, remediation,
|
|
||||||
builtin, enabled, priority, create_time, update_time, deleted)
|
|
||||||
KEY (id)
|
|
||||||
VALUES (
|
|
||||||
1000300005,
|
|
||||||
'shell_write_system_file',
|
|
||||||
'写入系统文件需审批',
|
|
||||||
'通过 Shell 向 /etc / /usr 等系统目录写入内容需要用户确认',
|
|
||||||
'ShellExecuteTool',
|
|
||||||
'command',
|
|
||||||
'shell_execution',
|
|
||||||
'HIGH',
|
|
||||||
'NEEDS_APPROVAL',
|
|
||||||
'(?i)(>\s*|tee\s+|cp\s+.*\s+)(/etc/|/usr/|/bin/|/sbin/|/boot/)',
|
|
||||||
NULL,
|
|
||||||
'请确认要修改的系统文件和内容后再允许执行',
|
|
||||||
TRUE, TRUE, 15,
|
|
||||||
NOW(), NOW(), 0
|
|
||||||
);
|
|
||||||
|
|
||||||
-- 安全规则:ShellExecuteTool — chmod 777 需审批(MEDIUM)
|
|
||||||
MERGE INTO mate_tool_guard_rule (id, rule_id, name, description, tool_name, param_name,
|
|
||||||
category, severity, decision, pattern, exclude_pattern, remediation,
|
|
||||||
builtin, enabled, priority, create_time, update_time, deleted)
|
|
||||||
KEY (id)
|
|
||||||
VALUES (
|
|
||||||
1000300006,
|
|
||||||
'shell_chmod_777',
|
|
||||||
'chmod 777 需审批',
|
|
||||||
'chmod 777 给予所有用户完全权限,存在安全风险',
|
|
||||||
'ShellExecuteTool',
|
|
||||||
'command',
|
|
||||||
'shell_execution',
|
|
||||||
'MEDIUM',
|
|
||||||
'NEEDS_APPROVAL',
|
|
||||||
'(?i)chmod\s+(777|a\+rwx|o\+rwx)',
|
|
||||||
NULL,
|
|
||||||
'请确认是否真的需要给予所有用户完全权限',
|
|
||||||
TRUE, TRUE, 30,
|
|
||||||
NOW(), NOW(), 0
|
|
||||||
);
|
|
||||||
|
|||||||
@ -347,6 +347,9 @@ CREATE TABLE IF NOT EXISTS mate_tool_guard_config (
|
|||||||
denied_tools_json TEXT,
|
denied_tools_json TEXT,
|
||||||
file_guard_enabled TINYINT(1) NOT NULL DEFAULT 1,
|
file_guard_enabled TINYINT(1) NOT NULL DEFAULT 1,
|
||||||
sensitive_paths_json TEXT,
|
sensitive_paths_json TEXT,
|
||||||
|
audit_enabled TINYINT(1) NOT NULL DEFAULT 1,
|
||||||
|
audit_min_severity VARCHAR(16) NOT NULL DEFAULT 'INFO',
|
||||||
|
audit_retention_days INT NOT NULL DEFAULT 90,
|
||||||
create_time DATETIME NOT NULL,
|
create_time DATETIME NOT NULL,
|
||||||
update_time DATETIME NOT NULL
|
update_time DATETIME NOT NULL
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
|
|||||||
@ -357,6 +357,9 @@ CREATE TABLE IF NOT EXISTS mate_tool_guard_config (
|
|||||||
denied_tools_json TEXT,
|
denied_tools_json TEXT,
|
||||||
file_guard_enabled BOOLEAN NOT NULL DEFAULT TRUE,
|
file_guard_enabled BOOLEAN NOT NULL DEFAULT TRUE,
|
||||||
sensitive_paths_json TEXT,
|
sensitive_paths_json TEXT,
|
||||||
|
audit_enabled BOOLEAN NOT NULL DEFAULT TRUE,
|
||||||
|
audit_min_severity VARCHAR(16) NOT NULL DEFAULT 'INFO',
|
||||||
|
audit_retention_days INT NOT NULL DEFAULT 90,
|
||||||
create_time DATETIME NOT NULL,
|
create_time DATETIME NOT NULL,
|
||||||
update_time DATETIME NOT NULL
|
update_time DATETIME NOT NULL
|
||||||
);
|
);
|
||||||
|
|||||||
@ -488,6 +488,15 @@ export default {
|
|||||||
audit: {
|
audit: {
|
||||||
title: 'Audit Logs',
|
title: 'Audit Logs',
|
||||||
desc: 'View tool security check records',
|
desc: 'View tool security check records',
|
||||||
|
config: {
|
||||||
|
title: 'Audit Configuration',
|
||||||
|
enabled: 'Enable Audit Logging',
|
||||||
|
enabledHint: 'When disabled, tool invocation audit logs will not be recorded',
|
||||||
|
minSeverity: 'Minimum Severity',
|
||||||
|
minSeverityHint: 'Only record audit events at this severity level and above',
|
||||||
|
retentionDays: 'Retention Days',
|
||||||
|
retentionDaysHint: 'Audit logs older than this will be auto-cleaned (0=never)',
|
||||||
|
},
|
||||||
stats: {
|
stats: {
|
||||||
total: 'Total Checks',
|
total: 'Total Checks',
|
||||||
blocked: 'Blocked',
|
blocked: 'Blocked',
|
||||||
|
|||||||
@ -488,6 +488,15 @@ export default {
|
|||||||
audit: {
|
audit: {
|
||||||
title: '审计日志',
|
title: '审计日志',
|
||||||
desc: '查看工具安全检查记录',
|
desc: '查看工具安全检查记录',
|
||||||
|
config: {
|
||||||
|
title: '审计配置',
|
||||||
|
enabled: '启用审计日志',
|
||||||
|
enabledHint: '关闭后将不再记录工具调用审计日志',
|
||||||
|
minSeverity: '最低记录等级',
|
||||||
|
minSeverityHint: '仅记录达到此等级及以上的审计事件',
|
||||||
|
retentionDays: '保留天数',
|
||||||
|
retentionDaysHint: '超过此天数的审计日志将被自动清理(0=永不清理)',
|
||||||
|
},
|
||||||
stats: {
|
stats: {
|
||||||
total: '总检查',
|
total: '总检查',
|
||||||
blocked: '已阻止',
|
blocked: '已阻止',
|
||||||
|
|||||||
@ -584,6 +584,9 @@ export interface GuardConfig {
|
|||||||
deniedToolsJson?: string
|
deniedToolsJson?: string
|
||||||
fileGuardEnabled: boolean
|
fileGuardEnabled: boolean
|
||||||
sensitivePathsJson?: string
|
sensitivePathsJson?: string
|
||||||
|
auditEnabled?: boolean
|
||||||
|
auditMinSeverity?: string
|
||||||
|
auditRetentionDays?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AuditLogEntry {
|
export interface AuditLogEntry {
|
||||||
|
|||||||
@ -7,6 +7,46 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Audit Config -->
|
||||||
|
<div class="config-panel">
|
||||||
|
<h3 class="config-title">{{ t('security.audit.config.title') }}</h3>
|
||||||
|
<div class="config-grid">
|
||||||
|
<div class="config-item">
|
||||||
|
<div class="config-label-row">
|
||||||
|
<label>{{ t('security.audit.config.enabled') }}</label>
|
||||||
|
<label class="toggle-switch">
|
||||||
|
<input type="checkbox" v-model="auditConfig.auditEnabled" @change="saveAuditConfig" />
|
||||||
|
<span class="toggle-slider"></span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<p class="config-hint">{{ t('security.audit.config.enabledHint') }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="config-item">
|
||||||
|
<label>{{ t('security.audit.config.minSeverity') }}</label>
|
||||||
|
<select v-model="auditConfig.auditMinSeverity" @change="saveAuditConfig" class="filter-select">
|
||||||
|
<option value="INFO">{{ t('security.severity.INFO') }}</option>
|
||||||
|
<option value="LOW">{{ t('security.severity.LOW') }}</option>
|
||||||
|
<option value="MEDIUM">{{ t('security.severity.MEDIUM') }}</option>
|
||||||
|
<option value="HIGH">{{ t('security.severity.HIGH') }}</option>
|
||||||
|
<option value="CRITICAL">{{ t('security.severity.CRITICAL') }}</option>
|
||||||
|
</select>
|
||||||
|
<p class="config-hint">{{ t('security.audit.config.minSeverityHint') }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="config-item">
|
||||||
|
<label>{{ t('security.audit.config.retentionDays') }}</label>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
v-model.number="auditConfig.auditRetentionDays"
|
||||||
|
@change="saveAuditConfig"
|
||||||
|
class="filter-input retention-input"
|
||||||
|
min="0"
|
||||||
|
max="3650"
|
||||||
|
/>
|
||||||
|
<p class="config-hint">{{ t('security.audit.config.retentionDaysHint') }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Stats Cards -->
|
<!-- Stats Cards -->
|
||||||
<div class="stats-grid">
|
<div class="stats-grid">
|
||||||
<div class="stat-card">
|
<div class="stat-card">
|
||||||
@ -148,6 +188,37 @@ const auditTotal = ref(0)
|
|||||||
const auditFilters = reactive({ toolName: '', decision: '' })
|
const auditFilters = reactive({ toolName: '', decision: '' })
|
||||||
const expandedRows = ref(new Set<number>())
|
const expandedRows = ref(new Set<number>())
|
||||||
|
|
||||||
|
// Audit config
|
||||||
|
const auditConfig = reactive({
|
||||||
|
auditEnabled: true,
|
||||||
|
auditMinSeverity: 'INFO',
|
||||||
|
auditRetentionDays: 90,
|
||||||
|
})
|
||||||
|
|
||||||
|
async function loadAuditConfig() {
|
||||||
|
try {
|
||||||
|
const res: any = await securityApi.getGuardConfig()
|
||||||
|
const data = res.data || {}
|
||||||
|
auditConfig.auditEnabled = data.auditEnabled ?? true
|
||||||
|
auditConfig.auditMinSeverity = data.auditMinSeverity || 'INFO'
|
||||||
|
auditConfig.auditRetentionDays = data.auditRetentionDays ?? 90
|
||||||
|
} catch {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function saveAuditConfig() {
|
||||||
|
try {
|
||||||
|
await securityApi.updateGuardConfig({
|
||||||
|
auditEnabled: auditConfig.auditEnabled,
|
||||||
|
auditMinSeverity: auditConfig.auditMinSeverity,
|
||||||
|
auditRetentionDays: auditConfig.auditRetentionDays,
|
||||||
|
})
|
||||||
|
} catch {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function loadAuditLogs() {
|
async function loadAuditLogs() {
|
||||||
try {
|
try {
|
||||||
const params: any = {
|
const params: any = {
|
||||||
@ -183,7 +254,7 @@ function toggleExpand(id: number) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await Promise.all([loadAuditLogs(), loadAuditStats()])
|
await Promise.all([loadAuditConfig(), loadAuditLogs(), loadAuditStats()])
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -192,6 +263,95 @@ onMounted(async () => {
|
|||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
/* Config Panel */
|
||||||
|
.config-panel {
|
||||||
|
background: var(--mc-bg-elevated);
|
||||||
|
border: 1px solid var(--mc-border-light);
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 20px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.config-title {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--mc-text-primary);
|
||||||
|
margin: 0 0 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.config-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.config-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.config-item label {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--mc-text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.config-label-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.config-hint {
|
||||||
|
font-size: 11px;
|
||||||
|
color: var(--mc-text-tertiary);
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.retention-input {
|
||||||
|
max-width: 120px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Toggle Switch */
|
||||||
|
.toggle-switch {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
width: 40px;
|
||||||
|
height: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-switch input { opacity: 0; width: 0; height: 0; }
|
||||||
|
|
||||||
|
.toggle-slider {
|
||||||
|
position: absolute;
|
||||||
|
cursor: pointer;
|
||||||
|
inset: 0;
|
||||||
|
background: var(--mc-border);
|
||||||
|
border-radius: 22px;
|
||||||
|
transition: 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-slider::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
left: 3px;
|
||||||
|
bottom: 3px;
|
||||||
|
background: white;
|
||||||
|
border-radius: 50%;
|
||||||
|
transition: 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-switch input:checked + .toggle-slider {
|
||||||
|
background: var(--mc-accent, #3b82f6);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-switch input:checked + .toggle-slider::before {
|
||||||
|
transform: translateX(18px);
|
||||||
|
}
|
||||||
|
|
||||||
/* Stats Grid */
|
/* Stats Grid */
|
||||||
.stats-grid {
|
.stats-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user