feat: 新增资产拦截规则(全局黑名单)增删改查

新增独立于命令拦截(intercept_rules)的资产拦截功能,仅提供规则的
存储与管理;具体匹配/拦截逻辑另行实现。

- db: 新增 asset_intercept_rules 表(schema.sql,幂等)与 CRUD 层
  (db/asset_intercept.go);kind 支持全等/模糊的 域名·IP·URL 及 CIDR
- db: 首启动 seed 内置模糊拦截政府(.gov/.gov.cn)与教育(.edu/.edu.cn)
  网站,settings 标记位门控,可禁用/删除且重启不复活
- server: /api/asset-intercept/rules 的 list/create/update/delete/toggle;
  cidr、exact_ip 做格式校验
- web: 新增「资产拦截」页(/system/intercept/assets)与侧边栏入口、
  api 与类型定义
This commit is contained in:
Autumn-27 committed 2026-09-19 07:58:23 -04:00
1 parent a590b415ba
commit dfc9d2fa2e
9 files changed
+687

No files matched your search

+32
View File
@@ -261,9 +261,41 @@ ON CONFLICT (name) DO NOTHING`,
if err := d.seedDefaultInterceptRulesV2(); err != nil {
return fmt.Errorf("seed intercept rules v2: %w", err)
}
if err := d.seedDefaultAssetInterceptRules(); err != nil {
return fmt.Errorf("seed asset intercept rules: %w", err)
}
return nil
}
// seedDefaultAssetInterceptRules inserts the built-in asset blocklist (fuzzy
// domain matches for government / education sites) once on first startup. Gated
// by a settings flag so a user's later disable/delete is never resurrected on
// restart — same policy as the intercept-rule seed.
func (d *DB) seedDefaultAssetInterceptRules() error {
if v, _, _ := d.GetSetting("asset_intercept_default_rules_v1"); v == "done" {
return nil
}
rules := []struct {
kind string
pattern string
note string
}{
{"fuzzy_domain", ".gov", "[内置] 政府网站 (.gov)"},
{"fuzzy_domain", ".gov.cn", "[内置] 政府网站 (.gov.cn)"},
{"fuzzy_domain", ".edu", "[内置] 教育网站 (.edu)"},
{"fuzzy_domain", ".edu.cn", "[内置] 教育网站 (.edu.cn)"},
}
for _, r := range rules {
if _, err := d.Exec(`
INSERT INTO asset_intercept_rules(enabled, kind, pattern, note, builtin)
VALUES (true, $1, $2, $3, true)
ON CONFLICT DO NOTHING`, r.kind, r.pattern, r.note); err != nil {
return fmt.Errorf("asset rule %q: %w", r.pattern, err)
}
}
return d.SetSetting("asset_intercept_default_rules_v1", "done")
}
// builtinSkillVisibility maps a shipped skill's directory name → the built-in
// agent keys that should see it by default. The skill FILES themselves live on the
// filesystem (SkillDir, loaded by norma at runtime); DB only carries this visibility