From bcf37d95fee75c4fa6ce5c7053fc4ff15c81fea4 Mon Sep 17 00:00:00 2001 From: matevip Date: Sun, 5 Apr 2026 12:00:50 +0800 Subject: [PATCH] fix(guard): align tool guard rule names with runtime @Tool method names and add audit config --- .../mate/tool/builtin/ShellExecuteTool.java | 2 +- .../config/ToolGuardSchemaMigration.java | 11 ++ .../guard/guardian/ShellCommandGuardian.java | 7 + .../guard/model/ToolGuardConfigEntity.java | 7 + .../guard/service/ToolGuardAuditService.java | 45 +++++ .../guard/service/ToolGuardConfigService.java | 26 +++ .../service/ToolGuardRuleSeedService.java | 179 ++++++++++++++++-- .../src/main/resources/db/data-en.sql | 153 ++------------- .../src/main/resources/db/data-mysql-en.sql | 147 +------------- .../src/main/resources/db/data-mysql-zh.sql | 147 +------------- .../src/main/resources/db/data-zh.sql | 153 ++------------- .../src/main/resources/db/schema-mysql.sql | 3 + .../src/main/resources/db/schema.sql | 3 + mateclaw-ui/src/i18n/locales/en-US.ts | 9 + mateclaw-ui/src/i18n/locales/zh-CN.ts | 9 + mateclaw-ui/src/types/index.ts | 3 + .../src/views/Security/AuditLogs/index.vue | 162 +++++++++++++++- 17 files changed, 499 insertions(+), 567 deletions(-) diff --git a/mateclaw-server/src/main/java/vip/mate/tool/builtin/ShellExecuteTool.java b/mateclaw-server/src/main/java/vip/mate/tool/builtin/ShellExecuteTool.java index 17a4dfd5..b34466a0 100644 --- a/mateclaw-server/src/main/java/vip/mate/tool/builtin/ShellExecuteTool.java +++ b/mateclaw-server/src/main/java/vip/mate/tool/builtin/ShellExecuteTool.java @@ -42,7 +42,7 @@ public class ShellExecuteTool { @Tool(description = "在本地服务器上执行 Shell 命令。用于执行系统命令、查看文件、运行脚本等操作。" + "Windows 下使用 cmd.exe,Linux/macOS 下使用 /bin/sh。" - + "注意:每次执行都需要用户审批确认。返回包含 exitCode、stdout、stderr、timedOut 的结构化结果。") + + "危险操作(如 rm -rf、格式化磁盘等)会触发安全审批。返回包含 exitCode、stdout、stderr、timedOut 的结构化结果。") public String execute_shell_command( @ToolParam(description = "要执行的 Shell 命令") String command, @ToolParam(description = "超时秒数,默认 60 秒", required = false) Integer timeoutSeconds) { diff --git a/mateclaw-server/src/main/java/vip/mate/tool/guard/config/ToolGuardSchemaMigration.java b/mateclaw-server/src/main/java/vip/mate/tool/guard/config/ToolGuardSchemaMigration.java index 5da670c6..19f736f5 100644 --- a/mateclaw-server/src/main/java/vip/mate/tool/guard/config/ToolGuardSchemaMigration.java +++ b/mateclaw-server/src/main/java/vip/mate/tool/guard/config/ToolGuardSchemaMigration.java @@ -24,6 +24,7 @@ public class ToolGuardSchemaMigration implements ApplicationRunner { createGuardRuleTable(); createGuardConfigTable(); createAuditLogTable(); + migrateGuardConfigAuditColumns(); } 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) { try { jdbcTemplate.execute(sql); diff --git a/mateclaw-server/src/main/java/vip/mate/tool/guard/guardian/ShellCommandGuardian.java b/mateclaw-server/src/main/java/vip/mate/tool/guard/guardian/ShellCommandGuardian.java index a0e3b406..63e21db4 100644 --- a/mateclaw-server/src/main/java/vip/mate/tool/guard/guardian/ShellCommandGuardian.java +++ b/mateclaw-server/src/main/java/vip/mate/tool/guard/guardian/ShellCommandGuardian.java @@ -186,6 +186,13 @@ public class ShellCommandGuardian implements ToolGuardGuardian { "此命令可能被用于远程控制,请勿执行")); // === 高风险(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", "rm\\s+-(rf|fr)", GuardSeverity.HIGH, GuardCategory.COMMAND_INJECTION, diff --git a/mateclaw-server/src/main/java/vip/mate/tool/guard/model/ToolGuardConfigEntity.java b/mateclaw-server/src/main/java/vip/mate/tool/guard/model/ToolGuardConfigEntity.java index 0245f25c..b46ed8fd 100644 --- a/mateclaw-server/src/main/java/vip/mate/tool/guard/model/ToolGuardConfigEntity.java +++ b/mateclaw-server/src/main/java/vip/mate/tool/guard/model/ToolGuardConfigEntity.java @@ -22,6 +22,13 @@ public class ToolGuardConfigEntity { private Boolean fileGuardEnabled; private String sensitivePathsJson; + /** 审计日志总开关 */ + private Boolean auditEnabled; + /** 最低记录等级(INFO/LOW/MEDIUM/HIGH/CRITICAL) */ + private String auditMinSeverity; + /** 审计日志保留天数(0=永不清理) */ + private Integer auditRetentionDays; + @TableField(fill = FieldFill.INSERT) private LocalDateTime createTime; diff --git a/mateclaw-server/src/main/java/vip/mate/tool/guard/service/ToolGuardAuditService.java b/mateclaw-server/src/main/java/vip/mate/tool/guard/service/ToolGuardAuditService.java index d0b36c2b..fa3d7e22 100644 --- a/mateclaw-server/src/main/java/vip/mate/tool/guard/service/ToolGuardAuditService.java +++ b/mateclaw-server/src/main/java/vip/mate/tool/guard/service/ToolGuardAuditService.java @@ -8,16 +8,20 @@ import com.fasterxml.jackson.databind.ObjectMapper; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.scheduling.annotation.Async; +import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import vip.mate.tool.guard.model.*; import vip.mate.tool.guard.repository.ToolGuardAuditLogMapper; +import java.time.LocalDateTime; import java.util.HashMap; import java.util.List; import java.util.Map; /** * 工具安全审计服务 + *

+ * 支持审计开关、最低记录等级过滤、过期日志自动清理。 */ @Slf4j @Service @@ -26,13 +30,33 @@ public class ToolGuardAuditService { private final ToolGuardAuditLogMapper auditMapper; private final ObjectMapper objectMapper; + private final ToolGuardConfigService configService; /** * 异步记录审计日志 + *

+ * 受审计开关和最低等级过滤控制: + *

*/ @Async public void record(ToolInvocationContext context, GuardEvaluation evaluation, String pendingId) { 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(); entity.setConversationId(context.conversationId()); entity.setAgentId(context.agentId()); @@ -99,6 +123,27 @@ public class ToolGuardAuditService { 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() + .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) { try { return objectMapper.writeValueAsString(evaluation.findingsToMapList()); diff --git a/mateclaw-server/src/main/java/vip/mate/tool/guard/service/ToolGuardConfigService.java b/mateclaw-server/src/main/java/vip/mate/tool/guard/service/ToolGuardConfigService.java index ba6fb7c2..480cc522 100644 --- a/mateclaw-server/src/main/java/vip/mate/tool/guard/service/ToolGuardConfigService.java +++ b/mateclaw-server/src/main/java/vip/mate/tool/guard/service/ToolGuardConfigService.java @@ -11,6 +11,8 @@ import org.springframework.stereotype.Service; import vip.mate.tool.guard.model.ToolGuardConfigEntity; import vip.mate.tool.guard.repository.ToolGuardConfigMapper; +import vip.mate.tool.guard.model.GuardSeverity; + import java.util.List; import java.util.Set; @@ -51,6 +53,9 @@ public class ToolGuardConfigService { if (config.getDeniedToolsJson() != null) existing.setDeniedToolsJson(config.getDeniedToolsJson()); if (config.getFileGuardEnabled() != null) existing.setFileGuardEnabled(config.getFileGuardEnabled()); 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); // 通知 AgentService 刷新缓存(denied 工具列表变更需要重建 agent 的工具集) eventPublisher.publishEvent(new ToolGuardConfigChangedEvent(this)); @@ -90,6 +95,27 @@ public class ToolGuardConfigService { 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() { diff --git a/mateclaw-server/src/main/java/vip/mate/tool/guard/service/ToolGuardRuleSeedService.java b/mateclaw-server/src/main/java/vip/mate/tool/guard/service/ToolGuardRuleSeedService.java index 9baea535..4f4daf5d 100644 --- a/mateclaw-server/src/main/java/vip/mate/tool/guard/service/ToolGuardRuleSeedService.java +++ b/mateclaw-server/src/main/java/vip/mate/tool/guard/service/ToolGuardRuleSeedService.java @@ -1,6 +1,7 @@ package vip.mate.tool.guard.service; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.ApplicationArguments; @@ -9,17 +10,23 @@ import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import vip.mate.tool.guard.model.GuardCategory; 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.repository.ToolGuardConfigMapper; import vip.mate.tool.guard.repository.ToolGuardRuleMapper; -import java.util.ArrayList; -import java.util.List; +import java.util.*; +import java.util.stream.Collectors; /** * 规则种子服务 *

- * 首次启动时将内置规则写入 DB。 - * 已存在则跳过(通过 rule_id UNIQUE 约束)。 + * 启动时完成三项工作: + *

    + *
  1. 迁移旧版工具名(类名 → @Tool 方法名)+ 清理旧 legacy 规则
  2. + *
  3. 按 rule_id 逐条 upsert 内置规则(不存在则插入,已存在则同步更新)
  4. + *
  5. 迁移 guardedToolsJson 中的旧工具名
  6. + *
*/ @Slf4j @Component @@ -28,38 +35,176 @@ import java.util.List; public class ToolGuardRuleSeedService implements ApplicationRunner { private final ToolGuardRuleMapper ruleMapper; + private final ToolGuardConfigMapper configMapper; + + /** 旧类名 → 新 @Tool 方法名 */ + private static final Map TOOL_NAME_RENAMES = Map.of( + "ShellExecuteTool", "execute_shell_command", + "WriteFileTool", "write_file", + "EditFileTool", "edit_file" + ); + + /** 旧 SQL 种子中的 legacy rule_id,已被 Java 种子的新规则完全覆盖 */ + private static final Set 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 public void run(ApplicationArguments args) { + migrateOldData(); seedBuiltinRules(); } + // ==================== 旧数据迁移 ==================== + + /** + * 将 DB 中旧版数据统一迁移: + *
    + *
  • rule 表旧工具名(类名 → @Tool 方法名)
  • + *
  • 清理 legacy rule_id(旧 SQL 种子残留)
  • + *
  • config 表 guardedToolsJson 中的旧工具名
  • + *
+ */ + private void migrateOldData() { + try { + // 1. 迁移 rule 表旧工具名 + for (var entry : TOOL_NAME_RENAMES.entrySet()) { + int updated = ruleMapper.update(null, + new LambdaUpdateWrapper() + .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() + .eq(ToolGuardRuleEntity::getRuleId, legacyId) + .eq(ToolGuardRuleEntity::getBuiltin, true)); + if (deleted > 0) { + log.info("[RuleSeed] Removed legacy rule: {}", legacyId); + } + } + } + + private void migrateGuardedToolsJson() { + try { + List 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 内置规则: + *
    + *
  • 不存在 → 插入
  • + *
  • 已存在 → 同步更新 pattern / severity / decision / priority / toolName 等字段
  • + *
+ * 这样后续版本修正了 regex 或 severity,已有部署也能在重启时自动拿到更新。 + */ void seedBuiltinRules() { try { - Long existingCount = ruleMapper.selectCount( + // 加载已有 builtin 规则(按 rule_id 索引) + List existingList = ruleMapper.selectList( new LambdaQueryWrapper() .eq(ToolGuardRuleEntity::getBuiltin, true)); - if (existingCount > 0) { - log.info("[RuleSeed] {} builtin rules already exist, skipping seed", existingCount); - return; - } + Map existingMap = existingList.stream() + .collect(Collectors.toMap(ToolGuardRuleEntity::getRuleId, e -> e, (a, b) -> a)); List rules = buildBuiltinRules(); int inserted = 0; + int updated = 0; + int unchanged = 0; + for (ToolGuardRuleEntity rule : rules) { - try { - ruleMapper.insert(rule); - inserted++; - } catch (Exception e) { - log.debug("[RuleSeed] Rule {} already exists", rule.getRuleId()); + ToolGuardRuleEntity existing = existingMap.get(rule.getRuleId()); + if (existing == null) { + // 新规则 → 插入 + try { + 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() + .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) { 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 buildBuiltinRules() { List rules = new ArrayList<>(); @@ -97,6 +242,10 @@ public class ToolGuardRuleSeedService implements ApplicationRunner { "execute_shell_command", "此命令可能被用于远程控制", 200)); // === 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)", GuardSeverity.HIGH, GuardCategory.COMMAND_INJECTION, "NEEDS_APPROVAL", "execute_shell_command", "使用 rm -ri 或指定具体文件", 150)); diff --git a/mateclaw-server/src/main/resources/db/data-en.sql b/mateclaw-server/src/main/resources/db/data-en.sql index ebf8d34c..b24c8cb5 100644 --- a/mateclaw-server/src/main/resources/db/data-en.sql +++ b/mateclaw-server/src/main/resources/db/data-en.sql @@ -1720,149 +1720,26 @@ VALUES ( -- ==================== ToolGuard Default Config & Rule Seed Data ==================== --- Global security config (single row) -MERGE INTO mate_tool_guard_config (id, enabled, guard_scope, guarded_tools_json, denied_tools_json, - file_guard_enabled, sensitive_paths_json, create_time, update_time) -KEY (id) -VALUES ( +-- Global security config (single row, insert only if not exists) +-- Note: tool names in guarded_tools_json must match @Tool method names (execute_shell_command / write_file / edit_file) +-- Use SELECT + INSERT to avoid overwriting user-modified config on restart (H2 MERGE would overwrite all columns) +INSERT 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) +SELECT 1000000001, TRUE, 'all', - '["WriteFileTool","EditFileTool","ShellExecuteTool"]', + '["write_file","edit_file","execute_shell_command"]', '[]', TRUE, '["/etc","/usr","/bin","/sbin","/boot","/sys","/proc","/dev"]', + TRUE, 'INFO', 90, 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) -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 ( - 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 -); +-- Security rules are managed by ToolGuardRuleSeedService (Java) as single source of truth. +-- Removed 6 legacy SQL rules (rule_id: write_file_any, edit_file_any, shell_rm_approval, +-- shell_rm_rf_block, shell_write_system_file, shell_chmod_777). +-- Their superset is registered in ToolGuardRuleSeedService.buildBuiltinRules() with correct tool names. diff --git a/mateclaw-server/src/main/resources/db/data-mysql-en.sql b/mateclaw-server/src/main/resources/db/data-mysql-en.sql index fc6ae5d0..a3d476eb 100644 --- a/mateclaw-server/src/main/resources/db/data-mysql-en.sql +++ b/mateclaw-server/src/main/resources/db/data-mysql-en.sql @@ -1719,149 +1719,22 @@ ON DUPLICATE KEY UPDATE agent_id=VALUES(agent_id), filename=VALUES(filename), co -- ==================== ToolGuard Default Config & Rule Seed Data ==================== --- Global security config (single row) -INSERT INTO mate_tool_guard_config (id, enabled, guard_scope, guarded_tools_json, denied_tools_json, - file_guard_enabled, sensitive_paths_json, create_time, update_time) +-- Global security config (single row, insert only if not exists, never overwrite user config) +-- Note: tool names in guarded_tools_json must match @Tool method names (execute_shell_command / write_file / edit_file) +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 ( 1000000001, TRUE, 'all', - '["WriteFileTool","EditFileTool","ShellExecuteTool"]', + '["write_file","edit_file","execute_shell_command"]', '[]', TRUE, '["/etc","/usr","/bin","/sbin","/boot","/sys","/proc","/dev"]', + TRUE, 'INFO', 90, 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) -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 ( - 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); +-- Security rules are managed by ToolGuardRuleSeedService (Java) as single source of truth. +-- Removed 6 legacy SQL rules. Their superset is registered in ToolGuardRuleSeedService.buildBuiltinRules() with correct tool names. diff --git a/mateclaw-server/src/main/resources/db/data-mysql-zh.sql b/mateclaw-server/src/main/resources/db/data-mysql-zh.sql index 2c18ba96..0a5d77e3 100644 --- a/mateclaw-server/src/main/resources/db/data-mysql-zh.sql +++ b/mateclaw-server/src/main/resources/db/data-mysql-zh.sql @@ -1721,149 +1721,22 @@ ON DUPLICATE KEY UPDATE agent_id=VALUES(agent_id), filename=VALUES(filename), co -- ==================== ToolGuard 默认配置与规则种子数据 ==================== --- 全局安全配置(只有一行) -INSERT INTO mate_tool_guard_config (id, enabled, guard_scope, guarded_tools_json, denied_tools_json, - file_guard_enabled, sensitive_paths_json, create_time, update_time) +-- 全局安全配置(只有一行,仅首次初始化时插入,不覆盖用户修改) +-- 注意:guarded_tools_json 中的工具名必须与 @Tool 方法名一致(execute_shell_command / write_file / edit_file) +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 ( 1000000001, TRUE, 'all', - '["WriteFileTool","EditFileTool","ShellExecuteTool"]', + '["write_file","edit_file","execute_shell_command"]', '[]', TRUE, '["/etc","/usr","/bin","/sbin","/boot","/sys","/proc","/dev"]', + TRUE, 'INFO', 90, 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) -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 ( - 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); +-- 安全规则由 ToolGuardRuleSeedService (Java) 统一种子化,不在 SQL 中重复维护 +-- 已移除旧的 6 条 SQL 规则,其超集已在 ToolGuardRuleSeedService.buildBuiltinRules() 中以正确的工具名注册。 diff --git a/mateclaw-server/src/main/resources/db/data-zh.sql b/mateclaw-server/src/main/resources/db/data-zh.sql index b19f185e..fb4296b7 100644 --- a/mateclaw-server/src/main/resources/db/data-zh.sql +++ b/mateclaw-server/src/main/resources/db/data-zh.sql @@ -1724,149 +1724,26 @@ VALUES ( -- ==================== ToolGuard 默认配置与规则种子数据 ==================== --- 全局安全配置(只有一行) -MERGE INTO mate_tool_guard_config (id, enabled, guard_scope, guarded_tools_json, denied_tools_json, - file_guard_enabled, sensitive_paths_json, create_time, update_time) -KEY (id) -VALUES ( +-- 全局安全配置(只有一行,仅首次初始化时插入) +-- 注意:guarded_tools_json 中的工具名必须与 @Tool 方法名一致(execute_shell_command / write_file / edit_file) +-- 使用 SELECT + INSERT 确保已存在时不覆盖(H2 的 MERGE 会覆盖所有列,会重置用户修改的配置) +INSERT 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) +SELECT 1000000001, TRUE, 'all', - '["WriteFileTool","EditFileTool","ShellExecuteTool"]', + '["write_file","edit_file","execute_shell_command"]', '[]', TRUE, '["/etc","/usr","/bin","/sbin","/boot","/sys","/proc","/dev"]', + TRUE, 'INFO', 90, NOW(), NOW() -); +FROM DUAL +WHERE NOT EXISTS (SELECT 1 FROM mate_tool_guard_config WHERE id = 1000000001); --- 安全规则:WriteFileTool — 任意路径写入需要审批(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 ( - 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 -); +-- 安全规则由 ToolGuardRuleSeedService (Java) 统一种子化,不在 SQL 中重复维护 +-- 已移除旧的 6 条 SQL 规则(rule_id: write_file_any, edit_file_any, shell_rm_approval, +-- shell_rm_rf_block, shell_write_system_file, shell_chmod_777), +-- 它们的超集已在 ToolGuardRuleSeedService.buildBuiltinRules() 中以正确的工具名注册。 diff --git a/mateclaw-server/src/main/resources/db/schema-mysql.sql b/mateclaw-server/src/main/resources/db/schema-mysql.sql index de226ac1..d2036df6 100644 --- a/mateclaw-server/src/main/resources/db/schema-mysql.sql +++ b/mateclaw-server/src/main/resources/db/schema-mysql.sql @@ -347,6 +347,9 @@ CREATE TABLE IF NOT EXISTS mate_tool_guard_config ( denied_tools_json TEXT, file_guard_enabled TINYINT(1) NOT NULL DEFAULT 1, 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, update_time DATETIME NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; diff --git a/mateclaw-server/src/main/resources/db/schema.sql b/mateclaw-server/src/main/resources/db/schema.sql index 99fe0986..6fb75a5f 100644 --- a/mateclaw-server/src/main/resources/db/schema.sql +++ b/mateclaw-server/src/main/resources/db/schema.sql @@ -357,6 +357,9 @@ CREATE TABLE IF NOT EXISTS mate_tool_guard_config ( denied_tools_json TEXT, file_guard_enabled BOOLEAN NOT NULL DEFAULT TRUE, 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, update_time DATETIME NOT NULL ); diff --git a/mateclaw-ui/src/i18n/locales/en-US.ts b/mateclaw-ui/src/i18n/locales/en-US.ts index 6f8e9304..16be5a74 100644 --- a/mateclaw-ui/src/i18n/locales/en-US.ts +++ b/mateclaw-ui/src/i18n/locales/en-US.ts @@ -488,6 +488,15 @@ export default { audit: { title: 'Audit Logs', 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: { total: 'Total Checks', blocked: 'Blocked', diff --git a/mateclaw-ui/src/i18n/locales/zh-CN.ts b/mateclaw-ui/src/i18n/locales/zh-CN.ts index 33ddc1d8..0127a51f 100644 --- a/mateclaw-ui/src/i18n/locales/zh-CN.ts +++ b/mateclaw-ui/src/i18n/locales/zh-CN.ts @@ -488,6 +488,15 @@ export default { audit: { title: '审计日志', desc: '查看工具安全检查记录', + config: { + title: '审计配置', + enabled: '启用审计日志', + enabledHint: '关闭后将不再记录工具调用审计日志', + minSeverity: '最低记录等级', + minSeverityHint: '仅记录达到此等级及以上的审计事件', + retentionDays: '保留天数', + retentionDaysHint: '超过此天数的审计日志将被自动清理(0=永不清理)', + }, stats: { total: '总检查', blocked: '已阻止', diff --git a/mateclaw-ui/src/types/index.ts b/mateclaw-ui/src/types/index.ts index f742091a..097e6b9a 100644 --- a/mateclaw-ui/src/types/index.ts +++ b/mateclaw-ui/src/types/index.ts @@ -584,6 +584,9 @@ export interface GuardConfig { deniedToolsJson?: string fileGuardEnabled: boolean sensitivePathsJson?: string + auditEnabled?: boolean + auditMinSeverity?: string + auditRetentionDays?: number } export interface AuditLogEntry { diff --git a/mateclaw-ui/src/views/Security/AuditLogs/index.vue b/mateclaw-ui/src/views/Security/AuditLogs/index.vue index 26f3b01e..5efd9c71 100644 --- a/mateclaw-ui/src/views/Security/AuditLogs/index.vue +++ b/mateclaw-ui/src/views/Security/AuditLogs/index.vue @@ -7,6 +7,46 @@ + +
+

{{ t('security.audit.config.title') }}

+
+
+
+ + +
+

{{ t('security.audit.config.enabledHint') }}

+
+
+ + +

{{ t('security.audit.config.minSeverityHint') }}

+
+
+ + +

{{ t('security.audit.config.retentionDaysHint') }}

+
+
+
+
@@ -148,6 +188,37 @@ const auditTotal = ref(0) const auditFilters = reactive({ toolName: '', decision: '' }) const expandedRows = ref(new Set()) +// 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() { try { const params: any = { @@ -183,7 +254,7 @@ function toggleExpand(id: number) { } onMounted(async () => { - await Promise.all([loadAuditLogs(), loadAuditStats()]) + await Promise.all([loadAuditConfig(), loadAuditLogs(), loadAuditStats()]) }) @@ -192,6 +263,95 @@ onMounted(async () => {