# Nginx 配置只讀漂移偵測器

| 項目 | 內容 |
|------|------|
| 日期 | 2026-06-11 |
| 狀態 | `repo_only_detector_ready` |
| 工具 | `scripts/security/nginx-config-drift-detector.py` |
| Snapshot | `docs/security/nginx-config-drift-repo.snapshot.json` |
| runtime gate | `0` |

## 1. 目的

本工具把 Nginx 從「靠人記得不要手改」推進到「有可重跑的 source-of-truth 指紋與後續 live 比對格式」。目前只讀 repo 內配置，不 SSH、不 reload、不修改主機。

## 2. 已納管 source-of-truth

| config id | 主機 | repo source | live path | 等級 |
|-----------|------|-------------|-----------|------|
| `host188_all_sites` | `192.168.0.188` | `infra/ansible/roles/nginx/templates/188-all-sites.conf.j2` | `/etc/nginx/sites-enabled/all-sites.conf` | C0 |
| `host188_internal_tools_https` | `192.168.0.188` | `infra/ansible/roles/nginx/templates/188-internal-tools-https.conf.j2` | 待 owner 確認 | C0 |
| `host110_ollama_proxy` | `192.168.0.110` | `infra/ansible/roles/nginx/templates/110-ollama-proxy.conf.j2` | `/etc/nginx/sites-enabled/110-ollama-proxy.conf` | C1 |

## 3. 可產出的證據

工具會輸出：

1. repo raw / normalized SHA-256。
2. `server_name` 清單。
3. `listen` 清單。
4. `proxy_pass` upstream 清單。
5. TLS certificate / key path 清單。
6. `/admin` route、ACME challenge route、WebSocket route。
7. live conf 若由 owner 提供，會比較 normalized hash、server name、upstream 與 TLS path 差異。

## 4. 指令

repo-only snapshot：

```bash
python3 scripts/security/nginx-config-drift-detector.py \
  --root . \
  --generated-at 2026-06-11T12:00:00+08:00 \
  --output docs/security/nginx-config-drift-repo.snapshot.json
```

未來 owner 提供 live conf 匯出檔後，可用比較模式：

```bash
python3 scripts/security/nginx-config-drift-detector.py \
  --root . \
  --live-file host188_all_sites=/path/to/redacted-live-188-all-sites.conf \
  --live-file host110_ollama_proxy=/path/to/redacted-live-110-ollama-proxy.conf
```

## 5. 判讀規則

| 狀態 | 意義 | 可做事項 |
|------|------|----------|
| `repo_only_no_live_evidence` | 只有 repo source-of-truth 指紋，尚未比較 live | 可作為 owner request packet，不能宣稱 live 無漂移 |
| `matched` | owner 提供的 live 檔與 repo normalized hash / 語意比對一致 | 可記 evidence，仍不代表 reload 已授權 |
| `drift_detected` | live 與 repo 出現 hash 或語意差異 | 建立 P0 drift evidence 與 owner decision，不自動覆寫 live |
| `live_file_missing` | 指定的 live 匯出檔不存在 | 要求補件，不做判斷 |

## 6. 邊界

1. 本工具不執行 SSH。
2. 本工具不執行 `nginx -t`。
3. 本工具不 reload / restart Nginx。
4. 本工具不讀 TLS private key 內容。
5. 本工具不收 secret value。
6. 本工具不開 runtime gate。

## 7. 完成度

| 工作 | 完成度 | 說明 |
|------|--------|------|
| repo source-of-truth 指紋 | `100%` | 已覆蓋三份 Nginx source templates |
| domain / upstream / TLS / admin / ACME 摘要 | `100%` | 已由 parser 產出 |
| owner-provided live file 比對格式 | `70%` | 支援手動提供 live conf 檔，不主動取得 live |
| live Nginx 證據收集 | `0%` | 本階段不 SSH、不讀主機 |
| Nginx reload / restart | `0%` | 未授權且未執行 |

## 8. Preflight 銜接

`docs/security/PUBLIC-GATEWAY-PREFLIGHT-INVENTORY.md` 會消費本工具與 DNS / TLS 清冊的 repo-only 結果，固定 Nginx reload / route change 前必備的 owner、live conf、rendered diff、`nginx -t`、route smoke、maintenance window 與 rollback owner 欄位。

此銜接仍不代表 live conf 已收、drift 已判定、`nginx -t` 已執行或 reload 已授權。
