Files
Cyrene_v2/internal/capability/browser/ssrf.go
T
AskaEth 2d211c2d16 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)。
2026-10-06 21:16:23 +08:00

42 lines
2.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package browser
import (
"context"
"fmt"
"net/url"
iotools "git.yeij.top/AskaEth/Cyrene_v2/plugins/tools/io"
)
// GuardURL 是浏览器侧访问 SSRF 判定的**唯一入口**,判定本体**只有一份**:
// `plugins/tools/io.ValidateRequestURL`(design/28 §4:「复用既有 `io/ssrf` 白名单,
// **不新增第三份实现**」)。
//
// **为什么这里只留一层薄门面(切片 X3 的收口)**:本包原先自带一份与 io 同策的实现
// (`guard.go`:自己的 scheme 判定 + 网段表 + 白名单比对),只因为当时 io 侧的
// `validateRequestURL` 没导出、该包又不在那一片的文件面里。两份同策代码的危险不在
// 当下的结论,而在**以后只改一处** —— 改完两边静默分叉,浏览器侧的导航就成了绕过面。
// 收口后本文件只做两件事:
//
// 1. 调 `io.ValidateRequestURL`(**唯一**判定源:scheme → 白名单短路 → 字面 IP 网段
// 否决 → 解析后再按同一张表否决);
// 2. 把它的错误翻成本包对外的 `ErrBlockedURL` —— 这是**契约**不是判定:
// `ErrBlockedURL` / `ReasonBlockedURL` 是工具层与组合根(含后续 M3 面板入口)用来
// 分类降级与记日志的标识,收口只搬判定,不动契约。
//
// 两个错误身份都保住(`%w:%w`):`errors.Is(err, ErrBlockedURL)` 成立(本包契约),
// 网段/解析类拒绝上 `errors.Is(err, iotools.ErrSSRF)` 同样成立(判定源),io 侧的原因
// 文案(哪个网段、解析到哪个地址)一字不丢地进日志。形状错误(空 URL、非 http(s))
// 在 io 侧本就不带 ErrSSRF,那几档只有本包身份。
//
// 为什么浏览器侧必须有这道闸:导航是**服务端代取用户/模型给的任意 URL**,不过闸就
// 等于把云元数据端点(`169.254.169.254`)、内网管理面暴露给一次提示词注入
// (design/28 §4 第 1 条;M3 面板入口同样过闸)。
func GuardURL(ctx context.Context, rawURL string, allowed []string) (*url.URL, error) {
u, err := iotools.ValidateRequestURL(ctx, rawURL, allowed)
if err != nil {
return nil, fmt.Errorf("%w:%w", ErrBlockedURL, err)
}
return u, nil
}