# 编码 / 换行审查 — Ubuntu 工作区(阶段 1) | 项 | 内容 | |----|------| | 日期 | 2026-06-04 | | 范围 | Git 索引 vs 工作区、运行时 UTF-8/EOL、Windows 遗留路径 | | 前置 | `docs/audit/2026-06-02-windows-ubuntu-encoding-deep-dive.md` | --- ## 阶段 1 结论(摘要) | 维度 | Git 索引(部署真相) | 本机工作区(tar/检出) | |------|----------------------|----------------------| | `check_text_eol.py` | **PASS**(206 路径无 CR) | — | | `check_shell_eol.sh` | **PASS** | — | | `check_worktree_eol.py` | — | **FAIL**(约 171 个跟踪文件磁盘含 `\r`) | | 运行时写 `.env` | `install.py` / `sync_mysql_mcp_env` 已用 `text_io` | — | | 新脚本 `proxy-env.sh` 等 | 未入库前曾 **CRLF** | 已 `sed` 去 CR | **核心区分**:Ubuntu 生产以 **`git pull` 的索引 blob** 为准;离线 tar 解压到本机后,工作区可能是 CRLF,会导致 `source *.sh` 报 `未找到命令`(行尾 `\r`)。 --- ## 1. 已有防护(保持) | 组件 | 路径 | |------|------| | SSOT | `server/utils/text_io.py` | | 索引门控 | `scripts/check_text_eol.py` | | Shell 门控 | `deploy/check_shell_eol.sh` | | 编辑器 | `.editorconfig` → `charset=utf-8`, `eol=lf` | | Git | `.gitattributes` → `*.py/sh/vue/ts` = `eol=lf` | | 部署 Pre-flight | `deploy/pre_deploy_check.sh` 调用上述门控 | --- ## 2. 本轮发现(按严重度) ### P1 — 工作区 CRLF vs 索引 LF - **现象**:`grep -l $'\r'` 在 `server/**/*.py` 等约 **171** 个已跟踪文件命中;`file scripts/proxy-env.sh` 显示 `CRLF line terminators`。 - **影响**:bash `source scripts/proxy-env.sh` 出现 `:未找到命令`;不影响已从 Git 拉取的 Ubuntu 服务器(索引为 LF)。 - **修复**: ```bash git config core.autocrlf false bash scripts/normalize_worktree_lf.sh python3 scripts/check_worktree_eol.py ``` ### P2 — `docker/sync_root_env.py` 未走 `text_io`(已修) - **问题**:`read_text`/`write_text` 未归一化 CRLF,Windows 生成的 `docker/.env` 可能把 `\r` 带进 `NEXUS_*`。 - **修复**:改用 `read_utf8_lf` / `write_utf8_lf`。 ### P2 — `linux_mcp_mysql.sh` 读 `.env` 未去 `\r`(已修) - **问题**:`export MYSQL_PASSWORD=xxx\r` 导致 MCP 连库失败。 - **修复**:`line="${line%$'\r'}"`。 ### P3 — `web/agent/agent.py` 读 `/etc/os-release` 无 encoding(已修) - **修复**:`read_text(encoding="utf-8")`(Linux 标准 UTF-8)。 ### 合理设计(非缺陷) | 位置 | 说明 | |------|------| | `servers.py` CSV 导入 | `utf-8-sig` → 失败则 `gbk`(中文 Excel) | | `sync_v2.read_file` | `detect_text_eol` + 前端 `stripCr` / `serializeContent` | | `sync_v2.write_file` | `content.encode("utf-8")` 字节写入远程 | | `posix_paths.py` | 拒绝远程路径中的 `\` | | `auth_jwt` / `main` | HTTP header `latin-1`(RFC 7230) | ### 文档 / 配置中的 Windows 路径(仅文档,不影响运行) - `docs/handoff-*.md`、`mysql-mcp-setup.md` 仍含 `C:\Users\...` — 阶段 2 可改为 `$NEXUS_ROOT` / `~/Nexus`。 --- ## 3. 远程文件链(复查) ``` read-file: SSH cat → str → detect_text_eol → JSON { content, eol } write-file: JSON → .encode("utf-8") → SFTP/tee(不经本机换行转换) ``` 经典 Mac `\r` 在 API 层标为 `eol: LF`;前端 `stripCr` 统一编辑为 LF。 --- ## 4. 阶段 2(已完成 — 见 phase2 文档) - [x] `frontend/` 工作区 LF 清零(`check_worktree_eol` OK) - [x] `.cursor/rules/*.mdc` 归一化 + 门控扩展 - [x] `web/agent/agent.py` I/O 审查 - [x] `mysql-mcp-setup.md` Linux/WSL 路径 - [ ] `vue-tsc` 3 处类型错误(非编码) - [ ] 历史 handoff 文档 Windows 路径(可选) 详见:`docs/audit/2026-06-04-encoding-review-ubuntu-phase2.md` --- ## 5. Closure | H | 判定 | 依据 | |---|------|------| | H-index-LF | PASS | `check_text_eol` + `check_shell_eol` | | H-worktree-CRLF | FIXED | `normalize_worktree_lf.sh` + `check_worktree_eol` OK | | H-sync-root-env | FIXED | `docker/sync_root_env.py` → `text_io` | | H-mcp-sh-env | FIXED | `linux_mcp_mysql.sh` strip `\r` | | H-agent-os-release | FIXED | `encoding=utf-8` | ## DoD(阶段 1) - [x] 跑通双门控 + 工作区扫描 - [x] 修复本轮 3 处代码 - [x] 新增 `check_worktree_eol.py` / `normalize_worktree_lf.sh` - [x] 审计记录与 changelog ## 验证 ```bash python3 scripts/check_text_eol.py bash deploy/check_shell_eol.sh bash scripts/normalize_worktree_lf.sh python3 scripts/check_worktree_eol.py pytest tests/test_text_io.py -q python3 docker/sync_root_env.py ```