
luckoneandClaude Code
f3fb37f70d
feat(notify): 漏洞发现支持推送到钉钉/飞书/企业微信等六种渠道
新增「系统 → 通知推送」页,把扫描发现的漏洞推送到钉钉、飞书、企业微信、
通用 Webhook、Telegram、邮件。同一类型可配任意多个机器人实例,每个实例独立
设启停、限流与过滤规则(最低级别 / 任务资产范围 / 漏洞类型关键词 / 是否接收
处置状态变更)。推送时机分实时与汇总两种模式,「高危实时、其余汇总」建两个
渠道即可表达,策略不写死在代码里。带投递历史与失败重发。
三个关键设计:
1. 写漏洞的事务只做一次盲 INSERT。notification_events 由 RecordFindingTx
在同一事务内写入,保证「漏洞落库」与「推送任务存在」原子一致;这条 INSERT
刻意不读渠道表、不跑用户的过滤规则,否则一条配错的过滤条件就能污染甚至
中止事务,让高危漏洞存不进库。为把失败隔离在这一条语句上(PostgreSQL 中
事务内任一语句报错会让整个事务作废、连 COMMIT 都失败),它被 SAVEPOINT
包住,失败时只记日志。
2. 投递用租约领取而非长事务。FOR UPDATE SKIP LOCKED 领取后把行置为 sending、
把 next_attempt_at 推到未来作为租约,提交后再做网络投递,因此投递期间不
持有数据库锁;崩溃留下的 sending 行会被下一轮重新领取,自愈且不会无限重试。
3. 限流不消耗重试预算。先按渠道令牌桶算出本轮还能发几条,再按这个数量领取;
顺序反过来会让被限流挡下的投递白计一次尝试,三次预算被等待耗光后落入失败。
审计并修复的四个问题:
- 推送凭据经错误信息外泄:http.Client.Do 返回的 *url.Error 会把完整 URL 打进
错误文本,而钉钉 access_token、企业微信 key、飞书 hook id、Telegram
/bot<token>/ 都就在 URL 里。该串流入 last_error(明文落库)、投递历史接口
(绕过渠道掩码)、服务端日志与前端错误提示。现统一脱敏为 scheme://host
+ 底层原因,并拒绝跨主机重定向。
- 最低级别门槛打错字会让过滤器静默失效:未知级别序数为 0,判定退化成
rank >= 0 恒真,用户以为限制「仅高危」实际全推。现于写入路径校验取值。
- 汇总批次无上限:一次领取把全部待发行读进内存、消息被渠道长度上限截掉大半
且静默丢失。现单批上限 500 条,超出部分留库成为下一批。
- 邮件渠道把 SMTP 4xx(灰名单等临时失败)判成永久失败,导致这类最该重试的
场景从不重试。现按应答码首位区分 4xx/5xx。
测试:notify 包 82% 覆盖(含用自建最小 SMTP 服务器驱动的完整邮件协议会话、
两种签名算法对 OpenSSL 基准值的比对、UTF-8 边界截断、以及模板能力边界的
反射断言);db 与 server 侧共 29 个用例跑真实 PostgreSQL,其中端到端用例
真发 HTTP 到假接收端并断言消息内容与投递状态。
Co-Authored-By: Claude Code <[email protected]>
2026-09-30 16:25:06 +08:00
..
2026-08-11 09:13:12 -04:00
2026-09-12 03:25:47 -04:00
2026-09-19 09:06:22 -04:00
2026-09-19 09:06:22 -04:00
2026-09-19 09:06:22 -04:00
2026-09-12 03:25:47 -04:00
2026-08-24 10:32:10 -04:00
2026-09-16 22:36:07 +08:00
2026-08-28 15:25:20 +08:00
2026-08-28 07:37:24 +08:00
2026-08-31 11:22:34 -04:00
2026-08-24 19:29:14 +08:00
2026-08-31 11:22:34 -04:00
2026-09-30 16:24:47 +08:00
2026-08-24 19:29:14 +08:00
2026-08-31 12:20:31 -04:00
2026-08-24 19:28:18 +08:00
2026-09-11 11:37:56 -04:00
2026-09-17 12:52:57 -04:00
2026-09-15 23:51:37 +08:00
2026-08-24 19:29:38 +08:00
2026-08-25 14:56:15 +08:00
2026-07-26 04:27:45 -04:00
2026-08-28 15:25:20 +08:00
2026-09-30 04:12:57 -04:00
2026-09-09 11:52:15 -04:00
2026-08-24 19:29:00 +08:00
2026-08-28 14:03:07 +08:00
2026-09-17 11:31:27 -04:00
2026-09-11 08:47:57 +08:00
2026-09-24 13:32:45 -04:00
2026-08-31 10:58:32 -04:00
2026-08-31 11:10:47 -04:00
2026-09-10 16:06:08 +08:00
2026-09-10 10:15:24 -04:00
2026-09-10 13:03:20 +08:00
2026-09-10 13:03:20 +08:00
2026-09-30 16:25:06 +08:00
2026-08-28 12:56:29 +08:00
2026-09-30 16:25:06 +08:00
2026-08-24 19:29:00 +08:00
2026-08-24 19:29:00 +08:00
2026-09-17 12:52:57 -04:00
2026-09-10 15:10:50 +08:00
2026-09-15 20:08:12 +08:00
2026-09-15 23:51:37 +08:00
2026-09-15 23:51:37 +08:00
2026-09-16 17:24:15 +08:00
2026-09-30 04:12:57 -04:00
2026-09-16 17:24:15 +08:00
2026-09-12 03:00:28 -04:00
2026-08-25 09:40:05 -04:00
2026-08-28 15:25:20 +08:00
2026-08-24 19:28:18 +08:00
2026-09-09 13:35:04 -04:00
2026-09-09 13:35:04 -04:00
2026-07-26 04:27:45 -04:00
2026-07-26 04:27:45 -04:00
2026-09-30 16:25:06 +08:00
2026-09-30 16:25:06 +08:00
2026-09-30 16:25:06 +08:00
2026-09-30 16:25:06 +08:00
2026-07-26 04:27:45 -04:00
2026-09-11 00:41:01 +08:00
2026-09-12 03:00:28 -04:00
2026-08-24 19:30:14 +08:00
2026-08-28 12:56:29 +08:00
2026-08-28 12:56:29 +08:00
2026-09-11 00:54:51 +08:00
2026-08-28 15:25:20 +08:00
2026-09-11 00:54:51 +08:00
2026-09-12 03:25:47 -04:00
2026-08-24 19:29:14 +08:00
2026-08-24 08:55:55 -04:00
2026-08-24 09:16:44 -04:00
2026-08-24 09:16:44 -04:00
2026-08-24 19:29:00 +08:00
2026-08-24 19:29:00 +08:00
2026-08-31 09:26:33 -04:00
2026-08-24 19:29:00 +08:00
2026-09-19 09:06:22 -04:00
2026-08-28 08:00:36 +08:00
2026-08-25 14:56:15 +08:00
2026-08-24 19:29:00 +08:00
2026-08-09 09:09:59 -04:00
2026-08-24 10:16:17 -04:00
2026-08-24 19:29:00 +08:00
2026-08-24 19:29:46 +08:00
2026-09-19 09:27:03 -04:00
2026-08-31 09:26:33 -04:00
2026-09-19 09:06:22 -04:00
2026-07-26 04:27:45 -04:00
2026-08-25 12:05:26 +08:00
2026-08-28 12:56:29 +08:00
2026-08-25 12:05:26 +08:00
2026-08-09 02:19:29 -04:00