# Gitr 重写计划 ## 目标 这个项目是对 Gogs 核心后端的 Rust 重写,当前约束有三个: - 尽量按 Gogs 原有模块边界重写,而不是只做概念相似 - 尽量保持运行时和部署成本轻量 - 尽量用确定性的端到端测试验证行为正确 当前技术选型: - HTTP: `actix-web` - 数据库: `SQLite` + `rusqlite` - Git 交互: 外部 `git` 二进制 当前不包含: - `frontend` - HTML 模板与浏览器页面 - session/cookie 登录流 ## 当前定位 当前代码已经不是“脚手架阶段”,而是已经完成了第一批核心后端闭环: - 用户与本地密码认证 - access token 鉴权 - 仓库创建与 bare Git 初始化 - Git over HTTP 最小读写链路 - 协作者与最小权限模型 - fork - 分支列表 - 最小 PR/MR 创建、列表、详情、compare、merge、close、reopen 这意味着项目现在已经具备一个“最小可用的 Git 服务后端核心”,但距离 Gogs 的完整产品能力还差几个大块。 ## 已完成功能 ### 1. 配置与基础设施 对应模块: - [`src/conf.rs`](./src/conf.rs) - [`src/repox.rs`](./src/repox.rs) 已完成: - 从 `gitr.toml` 或默认值加载配置 - 自动准备数据库目录和仓库根目录 - 统一推导 `owner/repo.git` 的磁盘路径 ### 2. 用户、认证与访问令牌 对应模块: - [`src/db.rs`](./src/db.rs) - [`src/service.rs`](./src/service.rs) - [`src/http.rs`](./src/http.rs) 已完成: - 创建本地用户 - 用户名、邮箱唯一性校验 - 用户名合法性校验 - 使用 `argon2` 存储密码哈希 - 支持用户名或邮箱登录 - 登录后签发 access token - 支持额外创建命名 token - 支持列出当前用户 token - 支持删除当前用户 token - token 名在同一用户下唯一 - 数据库只存 token 的 SHA-256 hash - Bearer token 鉴权 - token 被使用后更新 `updated_unix` 当前安全边界: - `POST /api/admin/users` 只允许首个用户 bootstrap - bootstrap 之后只能由 admin 创建新用户 - API 不再暴露 `password_hash` - 匿名读取用户资料时隐藏邮箱 ### 3. 仓库核心 对应模块: - [`src/db.rs`](./src/db.rs) - [`src/service.rs`](./src/service.rs) - [`src/git.rs`](./src/git.rs) 已完成: - 创建仓库元数据 - 同 owner 下仓库名唯一 - 仓库名合法性校验 - 初始化 bare Git 仓库 - 设置默认分支 - 运行 `update-server-info` - 支持 `auto_init` - `auto_init` 时创建首个 README 提交 - Git 初始化失败时回滚数据库记录和仓库目录 ### 4. 权限与协作 对应模块: - [`src/db.rs`](./src/db.rs) - [`src/models.rs`](./src/models.rs) - [`src/service.rs`](./src/service.rs) 已完成: - `access` 表 - `collaboration` 表 - 最小权限枚举:`Read / Write / Admin / Owner` - owner 隐式拥有 `Owner` - 公有仓库匿名只读 - 协作者添加、更新、删除 - 协作者列表 - 协作者单项检查 - collaborator permission 严格校验,只接受 `read / write / admin` - Git HTTP 和 API 复用同一套权限判断 当前语义: - 私有仓库未授权访问尽量返回 `404` - 公有仓库上的权限不足返回 `403` ### 5. Git over HTTP 对应模块: - [`src/http.rs`](./src/http.rs) - [`src/git.rs`](./src/git.rs) - [`src/service.rs`](./src/service.rs) 已完成: - 通过 `git http-backend` 提供最小 Git HTTP 能力 - 公有仓库匿名 `git-upload-pack` - 私有仓库 Basic 认证 - Basic 认证支持密码或 access token - 按读写权限区分 `upload-pack` / `receive-pack` ### 6. Fork 对应模块: - [`src/db.rs`](./src/db.rs) - [`src/service.rs`](./src/service.rs) - [`src/git.rs`](./src/git.rs) 已完成: - fork 元数据:`is_fork`、`fork_id` - 禁止 fork 到原 owner 自己 - 禁止同一用户重复 fork 同一仓库 - 通过 bare clone 复制源仓库 ### 7. 分支 对应模块: - [`src/git.rs`](./src/git.rs) - [`src/service.rs`](./src/service.rs) 已完成: - 列出分支 - 校验分支存在性 ### 8. 最小 PR / MR 主链 说明: - 当前明确不接 Gogs 的 issue/comment/timeline 体系 - 只保留代码合并请求本身 对应模块: - [`src/models.rs`](./src/models.rs) - [`src/db.rs`](./src/db.rs) - [`src/service.rs`](./src/service.rs) - [`src/http.rs`](./src/http.rs) 已完成: - `pull_request` 表 - 创建 PR/MR - 列出 PR/MR - 获取 PR/MR 详情 - compare - merge - close - reopen - 校验 base branch / head branch 存在 - 校验 head repo 必须为同仓库或其 fork - 校验创建者对 base repo 有读权限 - 校验创建者对 head repo 有写权限 - 阻止同一 head/base 分支对的未合并重复 PR - 计算 merge base - 通过临时克隆试合并,判断 `Mergeable / Conflict` - merge 后记录 `merged_commit_id` - merged PR 详情不会再把 base-only 的后续提交混入 compare - PR index 在数据库事务内分配,并有唯一索引保护 ### 9. 已暴露的 API 对应模块: - [`src/http.rs`](./src/http.rs) - [`src/main.rs`](./src/main.rs) 当前已有接口: - `POST /api/admin/users` - `POST /api/user/login` - `POST /api/user/tokens` - `GET /api/user/tokens` - `DELETE /api/user/tokens/{id}` - `GET /api/users/{username}` - `GET /api/users/{username}/repos` - `GET /api/user/repos` - `POST /api/repos` - `GET /api/repos/search` - `GET /api/repos/{owner}/{repo}` - `POST /api/repos/{owner}/{repo}/forks` - `GET /api/repos/{owner}/{repo}/branches` - `GET /api/repos/{owner}/{repo}/compare` - `POST /api/repos/{owner}/{repo}/pulls` - `GET /api/repos/{owner}/{repo}/pulls` - `GET /api/repos/{owner}/{repo}/pulls/{index}` - `POST /api/repos/{owner}/{repo}/pulls/{index}/merge` - `POST /api/repos/{owner}/{repo}/pulls/{index}/close` - `POST /api/repos/{owner}/{repo}/pulls/{index}/reopen` - `POST /api/repos/{owner}/{repo}/collaborators` - `GET /api/repos/{owner}/{repo}/collaborators` - `GET /api/repos/{owner}/{repo}/collaborators/{username}` - `DELETE /api/repos/{owner}/{repo}/collaborators/{username}` - `GET /healthz` ### 10. Repo 可见性与列表 API 对应模块: - [`src/db.rs`](./src/db.rs) - [`src/service.rs`](./src/service.rs) - [`src/http.rs`](./src/http.rs) - [`src/models.rs`](./src/models.rs) 已完成: - owner 维度 repo 列表接口 - 当前用户可见 repo 集合接口 - 基于可见性过滤的 repo 搜索接口 - 统一 repo 可见性过滤函数 - repo permission DTO - repo 列表/详情返回当前请求视角下的 permission 信息 ### 11. API 错误语义与返回结构 对应模块: - [`src/error.rs`](./src/error.rs) - [`tests/core_flow.rs`](./tests/core_flow.rs) 已完成: - API 错误响应统一为结构化 JSON - 错误响应包含稳定的 `code` / `message` / `status` - `400/401/403/404/409/500` 具备稳定错误码语义 - `500` 响应不再把底层 I/O / DB / Git 细节直接暴露给客户端 ## 已验证行为 主要测试文件: - [`tests/core_flow.rs`](./tests/core_flow.rs) 目前已覆盖的行为包括: - 用户创建、重复拒绝、非法用户名拒绝 - bootstrap admin 与后续 admin-only 创建用户 - 密码登录、错误密码失败 - token 创建、唯一性、list/delete、使用后更新时间 - 仓库创建、自动初始化、重复拒绝、非法仓库名拒绝 - Git 初始化失败回滚 - 公有仓库匿名 Git HTTP pull - 私有仓库 Git HTTP 鉴权 - 协作者读权限与禁止 push - fork - 分支列表 - PR/MR 创建、去重、列表、详情、compare - PR/MR merge、close、reopen - reopen 时 duplicate open PR 拒绝 - merged PR compare 结果稳定 - 私有仓库元数据与读接口的未授权不可见 - API 响应不暴露 `password_hash` - owner repo list 会隐藏无权限 private repo - 当前用户 repo list 会包含 owned/public/collaborator 可见仓库 - repo search 会按当前可见性过滤结果 - collaborator list/check 返回协作者及权限 - private repo 的 collaborator 读接口对未授权用户继续返回 `404` - validation / unauthorized / conflict / not-found 错误返回结构化 JSON - internal error 返回 `internal_error`,且 message 已脱敏 当前测试状态: - `cargo test` - 现状:`38 passed` ## 还需要完成的功能 下面按优先级拆分,而不是按“想到什么做什么”。 ### Phase 1A: 补齐当前这一批核心 API 目标: - 把“已经有底层能力但 API 还不完整”的部分补齐 还缺: - token 使用审计字段进一步丰富 建议优先级: 1. token 使用审计字段进一步丰富 2. 组织/团队出现前的权限边界再抽象 3. organization / team 模型 ### Phase 1B: 强化权限与仓库可见性模型 目标: - 让“谁能看到什么 repo、谁能对什么 repo 发 PR/fork/compare”更接近 Gogs 还缺: - 更完整的 public/private/not-found 语义梳理 - 组织/团队出现前的权限边界再抽象 - token 使用审计字段进一步丰富 ### Phase 2: 组织、团队、组织仓库 这是后续真正会改变权限模型的一大块。 还缺: - organization 用户模型 - team - team repo permission - org 仓库创建 - org 成员与 owner/admin 关系 这部分完成后,repo 权限才会开始接近 Gogs 的真实结构。 ### Phase 3: SSH 与 hook 还缺: - SSH push/pull 链路 - server-side hook - deploy key - 受保护分支最小实现 这部分是“能不能真正拿来替代现有 Git 服务”的关键。 ### Phase 4: Issue / Comment / Timeline 体系 当前 PR/MR 是脱离 issue 系统的最小闭环。 如果要继续接近 Gogs,还缺: - issue - issue index - comment - close/reopen timeline - label/milestone - PR 与 issue 的完整关联 这块工作量会明显高于当前阶段。 ### Phase 5: Web 产品层 当前明确未做: - HTML/template - session 登录流 - 浏览器交互页面 - frontend 整合 这块应在后端主链稳定后再接。 ## 建议开发顺序 如果继续推进,建议顺序如下: 1. 补 token 使用审计字段 2. 再抽象一层 organization / team 之前的权限边界 3. 开始组织/团队模型 4. 再进入 SSH/hook 5. 最后再考虑 issue/timeline 和 Web 层 ## 当前结论 当前仓库已经完成: - “单用户/协作者/私有仓库/fork/最小 PR”的第一批核心后端闭环 当前最值得继续做的,不是再加零散功能,而是: - 先把 token 审计与权限边界抽象补扎实 - 再进入 organization / team 这条真正影响权限模型的主线