對齊 ADR-016 / conversion.md v0.6.1 §3.1:visionA 端不再需要 FAA 設定(v0.5 T1 加的 FAAAPIKey/FAABaseURL 撤回)。
config 砍除:
- internal/config/config.go: ConversionConfig.FAABaseURL + FAAAPIKey 兩欄位
- internal/config/load.go: VISIONA_FAA_BASE_URL + VISIONA_FAA_API_KEY 兩 env 讀取
- Enabled() 簡化為「ConverterBaseURL + ConverterAPIKey 兩個非空」
- internal/config/load_test.go: TestLoad_ConversionEnabled 從 6 case 簡化為 4 case (all_set / missing_converter_url / missing_converter_key / all_empty)
.env*.example 對齊(3 個檔):
- visionA-backend/.env.example: 砍 2 個 FAA env row + 註解;header 改「2 欄位啟用」
- .env.stage.example: 同上;VISIONA_CONVERTER_API_KEY 保留 CHANGE_ME_OPENSSL_RAND_HEX_32 placeholder
- .env.dev.example: 註解區塊統一對齊
T3 review polish:
- m-2 internal/api/conversion.go: i18n message map 砍 4 個 dead case (download_token_failed / mc_token_unavailable / idp_misconfigured / idp_unavailable) — 對應 v0.5 mc_token_client 撤回時砍的 sentinel;落入 default「內部錯誤」、行為不變
- m-3 internal/conversion/util.go: hashObjectKey godoc 補「設計約束(重要)」段 + 3 條「不應做的事」(不出現在 response body/header / 不組 URL / 不寫進 user-facing 錯誤訊息)— 明示用途限定於 slog 欄位內、避免 misuse vector
- cmd/api-server/main.go: godoc 對齊 T4 完成狀態
驗證:
- B 層 verification 主動跑(T3 reviewer 接受暫緩、backend 主動跑避免 reviewer 二次要求):
* 跨檔 grep: production code 0 functional 命中(殘留全是註解 audit trail / test fixture name)
* 17 packages race -count=3 全綠
* 3 個 .env 環境一致性驗證
- go build ./... exit 0
- go test -race -count=3 ./... 17 packages 全綠
- Reviewer 5 軸(v0.6-t4-review)✅ 通過(0 Critical / 0 Major / 2 Minor / 4 Suggestion)
v0.6 對齊改造事實上完工:
- T1 ConverterClient.GetResult method
- T2 flow.go DownloadStream/PromoteToModels 改用 GetResult + e2e endpoint
- T3 faa_client 整檔砍 + ErrFAA* sentinel 清 + s-3/s-4/s-5 必補 + mockFAA regression-only
- T4 config FAA 欄位砍 + .env 清 + i18n/godoc polish
main.go startup log 已是「converter_api_key_set only」、無 FAA 殘留 / 無 tenant_id(T2-T3 已處理)。e2e regression 防護由 mockFAA negative assertion 守住(T3)。
下一步:
- visionA backend 端 ADR-016 對齊完工,等使用者跨 repo 加 converter GET /api/v1/jobs/{id}/result endpoint
- stage redeploy + e2e 完整測試
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
49 lines
2.2 KiB
Go
49 lines
2.2 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
|
||
//
|
||
// **設計約束(重要):此 hash 僅供內部 log / observability 用、不應對外暴露**。
|
||
// 具體不應:
|
||
// - 出現在 HTTP response body / header(frontend 不需要、洩漏內部 storage 結構)
|
||
// - 拿來組 presigned URL / download URL 的 path(hash 不可逆、不能用來定位物件)
|
||
// - 寫進使用者可見的錯誤訊息(用 request_id 追蹤即可)
|
||
//
|
||
// 用途限定於 slog 欄位(如 `slog.String("object_key_hash", hashObjectKey(...))`),
|
||
// 配合 request_id 在 log aggregator 內串接同一 NEF 物件在多個 service 之間的流向。
|
||
//
|
||
// 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]
|
||
}
|