visionA/.env.stage.example
jim800121chen 86b7175649 feat(visionA-backend): Phase 0.8b 步驟 2 — visionA → converter / FAA 改 API key 認證
對齊 ADR-015:visionA backend 從 OAuth client_credentials 改 pre-shared API key 服務間認證。Phase 0.8 stage e2e 撞 4 個 blocker(MC scope 沒註冊 / converter image 舊版 / converter 缺 env / FAA 不確定)後,使用者拍板 1:1 internal trust 用 OAuth 過度設計,改 API key。

實作(5 個增量 task,T1-T5 全綠 + Reviewer 5 輪 + final cross-task review):

T1 config + env:
- ConversionConfig 新增 ConverterAPIKey / FAAAPIKey 欄位
- Enabled() 改判定 4 欄位齊全(含兩個 API key)
- .env*.example 移除 OIDC service client / OIDC tenant / FAA delegated TTL env、新增 API key env
- TenantID / DelegatedTTLSeconds T1 暫留、T5 整批清

T2 client 改造:
- converter_client / faa_client 移除 MCTokenClient 依賴
- 直接讀 cfg.Conversion.{Converter,FAA}APIKey、set Authorization: Bearer <key>
- NewConverterClient / NewFAAClient APIKey 為空時 panic(fail-fast,對齊 ADR-015 §3.5.3 #1)
- 新增 ErrConverterAuthFailed / ErrFAAAuthFailed sentinel
- 對外 mask 成 converter_unavailable / faa_unavailable(不洩漏 401 細節,對齊 ADR-015 §3.5.3 #3)

T3 砍 mc_token_client:
- mc_token_client.go (624 行) + mc_token_client_test.go (864 行) 整檔砍
- 砍 5 個僅 mc_token_client 用的 sentinel(ErrServiceClientUnauthorized / ErrMCTokenUnavailable / ErrIDPMisconfigured / ErrIDPUnavailable / ErrDownloadTokenFailed)
- helper(truncate / silentLogger)搬到 util.go / testing_helpers_test.go

T4 flow + handler stream proxy:
- Service interface DownloadRedirectURL → DownloadStream(ctx) (io.ReadCloser, *DownloadMetadata, error)
- flow.DownloadStream 用 faa.GetFile 直接 stream NEF binary(取代 MC delegated token + 302)
- handler conversionDownloadHandler 改 io.Copy + Content-Type/Disposition/Cache-Control header
- 新增 sanitizeDownloadFilename helper 防 HTTP header injection
- 跨 package handler test (conversion_test.go) 改測 ErrFAAUnavailable + 補 *_AuthFailed 對稱 test

T5 wire 切換 + cleanup:
- main.go 砍 mcTokenClient wire、改 APIKey 注入、startup log 用 *_api_key_set boolean(不印 key)
- ConverterClient/FAAClient struct Tokens 欄位移除
- mc_token_stub.go (T4 過渡期) 整檔砍
- ConversionConfig TenantID / DelegatedTTLSeconds 欄位移除
- e2e_test.go TestConversionE2E_Download302Redirect 改寫為 TestConversionE2E_DownloadStream
- 補 MaxDownloadStreamBytes = 1 GiB size cap(io.CopyN,T4 reviewer Minor M-1)
- escapeObjectKeyPath Phase 1+ 預留 godoc + //nolint:unused(T4 reviewer Minor M-2)
- conversion.md §4.1 line 502 filename 來源描述歧義修訂(T4 reviewer Minor M-3,由 architect 處理)
- conversion_e2e_test.go 檔頭 docstring 更新(final reviewer Minor #1)

驗證:
- go build ./... exit 0
- go test -race -count=3 ./... 17 packages 全綠
- ADR-015 §6 砍除清單 100% cover(reviewer 獨立 grep 確認 MC chain / TenantID / DelegatedTTLSeconds 全清)
- ADR-015 §3.5.3 部署檢查清單 visionA 範圍 4/4 達成(fail-fast / mask / 不印 token / placeholder env)

不動:
- OIDCConfig.ServiceClientID/Secret 欄位保留(使用者拍板 backward compat)
- user login OIDC 完全不動

下一步:
- 步驟 4 — converter scheduler middleware 改 API key(jimchen 跨 repo,ADR-015 §3.5.1 Go snippet)
- 步驟 5 — FAA middleware 改 API key(warrenchen 跨 repo,ADR-015 §3.5.2 C# snippet)
- 步驟 6 — stage redeploy + e2e 完整測試

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 09:45:45 +08:00

148 lines
7.1 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# visionA — stage 環境變數範本
#
# 使用方式:
# 1. 在 stage host 上:
# cp .env.stage.example .env.stage
# nano .env.stage # 填入 secrets見下方說明
# 2. .env.stage 與 docker-compose.stage.yml 同目錄
# 3. ⚠️ 不進 git.gitignore 已排除)
#
# Secret 產生方式:
# openssl rand -hex 32
#
# 對齊:
# - visionA-backend/internal/config/config.goA1 後 ClientSecret 變選填、預留 ServiceClient*
# - .autoflow/04-architecture/oidc-tdd.md §13.1
# - .autoflow/progress.md Phase 0.7 → S6OIDC public PKCE-only client
# ============================================================
# OIDC — Member Center @ stage
# ============================================================
# Issuer URL — 結尾斜線**必要**MC discovery 回的 issuer 帶 slash否則 client init reject
VISIONA_OIDC_ISSUER_URL=https://stage-9527.innovedus.com:7850/
# Login clientpublic PKCE-only — 無 secret
VISIONA_OIDC_CLIENT_ID=b8093fea1a504a5d8f0e04bee9f78f2e
# 留空 → backend 走 PKCE-only modeA1 後支援;見 ADR-013
VISIONA_OIDC_CLIENT_SECRET=
# Phase 0.8b 移除VISIONA_OIDC_SERVICE_CLIENT_ID / _SECRET
# 服務間認證從 OAuth client_credentials 改為 pre-shared API key見 ADR-015
# 兩個 service client env 不再讀取OIDCConfig.ServiceClientID/Secret struct 欄位
# 為了 backward compat 暫保留、但 conversion 模組不再依賴)。
# 已洩漏的 stage service client secret 自此作廢,無 rotate 需求。
# Callback URL — 必須與 MC 端 client 設定的 redirect_uri 完全一致
VISIONA_OIDC_REDIRECT_URL=https://stage-9527.innovedus.com:9527/api/auth/callback
# Frontend URL — OIDC callback 完成後 302 回的目標(同 host 同 port
VISIONA_FRONTEND_URL=https://stage-9527.innovedus.com:9527
# ============================================================
# Cookie sessionOIDC 登入後在 browser 端的 session cookie
# ============================================================
# Cookie HMAC 簽章金鑰 — **必須換掉**
# 產生openssl rand -hex 32
VISIONA_SESSION_SECRET=CHANGE_ME_OPENSSL_RAND_HEX_32
# CookieDomain留空 = host-only cookie推薦stage 只有單一 host
# 若未來要跨子網域共享 session 才設成 .innovedus.com 之類
VISIONA_SESSION_COOKIE_DOMAIN=
# CookieSecurestage 走 HTTPS → 必須 true
VISIONA_SESSION_COOKIE_SECURE=true
# Session TTL預設值。如要改去掉註解填值
# VISIONA_SESSION_ABSOLUTE_TTL=168h
# VISIONA_SESSION_IDLE_TTL=24h
# ============================================================
# Server — port 都對齊 nginx.stage.conf
# ============================================================
VISIONA_HOST=0.0.0.0
VISIONA_API_PORT=3721
VISIONA_TUNNEL_PORT=3800
VISIONA_PROXY_INTERNAL_PORT=3801
VISIONA_PROXY_INTERNAL_URL=http://127.0.0.1:3801
# api-server 端的 SessionStore backendproxy-client = 透過 internal HTTP 查 remote-proxy
# remote-proxy 端的 SessionStore backendinmemory = 自己持有 yamux session
# 兩個 binary 共讀此 .env但各自只看自己需要的欄位
VISIONA_SESSION_BACKEND=proxy-client
# Agent 連 tunnel 用的對外 URL/api/pairing/exchange 回給 agent
# 注意 ws→wss、host:port 與對外 HTTPS 一致
VISIONA_RELAY_PUBLIC_URL=wss://stage-9527.innovedus.com:9527
# ============================================================
# CORS — stage 同 host 同源frontend 與 backend 都從 :9527 出來),不需放
# ============================================================
VISIONA_CORS_ALLOWED_ORIGINS=
# ============================================================
# Storage — 雛形 LocalFShost 的 /opt/visiona/data/ 掛進 container
# ============================================================
VISIONA_STORAGE_BACKEND=localfs
VISIONA_STORAGE_LOCALFS_ROOT=/data/storage
# presigned URL 對外可達 base與公司 host nginx 對外一致
VISIONA_STORAGE_LOCALFS_BASE_URL=https://stage-9527.innovedus.com:9527/storage
# presigned URL HMAC secret — **必須換掉**
# 產生openssl rand -hex 32
VISIONA_STORAGE_SIGNING_SECRET=CHANGE_ME_OPENSSL_RAND_HEX_32
# ============================================================
# Model upload
# ============================================================
# 模型上傳大小上限MB— 注意要與 nginx.stage.conf 的 client_max_body_size 對齊
# 目前 nginx 設 100M這裡也 100要改大兩處要一起改
VISIONA_MODEL_MAX_SIZE_MB=100
# ============================================================
# Pairing token雛形留空 = 動態配發;填值 = 寫死)
# 對齊 .autoflow/02-prd/feature-pairing-token.md
# ============================================================
VISIONA_PAIRING_TOKEN=
# ============================================================
# Misc
# ============================================================
VISIONA_LOG_LEVEL=info
# stage 不塞 demo data避免 storage 被假資料污染)
VISIONA_SEED_DEMO_DATA=false
# Phase 0.7 security audit (2026-05-01) 後 stage/prod 不再讀此值;
# 已從 api.Deps 移除(見 .autoflow/05-implementation/review/phase-0.7-security-audit.md C1
# 留註解作為 audit trailstage 部署不需設定 VISIONA_STATIC_USER_ID。
# ============================================================
# Phase 0.8 / 0.8b — 轉檔功能整合converter / FAA pre-shared API key
# ============================================================
# 對齊 .autoflow/04-architecture/conversion.md §3 + ADR-015。
#
# Phase 0.8b 變更:服務間認證從 OAuth client_credentials 改為 pre-shared API key。
#
# 啟用判定4 個欄位ConverterBaseURL / FAABaseURL / ConverterAPIKey / FAAAPIKey
# **全部非空**才視為啟用;任一缺 → 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
# kneron_model_converter task-scheduler base URLstage 公司內網)
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