REWRITE_PROGRESS.md 10 KB

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. 配置与基础设施

对应模块:

已完成:

  • gitr.toml 或默认值加载配置
  • 自动准备数据库目录和仓库根目录
  • 统一推导 owner/repo.git 的磁盘路径

2. 用户、认证与访问令牌

对应模块:

已完成:

  • 创建本地用户
  • 用户名、邮箱唯一性校验
  • 用户名合法性校验
  • 使用 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. 仓库核心

对应模块:

已完成:

  • 创建仓库元数据
  • 同 owner 下仓库名唯一
  • 仓库名合法性校验
  • 初始化 bare Git 仓库
  • 设置默认分支
  • 运行 update-server-info
  • 支持 auto_init
  • auto_init 时创建首个 README 提交
  • Git 初始化失败时回滚数据库记录和仓库目录

4. 权限与协作

对应模块:

已完成:

  • access
  • collaboration
  • 最小权限枚举:Read / Write / Admin / Owner
  • owner 隐式拥有 Owner
  • 公有仓库匿名只读
  • 协作者添加、更新、删除
  • 协作者列表
  • 协作者单项检查
  • collaborator permission 严格校验,只接受 read / write / admin
  • Git HTTP 和 API 复用同一套权限判断

当前语义:

  • 私有仓库未授权访问尽量返回 404
  • 公有仓库上的权限不足返回 403

5. Git over HTTP

对应模块:

已完成:

  • 通过 git http-backend 提供最小 Git HTTP 能力
  • 公有仓库匿名 git-upload-pack
  • 私有仓库 Basic 认证
  • Basic 认证支持密码或 access token
  • 按读写权限区分 upload-pack / receive-pack

6. Fork

对应模块:

已完成:

  • fork 元数据:is_forkfork_id
  • 禁止 fork 到原 owner 自己
  • 禁止同一用户重复 fork 同一仓库
  • 通过 bare clone 复制源仓库

7. 分支

对应模块:

已完成:

  • 列出分支
  • 校验分支存在性

8. 最小 PR / MR 主链

说明:

  • 当前明确不接 Gogs 的 issue/comment/timeline 体系
  • 只保留代码合并请求本身

对应模块:

已完成:

  • 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

对应模块:

当前已有接口:

  • 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

对应模块:

已完成:

  • owner 维度 repo 列表接口
  • 当前用户可见 repo 集合接口
  • 基于可见性过滤的 repo 搜索接口
  • 统一 repo 可见性过滤函数
  • repo permission DTO
  • repo 列表/详情返回当前请求视角下的 permission 信息

11. API 错误语义与返回结构

对应模块:

已完成:

  • API 错误响应统一为结构化 JSON
  • 错误响应包含稳定的 code / message / status
  • 400/401/403/404/409/500 具备稳定错误码语义
  • 500 响应不再把底层 I/O / DB / Git 细节直接暴露给客户端

已验证行为

主要测试文件:

目前已覆盖的行为包括:

  • 用户创建、重复拒绝、非法用户名拒绝
  • 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 这条真正影响权限模型的主线