feat(visionA-backend): Phase 0.8b v0.6 T4 — config FAA 欄位砍 + .env 清 + i18n/godoc polish
對齊 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>
This commit is contained in:
parent
6024c294d3
commit
9e29ebf767
@ -79,16 +79,18 @@ VISIONA_PAIRING_TOKEN=
|
||||
# ============================================================
|
||||
# Phase 0.8 / 0.8b — 轉檔功能整合(dev 通常不啟用,留空即可)
|
||||
# ============================================================
|
||||
# 對齊 .autoflow/04-architecture/conversion.md §3 + ADR-015。
|
||||
# 對齊 docs/autoflow/04-architecture/conversion.md §3 + ADR-015 + ADR-016。
|
||||
#
|
||||
# 4 個欄位全部非空才會啟用 conversion 模組;dev 全空 = sidebar tab 顯示但 endpoint 不註冊。
|
||||
# 若要在 dev 連 stage 的 converter / FAA 測整合,依 .env.stage.example 模板填入。
|
||||
# 2 個欄位(ConverterBaseURL / ConverterAPIKey)全部非空才會啟用 conversion 模組;
|
||||
# dev 全空 = sidebar tab 顯示但 endpoint 不註冊。
|
||||
# 若要在 dev 連 stage 的 converter 測整合,依 .env.stage.example 模板填入。
|
||||
#
|
||||
# Phase 0.8b v0.6 T4:原 FAA 相關 env(VISIONA_FAA_BASE_URL / VISIONA_FAA_API_KEY)
|
||||
# 已撤回(ADR-016:visionA 端不再直接呼叫 FAA;download / promote 改走 converter.GetResult)。
|
||||
#
|
||||
# 產生 API key:openssl rand -hex 32
|
||||
# VISIONA_CONVERTER_BASE_URL=http://192.168.0.130:9501
|
||||
# VISIONA_FAA_BASE_URL=http://192.168.0.130:5081
|
||||
# VISIONA_CONVERTER_API_KEY=
|
||||
# VISIONA_FAA_API_KEY=
|
||||
|
||||
# ============================================================
|
||||
# 進階:port 衝突時可改
|
||||
|
||||
@ -115,33 +115,29 @@ VISIONA_SEED_DEMO_DATA=false
|
||||
# 留註解作為 audit trail;stage 部署不需設定 VISIONA_STATIC_USER_ID。
|
||||
|
||||
# ============================================================
|
||||
# Phase 0.8 / 0.8b — 轉檔功能整合(converter / FAA pre-shared API key)
|
||||
# Phase 0.8 / 0.8b — 轉檔功能整合(converter pre-shared API key)
|
||||
# ============================================================
|
||||
# 對齊 .autoflow/04-architecture/conversion.md §3 + ADR-015。
|
||||
# 對齊 docs/autoflow/04-architecture/conversion.md §3 + ADR-015 + ADR-016。
|
||||
#
|
||||
# Phase 0.8b 變更:服務間認證從 OAuth client_credentials 改為 pre-shared API key。
|
||||
#
|
||||
# 啟用判定:4 個欄位(ConverterBaseURL / FAABaseURL / ConverterAPIKey / FAAAPIKey)
|
||||
# **全部非空**才視為啟用;任一缺 → 5 個 /api/conversion/* endpoint 不註冊。
|
||||
# 啟用判定:2 個欄位(ConverterBaseURL / ConverterAPIKey)**全部非空**才視為啟用;
|
||||
# 任一缺 → 5 個 /api/conversion/* endpoint 不註冊。
|
||||
#
|
||||
# Phase 0.8b 移除(不再讀取,也別再放進 .env.stage):
|
||||
# - VISIONA_OIDC_SERVICE_CLIENT_ID / _SECRET(服務間認證取消 MC client_credentials)
|
||||
# - VISIONA_CONVERSION_TENANT_ID / VISIONA_OIDC_TENANT_ID(取消 tenant 概念)
|
||||
# - VISIONA_FAA_DELEGATED_TTL_SECONDS(取消 delegated download token 機制;改 server-side stream proxy)
|
||||
#
|
||||
# Phase 0.8b v0.6 T4 移除(不再讀取,也別再放進 .env.stage;ADR-016 撤回 v0.5 設計缺口):
|
||||
# - VISIONA_FAA_BASE_URL(visionA 端不再直接呼叫 FAA)
|
||||
# - VISIONA_FAA_API_KEY(同上;download / promote 改走 converter.GetResult)
|
||||
|
||||
# kneron_model_converter task-scheduler base URL(stage 公司內網)
|
||||
VISIONA_CONVERTER_BASE_URL=http://192.168.0.130:9501
|
||||
|
||||
# File Access Agent base URL
|
||||
VISIONA_FAA_BASE_URL=http://192.168.0.130:5081
|
||||
|
||||
# Pre-shared API key — visionA → converter 服務間認證(Phase 0.8b 新增;ADR-015 §3)
|
||||
# **必須換掉**:openssl rand -hex 32 產生 64 字元 hex;與 converter 端 CONVERTER_API_KEY 對齊
|
||||
# 雙方獨立持有、不共用、嚴格分環境(dev / stage / prod 各自獨立 key)
|
||||
# log 永遠不印此值全文;部署時用 AWS Secrets Manager / Vault 注入
|
||||
VISIONA_CONVERTER_API_KEY=CHANGE_ME_OPENSSL_RAND_HEX_32
|
||||
|
||||
# Pre-shared API key — visionA → FAA 服務間認證(Phase 0.8b 新增;ADR-015 §3)
|
||||
# **必須換掉**:openssl rand -hex 32;與 FAA 端 FAA_API_KEY 對齊(warrenchen 配置)
|
||||
# 與 ConverterAPIKey **不共用**(每條 trust boundary 各自獨立,避免一處洩漏連坐)
|
||||
VISIONA_FAA_API_KEY=CHANGE_ME_OPENSSL_RAND_HEX_32
|
||||
|
||||
@ -80,7 +80,8 @@ VISIONA_FRONTEND_URL=http://localhost:3000
|
||||
# 服務間認證從 OAuth client_credentials 改為 pre-shared API key(見 ADR-015、conversion.md §3)。
|
||||
# 兩個 service client env 不再讀取(OIDCConfig.ServiceClientID/Secret struct 欄位
|
||||
# 為了 backward compat 暫保留、但 conversion 模組不再依賴)。
|
||||
# 取代設定見下方 Phase 0.8 / 0.8b 區塊的 VISIONA_CONVERTER_API_KEY / VISIONA_FAA_API_KEY。
|
||||
# 取代設定見下方 Phase 0.8 / 0.8b 區塊的 VISIONA_CONVERTER_API_KEY
|
||||
# (Phase 0.8b v0.6 T4 起 visionA 端不再直接呼叫 FAA、原 VISIONA_FAA_API_KEY 已撤回)。
|
||||
|
||||
# Cookie HMAC 簽章 secret(⚠️ 至少 32 byte 隨機字串;prod 用 openssl rand -hex 32)
|
||||
VISIONA_SESSION_SECRET=CHANGE_ME_TO_RANDOM_64_BYTES_in_production
|
||||
@ -157,40 +158,34 @@ VISIONA_PAIRING_TOKEN=
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Phase 0.8 / 0.8b — 轉檔功能整合(converter / FAA pre-shared API key)
|
||||
# Phase 0.8 / 0.8b — 轉檔功能整合(converter pre-shared API key)
|
||||
# ============================================================
|
||||
# 對齊 .autoflow/04-architecture/conversion.md §3 + ADR-015。
|
||||
# 對齊 docs/autoflow/04-architecture/conversion.md §3 + ADR-015 + ADR-016。
|
||||
#
|
||||
# Phase 0.8b 變更:服務間認證從 OAuth client_credentials 改為 pre-shared API key。
|
||||
#
|
||||
# 啟用判定:4 個欄位(ConverterBaseURL / FAABaseURL / ConverterAPIKey / FAAAPIKey)
|
||||
# **全部非空**才視為啟用;任一缺 → 5 個 /api/conversion/* endpoint 不註冊 / 回 501。
|
||||
# 啟用判定:2 個欄位(ConverterBaseURL / ConverterAPIKey)**全部非空**才視為啟用;
|
||||
# 任一缺 → 5 個 /api/conversion/* endpoint 不註冊 / 回 501。
|
||||
#
|
||||
# Phase 0.8b 移除(不再讀取):
|
||||
# - VISIONA_OIDC_SERVICE_CLIENT_ID / _SECRET(OAuth client_credentials 機制取消)
|
||||
# - VISIONA_OIDC_TENANT_ID(取消 tenant 概念,converter 端的 user_id 仍由 visionA 灌入)
|
||||
# - VISIONA_FAA_DELEGATED_TTL_SECONDS(delegated download token 機制取消,改 server-side stream proxy)
|
||||
#
|
||||
# Phase 0.8b v0.6 T4 移除(不再讀取;ADR-016 撤回 v0.5 設計缺口):
|
||||
# - VISIONA_FAA_BASE_URL(visionA 端不再直接呼叫 FAA)
|
||||
# - VISIONA_FAA_API_KEY(同上;download / promote 改走 converter.GetResult)
|
||||
|
||||
# kneron_model_converter task-scheduler base URL
|
||||
# dev/stage:http://192.168.0.130:9501
|
||||
# prod:https://converter.visiona.cloud
|
||||
VISIONA_CONVERTER_BASE_URL=
|
||||
|
||||
# File Access Agent base URL
|
||||
# dev/stage:http://192.168.0.130:5081
|
||||
# prod:https://faa.innovedus.com
|
||||
VISIONA_FAA_BASE_URL=
|
||||
|
||||
# Pre-shared API key — visionA → converter 服務間認證(Phase 0.8b 新增;ADR-015 §3)
|
||||
# 產生:openssl rand -hex 32(64 字元 hex)
|
||||
# 與 converter 端 CONVERTER_API_KEY env 對齊(雙方獨立持有,嚴格分環境 dev / stage / prod)
|
||||
# ⚠️ 不可 commit;prod 用 Secrets Manager / Vault;log 永遠不印此值全文
|
||||
VISIONA_CONVERTER_API_KEY=
|
||||
|
||||
# Pre-shared API key — visionA → FAA 服務間認證(Phase 0.8b 新增;ADR-015 §3)
|
||||
# 產生方式同上;與 FAA 端 FAA_API_KEY env 對齊(warrenchen 配置)
|
||||
# 與 ConverterAPIKey **不共用**(每條 trust boundary 各自獨立,避免一處洩漏連坐)
|
||||
VISIONA_FAA_API_KEY=
|
||||
|
||||
# 上傳模型檔大小上限(MB)— 與 converter 端 limit 對齊
|
||||
VISIONA_CONVERTER_MAX_MODEL_SIZE_MB=500
|
||||
|
||||
@ -141,16 +141,17 @@ func main() {
|
||||
// 對齊 docs/autoflow/04-architecture/conversion.md、ADR-015、ADR-016。
|
||||
//
|
||||
// 啟用條件:cfg.Conversion.Enabled() —
|
||||
// 由 ConverterBaseURL + ConverterAPIKey 決定(FAABaseURL / FAAAPIKey 由 T4 砍除 env 校驗)。
|
||||
// 由 ConverterBaseURL + ConverterAPIKey 決定(v0.6 T4 起 visionA 端不再需要 FAA env)。
|
||||
// 不啟用時 deps.Conversion 為 nil,5 個 endpoint 自動回 501(registerConversionRoutes 處理)。
|
||||
//
|
||||
// **Phase 0.8b T5**:完全切換至 pre-shared API key 認證 — 不再 wire MCTokenClient、
|
||||
// 不再讀 OIDCConfig.ServiceClientID/Secret、不再有 tenant_id / delegated_ttl_sec
|
||||
// 概念。參見 ADR-015 §6 變更影響清單。
|
||||
//
|
||||
// **Phase 0.8b v0.6 T3**:撤回 visionA → FAA 直接呼叫(ADR-016 撤回 v0.5 設計缺口)。
|
||||
// faa_client.go / FAAClient interface / FlowOpts.FAA 全部砍除;download / promote 流程
|
||||
// 改走 converter.GetResult。FAABaseURL / FAAAPIKey env 仍保留在 config 直到 T4 一併砍。
|
||||
// **Phase 0.8b v0.6 T3 + T4**:撤回 visionA → FAA 直接呼叫(ADR-016 撤回 v0.5 設計缺口)。
|
||||
// T3 砍 faa_client.go / FAAClient interface / FlowOpts.FAA;T4 砍 ConversionConfig
|
||||
// FAABaseURL / FAAAPIKey 兩欄位與對應 env(VISIONA_FAA_BASE_URL / VISIONA_FAA_API_KEY),
|
||||
// `Enabled()` 簡化為只判 converter 兩欄位。download / promote 流程改走 converter.GetResult。
|
||||
var conversionService conversion.Service
|
||||
if cfg.Conversion.Enabled() {
|
||||
// 不再檢查 ServiceClientID/Secret —— Phase 0.8b 起 conversion 不依賴 OIDC service client。
|
||||
|
||||
@ -508,17 +508,15 @@ func errorMessageFor(code string) string {
|
||||
case "converter_unavailable":
|
||||
return "轉檔服務暫時無法使用"
|
||||
case "faa_unavailable":
|
||||
// converter promote 內部 PUT FAA 失敗時透傳,由 SRE 區分 converter 不可達 vs
|
||||
// converter→FAA push 失敗(ADR-016:visionA 端不再直接呼叫 FAA)。
|
||||
return "檔案存取服務暫時無法使用"
|
||||
case "download_token_failed":
|
||||
return "無法取得下載授權"
|
||||
case "mc_token_unavailable":
|
||||
return "無法取得下載授權,請重試"
|
||||
case "idp_misconfigured":
|
||||
return "系統設定錯誤,請聯絡支援"
|
||||
case "idp_unavailable":
|
||||
return "認證服務暫時無法使用"
|
||||
case "service_busy":
|
||||
return "系統繁忙,請稍後再試"
|
||||
// Phase 0.8b v0.6 T3 / T4:以下 i18n key 對應的 sentinel 已砍除,不再會被產生:
|
||||
// - download_token_failed / mc_token_unavailable(v0.5 mc_token_client 撤回)
|
||||
// - idp_misconfigured / idp_unavailable(同上)
|
||||
// 故 case 直接省略;errorMessageFor 落入 default。
|
||||
default:
|
||||
return "內部錯誤"
|
||||
}
|
||||
|
||||
@ -182,30 +182,31 @@ type LoggerConfig struct {
|
||||
|
||||
// ConversionConfig 控制 Phase 0.8 / 0.8b 轉檔功能整合。
|
||||
//
|
||||
// 對齊 .autoflow/04-architecture/conversion.md §3、`adr/adr-015-server-to-server-api-key.md`。
|
||||
// 對齊 docs/autoflow/04-architecture/conversion.md §3、
|
||||
// `adr/adr-015-server-to-server-api-key.md`、`adr/adr-016-download-via-converter.md`。
|
||||
//
|
||||
// 啟用判定(由 Enabled() 給 main.go 用):Phase 0.8b 起,4 個欄位(ConverterBaseURL /
|
||||
// FAABaseURL / ConverterAPIKey / FAAAPIKey)**全部非空**才視為啟用;任一缺即視為未啟用,
|
||||
// 啟用判定(由 Enabled() 給 main.go 用):Phase 0.8b v0.6 起,2 個必要欄位
|
||||
// (ConverterBaseURL / ConverterAPIKey)**全部非空**才視為啟用;任一缺即視為未啟用,
|
||||
// 5 個 /api/conversion/* endpoint 不會 wire(main.go 在 wire 階段跳過、log warn)。
|
||||
//
|
||||
// **Phase 0.8b 變更**:服務間認證從 OAuth client_credentials 改為 pre-shared API key(ADR-015);
|
||||
// `Enabled()` 加入兩個 API key 非空檢查。
|
||||
// **Phase 0.8b 變更**:服務間認證從 OAuth client_credentials 改為 pre-shared API key(ADR-015)。
|
||||
//
|
||||
// **Phase 0.8b T5 完成**(見 conversion.md §3.2 / ADR-015 §5 §7):原暫留欄位
|
||||
// TenantID / DelegatedTTLSeconds 已移除 — MC 認證鏈與 delegated download token 機制
|
||||
// 都不存在了,兩個欄位連同對應 env(VISIONA_OIDC_TENANT_ID /
|
||||
// VISIONA_FAA_DELEGATED_TTL_SECONDS)一併清除。
|
||||
//
|
||||
// **Phase 0.8b v0.6 T4 完成**(見 ADR-016 §2 / conversion.md v0.6.1 §3.1):原 FAA 相關
|
||||
// 欄位 FAABaseURL / FAAAPIKey 已移除 — visionA 端不再直接呼叫 FAA,download / promote
|
||||
// 流程改走 converter.GetResult(ADR-016 撤回 v0.5 設計缺口),兩個欄位連同對應 env
|
||||
// (VISIONA_FAA_BASE_URL / VISIONA_FAA_API_KEY)一併清除;`Enabled()` 也簡化為只判
|
||||
// converter 兩欄位。
|
||||
type ConversionConfig struct {
|
||||
// ConverterBaseURL 是 kneron_model_converter task-scheduler 服務的 base URL。
|
||||
// 例:http://192.168.0.130:9501(dev / stage) / https://converter.visiona.cloud(prod)
|
||||
// 對齊 VISIONA_CONVERTER_BASE_URL;留空 = 不啟用 Phase 0.8 轉檔功能。
|
||||
ConverterBaseURL string
|
||||
|
||||
// FAABaseURL 是 File Access Agent 的 base URL。
|
||||
// 例:http://192.168.0.130:5081(dev / stage) / https://faa.innovedus.com(prod)
|
||||
// 對齊 VISIONA_FAA_BASE_URL;留空 = 不啟用 Phase 0.8 轉檔功能。
|
||||
FAABaseURL string
|
||||
|
||||
// ConverterAPIKey 是 visionA → converter 服務間認證的 pre-shared API key(Phase 0.8b 新增)。
|
||||
// 對齊 VISIONA_CONVERTER_API_KEY;以 `Authorization: Bearer <key>` 形式帶上。
|
||||
// 雙方獨立產生(`openssl rand -hex 32`),visionA 端的值必須與 converter 端的
|
||||
@ -216,12 +217,6 @@ type ConversionConfig struct {
|
||||
// 部署用 AWS Secrets Manager / Vault;嚴格分環境(dev / stage / prod 各自獨立 key)。
|
||||
ConverterAPIKey string
|
||||
|
||||
// FAAAPIKey 是 visionA → FAA 服務間認證的 pre-shared API key(Phase 0.8b 新增)。
|
||||
// 對齊 VISIONA_FAA_API_KEY;以 `Authorization: Bearer <key>` 形式帶上。
|
||||
// 與 ConverterAPIKey **不共用**(每條 trust boundary 各自獨立,避免一處洩漏連坐 — ADR-015 §3);
|
||||
// 對應 FAA 端的 `FAA_API_KEY` env,由 warrenchen 配置(跨 repo 同步)。
|
||||
FAAAPIKey string
|
||||
|
||||
// MaxModelSizeMB 是 visionA-backend 端對上傳模型檔的大小上限(MB)。
|
||||
// 與 converter 端 limit 對齊(converter 預設 500 MB)。
|
||||
// 對齊 VISIONA_CONVERTER_MAX_MODEL_SIZE_MB;預設 500。
|
||||
@ -230,14 +225,12 @@ type ConversionConfig struct {
|
||||
|
||||
// Enabled 回傳 Phase 0.8 / 0.8b conversion 是否啟用。
|
||||
//
|
||||
// **Phase 0.8b 變更**(ADR-015 §6):除既有的 ConverterBaseURL / FAABaseURL 外,
|
||||
// 加入 ConverterAPIKey / FAAAPIKey 非空檢查;4 個欄位皆非空才算啟用。
|
||||
// 任一缺 → 視為未啟用,main.go 不會 wire conversion.Service(5 個 endpoint 回 501 / 不註冊)。
|
||||
// **Phase 0.8b v0.6 T4 簡化**(ADR-016 §2 / conversion.md v0.6.1 §3.1):visionA 端撤回
|
||||
// 對 FAA 的直接呼叫,download / promote 改走 converter.GetResult;只剩 ConverterBaseURL
|
||||
// 與 ConverterAPIKey 兩個欄位需非空。任一缺 → 視為未啟用,main.go 不會 wire
|
||||
// conversion.Service(5 個 endpoint 回 501 / 不註冊)。
|
||||
func (c ConversionConfig) Enabled() bool {
|
||||
return c.ConverterBaseURL != "" &&
|
||||
c.FAABaseURL != "" &&
|
||||
c.ConverterAPIKey != "" &&
|
||||
c.FAAAPIKey != ""
|
||||
return c.ConverterBaseURL != "" && c.ConverterAPIKey != ""
|
||||
}
|
||||
|
||||
// CORSConfig 控制 api-server 對瀏覽器的 CORS 白名單。
|
||||
|
||||
@ -68,15 +68,17 @@ func Load() *Config {
|
||||
CORS: CORSConfig{
|
||||
AllowedOrigins: getEnvStringSlice("VISIONA_CORS_ALLOWED_ORIGINS", nil),
|
||||
},
|
||||
// Phase 0.8 / 0.8b conversion (見 .autoflow/04-architecture/conversion.md §3、ADR-015)
|
||||
// Phase 0.8 / 0.8b conversion (見 docs/autoflow/04-architecture/conversion.md §3、
|
||||
// ADR-015、ADR-016)
|
||||
// Phase 0.8b T5:原暫留欄位 TenantID / DelegatedTTLSeconds 與對應 env
|
||||
// (VISIONA_OIDC_TENANT_ID / VISIONA_FAA_DELEGATED_TTL_SECONDS)已移除 —
|
||||
// MC 認證鏈與 delegated download token 機制不存在了。
|
||||
// Phase 0.8b v0.6 T4:原 FAA 相關欄位 FAABaseURL / FAAAPIKey 與對應 env
|
||||
// (VISIONA_FAA_BASE_URL / VISIONA_FAA_API_KEY)已移除 — ADR-016 撤回 v0.5
|
||||
// 設計缺口,visionA 端不再直接呼叫 FAA、download/promote 改走 converter.GetResult。
|
||||
Conversion: ConversionConfig{
|
||||
ConverterBaseURL: getEnvString("VISIONA_CONVERTER_BASE_URL", ""),
|
||||
FAABaseURL: getEnvString("VISIONA_FAA_BASE_URL", ""),
|
||||
ConverterAPIKey: getEnvString("VISIONA_CONVERTER_API_KEY", ""),
|
||||
FAAAPIKey: getEnvString("VISIONA_FAA_API_KEY", ""),
|
||||
MaxModelSizeMB: getEnvInt("VISIONA_CONVERTER_MAX_MODEL_SIZE_MB", 500),
|
||||
},
|
||||
}
|
||||
|
||||
@ -268,15 +268,19 @@ func TestLoad_CORSAllowedOrigins(t *testing.T) {
|
||||
|
||||
// TestLoad_ConversionDefaults 驗證 Phase 0.8 / 0.8b conversion 欄位的預設行為。
|
||||
//
|
||||
// 對齊 .autoflow/04-architecture/conversion.md §3 + ADR-015:留空時 Enabled() 為 false,
|
||||
// 5 個 endpoint 不會 wire(main.go 在 wire 階段會跳過)。
|
||||
// 對齊 docs/autoflow/04-architecture/conversion.md §3 + ADR-015 + ADR-016:留空時
|
||||
// Enabled() 為 false,5 個 endpoint 不會 wire(main.go 在 wire 階段會跳過)。
|
||||
//
|
||||
// Phase 0.8b T5:原暫留欄位 TenantID / DelegatedTTLSeconds 已從 ConversionConfig 移除
|
||||
// (MC 認證鏈與 delegated download token 機制不存在了);本 test 不再驗這兩欄位。
|
||||
//
|
||||
// Phase 0.8b v0.6 T4:原 FAA 相關欄位 FAABaseURL / FAAAPIKey 已移除(ADR-016 撤回
|
||||
// v0.5 設計缺口,visionA 端不再直接呼叫 FAA);本 test 不再驗這兩欄位,對應的
|
||||
// VISIONA_FAA_BASE_URL / VISIONA_FAA_API_KEY env 也不再 clear。
|
||||
func TestLoad_ConversionDefaults(t *testing.T) {
|
||||
for _, k := range []string{
|
||||
"VISIONA_CONVERTER_BASE_URL", "VISIONA_FAA_BASE_URL",
|
||||
"VISIONA_CONVERTER_API_KEY", "VISIONA_FAA_API_KEY",
|
||||
"VISIONA_CONVERTER_BASE_URL",
|
||||
"VISIONA_CONVERTER_API_KEY",
|
||||
"VISIONA_CONVERTER_MAX_MODEL_SIZE_MB",
|
||||
} {
|
||||
t.Setenv(k, "")
|
||||
@ -284,49 +288,36 @@ func TestLoad_ConversionDefaults(t *testing.T) {
|
||||
|
||||
cfg := Load()
|
||||
assert.Empty(t, cfg.Conversion.ConverterBaseURL)
|
||||
assert.Empty(t, cfg.Conversion.FAABaseURL)
|
||||
assert.Empty(t, cfg.Conversion.ConverterAPIKey, "Phase 0.8b:API key 預設留空")
|
||||
assert.Empty(t, cfg.Conversion.FAAAPIKey, "Phase 0.8b:API key 預設留空")
|
||||
assert.Equal(t, 500, cfg.Conversion.MaxModelSizeMB, "預設 500 MB(與 converter 對齊)")
|
||||
assert.False(t, cfg.Conversion.Enabled(), "全空 → 不啟用")
|
||||
}
|
||||
|
||||
// TestLoad_ConversionEnabled 驗證 Conversion.Enabled() 的判定邏輯(Phase 0.8b 修訂)。
|
||||
// TestLoad_ConversionEnabled 驗證 Conversion.Enabled() 的判定邏輯。
|
||||
//
|
||||
// Phase 0.8b 變更:4 個欄位(Converter URL / FAA URL / Converter API key / FAA API key)
|
||||
// 全部非空才視為啟用;任一缺即 disable。
|
||||
// Phase 0.8b v0.6 T4 簡化(ADR-016):visionA 端撤回對 FAA 的直接呼叫後,
|
||||
// 只剩 ConverterBaseURL + ConverterAPIKey 兩個欄位需非空;任一缺即 disable。
|
||||
func TestLoad_ConversionEnabled(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
converterURL string
|
||||
faaURL string
|
||||
converterKey string
|
||||
faaKey string
|
||||
wantEnabled bool
|
||||
}{
|
||||
{"all_set_enables",
|
||||
"http://converter:9501", "http://faa:5081",
|
||||
"http://converter:9501",
|
||||
"converter-key-32-bytes-hex-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"faa-key-32-bytes-hex-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
|
||||
true},
|
||||
{"missing_converter_url_disabled",
|
||||
"", "http://faa:5081",
|
||||
"converter-key", "faa-key",
|
||||
false},
|
||||
{"missing_faa_url_disabled",
|
||||
"http://converter:9501", "",
|
||||
"converter-key", "faa-key",
|
||||
"",
|
||||
"converter-key",
|
||||
false},
|
||||
{"missing_converter_key_disabled",
|
||||
"http://converter:9501", "http://faa:5081",
|
||||
"", "faa-key",
|
||||
false},
|
||||
{"missing_faa_key_disabled",
|
||||
"http://converter:9501", "http://faa:5081",
|
||||
"converter-key", "",
|
||||
"http://converter:9501",
|
||||
"",
|
||||
false},
|
||||
{"all_empty_disabled",
|
||||
"", "", "", "",
|
||||
"", "",
|
||||
false},
|
||||
}
|
||||
|
||||
@ -334,9 +325,7 @@ func TestLoad_ConversionEnabled(t *testing.T) {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Setenv("VISIONA_CONVERTER_BASE_URL", tc.converterURL)
|
||||
t.Setenv("VISIONA_FAA_BASE_URL", tc.faaURL)
|
||||
t.Setenv("VISIONA_CONVERTER_API_KEY", tc.converterKey)
|
||||
t.Setenv("VISIONA_FAA_API_KEY", tc.faaKey)
|
||||
cfg := Load()
|
||||
assert.Equal(t, tc.wantEnabled, cfg.Conversion.Enabled())
|
||||
})
|
||||
@ -347,39 +336,35 @@ func TestLoad_ConversionEnabled(t *testing.T) {
|
||||
//
|
||||
// Phase 0.8b T5:原暫留欄位 TenantID / DelegatedTTLSeconds 已移除,本 test
|
||||
// 不再驗這兩欄位(對應 env 也不再讀取)。
|
||||
//
|
||||
// Phase 0.8b v0.6 T4:原 FAA 相關欄位 FAABaseURL / FAAAPIKey 已移除(ADR-016),
|
||||
// 本 test 不再驗這兩欄位、對應 env 也不再讀取。
|
||||
func TestLoad_ConversionAllSet(t *testing.T) {
|
||||
const fakeConverterKey = "fake-converter-api-key-for-test-do-not-use-in-prod"
|
||||
const fakeFAAKey = "fake-faa-api-key-for-test-do-not-use-in-prod"
|
||||
|
||||
t.Setenv("VISIONA_CONVERTER_BASE_URL", "http://192.168.0.130:9501")
|
||||
t.Setenv("VISIONA_FAA_BASE_URL", "http://192.168.0.130:5081")
|
||||
t.Setenv("VISIONA_CONVERTER_API_KEY", fakeConverterKey)
|
||||
t.Setenv("VISIONA_FAA_API_KEY", fakeFAAKey)
|
||||
t.Setenv("VISIONA_CONVERTER_MAX_MODEL_SIZE_MB", "300")
|
||||
|
||||
cfg := Load()
|
||||
assert.Equal(t, "http://192.168.0.130:9501", cfg.Conversion.ConverterBaseURL)
|
||||
assert.Equal(t, "http://192.168.0.130:5081", cfg.Conversion.FAABaseURL)
|
||||
assert.Equal(t, fakeConverterKey, cfg.Conversion.ConverterAPIKey)
|
||||
assert.Equal(t, fakeFAAKey, cfg.Conversion.FAAAPIKey)
|
||||
assert.Equal(t, 300, cfg.Conversion.MaxModelSizeMB)
|
||||
assert.True(t, cfg.Conversion.Enabled())
|
||||
}
|
||||
|
||||
// TestLoad_ConversionAPIKeysOnly:Phase 0.8b T5 — 4 個必要欄位齊全即 Enabled。
|
||||
// TestLoad_ConversionAPIKeysOnly:Phase 0.8b v0.6 T4 — 2 個必要欄位齊全即 Enabled。
|
||||
//
|
||||
// 此 test 在 T1-T4 期間驗證「廢棄 env 不設也能 Enabled」;T5 完成後該邏輯
|
||||
// 由本 test 與 TestLoad_ConversionAllSet 共同覆蓋(因為廢棄 env 已徹底移除)。
|
||||
// 本 test 與 TestLoad_ConversionAllSet 共同覆蓋 Enabled() 的最小啟用條件:
|
||||
// 只要 ConverterBaseURL + ConverterAPIKey 兩個欄位都非空、即視為啟用,
|
||||
// MaxModelSizeMB 不影響啟用判定。
|
||||
func TestLoad_ConversionAPIKeysOnly(t *testing.T) {
|
||||
const fakeConverterKey = "fake-converter-api-key-only-test"
|
||||
const fakeFAAKey = "fake-faa-api-key-only-test"
|
||||
|
||||
t.Setenv("VISIONA_CONVERTER_BASE_URL", "http://192.168.0.130:9501")
|
||||
t.Setenv("VISIONA_FAA_BASE_URL", "http://192.168.0.130:5081")
|
||||
t.Setenv("VISIONA_CONVERTER_API_KEY", fakeConverterKey)
|
||||
t.Setenv("VISIONA_FAA_API_KEY", fakeFAAKey)
|
||||
|
||||
cfg := Load()
|
||||
assert.True(t, cfg.Conversion.Enabled(),
|
||||
"Phase 0.8b T5:4 個必要欄位齊全即 Enabled")
|
||||
"Phase 0.8b v0.6 T4:2 個必要欄位齊全即 Enabled")
|
||||
}
|
||||
|
||||
@ -30,6 +30,15 @@ func truncate(s string, max int) string {
|
||||
// - 目前 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 物件)。
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user