Hinln
|
f3e3f54b6c
|
fix: use Hinln/ARTEX for authenticated release updates
|
2026-10-08 19:05:50 +08:00 |
|
Autumn-27
|
e6ec569991
|
docs(changelog): 定版 0.3.15
|
2026-10-07 08:54:02 -04:00 |
|
Autumn
|
fd86f3ceca
|
Merge pull request #197 from Autumn-27/fix/auth-init-fail-open
fix: 密码初始化/登录接口在数据库读失败时 fail closed
|
2026-10-07 19:47:48 +08:00 |
|
Autumn-27
|
a951e4aad3
|
fix bug
|
2026-10-07 07:45:28 -04:00 |
|
Autumn
|
b55ceb1fdd
|
Merge pull request #191 from Autumn-27/feat/judge-token-usage
feat(intercept): 模型兜底审批单独计量 token 并在配置页展示
|
2026-10-04 14:43:54 +08:00 |
|
Autumn-27
|
86729b65dc
|
feat(intercept): 模型兜底审批单独计量 token 并在配置页展示
兜底审批(LLM judge)调模型判定漏网命令,其 token 消耗此前无法单独查看:
usage 行要么无 worker 归属、要么被并进复用的模型 profile 桶里。
- llmrec 增加 WithWorker 上下文覆盖,reviewer 调用前标注 worker='judge',
让审批调用的计量行可被单独筛出(复用现有 llm_usage.worker 列,无需迁移)。
- db.JudgeUsageStats 返回累计总量 + 近 N 天每日序列(WHERE worker='judge')。
- 新增 GET /api/intercept/judge/usage。
- 配置页「模型兜底审批」开关下方新增用量卡片:调用次数 / 输入 / 输出 /
缓存读写 五项统计 + 近 30 天每日消耗迷你柱图 + 刷新。
|
2026-10-04 02:43:26 -04:00 |
|
Autumn
|
d0033724a6
|
Merge pull request #189 from Autumn-27/fix/sse-same-origin
fix(web): SSE 活动流默认同源,修复反代部署连不上 :8787
|
2026-10-03 08:10:35 +08:00 |
|
Autumn-27
|
e2c8a23a98
|
fix(web): SSE 活动流默认同源,修复反代部署连不上 :8787
sseUrl() 原先无条件把 SSE 地址拼成 ${hostname}:8787,连生产静态导出
也带这个硬编码。反代到 443 的部署里页面从 https://域名/ 加载,SSE 却被
指向 https://域名:8787/...,而 8787 未对公网开放,导致活动流连不上、反复重连。
改为用 NODE_ENV 区分:生产默认同源(相对路径),仅 next dev 保留 :8787
以绕过 Next.js /api 反代对 SSE 的缓冲。NEXT_PUBLIC_SSE_BASE 覆盖口保留。
验证:NEXT_EXPORT=1 next build 后生产包里 :8787 分支已被 tree-shake。
补充 README 反向代理部署文档(同源说明 + nginx 关缓冲配置)。
Closes #169
|
2026-10-02 20:10:08 -04:00 |
|
Autumn
|
160fe13c24
|
Merge pull request #187 from Autumn-27/fix/notify-digest-and-mask
fix(notify): 汇总模式退化、目的地留空误判、SMTP 缺 SSRF 守卫
|
2026-10-01 19:00:43 +08:00 |
|
Autumn
|
314105e827
|
Merge pull request #185 from lucksec/feat/vuln-im-push
feat(notify): 漏洞发现支持推送到钉钉/飞书/企业微信等六种渠道
|
2026-10-01 18:58:50 +08:00 |
|
Autumn-27
|
5081d95b99
|
fix(notify): 邮件渠道的 SMTP 拨号补上 SSRF 守卫
emailDial 用的是裸 net.Dialer,没挂 blockInternalDial,Validate 也只检查
host 非空。于是 SMTP 是整套 SSRF 防护里唯一的缺口:host 填 169.254.169.254
或 127.0.0.1 能直接连上,而 smtp.NewClient 握手失败时会把对端返回的那一行
(textproto 的 short response)包进错误、经 last_error 由投递历史接口回显,
正是其它渠道已经关掉的半盲读原语;「连接被拒 vs 超时」的耗时差异还能
用来探测端口。
拨号阶段是最终生效点,也覆盖 DNS 重绑定,与 HTTP 系渠道共用同一道守卫。
RFC1918 私网继续放行,与 isBlockedDialIP 既有的取舍一致——内网自建 SMTP
中继是常见的合法部署。
这个缺口没有测试会发现:本包 TestMain 全局打开了 ARTEX_NOTIFY_ALLOW_LOCAL,
邮件用例无论守卫在不在都会通过。新增的两条用例自己清掉该变量,
并配一条反向用例确认显式放开后本机 SMTP 仍可投递。
|
2026-10-01 06:43:48 -04:00 |
|
Autumn-27
|
77834f0080
|
fix(notify): 目的地字段留空不应被判成地址变更
Telegram 渠道从第二次保存起会永久失败,用户什么都没改也存不上:
新建时 base_url 留空(用官方 API 地址),创建路径直接存下 base_url:""
→ 第一次保存,MergeConfig 把空串当显式清空、delete 掉该键
→ 第二次保存,前端照常提交 base_url:"",而 stored 里已经没这个键
→ sameConfigValue("", nil) 比较 `""` 与 `null`,判为不等 → changed=[base_url]
→ bot_token 是掩码回显值 → 400「目标地址已变更,请同时重新填写凭据字段」
此后每次保存都失败,除非重新粘贴一遍 Bot Token,而错误提示还把人
往「凭据有问题」上引。
根因是 MergeConfig 与 sameConfigValue 对「空」的口径不一致:前者认为
空串就是「该删掉这个键」,后者认为 "" 与键不存在是两个不同的值。
现在比较前先归一化,口径与 MergeConfig 的清空判定对齐。
这是上一轮修「改目标地址、保留凭据」那条凭据外发路径时引入的回归——
守卫本身是对的,只是把一个没变的空字段误判成了地址变更。配套用例覆盖了
两个方向的真实变更(空→自建反代、自建反代→空)仍必须要求重填 Token,
确认防护没有被削弱。
|
2026-10-01 06:43:48 -04:00 |
|
Autumn-27
|
93c1d39df3
|
fix(notify): 汇总模式按消息计量限流,批次大小不再被每轮请求预算掐死
令牌桶的额度此前被同时当成两个量纲用:对实时模式它是「发几条消息」,
对汇总模式却被直接当成「一批装几条漏洞」传给 ClaimDigestBatch。
notifyMaxSendsPerChannelPerTick(=5)是由租约时长倒推的 HTTP 请求预算,
而一个汇总批次只发一次请求,两者本不该相乘。稳态下更糟:rate_per_min=20
的渠道在 3 秒的 tick 里只补得到 1 个令牌,于是每条汇总消息只装 1 个漏洞,
头部还写着「近 30 分钟新增 1 个漏洞」——digest 退化成带汇总文案的实时推送,
MaxDigestBatchSize(500) 永不可达。
改为统一按**消息条数**计量:一批漏洞合成一条消息、消耗一个令牌,
rate_per_min 对 digest 依然生效(每分钟最多这么多条汇总消息),
而批次大小只受 MaxDigestBatchSize 这个内存上界约束。
ClaimDigestBatch 原先的注释声称「单批同时受限流额度与内存上界约束」,
那正是本问题的来源——限流额度本不该充当批次大小。注释一并改掉,
免得下次又按「rate_per_min 对 digest 不生效」把它改回去。
顺带让 takeTokens 接受 want 上限:原先整桶抽空后才由调用方截断,
多出来的令牌(飞书默认 100/min 时是 95 个)直接丢弃,渠道这一轮
没有待发投递时也照扣,注释声称的突发容量在任何情况下都做不到。
决策收在 digestTickPlan 里由新增用例直接钉住。现有端到端用例都手动给
stepDigest 传一个够大的 limit,绕过了 step 里的额度计算,所以覆盖不到这里。
|
2026-10-01 06:43:29 -04:00 |
|
 luckoneandClaude Code
|
f2f35ebc2e
|
fix(notify): 复测判定「已修复」时也要推送状态变更
复测结论为 fixed 时,db/finding_retests.go 里是裸的
`UPDATE findings SET status=...`,绕过了带通知的版本——于是配了
on_status_change 的渠道对这种状态流转完全收不到推送:状态在界面上悄悄变了,
运维要打开平台才知道。
把「更新状态 + 登记状态变更事件」抽成事务级的 SetFindingStatusTx,供
patchFinding 与复测路径共用,两者的语义(状态没变就不登记、快照带全渲染字段)
由同一份代码保证,不会再出现只改一处的情况。
附回归用例:复测判 fixed 后必须有一条 finding_status_changed 事件,
且快照里的 from/to 与渲染字段正确。
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-09-30 16:25:06 +08:00 |
|
 luckoneandClaude Code
|
ee8929115e
|
refactor(web): 通知页拆分为组件,1095 行降到 605 行
页面此前接近 1100 行,超过 CLAUDE.md 的 800 行硬上限。按项目的 _components/
约定拆开,每个文件都能单独读懂:
_components/channel-fields.ts 渠道字段表与配置值解析(纯数据,无视图)
_components/channel-form.tsx 按字段定义渲染控件的表单
_components/delivery-list.tsx 投递记录表与筛选
_components/stat-tile.tsx 概览统计卡片
page.tsx 只负责编排:加载、表单状态、调接口
拆分是纯模块搬移,未改行为;tsc 与 next build 均通过,/system/notify 仍正常
预渲染。
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-09-30 16:25:06 +08:00 |
|
 luckoneandClaude Code
|
a049f09b97
|
fix(notify): 安全审计修复 —— 掩码绕过、SSRF、静默丢失等 12 项
对推送功能做了一轮安全审计,每条都先复现、再修、再补回归测试。
以下按严重程度排列。
【严重】掩码可被「改目标地址、保留凭据」绕过
目标地址与凭据是两套独立字段,而配置合并对「未提及的键」保留原值。于是
只改地址、对凭据避而不谈,服务端就会把库里的真凭据发到任意地址。已实测
复现四个渠道:通用 Webhook 的 Authorization 头、Telegram 的 Bot Token
(进请求路径)、邮件的 SMTP 密码(STARTTLS 后交给对端)、钉钉/飞书的加签
密钥(该项不可利用,一并列出仅为说明面)。完全静默、不依赖重定向,所以
上一轮加的「拒绝跨主机跳转」挡不住它。
修法:新增 Channel.DestinationKeys() 声明「消息发往哪」,PrepareConfigUpdate
在地址变化时要求对**每一个**凭据字段显式表态(给新值,或显式留空表示不再
需要)——原样回传掩码值等于「沿用旧凭据」,正是攻击形状,一并拒绝。
刻意不做「自动丢弃凭据」:对可选字段(如 headers)那会变成「鉴权静默没了
但接口返回成功」,比报错更难排查。
【中】markdown 系三渠道对不可信内容零转义
钉钉/企微/飞书此前完全不转义(Telegram 与邮件都做了),而标题与摘要来自
模型输出、资产 url 来自被测目标。一条标题里的 `[文字](http://evil)` 会在
工程师的钉钉里变成可点击外链;`` 会被客户端拉取,
泄露阅读者 IP 并暴露「这条已被看过」。现统一单行化 + markdown 元字符转义。
修的过程中还纠了自己一个设计错误:转义一度被放进 markdownTitle,而它被
markdown 正文、Telegram 的 HTML、飞书卡片、Webhook 的 JSON 与邮件主题四种
语境共用,markdown 的反斜杠泄漏到了 Telegram 消息里(用户会看到 `\(1\)`)。
转义必须发生在各自的渲染出口——测试直接抓到了这个回归。
【中】投递地址的 SSRF 面
此前只校验 scheme 与 host,云元数据 169.254.169.254、环回、内网一律可投递;
而失败响应体前 200 字节会进 last_error 并被投递历史接口回显,构成半盲读
原语。现在在**拨号阶段**设防(最终生效点,同时覆盖 DNS 重绑定与同主机
重定向)。环回/链路本地需显式 ARTEX_NOTIFY_ALLOW_LOCAL=1 才放行(本机
SMTP 中继是合法配置);RFC1918 私网**刻意放行**——内网自建 Mattermost /
SMTP 很常见,做到那个程度会把正常部署一起废掉,这条取舍写进了测试断言。
【中】汇总消息被截断后整批标记已送达 = 静默丢失
渠道都有长度上限(企微 4096 字节最紧)。此前渲染完整篇再截断、然后整批
标记成功:被截掉的那些既不在消息里、也不在失败列表里,投递历史还显示
成功。现改为按**整条**打包,只标记真正装下的,其余回队续发,消息头部
如实写明还有多少条在下一条。被推迟的条目**不消耗重试次数**(领取时乐观
+1 的那次减回去),否则 500 条的积压会在第三段就把尾部判成失败。
【中】其余修复
- min_severity 打错字让过滤器静默失效(未知级别序数为 0 → rank>=0 恒真,
用户以为「仅高危」实际全推)。改为写入时校验取值。
- rate_per_min=0(不限流)不可达:文档/UI/令牌桶都按 0=不限流解释,唯独
写库那层 `if <=0 取默认值` 把它改成 20 或 100。默认值改到接口层填。
- digest 渠道完全绕过令牌桶(allow 被扣却没人用)。
- 失败处置按整批 max(attempts) 判断,让老投递连坐同批的新投递。
- 汇总批次里快照无法解析的投递被静默标记成功。
- url.Parse 失败时错误文本仍带完整地址(上一轮只修了 http.Client.Do 那侧;
且当时的用例全走 scheme 分支、没覆盖解析失败路径,是假保证)。
- 单渠道每轮投递条数可能超出租约时长(多实例下重复发送)。加了防漂移
断言,写的时候立刻发现原取值 6 恰好用满租约、零余量,已改 5。
- Telegram 截断可能切断 HTML 实体,导致整条被拒收。
- 邮件把 SMTP 4xx(灰名单等临时失败)判成永久失败,最该重试的场景从不重试。
- 提交嵌套结构时会把掩码字面量真的写进库,导致鉴权静默失效。
测试:notify 包从 82% 提到 86%,新增 SSRF 守卫、掩码绕过(用攻击形状的
输入而非「防御逻辑的正确输入」)、分段投递收敛、markdown 转义、SMTP 4xx/5xx
分类等回归用例;端到端补了一条「60 条长标题跨多轮发完且不卡死」的收敛测试。
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-09-30 16:25:06 +08:00 |
|
 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 <noreply@anthropic.com>
|
2026-09-30 16:25:06 +08:00 |
|
 luckoneandClaude Code
|
18589b270e
|
fix(db): 修正公司 ICP 归属用例连接关闭顺序导致的资产残留
清理注册在 t.Cleanup 里,而连接关闭用的是 defer d.Close()。defer 在函数
返回时先执行、t.Cleanup 在其后,于是两条 DELETE 全部落在**已关闭的连接**
上,错误又被 `_, _ =` 丢弃,测试资产与公司因此永久残留在库里。
该用例用 MAX(companies.id)+1 当假 TaskID 给资产打标。残留本身不会立刻报错,
但一旦这个数字与其他用例的任务 id 相撞,那个按「恰好 N 个资产」断言的用例
就会失败,而现象(某个无关测试的资产计数不对)与原因(另一个测试的连接
关闭顺序)相距极远,排查成本很高。
改为关闭连接也走 t.Cleanup 并注册在清理之前(t.Cleanup 后进先出,保证清理
先跑),同时让清理失败显式报错而不是被吞掉。
注:同一模式(defer d.Close() + 在 t.Cleanup 里写库)在 db 包另有十余处,
本次只修被实证触发的那一处。
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-09-30 16:24:47 +08:00 |
|
Autumn
|
50b7b2a05b
|
Merge pull request #184 from Autumn-27/fix/finding-asset-tree-scroll
fix(findings): 「按资产」视图资产列表溢出时补回滚动条
|
2026-09-30 16:17:08 +08:00 |
|
Autumn-27
|
4b1eda8e92
|
fix(findings): 「按资产」视图资产列表溢出时补回滚动条
左侧资产树的滚动容器靠 height:100% 取高,但外层卡片只给了 max-height
没有确定高度,百分比高度解析失败,资产多时列表撑破卡片或被截断且无法
滚动。改为把高度上限直接放到资产树的原生滚动容器上(overflow-y-auto +
max-h,随窗口自适应),资产少随内容收缩、资产多封顶并出滚动条。
Closes #170
|
2026-09-30 04:16:43 -04:00 |
|
Autumn
|
b590898d1f
|
Merge pull request #183 from Autumn-27/feat/intercept-delete-path
feat(intercept): 新增内置拦截规则「删除类接口路径」
|
2026-09-30 16:15:15 +08:00 |
|
Autumn-27
|
527092f23b
|
feat(intercept): 新增内置拦截规则「删除类接口路径」
内置的 HTTP 破坏性规则只认 DELETE 方法(curl -X DELETE、requests.delete(、
method:'DELETE'),路径类规则的词表又只有 /clear /wipe /flush /purge /truncate
/drop /destroy /factory-reset /reset-all。而多数应用的删除接口用 GET/POST 就能
触发,于是 `curl 'http://t/api/user/delete?id=1'` 不命中任何内置规则,会真实删掉
目标数据。
补一条 deny 规则覆盖 /delete /del /remove /unlink /erase /destroy,允许
/deleteAll、/delete_user、/delete-user 这类后缀形式(destroy 是重复覆盖:v1 那条
不允许后缀,/destroyAll 是漏的)。动词后强制跟分隔符,/delivery、/details、
/delta、/delegate 不会被误拦。
种子走独立标记位 intercept_default_rules_v3,已有实例升级后也会拿到——改 v1 的
字面量对老库无效(标记位已是 done)。插入带 WHERE NOT EXISTS 兜底,标记位丢失也
不会插重复。正则提为包级常量,配纯正则单测(不依赖 DB)覆盖命中与误伤两侧。
|
2026-09-30 04:12:57 -04:00 |
|
Autumn
|
a8afd0bb98
|
Merge pull request #182 from Autumn-27/feat/traffic-clear-all
feat(traffic): 流量列表新增「清空全部」,并借空库时机压实索引
|
2026-09-30 14:55:47 +08:00 |
|
Autumn-27
|
2f5f7c0227
|
feat(traffic): 流量列表新增「清空全部」,并借空库时机压实索引
一次删除全部流量记录,忽略当前筛选条件。与按 host 删除的两条路径相比多做
两件事:
- 清理索引已不再记录的历史 host 目录。按 host 删除只能从索引反查目录,
行已消失的孤立目录会一直留着;「清空全部」既然语义是不留残余,就直接
扫顶层目录(跳过 _index/_blobs/_ca/_delete_staging)。
- 收尾做一次全量压实(optimize + VACUUM + wal_checkpoint(TRUNCATE)),把
索引占用的磁盘空间还给系统,并把实际释放量返回给前端提示。
VACUUM 的耗时与临时空间只和它保留的内容成正比,所以空库是做全量压实唯一
免费的时机——也正因如此,这一步顺带成为已有实例的转换途径:auto_vacuum
只能通过 VACUUM 生效,清空一次之后旧库即转为增量回收模式,此后日常按
host 删除就能自行回收空间(TestDeleteAllConvertsLegacyIndex 覆盖)。
已绑定到漏洞的流量证据保存在独立的证据库中,不受影响——绑定时已拷出独立
副本,正是为了让热流量可以随时清空而不带走证据。确认弹窗里明确写了这点。
前端把「清空全部」做成 outline 样式而非第二个 destructive 按钮:它忽略一切
筛选条件,不该看起来和「删除该目标」只差一次误点;无流量时禁用。
测试:新增 TestDeleteAllPurgesAndCompacts(清空后索引、正文、blob 引用与
孤立目录全清,空间回收到 1/8 以下,清空后仍可继续录制)与
TestDeleteAllConvertsLegacyIndex(旧库经清空后转为增量回收,随后普通删除
即可回收)。
|
2026-09-30 02:50:49 -04:00 |
|
Autumn
|
61d486160e
|
Merge pull request #180 from Autumn-27/fix/traffic-index-reclaim
fix(traffic): 删除流量后把索引空间真正还给操作系统
|
2026-09-30 13:54:28 +08:00 |
|
Autumn-27
|
3227f2e54c
|
fix(traffic): 删除流量后把索引空间真正还给操作系统
删除流量只让数据不可见,磁盘占用从不下降。两处原因叠加:
1. SQLite 删行仅把页挂到 freelist,而索引库建库时未启用 auto_vacuum,
文件永不收缩。256KB 以下的正文全部内联在这个库里,所以体积主体就在
这里,且只增不减。
2. ex_fts 是 contentless_delete 全文索引,DELETE 只写 tombstone、不回收
原 postings,从来没有合并过——删流量反而让索引变大(实测 exchanges
清零后 ex_fts_data 仍占 3.3MB / 840 行)。
trigram 索引约为正文体积的 2 倍,加上内联正文,抓包量大的实例会为早已
删掉的流量长期占用数倍磁盘:实测抓 6MB 文本正文 → 索引 16.2MB,删光后
仍是 16.2MB。
修复:
- 新建索引库在建表前启用 auto_vacuum=incremental。该 pragma 只在库中尚
无表时可设,且只有紧随的 VACUUM 才把它写入文件头,两步都必须落在同一
条连接上,故新增 initIndex 固定一条 *sql.Conn 串起 pragma 与建表。
- 新增 reclaim/reclaimChunk:删除提交后在后台分块执行全文索引增量合并、
incremental_vacuum 与 wal_checkpoint(TRUNCATE)(不做 TRUNCATE 则空间
留在 WAL 里、文件大小不变,PASSIVE 也清不掉)。接入 DeleteHost、
HostDeleteStage.Commit 与 RecoverHostDeleteStages 三条路径。
- 回收分块进行并在块间释放写锁:record() 由 go-mitmproxy 在把响应写回
客户端之前同步调用,一次性回收数 GB 会连带卡住被测请求。Close 先发停止
信号,剩余预算留给下次删除,不拖住进程退出。
- 终止条件按「是否有进展」判定:incremental_vacuum 只能释放挪得到文件
末尾的页,残留少量空闲页是正常结果;另加步数上限兜底。fts5 无法查询
索引是否已合并完(其特殊 INSERT 自身即计一次 changes),故改为固定合并
预算,未做完的留给后续删除。
- busy_timeout 改由 DSN 提供:它是每连接设置,原先的 db.Exec 只配到池中
碰巧被选中的那一条,其余连接在有写者时会立即失败而非等待。驱动按第一个
'?' 切分 DSN,故数据目录路径含 '?' 时退回裸路径 DSN。
已有实例的索引库仍是旧模式(auto_vacuum 无法事后开启),incremental_vacuum
在其上为空操作,启动时打印提示;此类库的 tombstone 增长已止住,已占体积
待后续「存储压缩」入口一次性回收。
测试:新增 reclaim_test.go(空间回收回归、tombstone 合并、新库模式、旧库
不卡死)与 upgrade_test.go(旧装机升级后同库同数据、全文与正文可用、
legacy path 行不受影响;以及降级回旧二进制仍可读写)。
|
2026-09-30 01:44:44 -04:00 |
|
Autumn
|
ca5512b48f
|
Merge pull request #179 from Autumn-27/feat/traffic-search-filter-sort
feat(traffic): 流量列表支持内容检索、路径/状态码/长度筛选与列排序 (#177)
|
2026-09-30 10:04:15 +08:00 |
|
Autumn-27
|
a4960b514e
|
feat(traffic): 流量列表支持内容检索、路径/状态码/长度筛选与列排序 (#177)
- 后端 traffic.Page 改为 PageQuery:新增响应内容(FTS)、路径(url_template)、
状态码(精确/Nxx 分桶)、响应长度范围筛选,并支持按 ts/status/resp_len 排序
(尾随 id DESC 保证分页稳定);补 status/resp_len 两个索引(IF NOT EXISTS,旧库自动生效)
- server getTraffic 解析 body/path/status/resp_min/resp_max/sort/order 参数
- 前端流量页新增高级筛选行(响应内容/路径/状态码/长度范围)与可排序表头,
排序偏好持久化到 localStorage;抽出公共组件 ui/sortable-head
- 仅改动前端页走的 Page,不动 Agent 工具的 query 契约
|
2026-09-29 21:58:17 -04:00 |
|
Autumn-27
|
02b1dbe6f8
|
chore(deps): 升级 norma 到 v0.4.3——工具输出全局兜底截断(harness 统一 CaptureOnce),任何工具都不再溢爆上下文
|
2026-09-29 21:14:08 -04:00 |
|
Autumn-27
|
71794729fc
|
fix(tools): MCP/自定义工具输出统一走 Capture 截断,修复 mcp 截断不生效 (#176)
|
2026-09-29 10:09:23 -04:00 |
|
榆木
|
25b6018818
|
fix(llm): 一次性 LLM 调用补挂 session id,让自定义会话头真正生效 (#175)
自定义会话头(profile 的 session_header_key)的头值取自请求 context 上的
session id,而该 id 由 agentcore 仅在挂载 transcript store 时才写入 context
(agentcore.Prompt 中 `if s.writer != nil` 那一行)。
目标拆解(第 0 轮,DecomposeGoalsWithProvider)与冷节点压缩(§4 body 调用)
都是不挂 store 的一次性调用,context 上没有 session id,quotaAwareTransport
因此跳过该头。对 opencode zen 这类「缺 x-opencode-session 直接 400
MissingSessionID」的端点,表现为「第 0 轮目标拆解 400 失败、后续 planner
轮次却完全正常」;压缩失败则只留一行日志,极难关联到本设置。
改为在这两条路径显式挂上按探索稳定的 session id(exp<N>-goals /
exp<N>-compactor),与旁路问答、连接测试已有的做法一致。附带修好用量归因:
这两个 id 能被 llmrec.parseSession 正确解析,此前这两条路径的 token 完全
记不进 llm_usage。
|
2026-09-29 18:21:30 +08:00 |
|
Autumn-27
|
69fe9357d3
|
chore(deps): 升级 norma 到 v0.4.2——修复 noa 压缩后 thinking/tool 消息被 provider 拒绝(#174)
|
2026-09-29 04:18:58 -04:00 |
|
Autumn-27
|
86162d7eda
|
docs(changelog): 定版 0.3.14
|
2026-09-24 13:35:48 -04:00 |
|
Autumn-27
|
87b3c3c770
|
feat(tasks): 漏洞列改为按严重度分档显示 严/高/中/低
- TaskListMetricsAll 用 COUNT(*) FILTER 按 severity 分四档统计(同一条查询)
- TaskListMetrics.Findings 及 TaskDTO.findings 由数字改为 {critical,high,medium,low}
- 列表页「漏洞」列渲染 x/x/x/x,配色沿用 severity 语义、为 0 的档位弱化
- severity 为空/白名单外的记录不计入任一档;mock 同步为对象结构
|
2026-09-24 13:32:45 -04:00 |
|
Autumn-27
|
e65d3e5202
|
feat(tasks): 任务列表新增漏洞数量列,描述/目标列收窄
- 任务列表接口 TaskListMetricsAll 批量统计每任务的漏洞数(findings 表,
按 task_id),经 TaskDTO.findings 下发;列表页新增「漏洞」列,>0 高亮
- 描述/目标列宽 max-w-xs → max-w-40,目标列补 title 悬浮全文
- mock data/handler 同步补 findings 字段
|
2026-09-24 13:26:22 -04:00 |
|
Autumn-27
|
9bc8d16a0b
|
fix(graph): 折叠后消除 digest↔finding 的反向重复边
yields(A→B) 与 derived_from(B→A) 互为逆关系,原图因产出/引用的 intent 不同
不成环;折叠进同一 digest 后两条边塌缩到 digest↔finding 同一对节点,分层布局
把其中一条画成叠着的反向箭头。重连后丢弃已存在正向 yields 的反向 derived_from,
保留生产方向(→成员)。
|
2026-09-24 13:23:06 -04:00 |
|
Autumn-27
|
b5704eb361
|
refactor(graph_overview): related_tasks 冷区统一走 coldDigestsRecent 并封顶
- coldDigestsRecent 改为接收 store 的自由函数,主概览与关联任务概览共用
- related_tasks 的 cold_digests 由无上限的 activeDigestBodies 换成
coldDigestsRecent(ts, 6):按最新成员时间排序、每源截 6,溢出 digest id
带 inherited/source_task_id 入 cold_digests_more,仍可 expand_digest 展开
- 删除随之无用的 activeDigestBodies
|
2026-09-24 13:11:28 -04:00 |
|
Autumn-27
|
3aac6754a8
|
refactor(graph_overview): 概览各列表加数量上限,止住上下文膨胀
用"最新一窗 + 计数/pull 兜底"替换 hot/cold 拆分与 balancedCap:
- recent_facts 20、recent_done_intents 12、open_intents 30(按 priority)
- cold_digests 15,按最新成员时间(max member id)降序,溢出的更旧 digest
只给裸 id(cold_digests_more),仍可 expand_digest 展开
- 新增 CountOpenIntents,frontier_open 报开放意图真实总数(与截断视图解耦)
- 删除 balancedCap/unfoldedCap/unfolded_truncated 及其测试
掉出窗口的节点不丢:facts/done_intents_total/frontier_open/findings_total
计数在,list_facts/list_findings/node_detail/expand_digest 可按需回捞
|
2026-09-24 13:05:27 -04:00 |
|
Autumn-27
|
43d1743dc0
|
refactor(graph_overview): finding_list 限最新 10 条,findings 计数改名 findings_total
- finding_list 只带最新一窗(≤10,vulnNodes 按 id 降序即最新在前),
全量/更早的用 list_findings 取
- 顶层计数字段 findings → findings_total,与 done_intents_total 命名惯例
一致、并与 finding_list 明确区分计数/明细;同步 planner 验收提示文案
|
2026-09-24 12:32:43 -04:00 |
|
Autumn-27
|
06a43f37ff
|
refactor(graph_overview): 精简态势概览字段
- 删除 cold_index 字段及其 expand_index 工具(含两处注册),移除
仅服务它的 coldDigestOverview 分桶逻辑(改用 activeDigestBodies)
- 删除 covered_members 字段(悬空血缘解析表)
- 删除 coverage.scope 字段(范围根资产 + company 富化)
- finding_list 每条仅保留 id/summary/from_intent,去掉 evidence/assets,
并清理随之无用的 findingMeta 预计算与 assetValue 辅助函数
|
2026-09-24 12:24:01 -04:00 |
|
Autumn
|
bf7f414477
|
Update CHANGELOG.md
|
2026-09-19 23:37:57 +08:00 |
|
Autumn-27
|
7b92395aa0
|
docs(changelog): 版本号改为 0.3.13
|
2026-09-19 11:23:33 -04:00 |
|
Autumn-27
|
2943eb2ea6
|
docs(changelog): 定版 0.4.0
|
2026-09-19 11:20:03 -04:00 |
|
Autumn-27
|
37950f4a6f
|
fix(task-archive): 遇到符号链接跳过而非整包失败
归档格式端到端只支持普通文件与目录(解包端对其它类型直接报错),原打包器遇到
任何 symlink 即整包失败(task archive refuses symlink),导致工作目录里一条软链
就卡死整个任务归档。改为跳过该符号链接并记日志:lstat 不跟随、不越出目录树、
不写 symlink 条目;链接指向树内时目标文件仍会被单独遍历归档。安全防护不变。
新增 TestTaskArchivePackageSkipsSymlink 覆盖。
|
2026-09-19 11:08:15 -04:00 |
|
Autumn-27
|
33c26dc72a
|
fix(intercept): 收紧裁判输出协议,减少 1024 截断导致的 fail-open
- 裁判 comment 上限 500→120 汉字,每段一句话、宁短勿长,合规裁决远低于
MaxTokens=1024,基本消除截断(截断会致输出无法解析而按失败策略放行)。
- 硬化「只输出 JSON、不带思考/前言/代码块包裹」,减少非 JSON 前言吃掉 token
预算。保留 实际操作/成功后的后果/命中规则 三段结构,与 ParseVerdict 一致。
- docs(readme): 精简审批详情/上下文模型审查一节。
|
2026-09-19 10:24:08 -04:00 |
|
Autumn-27
|
777730e255
|
feat: 任务模板支持预设分类与任务级拦截/允许规则
- db: task_templates 加 category_id(FK task_categories, ON DELETE SET NULL)
与 intercept_rules JSONB(规则快照);带幂等 ALTER 补旧库。
- db/task_templates.go: 用 JSONB 存取规则;PATCH 用 Set 标志区分改/清。
- server: 模板请求体加 category_id + intercept_rules,复用 buildTaskInterceptRules
校验;PATCH 靠原始 key presence 判断是否更新(可清分类为 null)。
- web: 抽共享组件 asset-intercept-rules-editor(NativeSelect 版,避免 Sheet 内
下拉 portal 误关抽屉),创建表单与模板管理器共用;模板管理器新增分类下拉与
规则编辑区,另存为模板带当前分类/规则;应用模板回填分类与规则。
|
2026-09-19 09:27:03 -04:00 |
|
Autumn-27
|
d5359e1f04
|
feat: 资产拦截接入执行链,新增任务级拦截/允许规则
在 agent 下发意图(add_intent)与插入资产(insert_assets)两处接入资产闸门;
并新增任务级规则(拦截 block + 允许 allow 白名单),创建任务时录入、任务详情
总览里可编辑。
- 匹配/执行(db/asset_intercept_match.go):MatchAssetInterceptRules 纯匹配
(exact/fuzzy 的 域名·IP·URL + CIDR,URL host 会拆出归类);EvaluateAssetGate
「先拦截后允许」闸门——命中拦截即禁止;未命中但存在启用的允许规则且都不命中→
不允许测试;无启用允许规则则不启用白名单。附单元测试。
- 执行点:add_intent 命中即不下发意图;insert_assets 命中即跳过 Upsert 及
AddAutoScope 副作用。均合并 全局∪任务级 规则。
- 任务级规则:表 task_intercept_rules(task_id FK CASCADE + action block/allow,
幂等 ALTER 补旧库);db/task_intercept.go 提供 List/Split/CRUD/事务插入;
创建任务随 intercept_rules 提交;CRUD 路由 /api/tasks/{id}/intercept-rules。
- 前端:新建任务抽屉多行录入(拦截/允许 + 类型,用 NativeSelect 避免 Sheet 内
下拉 portal 导致误关抽屉);任务详情总览新增规则管理卡片(增删改+启用开关)。
|
2026-09-19 09:06:22 -04:00 |
|
Autumn-27
|
dfc9d2fa2e
|
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 与类型定义
|
2026-09-19 07:58:23 -04:00 |
|
Autumn-27
|
a590b415ba
|
chore(deps): 升级 norma 至 v0.4.1
|
2026-09-19 07:26:47 -04:00 |
|
Autumn-27
|
6f6be46480
|
feat(web): 登录前新增使用须知与免责声明弹窗,须勾选同意后方可登录
|
2026-09-18 08:09:05 -04:00 |
|