fix(guard): align tool guard rule names with runtime @Tool method names and add audit config

This commit is contained in:
matevip 2026-04-05 12:00:50 +08:00
parent e14759638e
commit bcf37d95fe
17 changed files with 499 additions and 567 deletions

View File

@ -42,7 +42,7 @@ public class ShellExecuteTool {
@Tool(description = "在本地服务器上执行 Shell 命令。用于执行系统命令、查看文件、运行脚本等操作。"
+ "Windows 下使用 cmd.exeLinux/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) {

View File

@ -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);

View File

@ -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,

View File

@ -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;

View File

@ -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;
/**
* 工具安全审计服务
* <p>
* 支持审计开关最低记录等级过滤过期日志自动清理
*/
@Slf4j
@Service
@ -26,13 +30,33 @@ public class ToolGuardAuditService {
private final ToolGuardAuditLogMapper auditMapper;
private final ObjectMapper objectMapper;
private final ToolGuardConfigService configService;
/**
* 异步记录审计日志
* <p>
* 受审计开关和最低等级过滤控制
* <ul>
* <li>auditEnabled=false 不记录</li>
* <li>maxSeverity 低于 auditMinSeverity 不记录</li>
* </ul>
*/
@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<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) {
try {
return objectMapper.writeValueAsString(evaluation.findingsToMapList());

View File

@ -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() {

View File

@ -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;
/**
* 规则种子服务
* <p>
* 首次启动时将内置规则写入 DB
* 已存在则跳过通过 rule_id UNIQUE 约束
* 启动时完成三项工作
* <ol>
* <li>迁移旧版工具名类名 @Tool 方法名+ 清理旧 legacy 规则</li>
* <li> rule_id 逐条 upsert 内置规则不存在则插入已存在则同步更新</li>
* <li>迁移 guardedToolsJson 中的旧工具名</li>
* </ol>
*/
@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<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
public void run(ApplicationArguments args) {
migrateOldData();
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() {
try {
Long existingCount = ruleMapper.selectCount(
// 加载已有 builtin 规则 rule_id 索引
List<ToolGuardRuleEntity> existingList = ruleMapper.selectList(
new LambdaQueryWrapper<ToolGuardRuleEntity>()
.eq(ToolGuardRuleEntity::getBuiltin, true));
if (existingCount > 0) {
log.info("[RuleSeed] {} builtin rules already exist, skipping seed", existingCount);
return;
}
Map<String, ToolGuardRuleEntity> existingMap = existingList.stream()
.collect(Collectors.toMap(ToolGuardRuleEntity::getRuleId, e -> e, (a, b) -> a));
List<ToolGuardRuleEntity> 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<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) {
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() {
List<ToolGuardRuleEntity> 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));

View File

@ -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.

View File

@ -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.

View File

@ -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() 中以正确的工具名注册。

View File

@ -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() 中以正确的工具名注册。

View File

@ -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;

View File

@ -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
);

View File

@ -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',

View File

@ -488,6 +488,15 @@ export default {
audit: {
title: '审计日志',
desc: '查看工具安全检查记录',
config: {
title: '审计配置',
enabled: '启用审计日志',
enabledHint: '关闭后将不再记录工具调用审计日志',
minSeverity: '最低记录等级',
minSeverityHint: '仅记录达到此等级及以上的审计事件',
retentionDays: '保留天数',
retentionDaysHint: '超过此天数的审计日志将被自动清理0=永不清理)',
},
stats: {
total: '总检查',
blocked: '已阻止',

View File

@ -584,6 +584,9 @@ export interface GuardConfig {
deniedToolsJson?: string
fileGuardEnabled: boolean
sensitivePathsJson?: string
auditEnabled?: boolean
auditMinSeverity?: string
auditRetentionDays?: number
}
export interface AuditLogEntry {

View File

@ -7,6 +7,46 @@
</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 -->
<div class="stats-grid">
<div class="stat-card">
@ -148,6 +188,37 @@ const auditTotal = ref(0)
const auditFilters = reactive({ toolName: '', decision: '' })
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() {
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()])
})
</script>
@ -192,6 +263,95 @@ onMounted(async () => {
</style>
<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 {
display: grid;