|
@@ -1,415 +0,0 @@
|
|
|
-# 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 这条真正影响权限模型的主线
|
|
|