fix(weixin_ilink): drop user file name from media failure log; fix TestLogin_LogRedaction data race

This commit is contained in:
AskaEth committed 2026-10-26 22:00:09 +08:00
1 parent d47185feb8
commit e39cc5d096
3 files changed
+85 -14

No files matched your search

+17 -4
View File
@@ -93,8 +93,9 @@ func (a *Adapter) sendGuard() error {
//
// **单条媒体的失败绝不连累文本**:媒体只是附件,回复的主体是文字。真机实测
// (2026-10-04)就是「媒体项构建失败 ⇒ 整条回复被判失败 ⇒ 她的中文文本一起没了」。
// 因此这里逐条构建,失败的那条跳过并留一条带来源的 Warn(kind/name/原因),文本项
// 照常发出;全部媒体都失败也仍然发文本。失败必须可诊断,但绝不等于整条回复失败。
// 因此这里逐条构建,失败的那条跳过并留一条带来源的 Warn(kind/size/序号/原因),
// 文本项照常发出;全部媒体都失败也仍然发文本。失败必须可诊断,但绝不等于整条回复
// 失败。
func (a *Adapter) sendToOne(ctx context.Context, peer string, m adapter.UnifiedMessage) error {
if peer == "" {
return ErrNoContextToken
@@ -109,14 +110,26 @@ func (a *Adapter) sendToOne(ctx context.Context, peer string, m adapter.UnifiedM
items = append(items, nativeTextItem(m.Content))
}
var mediaErr error
for _, md := range m.Media {
for i, md := range m.Media {
item, err := a.buildMediaItem(ctx, peer, md)
if err != nil {
if mediaErr == nil {
mediaErr = err
}
// 🔴 `md.Name` **整字段不进日志**(M56)。它是**用户侧自由文本**:出站媒体名
// 来自调用方给的 adapter.Media.Name,入站侧就是用户自己起的文件名,可以是
// 「身份证-张三.jpg」这类内容 —— 与同一行的 peer/kind/size 不是一类东西。
//
// 为什么删字段、而不是打码或截断:包内可复用的打码(trace.RedactTextLimited)
// 是**按形状**认凭据的,对「长得像人话的文件名」完全无效;截断则必然留下前 N
// 个字符,而中文文件名的头几个字往往就是全部有意义的部分 —— 两种修法都只是
// 把泄露面缩小一点,并没有关上。而这个字段对排障**零贡献**:失败原因在 err
// 里,出问题的是哪一条由 kind + size + 下标(index)唯一确定。删字段因此是
// 严格更强、又不损失诊断力的选择。包内已有同一口径的先例:入站取证行
// (inbound_debug.go 的 inboundMediaShape)同样明确「正文、文件名、URL 原串
// 与一切密钥都不取」—— 日志面从不承载用户侧的正文/文件名,两个方向一致。
a.log.Warn("outbound media item skipped",
"peer", peer, "kind", md.Kind, "name", md.Name, "size", md.Size, "err", err)
"peer", peer, "kind", md.Kind, "size", md.Size, "index", i, "err", err)
continue
}
items = append(items, item)