# MySQL Schema Apply / DDL Executor 安全策略

## 1. 文件目的

本文件整理第二階段 B 對 `Schema Apply / DDL Executor` 的安全策略。目標是在未來允許 Host 或工具執行資料庫 schema apply 前，先固定 gate、權限、備份、rollback、人工確認與停止線。

本文件只做安全策略設計，不實作 DDL executor、不執行 `CREATE TABLE` / `ALTER TABLE` / `DROP`、不修改資料庫、不修改 ConsoleHost 啟動流程、不新增 WebApi / ServiceHost，也不保存任何密碼或連線字串。

## 2. 目前狀態

| 項目 | 狀態 | 說明 |
| --- | --- | --- |
| Schema Attribute | 已完成 | 可用 C# class 維護 table、column、index、comment。 |
| SQL Generator | 已完成 | 可產生 MySQL 5.6.2 相容 SQL preview。 |
| Schema Inspector | 已完成 | 可讀取 expected / current schema，真實 MySQL metadata inspect 已採 manual-only。 |
| Dry Run Planner | 已完成 | 可產生差異與 SQL preview，不執行 DDL。 |
| ConsoleHost DryRun 顯示 | 已完成 | 目前只顯示 preview 與警告。 |
| DDL Executor | 尚未實作 | 本文件先定義安全策略。 |
| 自動 Apply | 尚未允許 | 未確認前不得導入。 |

## 3. 核心原則

1. `DryRun` 永遠是預設模式。
2. `Apply` 必須明確 gate，不得因設定檔存在就自動執行。
3. 正式 DB 與測試 DB 使用不同帳號權限。
4. DDL 前必須輸出可人工審核的 plan。
5. DDL 前必須記錄備份與 rollback 策略。
6. DDL 失敗時不得吞 exception，需輸出 table、operation、SQL preview 與已遮蔽錯誤。
7. 不得將密碼、token、connection string 寫入 repo、log、console 或文件。
8. 對 MySQL 5.6.2 要保守處理，不能假設 DDL 可 transaction rollback。

## 4. 建議模式分級

| 模式 | 是否允許連 DB | 是否允許 DDL | 用途 |
| --- | --- | --- | --- |
| `DryRunOnly` | 可選 | 否 | 預設模式，只產生差異與 SQL preview。 |
| `InspectOnly` | 是 | 否 | 讀取 `information_schema`，不修改 DB。 |
| `ManualApplyPreview` | 是 | 否 | 產生可審核 apply plan，等待人工確認。 |
| `ManualApply` | 是 | 是，僅測試 DB | 使用者明確確認後才可執行。 |
| `ProductionApply` | 是 | 是，但暫不建議 | 需另行設計審核、備份、維運窗口與 rollback。 |

第二階段 B 只建議完成 `DryRunOnly`、`InspectOnly` 與 `ManualApplyPreview` 策略；不建議直接開放 `ProductionApply`。

## 5. Apply Gate 草案

後續若進入實作，建議使用獨立 gate，不與 TaskStore / LogWriter gate 混用。

```text
HS_MYSQL_SCHEMA_APPLY_ENABLED
HS_MYSQL_SCHEMA_APPLY_ALLOW_DDL
HS_MYSQL_SCHEMA_APPLY_TARGET
HS_MYSQL_SCHEMA_APPLY_REQUIRE_CONFIRMATION
HS_MYSQL_SCHEMA_APPLY_CONFIRMATION_TOKEN
HS_MYSQL_SCHEMA_APPLY_BACKUP_CONFIRMED
HS_MYSQL_SCHEMA_APPLY_ROLLBACK_PLAN_CONFIRMED
```

建議規則：

- `HS_MYSQL_SCHEMA_APPLY_ENABLED=true` 只表示允許產生 apply plan。
- `HS_MYSQL_SCHEMA_APPLY_ALLOW_DDL=true` 才可執行 DDL。
- `HS_MYSQL_SCHEMA_APPLY_TARGET=Test` 時才允許第二階段 PoC DDL。
- `HS_MYSQL_SCHEMA_APPLY_TARGET=Production` 時，本階段仍應停止。
- `HS_MYSQL_SCHEMA_APPLY_BACKUP_CONFIRMED=true` 前不得執行 DDL。
- `HS_MYSQL_SCHEMA_APPLY_ROLLBACK_PLAN_CONFIRMED=true` 前不得執行 DDL。
- `CONFIRMATION_TOKEN` 必須是本次 plan 產出的 hash 或人工確認字串，不得寫死。

## 6. 權限策略

| 帳號用途 | 建議權限 | 備註 |
| --- | --- | --- |
| Inspect account | `SELECT` on `information_schema` / target schema metadata | 只讀 metadata。 |
| TaskStore test account | `SELECT`、`INSERT`、`UPDATE`、`DELETE` | 用於 manual-only DML 驗證。 |
| Apply test account | `CREATE`、`ALTER`、`INDEX`、必要時 `DROP` | 只限測試 DB，且需人工 gate。 |
| Production runtime account | 不應具備 DDL | 正式執行時避免誤 apply。 |
| Production apply account | 僅維運窗口使用 | 不應寫入 repo 或一般 host 設定。 |

## 7. Apply Plan 必要資訊

每次 apply 前必須先產生 plan，至少包含：

| 欄位 | 說明 |
| --- | --- |
| `PlanId` | 本次 plan 識別碼。 |
| `GeneratedAt` | 產生時間。 |
| `TargetDatabase` | 目標 DB 名稱，host 需遮蔽。 |
| `SchemaVersion` | 若未導入版本表，需標示 `NotAvailable`。 |
| `Operations` | 新增 table、欄位、index、comment 等操作。 |
| `SqlPreview` | 已遮蔽且可人工審查的 SQL。 |
| `DestructiveOperations` | 是否包含 DROP、MODIFY、CHANGE、縮短欄位、改 nullable。 |
| `RequiresBackup` | 是否需備份。 |
| `RollbackHint` | 人工 rollback 提示。 |
| `PlanHash` | 用於 confirmation token。 |

## 8. 高風險操作分類

| 操作 | 風險 | 第二階段建議 |
| --- | --- | --- |
| `CREATE TABLE` | 中 | 測試 DB 可 manual-only，正式 DB 暫不允許。 |
| `ADD COLUMN nullable` | 中 | 需人工確認。 |
| `ADD COLUMN not null` | 高 | 若無 default，可能失敗或影響既有資料。 |
| `ADD INDEX` | 中到高 | 大表可能鎖表，需維運窗口。 |
| `MODIFY COLUMN` | 高 | 可能截斷或轉型失敗。 |
| `CHANGE COLUMN` | 高 | 可能破壞程式欄位對應。 |
| `DROP COLUMN` | 極高 | 本階段不允許。 |
| `DROP TABLE` | 極高 | 本階段不允許。 |
| 改 table charset / collation | 高 | 需另行評估。 |

## 9. MySQL 5.6.2 注意事項

- DDL 大多不是一般 transaction rollback 能保護的操作。
- `ALTER TABLE` 可能造成 table lock。
- `TEXT` 欄位 index 需指定 prefix，不能直接任意加完整 index。
- `datetime` 沒有 timezone，需要由應用層統一時間策略。
- `COMMENT` 長度與字元集需保守處理。
- `IF NOT EXISTS` 支援度需依實際 SQL 類型確認。
- 大表 apply 前需先估計資料量與維運窗口。

## 10. Backup 與 Rollback 策略

執行 DDL 前至少要確認：

| 項目 | 必要性 | 說明 |
| --- | --- | --- |
| schema dump | 必要 | 保存目前 table schema。 |
| data backup | 視操作而定 | 對 DROP / MODIFY / CHANGE 類操作必須有資料備份。 |
| rollback SQL | 必要 | 至少提供人工 rollback hint。 |
| 維運窗口 | 正式 DB 必要 | 避免操作中斷現場流程。 |
| 操作人 | 必要 | 紀錄誰確認 apply。 |
| plan hash | 必要 | 防止確認的 plan 與執行的 plan 不一致。 |

第二階段 B 可先完成策略與 plan 格式；正式 backup executor 與 rollback executor 不納入本階段。

## 11. Apply 執行停止線

以下任一條件成立，必須停止，不得執行 DDL：

- 目標不是測試 DB，且未另行取得正式 Apply 明確授權。
- 缺少 backup 確認。
- 缺少 rollback plan 確認。
- plan 包含 `DROP TABLE` 或 `DROP COLUMN`。
- plan 包含縮短欄位長度。
- plan 包含 not null 欄位且沒有 default / backfill 策略。
- plan hash 與 confirmation token 不一致。
- schema inspector 無法讀取目前 schema。
- SQL preview 含未遮蔽密碼、token、connection string。
- 工作樹或文件顯示目前 schema 規格未收斂。

## 12. 後續實作前確認項目

若要從策略進入程式實作，需先確認：

1. 是否只做 `ManualApplyPreview`，不做真正 DDL。
2. Apply plan model 放在哪個專案。
3. DDL executor 是否獨立介面，是否 public。
4. 是否需要 `schema_migrations` 或 `schema_apply_history` table。
5. 是否允許在測試 DB 建立 apply history table。
6. confirmation token 來源與格式。
7. ConsoleHost 是否只顯示 plan，不提供 apply。
8. 是否要把正式 Apply 延到第三階段。

## 13. 建議測試策略

| 測試 | 目的 |
| --- | --- |
| Apply plan classification | 確認高風險操作會被標示。 |
| Gate disabled | 未開 gate 時只能 dry run。 |
| Production target block | 目標正式 DB 時停止。 |
| Missing backup block | 缺少 backup confirmation 時停止。 |
| Destructive operation block | DROP / MODIFY 等高風險操作需被擋下。 |
| Plan hash mismatch | 確認 token 不一致不得 apply。 |
| SQL preview redaction | 確認輸出不含敏感資訊。 |

## 14. 建議結論

第二階段 B 應先把 `Schema Apply / DDL Executor` 收斂為安全策略與 `ManualApplyPreview` 邊界，不建議直接進入真正 DDL executor。

若後續要實作，建議第一步只做 apply plan model 與高風險分類測試；真正執行 DDL 仍需使用者再次確認。
