# Windows 开发 / Ubuntu 部署 — 字符与换行审计

| 项 | 内容 |
|----|------|
| 日期 | 2026-06-02 |
| 范围 | 换行符 (LF/CRLF)、UTF-8、路径分隔符、部署脚本、远程文件 EOL |
| 生产目标 | Ubuntu（Supervisor + bash），开发机常见为 Windows |

## 结论摘要

| 类别 | 状态 | 说明 |
|------|------|------|
| 远程 Linux 路径 | ✅ 已治理 | `server/utils/posix_paths.py` + 2026-06-01 全量审计 |
| 远程文件 UTF-8 | ✅ | 读写 `utf-8` / `errors=replace`，SFTP 二进制 |
| 远程文件 EOL | ✅ 有意支持 | API 返回 `eol: LF\|CRLF`，前端按原 EOL 写回 |
| `.gitattributes` | ✅ 已配置 | `*.sh` / `*.py` → `eol=lf` |
| 工作区 CRLF 泄漏 | ⚠️ 发现 14 个 `.sh` | 见下表；已在本次审计中转为 LF |
| 部署路径 | ⚠️ 流程风险 | Windows 应用 **WSL/Git Bash** 跑 `deploy/*.sh`；勿用 PowerShell 直接 `tar` 打包（曾出现空包） |
| 门控 | ✅ 补强 | `deploy/check_shell_eol.sh`，接入 `pre_deploy_check.sh` |

---

## 1. 换行符 (CRLF vs LF)

### 风险

Ubuntu 上执行带 CR 的 shell 脚本会出现 `\r: command not found` 或 `bad interpreter`。历史记录见 `docs/changelog/2026-05-27-agent-install-fix-and-deploy.md`。

### 仓库策略（`.gitattributes`）

```
*.sh text eol=lf
*.py text eol=lf
*.bat / *.cmd text eol=crlf
```

### 本次扫描（Windows 工作区，2026-06-02）

以下文件检出 **CRLF**（已在本轮修复为 LF）：

| 文件 |
|------|
| `deploy/db_backup.sh` |
| `deploy/health_monitor.sh` |
| `deploy/install.sh` |
| `deploy/pre_deploy_check.sh` |
| `deploy/run_test_api_on_server.sh` |
| `deploy/uninstall.sh` |
| `deploy/upgrade.sh` |
| `scripts/run_full_acceptance.sh` |
| `scripts/wsl_*.sh`（5 个） |
| `web/agent/agent.sh` |

**已为 LF（无需改）**：`deploy/deploy-frontend.sh`、`web/agent/install.sh`、`scripts/run_full_e2e.sh` 等。

### 开发机建议

```bash
git config core.autocrlf false
git add --renormalize '*.sh' '*.py'
```

推送前在 WSL 或 CI 上执行：`bash deploy/check_shell_eol.sh`

---

## 2. 字符编码 (UTF-8)

| 位置 | 处理 |
|------|------|
| API 读远程文件 | `cat` → Python `str`，响应当 UTF-8 JSON |
| API 写远程文件 | `payload.content.encode("utf-8")` |
| 本机读推送源 | `open(..., encoding="utf-8", errors="replace")` |
| 安装向导写 `.env` / `config.json` | `Path.write_text`，`\n` 连接（Linux 安装目标为 LF） |
| 前端 | Vite/浏览器默认 UTF-8；Monaco 按 UTF-8 编辑 |

**注意**：Windows 记事本「UTF-8 BOM」写入的 `.env` 可能导致首行 key 带 BOM；安装向导应在 Linux 生成配置，勿在 Windows 记事本手改后上传。

---

## 3. 路径（反斜杠 vs `/`）

| 层 | 状态 |
|----|------|
| 后端远程路径 | ✅ `posix_paths` / `normalize_remote_abs_path`，拒绝 `\` |
| 前端 `remotePath.ts` | ✅ `normalizeRemotePath` + `coercePathString`（防 Ref/非字符串） |
| 后端 `os.path.join` 用于远程 | ✅ 已清除（仅本机 FS 与文档注释保留） |

详见：`docs/audit/2026-06-01-posix-path-full-audit.md`

---

## 4. 远程文件 EOL（业务语义，非缺陷）

- `POST /sync/read-file`：`eol = "CRLF" if "\r\n" in content else "LF"`
- 前端 `FileEditorWorkbench`：内部比较用 LF；保存时 `serializeContent(..., tab.eol)` 恢复原 EOL
- 测试：`tests/test_editor_write_conflict.py` 覆盖 CRLF 写回

在 Ubuntu 上编辑 Windows 生成的 `\r\n` 文件是**预期行为**，不是编码错误。

---

## 5. 部署流程（Windows → Ubuntu）

| 操作 | 推荐 | 避免 |
|------|------|------|
| 后端部署 | `git push` + 服务器 `git pull` + `supervisorctl restart` | 在 Windows 上改服务器 `.sh` 用 CRLF 保存 |
| 前端部署 | WSL/Git Bash：`bash deploy/deploy-frontend.sh` | PowerShell `tar` 路径/工作目录错误导致空包 |
| 门控 | 服务器或 WSL：`bash deploy/pre_deploy_check.sh` | 跳过门控直接覆盖 `web/app` |
| Agent 脚本 | 目标机 `bash install.sh`（仓库内须 LF） | `sh` 执行 CRLF 脚本 |

---

## 6. Closure（规则扫描）

| H | 判定 | 依据 |
|---|------|------|
| H1 注入 | N/A | 本审计无代码逻辑变更（EOL 脚本除外） |
| H2 路径 | PASS | posix_paths 已覆盖远程路径 |
| H3 编码 | PASS | API/前端 UTF-8；EOL 显式建模 |
| H4 CRLF 脚本 | FINDING→已修 | 14 个 `.sh` CRLF；已 LF 化 + 门控 |
| H5 部署 | WARN | 文档化 Windows tar/PS 风险 |

## DoD

- [x] 扫描仓库 `.sh` CRLF
- [x] 核对 `.gitattributes`、posix 路径审计、read/write-file EOL
- [x] 新增 `deploy/check_shell_eol.sh` 并接入 pre_deploy
- [x] 修复检出 CRLF 的 shell 脚本
- [x] changelog 记录
- [ ] 可选：CI 增加 `check_shell_eol.sh`（Gitea Actions）

## 涉及文件（本轮）

- `docs/audit/2026-06-02-windows-ubuntu-encoding-audit.md`（本文件）
- `deploy/check_shell_eol.sh`
- `deploy/pre_deploy_check.sh`（调用 EOL 检查）
- 上述 14 个 `.sh`（CRLF→LF）
