fix(multimodal): 视觉工具的空/畸形 data: URI 明确拒绝 + 入参嗅探与可行动报错
根因(从 checkpoints 取到的那一轮 tool_call 实际 ARGS 逐字节核实):
模型交给工具的 image 参数是 "data:image/png;base64," —— 只有前缀、
载荷为空(全长 22 字符)。两个加载器早就会剥 data: 前缀,但把空载荷
解码成零字节后照样挂上合法 MIME 放行:
image-crop → 零字节进 image.Decode ⇒ image: unknown format
vision → DataURI("image/png", nil) 发给上游 ⇒ 400 unsupported image
(模型复述不出入参里那条 58583 字符的 data: URI,只抄下了前缀。)
- 新增 checkInlinePayload:data: URI 解码后做内容嗅探(复用既有裁决)
- 空载荷 / 缺 ;base64 段 / 缺逗号 / 非法 base64 ⇒ 明确拒绝
- 报错含「不是图片」+ 嗅到的类型 + 支持格式 + 十六进制物证 + 可行动提示,
且不回显正文或 base64
- 裸 base64、http(s) URL、工具 schema、安全策略一律未动
- 测试:新增 16 个用例;全树 61 包 ok;4 个变异(含停用嗅探 ⇒ 5 用例红)
This commit is contained in:
1 parent
da1d23dd23
commit
789e3af74e
8 files changed
+636
-24
No files matched your search
@@ -9,6 +9,10 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
// pngSignature 是 PNG 的 8 字节魔数(http.DetectContentType 的判据)。
|
||||
// 体积口径类用例要在载荷头部带上它,才不会被内容嗅探当成文本否决。
|
||||
var pngSignature = []byte("\x89PNG\r\n\x1a\n")
|
||||
|
||||
// TestInlineImageLengthBoundary 钉住长度预检的边界与错误文案:恰好等于
|
||||
// 上限通过,多一个字符就报 ErrImageTooLarge。比较运算符一旦被挪位
|
||||
// (>= / <),或口径被换成另一个数,这里立刻红。
|
||||
@@ -90,13 +94,18 @@ func TestInlineImageSrc_RejectsOversizeDataURI(t *testing.T) {
|
||||
// (否则网关入口与解码层对「一张图能有多大」给出了两个答案),解码结果
|
||||
// 逐字节一致,绝不能误拒 —— 这正是「恰好 = 上限通过」的字节侧半边。
|
||||
//
|
||||
// 载荷头部带上 PNG 签名:本用例量的是体积口径,但 data: URI 解码后要过内容嗅探
|
||||
// (image.go 的 checkInlinePayload),纯填充字节会被嗅成 text/plain 而否决 ——
|
||||
// 那测的就是另一件事了。字节总长不变,故字符侧的口径换算不受影响。
|
||||
//
|
||||
// 判定口径是**字符数**(与网关入口一致,含 64 字符的 data: 前缀余量),
|
||||
// 因此多出几十字节的载荷仍可能落在余量内通过;字符侧的 +1 越界由
|
||||
// TestInlineImageLengthBoundary 钉住,余量本身不超过 64 字符
|
||||
// (TestMaxInlineImageCharsMatchesByteBudget)。
|
||||
func TestDecodeBase64_ExactBudgetImagePasses(t *testing.T) {
|
||||
t.Parallel()
|
||||
exact := bytes.Repeat([]byte{0x5a}, MaxInlineImageBytes)
|
||||
filler := bytes.Repeat([]byte{0x5a}, MaxInlineImageBytes-len(pngSignature))
|
||||
exact := append(append([]byte{}, pngSignature...), filler...)
|
||||
dataURI := DataURI("image/png", exact)
|
||||
if len(dataURI) > MaxInlineImageChars {
|
||||
t.Fatalf("满额图片编码后 %d 字符,超过上限 %d(口径不一致)", len(dataURI), MaxInlineImageChars)
|
||||
|
||||
Reference in new issue
Block a user