# AM62X Deployment 參數化實施報告

## 實施資訊

- **開始日期**: 2025-11-06
- **計劃文件**: `.ai/prpi/plans/2025-11-06-am62x-deployment-params.md`
- **實施階段**: Phase 1 & Phase 2 完成
- **Git Branch**: deploy-config

## Phase 1: 連線配置參數化 ✅

### 實施概要

將硬編碼的 SSH/SCP 連線參數移至配置系統，支援 User Config 和 Project Config 兩層繼承。

### 已完成項目

#### 1.1 UserConfig 擴展 ✅
**檔案**: `src/fwauto/user_config.py`

新增方法：
- `get_deployment_config(sdk_type: str) -> dict | None`
- `set_deployment_config(sdk_type: str, deployment_data: dict) -> None`

儲存位置：`~/.fwauto/config.toml`

#### 1.2 ProjectConfig 擴展 ✅
**檔案**: `src/fwauto/config.py`

新增屬性：
- `deployment_config` - 支援 Project > User 繼承
- `board_ip`, `board_user`, `deploy_path`, `ssh_options` - 便利屬性

預設值：
```python
board_ip: "192.168.50.170"
board_user: "root"
deploy_path: "/home/root"
ssh_options: "-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=5"
```

#### 1.3 Init 命令擴展 ✅
**檔案**: `src/fwauto/cli_commands/init.py`

新增 Step 3.5：AM62X deployment 配置收集
- 僅在 `sdk_type` 包含 "am62x" 時顯示
- 提示輸入：board_ip, board_user, deploy_path
- 自動儲存至 User Config

#### 1.4 Flash Node 修改 ✅
**檔案**: `src/fwauto/nodes/flash.py`

變更：
- 提取 `config.board_ip`, `config.board_user`, `config.deploy_path`, `config.ssh_options`
- 建立 `deployment_env` 字典
- 傳遞給 `execute_make_command()` 的 `env_vars` 參數

#### 1.5 Utils 層支援 ✅
**檔案**: `src/fwauto/utils.py`

變更：
- `execute_make_command()` 新增 `env_vars: dict[str, str] | None` 參數
- 合併環境變數：`env = os.environ.copy()` + `env.update(env_vars)`
- 傳遞給 `subprocess.Popen(..., env=env)`

#### 1.6 Makefile 修改 ✅
**檔案**: `src/fwauto/templates/sdk_am62x_linux/flash/Makefile`

變更：
```makefile
# 新增變數定義
BOARD_IP ?= 192.168.50.170
BOARD_USER ?= root
DEPLOY_PATH ?= /home/root
SSH_OPTIONS ?= -o StrictHostKeyChecking=no ...

# flash target 中 export
@export BOARD_IP="$(BOARD_IP)"; \
 export BOARD_USER="$(BOARD_USER)"; \
 export DEPLOY_PATH="$(DEPLOY_PATH)"; \
 export SSH_OPTIONS="$(SSH_OPTIONS)"; \
 bash flash.sh
```

#### 1.7 Shell Script 修改 ✅
**檔案**: `src/fwauto/templates/sdk_am62x_linux/flash/flash.sh`

變更：
```bash
# 使用環境變數 fallback 語法
BOARD_IP="${BOARD_IP:-192.168.50.170}"
BOARD_USER="${BOARD_USER:-root}"
DEPLOY_PATH="${DEPLOY_PATH:-/home/root}"
SSH_OPTS="${SSH_OPTIONS:--o StrictHostKeyChecking=no ...}"
```

### 測試結果

#### 自動化測試 ✅
- **測試檔案**:
  - `tests/test_user_config.py` - 新增 2 個測試
  - `tests/test_project_config.py` - 新增 3 個測試
- **結果**: 15/15 測試通過

#### 手動驗證 ✅
- User Config 配置：✅ 已驗證
- Project Config 覆寫：✅ 已驗證
- 預設值 Fallback：✅ 已驗證
- 環境變數傳遞：✅ 已驗證

---

## Phase 2: 基礎參數傳遞 ✅

### 實施概要

建立從 CLI 到遠端二進位的完整參數傳遞鏈路，支援 `fwauto flash --binary-args "arg1 arg2"`。

### 已完成項目

#### 2.1 CLI 新增參數 ✅
**檔案**: `src/fwauto/cli.py`

變更：
- `flash()` 命令新增 `binary_args: str = typer.Option("", "--binary-args", "-ba")`
- `run()` 命令新增相同參數
- 儲存至 `state["command_args"]["binary_args"]`

使用範例：
```bash
fwauto flash --binary-args "on"
fwauto flash -ba "--mode test --timeout 5"
fwauto run --binary-args "debug"
```

#### 2.2 Flash Node 提取參數 ✅
**檔案**: `src/fwauto/nodes/flash.py`

變更：
```python
# 提取參數
command_args = state.get("command_args") or {}
binary_args = command_args.get("binary_args", "")

# 安全檢查
dangerous_chars = [";", "|", "&", "$", "`", "\n", "\r"]
if any(c in binary_args for c in dangerous_chars):
    return error_result("dangerous shell metacharacters")

# 加入環境變數
if binary_args:
    deployment_env["BINARY_ARGS"] = binary_args
```

**安全特性**:
- 禁止 shell 命令注入攻擊
- 檢查並拒絕危險字符

#### 2.3 Makefile 轉發 ✅
**檔案**: `src/fwauto/templates/sdk_am62x_linux/flash/Makefile`

變更：
```makefile
# 新增變數
BINARY_ARGS ?=

# flash target
@export BOARD_IP="$(BOARD_IP)"; \
 export BOARD_USER="$(BOARD_USER)"; \
 export DEPLOY_PATH="$(DEPLOY_PATH)"; \
 export SSH_OPTIONS="$(SSH_OPTIONS)"; \
 export BINARY_ARGS="$(BINARY_ARGS)"; \
 bash flash.sh
```

#### 2.4 Shell Script 使用 ✅
**檔案**: `src/fwauto/templates/sdk_am62x_linux/flash/flash.sh`

變更：
```bash
execute_on_board() {
    local binary_name="$1"
    local binary_args="${BINARY_ARGS:-}"

    log_info "Executing $binary_name on board..."

    if [ -n "$binary_args" ]; then
        log_info "With arguments: $binary_args"
    fi

    # 執行帶參數
    ssh $SSH_OPTS "$BOARD_USER@$BOARD_IP" \
        "cd $DEPLOY_PATH && chmod +x ./$binary_name && ./$binary_name $binary_args"
}
```

### 測試結果

#### 自動化測試 ✅
- **測試檔案**: `tests/nodes/test_flash_makefile.py` - 新增 3 個測試
  - `test_flash_node_with_binary_args` - 參數傳遞
  - `test_flash_node_rejects_dangerous_binary_args` - 安全檢查
  - `test_flash_node_with_empty_binary_args` - 空參數處理
- **結果**: 25/25 測試通過（包含 Phase 1 測試）

#### 手動驗證 ⚠️ **發現問題**

**測試場景**:
```bash
alientek@alientek:~/kent/TI_am62x/projects/15_led$ fwauto flash --binary-args "off"
```

**問題描述**:
- 從輸出未顯示 "With arguments: off"
- 遠端程式顯示 usage 訊息（表示未收到參數）
- 根本原因：**現有專案使用舊版 template 檔案**

**原因分析**:
1. Phase 2 修改的是 `src/fwauto/templates/sdk_am62x_linux/` 中的模板
2. 使用者專案中的 `.fwauto/flash/Makefile` 和 `flash.sh` 是 Phase 1 建立的舊版本
3. 舊版本不包含 `BINARY_ARGS` 的 export 和處理邏輯

### 待解決問題

#### 問題：Template 版本不同步

**現狀**:
- FWAuto 核心已更新至 Phase 2
- 現有專案仍使用 Phase 1 template（沒有 BINARY_ARGS 支援）

**影響範圍**:
- 所有在 Phase 2 之前建立的 AM62X 專案
- 使用者需要手動更新或重新初始化

**潛在解決方案**:

**選項 A: 手動更新（臨時方案）**
```bash
# 備份現有檔案
cp .fwauto/flash/Makefile .fwauto/flash/Makefile.backup
cp .fwauto/flash/flash.sh .fwauto/flash/flash.sh.backup

# 從 FWAuto template 複製新版本
# （需要知道 FWAuto 安裝位置）
```

**選項 B: 實作 `fwauto update` 命令（推薦）**
```bash
fwauto update
# 自動偵測 template 版本差異
# 提示使用者確認後更新
```

功能需求：
- 偵測專案中的 template 版本
- 比較與核心 template 的差異
- 提供安全更新機制（保留使用者自訂修改）
- 支援選擇性更新（例如只更新 flash/, 不動 build/）

**選項 C: Template 版本管理系統**
- 在 `.fwauto/` 中加入 `template_version.txt`
- Init 時記錄 template 版本
- 執行命令時檢查版本，提示升級

**選項 D: 重新初始化（破壞性）**
```bash
fwauto init --overwrite
# 會覆蓋所有 .fwauto/ 檔案
```

---

## 修改檔案清單

### Phase 1 修改（9 個檔案）
- `src/fwauto/user_config.py`
- `src/fwauto/config.py`
- `src/fwauto/cli_commands/init.py`
- `src/fwauto/nodes/flash.py`
- `src/fwauto/utils.py`
- `src/fwauto/templates/sdk_am62x_linux/flash/Makefile`
- `src/fwauto/templates/sdk_am62x_linux/flash/flash.sh`
- `tests/test_user_config.py`
- `tests/test_project_config.py`

### Phase 2 額外修改（5 個檔案，部分與 Phase 1 重疊）
- `src/fwauto/cli.py` ⭐ 新增
- `src/fwauto/nodes/flash.py` 📝 繼續修改
- `src/fwauto/templates/sdk_am62x_linux/flash/Makefile` 📝 繼續修改
- `src/fwauto/templates/sdk_am62x_linux/flash/flash.sh` 📝 繼續修改
- `tests/nodes/test_flash_makefile.py` ⭐ 新增

---

## 配置範例

### User Config 範例
**檔案**: `~/.fwauto/config.toml`

```toml
[sdk.am62x]
type = "am62x"
path = "/opt/ti-processor-sdk-linux-am62xx-evm-09.02.01.10"
version = "09.02.01.10"

[device.am62x]
family = "am62x"
model = "AM625x"

[deployment.am62x]
board_ip = "192.168.50.169"
board_user = "root"
deploy_path = "/home/root/led"
ssh_options = "-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=5"
```

### Project Config 範例
**檔案**: `.fwauto/config.toml`

```toml
[sdk]
type = "am62x"
# path 從 User Config 繼承

[device]
family = "am62x"
model = "AM625x"

[build]
target = "build"
makefile = ".fwauto/build/Makefile"

[flash]
target = "flash"
makefile = ".fwauto/flash/Makefile"

# deployment 配置（可選，覆寫 User Config）
[deployment.am62x]
board_ip = "192.168.1.100"  # Project 特定 IP
```

---

## 下一步行動

### 立即處理（必要）
1. **決定 Template 更新策略**
   - 選擇選項 A/B/C/D
   - 提供使用者更新指引或實作自動更新

### Phase 2 完整驗證（等待 Template 更新後）
- [ ] 基本參數傳遞測試
- [ ] 多參數測試
- [ ] run 命令測試
- [ ] 向後兼容測試
- [ ] 安全檢查驗證

### Phase 3 準備（未來）
- Scenarios 系統設計確認
- 實作 Scenario dataclass
- CLI scenario 選項
- Scenario 與 binary_args 整合

---

## 技術決策記錄

### 環境變數作為參數傳遞機制
**決策**: 使用環境變數在 Python → Make → Bash 之間傳遞參數

**理由**:
- 跨平台兼容（Linux/macOS/Windows WSL）
- 避免 shell 引號轉義問題
- 清晰的參數隔離
- 易於 debug（可在任何層級檢查環境變數）

**替代方案**:
- ❌ 命令列參數：需要處理複雜的引號轉義
- ❌ 臨時檔案：增加複雜度和清理邏輯
- ❌ 直接 SSH：繞過 Makefile，破壞抽象層

### 安全檢查位置選擇
**決策**: 在 Flash Node（Python 層）進行參數驗證

**理由**:
- 早期驗證，避免無效操作進入底層
- Python 更易撰寫和測試複雜邏輯
- 集中式錯誤處理
- 可記錄詳細的安全日誌

### 配置繼承模式
**決策**: Project Config > User Config > Template defaults

**理由**:
- 符合直覺（專案優先於全域）
- 支援多專案不同配置
- 保留 template 預設值作為最終 fallback
- 與現有 SDK path 繼承模式一致

---

## 已知限制

1. **不支援 SSH 密碼認證**
   - 當前假設 SSH 公鑰已配置
   - 不處理 SSH 金鑰管理
   - 設計決策：KISS 原則

2. **Template 版本管理缺失**
   - 無法自動偵測 template 過期
   - 使用者需手動同步更新
   - 待 Phase 2 完整驗證後實作

3. **參數安全檢查基礎**
   - 僅檢查基本危險字符
   - 未實作完整的參數解析和驗證
   - 足夠應對常見威脅

---

## 貢獻者

- AI Assistant (Claude) - 實作與測試
- Kent (User) - 需求定義、計劃審查、手動驗證

---

**實施狀態**: Phase 1 ✅ 完成並驗證 | Phase 2 ✅ 實作完成，⚠️ 需 Template 更新後驗證
