對齊 ADR-016:visionA backend 不再直連 FAA、download 改走 converter GetResult。T3 砍除 v0.5 階段為 FAA delegated token 路線留的 faa_client.go 整檔 + 對應 sentinel + flow / e2e 殘留。 砍除: - internal/conversion/faa_client.go(整檔) - internal/conversion/faa_client_test.go(整檔) - errors.go: ErrFAAFileNotFound + ErrFAAAuthFailed 2 sentinel(+ ErrorCode/HTTPStatus mapping) - flow.go: faa FAAClient 欄位 + FlowOpts.FAA 必填 + a-h T3 預期清單 godoc - flow_test.go: flowStubFAA struct + newFlowStubFAA helper + fixture.faa - internal/api/conversion_test.go: TestConversion_Download_FAAAuthFailed - cmd/api-server/main.go: NewFAAClient wire + FAA: faaAPIClient field 保留: - ErrFAAUnavailable(converter promote 仍 PUT FAA、502 透傳路徑需要) - hashObjectKey helper 搬到 util.go(ownership 仍用) - e2e mockFAA 精簡為 regression-only(保留 negative assertion: FAA 0 命中)— reviewer 推薦雙層防護 新增(T3 必補,T1/T2 reviewer 累積): - s-3 TestDownloadStream_ConverterValidationFailed_Propagation(converter 4xx fallback → ErrValidationFailed 透傳) - s-4 TestPromoteToModels_StorageError_StreamClosed(instrumented stream wrapper 驗 fd leak 防護) - s-5 TestParseFilenameFromContentDisposition 9 個 sub-case(3 RFC 5987 + 5 hostile-input + 1 empty quoted) 發現:Go stdlib 自動 percent-decode RFC 5987 並寫入 params["filename"]、RFC 5987 優先於 ASCII filename T3 review M-1 修補(commit 內含): - internal/api/conversion.go:51,56 godoc + 501 user-facing message 從「FAA_BASE_URL」改為「VISIONA_CONVERTER_BASE_URL + VISIONA_CONVERTER_API_KEY」 - 對齊 ADR-016 visionA 端不再有 FAA 直連設計 驗證: - B 層 verification 強制跑(reviewer 規定 T3 不接受暫緩): * 跨檔 grep: MC chain 0 / FAA functional refs 0 / TenantID 0 * API contract test: TestConversionE2E_DownloadStream 6 斷言含 FAA negative * 安全 manual review: path traversal / unbounded read / secret in log / error mask 4 項 - go build ./... exit 0 - go test -race -count=3 ./... 17 packages 全綠 - Reviewer 5 軸(v0.6-t3-review)⚠️→ ✅ 通過(M-1 已修) a-h 8 條清單 100% 達成(逐條 grep 驗收);mockFAA 選方案 1(保留 + negative assertion)— 雙層防護。 下一步: - T4 砍 ConversionConfig.FAAAPIKey/FAABaseURL + load.go env 讀取 + .env*.example + m-2 i18n dead case 一併 - T5 main.go startup log 整理 + e2e regression 防護 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
40 lines
1.6 KiB
Go
40 lines
1.6 KiB
Go
// Package conversion 內部 utility helpers。
|
||
//
|
||
// 此檔收容跨檔共用的小型 helper(log truncate / object key hash 等),原本散落在
|
||
// mc_token_client.go / faa_client.go;Phase 0.8b T3 砍上述兩檔後搬到此獨立檔,
|
||
// 避免被連帶砍除(仍被 converter_client.go / flow.go 的 log 拼接使用)。
|
||
//
|
||
// Phase 0.8b v0.6 conversion (見 ADR-016 / docs/autoflow/04-architecture/conversion.md §2)
|
||
package conversion
|
||
|
||
import (
|
||
"crypto/sha256"
|
||
"encoding/hex"
|
||
)
|
||
|
||
// objectKeyHashLen 是 log 中 object_key 的截短後 hash 長度(前 16 hex chars)。
|
||
const objectKeyHashLen = 16
|
||
|
||
// truncate 把字串截到 max 長度(避免 log 太長)。
|
||
func truncate(s string, max int) string {
|
||
if len(s) <= max {
|
||
return s
|
||
}
|
||
return s[:max] + "...(truncated)"
|
||
}
|
||
|
||
// hashObjectKey 把 object_key 算 SHA-256 後取前 16 hex chars,當 log 用的穩定 hash。
|
||
//
|
||
// 為什麼不直接 log object_key:
|
||
// - object_key 可能含路徑("tenant/jobs/uuid/output.nef")— 過長
|
||
// - 目前 visionA 的 object_key 不直接含 user 敏感資訊,但保險起見統一 hash
|
||
// - 16 chars hex(64-bit)對 visionA 內部 job 數量來說碰撞機率極低,足以追蹤單一 request
|
||
//
|
||
// Phase 0.8b v0.6(T3):原本定義在 faa_client.go;砍 faa_client.go 時搬到 util.go
|
||
// (flow.go DownloadStream / PromoteToModels 仍用 hashObjectKey 為 log 加 target_object_key
|
||
// 標記,方便跨 service 追蹤同一個 NEF 物件)。
|
||
func hashObjectKey(objectKey string) string {
|
||
sum := sha256.Sum256([]byte(objectKey))
|
||
return hex.EncodeToString(sum[:])[:objectKeyHashLen]
|
||
}
|