行式输入安全(INV-LINE-01)

wesgine 统一处理行式输入的截断风险,避免 bufio.Scanner 默认上限导致的静默数据丢失。


核心问题

bufio.Scanner 超限时 Scan() 返回 false——与 EOF 同一个返回值:

for scanner.Scan() {
    // "这一行太长"被读成"输入结束了"
    // 循环正常退出,函数返回 nil
    // 调用方得到更短的答案和成功的状态
}

三次犯同样的错

本仓曾在三处犯同样的错误:

位置后果
Cell 导入丢弃 64KB 以上的行(数据丢失)
邮件头解析停在 Auto-Submitted: 之前,防环被长 References: 绕过(安全绕过)
pip list停在首个长行,低报环境能力(能力误判)

共同点不是"用了 Scanner",而是默认上限是别人给的数:64KB 从来不是谁决定的。


解决方案

内存输入

// 零拷贝、无上限
lines := bytes.Lines(data)

流式输入

// 超限报告而非结束流,下一个换行处重新同步
reader := lineio.NewReader(r, maxLineBytes)

internal/infra/lineio 的行为:


网络输入

读网络 body 必须显式 .Buffer(...):

scanner := bufio.NewScanner(conn)
scanner.Buffer(make([]byte, maxBytes), maxBytes)

上限一律命名常量并取自生产者上界:

同一条流只有一个名字。


截断处理策略

截断的处置必须显式选择:

场景策略
LLM delta(tool_call JSON 片段流)致命——丢一片拼不回来
wesgine 事件(自包含)跳过该条继续——丢一条只赔一条

lineio 自身的约束

禁止在 internal/infra/lineio 内部用 Scanner:


回归保护

测试 fixture 必须含 vacuity guard:


闸门

scripts/audit-lock/40-bounded-line-reads.sh


相关文档