feat(gateway): 文档存储端点 POST/GET /api/v1/documents(design/24 S1)
- 字节嗅探唯一裁决 + 扩展名白名单 deny-by-default(23 个文本/代码扩展名);
客户端 Content-Type 与文件名只作参考、可被否决。
- 内容寻址落盘名 sha256[:32]+ext ⇒ 同字节同扩展名天然去重;首次 201/deduped:false,
命中 200/同一 name/deduped:true。
- 独立限额 CHAT_DOCUMENT_MAX_BYTES(默认 20 MiB,与图片 5 MiB 刻意解耦)+ MaxBytesReader。
- 读侧 Bearer owner|admin + Content-Disposition: attachment + nosniff(与图片读侧刻意不同);
写侧审计 document.upload;错误码 unsupported_media_type/document_too_large/document_not_found。
- 元数据表 documents(0014,含 idx_documents_name 唯一、idx_documents_sha256);
guardDocumentPaths 防路径穿越(否则 ServeMux 会 307 泄漏路径)。
- 既有 /api/v1/upload 与 /api/v1/files/{name} 零改动(upload.go 零 diff)。
验收(主会话独立复跑,非自报):隔离 worktree(HEAD + 本切片)go build/vet 绿、
全树 58 包 0 FAIL、linux/amd64 + darwin/arm64 交叉编译绿、9 条新单测 PASS。
变异独立复现 3 条:白名单加 ".js" ⇒ 415 用例红;嗅探裁决一律放行 ⇒ 谎报类型用例红;
摘掉 guardDocumentPaths ⇒ 穿越用例红(307 重定向,正是那道防护存在的理由)。
This commit is contained in:
1 parent
52f08dc343
commit
407c934a05
7 files changed
+1061
No files matched your search
@@ -31,6 +31,13 @@ ADMIN_PATH=admin
|
||||
# ≤0(写 0 或负数)= 用默认值 5 MiB,不是「禁用上限」——一张图能有多大只能有一个答案。
|
||||
CHAT_IMAGE_MAX_BYTES=5242880
|
||||
|
||||
# POST /api/v1/documents 的单文件字节上限,默认 20971520(20 MiB)。
|
||||
# 它与上面的图片上限【刻意解耦】:图片上限被 vision 解码层钳住,文档上限由本项目的解析与上下文预算决定;
|
||||
# 合用一个数会让「调文档上限」静默改掉图片行为。
|
||||
# 文档读侧(GET /api/v1/documents/{name})要 Bearer owner/admin,且一律 attachment + nosniff(永不可内联渲染)。
|
||||
# ≤0(写 0 或负数)= 用默认值 20 MiB,不是「禁用上限」。
|
||||
CHAT_DOCUMENT_MAX_BYTES=20971520
|
||||
|
||||
# ---- 认证 / 管理员 ----
|
||||
# JWT_SECRET 必填,长度 >= 32;缺失或过短会在启动时 panic。
|
||||
JWT_SECRET=change-me-to-a-random-string-at-least-32-characters
|
||||
|
||||
Reference in new issue
Block a user