Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
e8dbf20
style: cargo fmt 全量格式化,修复 docker::tests 模块嵌套命名
jeeinn Sep 20, 2026
7522079
fix(restore): 拒绝含路径遍历条目的备份包,堵住 zip-slip 漏洞
jeeinn Sep 20, 2026
0e5dec4
refactor(commands): 清理死代码,无效测试转为真断言,修复 Nginx 端口解析 off-by-one
jeeinn Sep 21, 2026
73166af
ci: 新增 push/PR 测试流水线
jeeinn Sep 21, 2026
199a5a1
chore: 补充 MIT LICENSE 文件,声明 Cargo license 字段
jeeinn Sep 21, 2026
d3adcbf
fix(env-config): 多 PHP 服务的自定义扩展输入改为按服务独立
jeeinn Sep 21, 2026
14029f7
docs: 修订 AGENTS.md 失实描述,CHANGELOG 补记 9 月修复
jeeinn Sep 21, 2026
e754273
merge: 合并 master(phase 3 服务模板来源/运行时配置提取)到 fix/reliability-basics
jeeinn Sep 21, 2026
59c567d
fix(scripts): 移除 shebang,修复单元测试 SyntaxError
jeeinn Sep 21, 2026
9645872
feat(restore): 恢复前自动生成回滚包(R2)
jeeinn Sep 21, 2026
e7361d1
feat(ui): 恢复结果展示文件清单与错误明细(U2)
jeeinn Sep 21, 2026
6bdb3c6
refactor(env-config): Docker 阻塞调用统一走 spawn_blocking(R3)
jeeinn Sep 21, 2026
9670b99
chore: 移除误入版本库的临时文件 merge-paths.tmp
jeeinn Sep 21, 2026
8d5ed46
docs: CHANGELOG 补记第二批前 3 项与脚本测试修复
jeeinn Sep 21, 2026
160f071
refactor(contract): 容器状态枚举化,消除 Debug 字符串契约(R4)
jeeinn Sep 21, 2026
86492f1
refactor(paths): 路径解析收口为单一模块,用户配置迁至 app_data_dir(A1)
jeeinn Sep 21, 2026
c2adc3a
perf(backup): 备份改为流式写入,文件不再整体进内存(R5)
jeeinn Sep 21, 2026
c7a1e26
feat(log): 日志轮转 + 面板复制/清空/导出三个动作(R6、U4)
jeeinn Sep 21, 2026
1e51a1b
fix(ui): Docker 不可用时轮询退避,并停止每 5 秒刷日志(U3)
jeeinn Sep 21, 2026
f6ae21d
docs: 标注改进报告各条目状态,补记第二批后 5 项
jeeinn Sep 21, 2026
28dfe6e
fix(env-config): 镜像拉取命令改为 async,避免前端弹窗卡死
jeeinn Sep 21, 2026
41fa38e
fix(workspace): 配置的工作区不存在时先创建,回退不再静默
jeeinn Sep 21, 2026
f07486b
docs: CHANGELOG 补记镜像拉取卡死与工作区回退两项修复
jeeinn Sep 21, 2026
dfc8d43
fix(i18n): 合并 envConfig 下重复的 toast 节点,修复应用配置提示显示裸 key
jeeinn Sep 21, 2026
5bd70e8
ci: 增加 i18n key 完整性检查步骤
jeeinn Sep 21, 2026
8fd547a
fix(nginx): Dockerfile 去掉 USER nginx,修复容器启动即崩溃
jeeinn Sep 21, 2026
4ec4332
fix(dockerfile): 修正 PUID/PGID 映射条件并兼容 alpine/debian 基础镜像
jeeinn Sep 21, 2026
c69e63e
fix(ux): 全局工作区回退横幅、恢复致命错误面板与回滚快捷入口
jeeinn Sep 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
name: CI

on:
push:
branches: [master]
pull_request:

concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true

jobs:
check:
name: Test & Build
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22
cache: npm

- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy

- name: Rust cache
uses: swatinem/rust-cache@v2
with:
workspaces: src-tauri -> target

- name: Install Linux dependencies
run: |
sudo apt-get update
sudo apt-get install -y \
libwebkit2gtk-4.1-dev \
libappindicator3-dev \
librsvg2-dev \
patchelf \
libssl-dev \
libgtk-3-dev \
libsoup-3.0-dev \
libjavascriptcoregtk-4.1-dev

- name: Rust format check
working-directory: src-tauri
run: cargo fmt --check

- name: Rust clippy
working-directory: src-tauri
run: cargo clippy --all-targets -- -D warnings

- name: Rust tests
working-directory: src-tauri
run: cargo test

- name: Install frontend dependencies
run: npm ci

- name: Frontend tests
run: npm run test:run

# 语言包重复 key 会被 JSON.parse 静默折叠,界面上直接显示裸 key,
# 肉眼看不出问题,只能靠脚本兜底
- name: i18n key integrity check
run: npm run check:i18n

- name: Frontend type-check & build
run: npm run build
28 changes: 18 additions & 10 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,24 +70,24 @@

### 4. 环境恢复(RestorePage)
- **需求覆盖**: 需求 4.1-4.10
- **实现状态**: ✅ 完成
- **实现状态**: ✅ 完成(端口冲突检测除外,见「待完善功能」)
- **核心功能**:
- 备份包预览(manifest 解析、文件统计)
- SHA256 完整性验证
- 端口冲突检测与自动分配
- 路径遍历防护(zip-slip,恶意备份包整体拒绝)
- 配置文件、项目文件、SQL 文件还原(SQL 导入执行待完善)
- 进度通知与错误汇总

### 5. 基础设施模块
- **env_parser.rs**: .env 文件可靠读写,保留注释和空行(Property 9, 10)
- **backup_manifest.rs**: Manifest 序列化/反序列化(Property 11, 12)
- **测试覆盖**: 后端单元测试 + 3 个集成测试(backup_restore、config_generation、workspace_commands)+ 前端 8 个组件测试(Vitest),含属性测试(proptest)
- **测试覆盖**: 后端单元测试 + 4 个集成测试(backup_restore、config_generation、workspace_commands、docker_manager)+ 前端组件测试(Vitest)

## ✅ v0.2.0 / v0.3.0 新增功能

### 1. 前端国际化(i18n)
- 中/英双语支持,运行时动态切换(vue-i18n)
- 后端日志英文化
- ⚠️ 后端用户可见日志(ui_log!)当前为中文,i18n 化待完善

### 2. 主题预设系统
- 自动 / 明亮 / 暗黑三种模式,全组件适配
Expand Down Expand Up @@ -115,9 +115,9 @@
3. **测试**:
- **单元测试**:放在源文件内的 `#[cfg(test)] mod tests { ... }` 模块中
- **集成测试**:放在 `src-tauri/tests/integration/` 目录下
- 纯函数模块(env_parser、backup_manifest、config_generator)使用 `proptest` 进行属性测试
- 标签格式:`// Feature: env-config-and-backup, Property N: {property_text}`
- 运行测试:`cargo test`
- 解析/生成类纯函数应抽为可直接测试的函数,测试必须包含真断言(禁止 `assert!(true)` 占位)
- 安全或回归类测试建议标注:`// Feature: {feature}, Property: {描述}`
- 运行测试:`cargo test`;CI 同时执行 `cargo fmt --check` 与 `cargo clippy --all-targets -- -D warnings`
4. **模块注册**:
- 新增引擎模块需在 `engine/mod.rs` 中声明 `pub mod xxx;`
- 新增命令子模块需在 `commands/mod.rs` 中声明并 re-export
Expand Down Expand Up @@ -183,8 +183,8 @@
- 特性:
- 备份预览(manifest 解析)
- SHA256 完整性验证
- 端口冲突检测与自动分配
- 配置文件、项目文件还原(数据库 SQL 导入待完善)
- 路径遍历防护(zip-slip)
- 配置文件、项目文件还原(端口冲突检测、数据库 SQL 导入待完善)

### 7. 备份清单(v0.1.0 新增)
- 位置:`src-tauri/src/engine/backup_manifest.rs`
Expand Down Expand Up @@ -302,7 +302,7 @@
3. **权限校验**: 若新增了 Tauri 插件调用,请务必更新 `src-tauri/capabilities/default.json`。
4. **TDD 流程**:
- 优先编写单元测试
- 纯函数模块使用 proptest 进行属性测试
- 解析/生成类逻辑先抽纯函数再测
- 运行 `cargo test` 确保所有测试通过
5. **类型同步**: 修改 Rust 数据结构后,同步更新 `src/types/` 中的 TypeScript 类型定义。

Expand Down Expand Up @@ -339,6 +339,10 @@

### 待完善功能

#### 恢复端口冲突检测(中优先级)
- **当前状态**:恢复直接使用备份包中的端口,不检测宿主机端口冲突(早期文档宣称已实现,实际从未落地)
- **待完善**:恢复预览时读取 manifest.services 的端口映射,与当前运行容器/本机占用比对,冲突时提示改端口

#### 数据库备份/恢复(低优先级)
- **目标**:完善备份/恢复引擎中的数据库导出与导入
- **当前状态**:备份不导出数据库(`BackupOptions` 无 `include_database`),恢复仅提取 SQL 文件到本地、不执行导入
Expand All @@ -348,6 +352,10 @@
- 事务性恢复(失败时回滚)
- **优先级**: 低(当前版本可使用手动方式备份/恢复数据库)

#### 后端日志 i18n(低优先级)
- **当前状态**:`ui_log!` 输出的用户可见日志为中文 + emoji,英文界面下日志面板仍显示中文
- **建议策略**:结构化字段(模块、级别)保持英文,面向用户的固定短语如需双语,由前端按 key 翻译;不做完整后端 i18n

### 开发建议
1. **稳定优先**: v0.3.1 重点是稳定性和用户体验优化
2. **Bug 修复**: 优先处理用户反馈的问题和边界情况
Expand Down
38 changes: 38 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,46 @@
### 待发布功能
- 虚拟主机管理(Nginx 站点配置)

### 🐛 修复
- 一键停止改用 `docker compose stop`,保留容器并展示已停用状态
- 统一服务模板解析路径,释放后不覆盖用户修改
- 容器状态 running 文案中文化
- 恢复引擎拒绝含路径遍历条目的备份包,堵住 zip-slip 漏洞
- 修复 Nginx 多版本配置回读时非默认端口被错误重置为 80 的问题
- 修复环境配置页多 PHP 服务时自定义扩展输入互相串扰的问题
- 修复 `scripts/` 下两个同步脚本的单元测试因 shebang 被 vitest 报 SyntaxError、整个 suite 无法加载的问题
- 修复日志文件每次启动被清空、现场日志一重启即丢失的问题(改为轮转保留最近 3 份)
- 修复日志锁被毒化后每次写日志连锁 panic 的问题
- 修复备份打包大文件时整体读入内存的问题(改为 64KB 分块流式写入)
- 修复 `path.file_name().unwrap()` 对无名路径 panic 的问题
- 修复 Docker 不可用时仍每 5 秒全量轮询、且每轮都刷一条失败日志的问题
- 修复日志面板「复制」按钮复制的是后端文件日志全文、与界面显示内容对不上的问题
- 修复配置的工作区目录不存在时数据被静默写到默认目录的问题(改为先创建目录;创建失败才回退并在界面告警)
- 修复镜像拉取命令为同步执行、下载大镜像时整个窗口「未响应」的问题(改为 async + spawn_blocking)
- 修复 `envConfig` 语言节点下存在两个同名 `toast`、JSON 解析时后者静默覆盖前者,导致应用配置后的成功提示直接显示为裸 key(`envConfig.toast.applySuccess` / `backedUp`)的问题(合并节点,恢复被覆盖的 8 条文案)
- 修复 Nginx 容器启动即崩溃、无限重启的问题:Dockerfile 末尾 `USER nginx` 使 master 进程无权限创建 `/var/cache/nginx/client_temp`、也无法 bind 80 端口(改为 root 运行 master,worker 仍为 `nginx`,PUID/PGID 映射不变)
- 修复 PUID/PGID 用户映射在默认配置下从不生效的问题:判断条件写成「PUID/PGID 不等于 1000 才调整」,而默认值本身就是 1000,等于永远跳过(改为「与镜像内当前 UID/GID 不一致才调整」)
- 修复 Nginx 镜像模板只支持 alpine 基础镜像的问题:原实现用 `deluser/adduser`,若把 `NGINX*_VERSION` 换成 debian 版(如 `nginx:1.28`)则构建直接失败;现在按基础镜像分发命令(alpine 用 `deluser/adduser`,debian 用 `groupmod/usermod`)。PHP 模板同样补齐 alpine 版兼容性

### 🔧 改进
- 环境配置页 .env 解析主体抽为纯函数并以真断言测试覆盖
- 配置生成集成测试替换为端到端断言(validate / .env / compose / 自定义变量保留)
- 清理死代码:未注册使用的占位命令、无效占位测试、未使用的 proptest 依赖
- 新增 CI 测试流水线(fmt / clippy / cargo test / 前端测试 / 构建)
- 补充 MIT LICENSE 文件,声明 Cargo `license` 字段
- 恢复前自动生成回滚包(`.restore_rollback_<时间戳>.zip`),恢复出错可据此回退
- 恢复结果由「成功/失败一句话」改为返回完整明细,前端展示已恢复文件列表、逐条错误与回滚包路径
- 环境启动流程的 Docker 同步调用(`compose down`、`up` 等待、日志轮询)统一走 `spawn_blocking`,不再阻塞 async 执行线程
- **容器状态改为前后端共享的枚举契约**(`running`/`exited`/...),替换此前 `format!("{:?}")` 产出 `"Some(RUNNING)"` 再由前端 `includes('running')` 猜测的脆弱做法
- **路径解析收口为 `commands/paths.rs` 单一模块**;用户级配置 `workspace.json` 与日志迁至 Tauri 官方 `app_data_dir`,解决装进 `Program Files` 后无写权限的问题,首次启动自动从旧位置迁移
- 日志面板新增「清空」与「导出」动作(导出走后端文件日志,落盘到用户指定位置)
- 轮询间隔随 Docker 连续失败次数退避(5s → 15s → 30s),恢复后立即回到 5s
- 容器状态灯改为仅运行中时脉冲,停止状态不再一直闪烁
- 新增 `pnpm check:i18n` 检查脚本(`scripts/check-i18n-keys.mjs`):扫描语言包同层级重复 key、中英 key 集合一致性、源码 `t()` 引用的 key 是否存在,并配 10 条单元测试防回归

### 📁 文档
- 合并 `doc/` 与 `docs/` 为统一的 `docs/` 目录,更新 README、AGENTS、文档索引中的路径引用
- 修订 AGENTS.md 与实际实现不符的描述(proptest 属性测试、恢复端口冲突检测、后端日志英文化),未实现项移入「待完善功能」

---

Expand Down
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2026 jeeinn

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Loading
Loading