feat(backthink,browser): 自排工具面 C1-3 + 浏览器两处偏离收口(X2+X3 同文件一并落)

X2 C1-3(自排工具面与提示词):
- request_think(thinktool.go,照 transcode/tool.go 范式)+ reason 必填/urgency 闭集 + 双守门
  (安全闸 + owner 判定:群聊/陌生人一律拒)
- **成对**进两张唤醒态允许集(quiet + awake;CAPACITY_TOOL_SETS 是整体替换)
- 提示词抽共用段落 + 自排前缀优先(不枚举工具清单);面板加 self_wake 标签与筛选轴
- 4 个变异自检(拿掉 owner 判定/只加一张表/放宽 urgency/前端标签恒等)

X3 收口(与 X2 共用 wire_services.go ⇒ 一并落):
- 删掉第三份 SSRF 实现(guard.go),改由 io.ValidateRequestURL 唯一判定 + 薄门面(保两个错误身份)
- 浏览器会话挂进 a.close(真机:真 Chrome 被关、无残留、生产未扰动)
- a.wireBrowser() 归位到 wire_runtime.go,删掉 ioToolOptions 的临时挂点
- 5 个变异自检

顺带补提交 C1-2 漏掉的 internal/config/runtimeconfig/backthink_test.go(ed50053 漏 add)。
This commit is contained in:
AskaEth committed 2026-10-06 21:16:23 +08:00
1 parent 2bf3b536dd
commit 2d211c2d16
20 files changed
+1568 -176

No files matched your search

+18
View File
@@ -2,10 +2,13 @@ package browser
import (
"context"
"errors"
"net/http"
"net/http/httptest"
"strings"
"testing"
iotools "git.yeij.top/AskaEth/Cyrene_v2/plugins/tools/io"
)
// TestGuardURL_DeniesLoopbackAndPrivate 钉住守卫的**默认拒绝面**:回环、私网、
@@ -88,3 +91,18 @@ func TestGuardURL_RejectsHostResolvingToPrivate(t *testing.T) {
t.Errorf("httptest 地址 %s 应被拒(字面回环)", hostIP)
}
}
// TestGuardURL_KeepsBothErrorIdentities 钉住收口(切片 X3)之后的**双错误身份**:
// 判定本体搬去了 `io.ValidateRequestURL`,但本包的契约没动 —— 组合根/工具层仍按
// `ErrBlockedURL` 分类降级(`ReasonBlockedURL` 与它同源),而排障时能顺着链回溯到**唯一**
// 判定源(`io.ErrSSRF`)。少任何一个身份,「收口只搬判定、不动契约」就只是句口号。
func TestGuardURL_KeepsBothErrorIdentities(t *testing.T) {
t.Parallel()
_, err := GuardURL(context.Background(), "http://169.254.169.254/latest/meta-data/", nil)
if !errors.Is(err, ErrBlockedURL) {
t.Errorf("拒绝丢了本包契约身份 ErrBlockedURL: %v", err)
}
if !errors.Is(err, iotools.ErrSSRF) {
t.Errorf("拒绝丢了判定源身份 iotools.ErrSSRF: %v", err)
}
}