# 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（優先）
```python
# 方案：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 優先）
```python
# 修改前（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（台北）*
