## Phase 1-3: Control Plane + Contract System - awooop_phase1_control_plane_2026-05-04.sql: 12 張核心表 + RLS - awooop_phase1_batch1_rls_2026-05-04.sql: 全部 FORCE RLS + GRANT - packages/awooop-contracts/: 六合約 JSON Schema + golden fixtures - src/models/awooop_contracts.py: Pydantic v2 contract models(extra=forbid) - src/repositories/contract_repository.py: contract lifecycle(draft→published→active) - src/services/contract_service.py: HMAC publish sig + Redis multi-sig activate - src/services/schema_validator.py: LLM output validator(retry×3, E-SCHEMA-001) ## Phase 2: Tenant Isolation - awooop_phase2_budget_ledger_2026-05-04.sql: budget_ledger + RLS - src/services/budget_service.py: Token Budget Hard Kill 三層防線 - src/core/context.py: PROJECT_ID ContextVar(31 background loop 自動繼承) - src/db/base.py + models.py: project_id 欄位 + RLS set_config 注入 - src/hermes/nl_gateway.py: project_id Redis key 前綴(Phase A 雙寫) - src/services/anomaly_counter.py: per-project 改造(Phase A fallback) ## Phase 4: Platform Shell in Shadow Mode - awooop_phase4_run_state_2026-05-04.sql: run_state + step_journal + idempotency - src/services/run_state_machine.py: 8-state FSM + SKIP LOCKED + stale reaper - src/services/platform_runtime.py: UUID v7 + W3C trace_id + shadow_execute - src/services/audit_sink.py: PII/secret redaction 9 patterns - src/api/v1/platform/runs.py: POST/GET /v1/platform/runs(Router→Service 架構) - src/workers/platform_worker.py: SKIP LOCKED worker + heartbeat + reaper loop - src/main.py: platform router + lifespan worker start/stop ## Phase 5: MCP Gateway 五閘門 - awooop_phase5_mcp_gateway_2026-05-04.sql: 4 表 + RLS - src/plugins/mcp/gateway.py: McpGateway(Gate 1~5, E-MCP-GATE-001~009) - src/plugins/mcp/redaction_middleware.py: 雙層 redaction + 16K 截斷 - src/plugins/mcp/registry.py: __provider name mangling(ADR-116) - src/plugins/mcp/credential_resolver.py: k8s secret ref 解析 - tests/test_mcp_credential_isolation.py: 10 個迴歸測試(secret leak 防再現) ## Phase 6-8: EwoooC + Channel Hub + Approval Token - awooop_phase6_ewoooc_onboarding_2026-05-04.sql: ewoooc tenant + 4 read-only MCP tools - awooop_phase7_channel_hub_2026-05-04.sql: conversation_event + outbound_message - src/services/provider_proxy.py: ProviderProxy + PlatformEnvelope(ADR-115) - src/services/channel_hub.py: Telegram inbound mirror + Progressive Feedback(30s) - src/services/awooop_approval_token.py: HS256 + jti NX replay 防護 + suggest mode Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
5.2 KiB
5.2 KiB
INV-4: Hardcoded Namespace & IP Inventory
版本:v1.0 初稿
日期:2026-05-03(台北)
範圍:apps/api/src/ 全 codebase + k8s/
用途:Phase 2 多租戶改造 + EwoooC onboarding 前必須清理的硬碼
1. Hardcoded K8s Namespace
| 位置 | 行號 | 內容 | 影響 | 修補方式 |
|---|---|---|---|---|
apps/api/src/plugins/mcp/providers/k8s_provider.py |
40-41 | ALLOWED_NAMESPACES = {"awoooi-prod"} / DEFAULT_NAMESPACE = "awoooi-prod" |
🔴 P0-13:EwoooC K8s tool 無法操作自己的 namespace | 改為 config-driven:從 EffectivePolicy 或 project contract 讀 allowed namespaces |
apps/api/src/plugins/mcp/mcp_bridge.py |
592, 602, 631, 647, 681 | namespace = parameters.get("namespace", "awoooi-prod") |
🔴 P0-13:5 處預設值都寫死 | 改為 namespace = parameters.get("namespace", get_project_default_namespace(project_id)) |
apps/api/src/plugins/mcp/providers/signoz_provider.py |
169 | namespace = parameters.get("namespace", "awoooi-prod") |
🟠 SignOz query 預設 namespace 錯誤 | 同上 |
apps/api/src/main.py |
175 | sentry_sdk.set_tag("host", "k8s-awoooi-prod") |
🔵 Sentry tag 寫死,EwoooC 看到錯誤 host tag | 改為 settings.SENTRY_HOST_TAG |
apps/api/src/core/prompts.py |
120, 178, 192 | 系統 prompt 中出現 awoooi-prod |
🔵 LLM 可能在其他 tenant 錯誤建議 awoooi-prod namespace | 改為 {tenant_namespace} template variable |
2. Hardcoded IP Addresses
內網 IP(已知用途)
| IP | 用途 | 位置 | 改法 |
|---|---|---|---|
192.168.0.110 |
Gitea / Prometheus / Loki / MinIO | config.py:226,413,460,813 |
已在 config 以 default 存在,OK(K8s 覆蓋) |
192.168.0.111 |
Ollama Local Fallback | config.py + feedback_ollama_111_only.md(已更新) |
ADR-110 已改為第三層 fallback,config 需更新 |
192.168.0.112 |
ArgoCD | config.py:396 |
OK(config default) |
192.168.0.120 |
K3s API Server | config.py:531 |
OK(config default) |
192.168.0.121 |
K3s ingress? | config.py:837 |
確認用途 |
192.168.0.188 |
PostgreSQL / Redis / SigNoz / Grafana / ClickHouse | config.py 多處 |
OK(config default,K8s 以 env 覆蓋) |
🔴 問題:telemetry.py IP Assertion
| 位置 | 行號 | 內容 | 問題 |
|---|---|---|---|
apps/api/src/core/telemetry.py |
71 | if "192.168.0.188" not in endpoint: raise |
🔴 P0-08:EwoooC 啟動必失敗(EwoooC SigNoz 可能是不同 endpoint) |
| 修補方式 | 移除硬碼 assert,改為 if endpoint not in settings.ALLOWED_TELEMETRY_ENDPOINTS: |
GCP IP(新增,ADR-110,2026-05-03 生效)
| IP | 用途 | 位置 |
|---|---|---|
34.143.170.20 |
Ollama GCP-A Primary(SSD) | config.py(ADR-110 已加入 _ALLOWED_PUBLIC_IPS) |
34.21.145.224 |
Ollama GCP-B Secondary(SSD) | config.py(ADR-110 已加入 _ALLOWED_PUBLIC_IPS) |
注意:
- K8s NetworkPolicy egress:已新增 GCP-A/GCP-B /32 出口規則(ADR-110)
- INV-4 確認:GCP IP 已在
config.py._ALLOWED_PUBLIC_IPS白名單,非新增需求 - telemetry.py:71 assert:GCP IP 不影響(assert 是針對 OTEL endpoint,非 Ollama endpoint)
3. SSH Host Hardcodes
| 位置 | 內容 | 問題 | 修補 |
|---|---|---|---|
reference_four_hosts.md |
110/120/121/188 四主機清單 | 文件,不是程式碼,OK | 無 |
apps/api/src/plugins/mcp/providers/ssh_provider.py(若有) |
SSH 目標主機 | 需 grep 確認是否硬碼 | 改為 config-driven 白名單 |
4. 其他硬碼字串
| 位置 | 內容 | 問題 | 修補 |
|---|---|---|---|
apps/api/src/core/config.py:625 |
default="192.168.0.188=ollama" |
Ollama-to-host mapping,ADR-110 後需更新 | 改為 192.168.0.188=ollama_old(僅 fallback 相關) |
apps/api/src/core/config.py:828 |
default="192.168.0.188,192.168.0.110,192.168.0.111" |
主機清單 | 確認用途,若是 monitoring target 需加 GCP IP |
5. 改造策略(Phase 2)
K8s Namespace(優先)
# 方案:project contract 中定義允許的 K8s namespaces
# awooop_projects.k8s_namespaces: ["awoooi-prod"](AWOOOI)/ ["ewoooc-prod"](EwoooC)
# k8s_provider.py 從 project contract 讀,而非硬碼
def get_allowed_namespaces(project_id: str) -> set[str]:
contract = get_active_project_contract(project_id)
return set(contract.allowed_k8s_namespaces)
Telemetry Endpoint Assert(P0-08,PR-01 優先)
# 修改前(telemetry.py:71)
if "192.168.0.188" not in endpoint:
raise ValueError(f"Forbidden OTEL endpoint: {endpoint}")
# 修改後
allowed_endpoints = settings.ALLOWED_TELEMETRY_ENDPOINTS.split(",")
if not any(allowed in endpoint for allowed in allowed_endpoints):
raise ValueError(f"Forbidden OTEL endpoint: {endpoint}")
6. 驗收標準
grep -r "192.168.0.188" apps/api/src/中telemetry.py的 assert 行消失grep -r '"awoooi-prod"' apps/api/src/中的程式碼路徑(非 prompt 文字、非 comment)結果為 0- k8s_provider.py
ALLOWED_NAMESPACES改為 config-driven - INV-4 中標記 GCP IP 已確認加入 NetworkPolicy(ADR-110 完成)
最後更新:2026-05-03(台北)