- 新增 internal/channel/mediafetch:来源白名单(deny-by-default,支持 *.suffix) + 逐跳重定向校验 + 边读边限 + 超时;只回来源主机,绝不回完整 URL - 四渠道各自 media.go 接通入站内联:只从平台载荷给出的引用取回字节 (telegram file_id→getFile→file_path 形态校验;kook CDN;qq 文件段 url; weixin cdnURL + AES-ECB 解密) - 常量全部复用既有来源:documents.ExtAllowed / DefaultMaxBytes / MaxPerMessage - channelbridge 诚实提示文案改为对「渠道只给远程引用」与「代取失败」两种成因都成立 - 18 个测试函数(含四渠道「正文里的 URL ⇒ 0 次命中」红线反证、端到端进模型可见视图) - 变异验证:去掉尺寸上限 ⇒ 四渠道红(含修正后不再是假绿的 weixin 超量用例)
124 lines
5.2 KiB
Go
124 lines
5.2 KiB
Go
package channelbridge
|
||
|
||
// 本文件承载 IM 入站附件摄取的**诚实性与边界**用例(design/24 §4.4;切片 M1),
|
||
// 与 inbound_documents_test.go 是同一批夹具的搬家(夹具留在那边,同包可见):
|
||
//
|
||
// - 拒绝原因必须**分类正确**:超限说超限,绝不笼统说成「格式不支持」;
|
||
// - 渠道只给远程引用(目前适配器的现实形态)时不代取、不静默;
|
||
// - 图片类媒体保持现状(不走文档摄取);
|
||
// - 组合根未接线时照旧跑回合,但模型知道附件读不到。
|
||
|
||
import (
|
||
"context"
|
||
"strings"
|
||
"testing"
|
||
|
||
"git.yeij.top/AskaEth/Cyrene_v2/internal/channel/adapter"
|
||
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/documents"
|
||
)
|
||
|
||
// TestInboundOversizeFileIsHonestAboutSize 钉住诚实口径的**分类**:体积超限必须
|
||
// 说「超过体积上限」,绝不能笼统说成「格式不支持」——把原因说错也是不诚实。
|
||
func TestInboundOversizeFileIsHonestAboutSize(t *testing.T) {
|
||
t.Parallel()
|
||
env := newIngestEnv(t, documents.StoreConfig{MaxBytes: 8}, true)
|
||
msg := fileMessage("这个大吗", "big.txt", []byte("这是明显超过八个字节的正文\n"), "text/plain")
|
||
|
||
env.bridge.process(context.Background(), msg)
|
||
|
||
if names := docDirNames(t, env.uploads); len(names) != 0 {
|
||
t.Fatalf("超限附件被落库了:%v", names)
|
||
}
|
||
visible := env.model.visibleText()
|
||
if !strings.Contains(visible, "体积上限") {
|
||
t.Fatalf("超限附件的提示没有点明体积上限:%q", visible)
|
||
}
|
||
if strings.Contains(visible, "格式不在可读白名单内") {
|
||
t.Fatalf("超限附件被说成了「格式不支持」(原因说错):%q", visible)
|
||
}
|
||
if log := env.logs.String(); !strings.Contains(log, "inbound attachment rejected") {
|
||
t.Fatalf("缺少带来源的拒绝日志:%q", log)
|
||
}
|
||
}
|
||
|
||
// TestInboundRemoteOnlyMediaIsHonestWithoutFetch 钉住「字节为空」这一形态:桥接侧
|
||
// **不代取**(受支持格式的代取由适配器在入站时按平台资产白名单完成,切片 IM-1),
|
||
// 字节空 ⇒ 一行诚实提示 + 一条带来源的日志,绝不静默。
|
||
func TestInboundRemoteOnlyMediaIsHonestWithoutFetch(t *testing.T) {
|
||
t.Parallel()
|
||
env := newIngestEnv(t, documents.StoreConfig{}, true)
|
||
msg := directMessage()
|
||
msg.Content = "这个文件里是什么"
|
||
msg.Media = []adapter.Media{{
|
||
Kind: adapter.MediaFile, URL: "https://cdn.example.com/secret-token=abc/report.pdf",
|
||
Name: "report.pdf", Size: 1024, MIMEType: "application/pdf",
|
||
}}
|
||
|
||
env.bridge.process(context.Background(), msg)
|
||
|
||
if names := docDirNames(t, env.uploads); len(names) != 0 {
|
||
t.Fatalf("远程引用的附件被落库了:%v", names)
|
||
}
|
||
visible := env.model.visibleText()
|
||
if !strings.Contains(visible, "report.pdf") || !strings.Contains(visible, "远程引用") {
|
||
t.Fatalf("模型可见视图里没有诚实提示行:%q", visible)
|
||
}
|
||
log := env.logs.String()
|
||
if !strings.Contains(log, "no inlined bytes") {
|
||
t.Fatalf("缺少「无内联字节」的带来源日志:%q", log)
|
||
}
|
||
// 远程引用可能带凭据,绝不进日志。
|
||
if strings.Contains(log, "secret-token=abc") {
|
||
t.Fatalf("日志里出现了远程引用原串(可能含凭据):%q", log)
|
||
}
|
||
}
|
||
|
||
// TestInboundImageMediaKeepsExistingPath 钉住边界:图片类媒体**不**走文档摄取
|
||
// (design/24 §4.2 末:图片走既有视觉链路),因此不落库、不挂文档部件、不产生提示行。
|
||
func TestInboundImageMediaKeepsExistingPath(t *testing.T) {
|
||
t.Parallel()
|
||
env := newIngestEnv(t, documents.StoreConfig{}, true)
|
||
msg := directMessage()
|
||
msg.Content = "看这张图"
|
||
msg.Media = []adapter.Media{{
|
||
Kind: adapter.MediaImage, Name: "photo.png", MIMEType: "image/png",
|
||
Data: []byte("\x89PNG\r\n\x1a\n"), Size: 8,
|
||
}}
|
||
|
||
env.bridge.process(context.Background(), msg)
|
||
|
||
if names := docDirNames(t, env.uploads); len(names) != 0 {
|
||
t.Fatalf("图片类媒体被文档摄取落库了:%v", names)
|
||
}
|
||
visible := env.model.visibleText()
|
||
if strings.Contains(visible, "[附件 ") || strings.Contains(visible, "无法读取") {
|
||
t.Fatalf("图片类媒体产生了文档清单/提示行:%q", visible)
|
||
}
|
||
if !strings.Contains(visible, "看这张图") {
|
||
t.Fatalf("用户文本丢了:%q", visible)
|
||
}
|
||
if log := env.logs.String(); strings.Contains(log, "attachment") {
|
||
t.Fatalf("图片类媒体产生了附件日志:%q", log)
|
||
}
|
||
}
|
||
|
||
// TestInboundFileMediaWithoutStoreIsHonest 钉住「未接线」路径:组合根没给落盘配置时,
|
||
// 带文件的消息照旧能跑(模型收到诚实提示),只是不落库 —— 绝不假装读到了。
|
||
func TestInboundFileMediaWithoutStoreIsHonest(t *testing.T) {
|
||
t.Parallel()
|
||
env := newIngestEnv(t, documents.StoreConfig{}, false)
|
||
msg := fileMessage("这个文件呢", "notes.txt", []byte("正文\n"), "text/plain")
|
||
|
||
env.bridge.process(context.Background(), msg)
|
||
|
||
if env.model.calls() == 0 {
|
||
t.Fatal("未接线时回合没有跑到模型")
|
||
}
|
||
if !strings.Contains(env.model.visibleText(), "未接线文档存储") {
|
||
t.Fatalf("未接线时没有诚实提示:%q", env.model.visibleText())
|
||
}
|
||
if log := env.logs.String(); !strings.Contains(log, "document store not wired") {
|
||
t.Fatalf("未接线时没有带来源的日志:%q", log)
|
||
}
|
||
}
|