Skip to content

Repository files navigation

MoonCode Logo

MoonCode

面向团队的 AI 代码质量分析 SaaS 平台

English · 简体中文

Go 1.23 React 19 CI

MoonCode 管理代码仓库的不可变 commit 快照,使用 scc 生成基础质量指标,并通过飞书或钉钉接收团队消息、发送分析完成通知。当前代码仍处于首个正式版本之前,不包含旧 API、旧类型或迁移兼容层。

核心能力

  • 认证:由 Tinyauth v5 完成 GitHub OAuth 登录和会话管理;MoonCode 不保存密码,也不实现密码登录。
  • 多租户:Workspace 是业务隔离与 RBAC 边界,支持 owneradminmember
  • 代码托管凭证:GitHub/GitLab PAT 是当前用户的个人 Provider Connection,不属于 Workspace;管理员不能查看或代用他人的 PAT。
  • 仓库:用户只需提交仓库地址和 ref;公共 GitHub/GitLab 仓库通过匿名 HTTPS 同步,私有仓库可选用当前用户自己的 Provider Connection。
  • 快照:每个 Repository 对应一个受控 bare Git 对象库。同步只允许受控的 heads/tags refspec,解析后的 commit 固定在 refs/mooncode/snapshots/<snapshot-id>,历史快照不会随远端分支移动。
  • 分析:分析任务关联确定的 Commit Snapshot,由 Hatchet Worker checkout 固定 commit 后运行可替换的 Analyzer;首版默认使用 scc
  • Channel:飞书使用 WebSocket,钉钉使用 Stream Mode。runtime 统一执行发送者 allowlist、群聊 mention/prefix 策略、消息归一化和幂等入库;分析成功后通过 App API 发送通知。
  • 异步可靠性:Repository、Analysis、Notification 和数据保留清理都由 Hatchet Workflow/Task 执行;事务性 PostgreSQL outbox 负责弥合业务提交与 Hatchet 派发之间的崩溃窗口,没有本地任务 Worker fallback。
  • 数据保留:Workspace 可配置 1–3650 天的分析保留期;Hatchet 定期删除到期终态 Run/Report/Notification、幂等释放 Snapshot pin,并在引用归零后重新派发 Repository purge。

本地查看仓库、分析已有快照、删除 Repository,以及同步公共仓库都不需要 PAT。私有仓库的创建、刷新或来源修改使用发起用户显式选择的个人 PAT;任务会固化连接 ID 和凭据版本,PAT 更换后旧排队任务会拒绝执行。

技术栈与进程角色

  • 后端:Go 1.23、Gin、Cobra、Viper、pgx/v5、sqlc
  • 工作流:Hatchet v0.98.9,V1 engine
  • 数据库:PostgreSQL 17;MoonCode 与 Hatchet 使用独立 database 和 role
  • 认证:Tinyauth v5.1.2 + GitHub OAuth
  • 前端:React 19、TypeScript、Vite、Tailwind CSS
  • IM SDK:Lark/Feishu OpenAPI SDK、DingTalk Stream SDK

同一个 mooncode 二进制提供两个明确分离的角色:

  • mooncode serve:HTTP API、Tinyauth ForwardAuth 身份消费、飞书/钉钉长连接。
  • mooncode worker:workflow outbox dispatcher 与 Hatchet Worker;只有该角色执行远程 Git、代码分析和保留期清理。

API 与 Worker 共享 PostgreSQL 和 Repository 持久卷。首版要求只有一个 Git 存储节点。

Compose 将 PostgreSQL/Hatchet 放在内部 backend 网络;Worker 额外连接不发布任何端口的 outbound 网络,用于访问 GitHub/GitLab。数据库和 Worker 指标端口不会因此暴露到宿主机。

两个进程分别暴露 Prometheus 指标:API 在自身 HTTP 地址提供 /metrics,Worker 在独立的私有监听地址(默认 :9090)提供 /metrics/healthz。Compose 中可从后端网络访问 http://mooncode-api:8080/metricshttp://mooncode-worker:9090/metrics;这些端点不会通过公共 Traefik 路由暴露。

快速开始

前置条件

  • Docker 与 Docker Compose
  • 一个 GitHub OAuth App
  • 本机端口 3100 可用

GitHub OAuth App Callback URL:

http://mooncode.localhost:3100/api/oauth/callback/github

Tinyauth 的 OAuth API 通过 MoonCode 同域暴露:/api/oauth/*/api/user/logout 由 Traefik 转发给 Tinyauth,/api/v1/* 转发给 MoonCode API。Tinyauth 使用仅限 mooncode.localhost 的 host-only session Cookie,不启用跨子域 Cookie。

准备配置:

cp .env.example deploy/.env
mkdir -p deploy/secrets
openssl rand -base64 32  # 分别填入两个 MoonCode key,必须使用不同值
printf '%s' '<github-oauth-client-secret>' > deploy/secrets/github_oauth_client_secret

deploy/.env 中填写:

  • MOONCODE_SECRETS_KEY
  • MOONCODE_AUTH_CSRF_KEY
  • GITHUB_OAUTH_CLIENT_ID

首次使用自托管 Hatchet 时,先启动基础服务:

docker compose --env-file deploy/.env -f deploy/docker-compose.yml up -d postgres traefik hatchet

访问 http://hatchet.mooncode.localhost:3100 完成 Hatchet 初始化,创建 MoonCode client token,并把它写入 deploy/.envHATCHET_CLIENT_TOKEN。随后启动完整开发环境:

make compose-dev-up

访问:

停止环境:

make compose-dev-down

本地开发

项目源码必须位于工作区根目录的 worktree/ 下。可跨 worktree 共享的数据和缓存分别放在根目录 data/cache/,不得提交。

npm ci --prefix frontend

make generate
make test
make vet
make frontend-i18n frontend-lint frontend-build

运行 PostgreSQL 与 Git 集成测试:

MOONCODE_TEST_DATABASE_URL='postgres://mooncode:mooncode@127.0.0.1:5432/mooncode?sslmode=disable' \
  make integration-test

对已经完成 GitHub OAuth 登录的真实部署运行只读 smoke test:

MOONCODE_E2E_BASE_URL='https://mooncode.example.com' \
MOONCODE_E2E_SESSION_COOKIE='tinyauth=<session-cookie>' \
  make e2e-live

该检查只发送 GET 请求,依次验证 /healthz、Tinyauth 认证后的 /api/v1/session/api/openapi.yaml,不会伪造 Remote-* 身份头。没有真实 OAuth 会话时可以跳过此项。

直接运行单个角色:

go run ./cmd/mooncode serve --config mooncode.example.yaml
go run ./cmd/mooncode worker --config mooncode.example.yaml
go run ./cmd/mooncode version

目录结构

cmd/mooncode/                Cobra 命令入口
internal/app/                进程生命周期与 Wire 顶层装配
internal/conf/               配置加载与校验
internal/server/             HTTP 协议适配与认证中间件
internal/service/            面向传输层的应用服务门面
internal/biz/                业务模型、用例与工作流规则
internal/data/               PostgreSQL/sqlc 与外部数据适配
internal/worker/             Hatchet、调度器与长连接运行时
pkg/                         可被第三方独立使用的接口、Options 与默认实现
migrations/                  唯一初始 PostgreSQL migration
sql/queries/                 sqlc 查询定义
frontend/                    React 前端
deploy/                      Dockerfile 与 Compose

安全边界

  • Traefik 在 ForwardAuth 前删除客户端伪造的 Remote-* 头,只转发 Tinyauth 返回的身份头。
  • 改写请求使用 HMAC CSRF token。
  • PAT 与 Channel secret 使用 AES-GCM 加密,API 永不返回明文。
  • Provider Connection 查询始终带当前 user_id;Workspace owner 没有读取或使用成员 PAT 的路径。
  • 首版只允许 https://github.comhttps://gitlab.com,避免任意 Provider base URL 造成 SSRF。
  • Git 凭据通过单次命令的临时 HTTP authorization header 提供,不写入 Repository remote URL 或 Git 配置。
  • Git 与 Analyzer 子进程使用最小环境,只按需保留网络代理,不继承数据库 URL、Hatchet Token 或主密钥。
  • MoonCode API/Worker 容器使用非 root、只读根文件系统、no-new-privileges 和最小 capability。

CI

GitHub Actions 会校验:

  • go mod tidy 和 sqlc 生成结果无差异
  • golangci-lint、Go 单元测试与 go vet
  • PostgreSQL、事务性 outbox 和受控 bare Git 集成测试
  • 前端 i18n、ESLint 与生产构建
  • gitleaks 敏感信息扫描
  • PR 依赖变更审查、Go govulncheck 与 npm 高危漏洞审计
  • 后端/前端镜像构建及 Trivy HIGHCRITICAL 漏洞扫描
  • 使用 Syft 生成并上传两个镜像的 SPDX JSON SBOM

推送严格 SemVer 格式的 v* Tag 后,Release 工作流会重新执行生成校验、单元/集成测试和前端构建,随后向 GHCR 发布后端与前端的 linux/amd64linux/arm64 镜像。预发布版本不会覆盖 latest。镜像携带版本、commit 和构建时间,附带 OCI SBOM/构建来源证明,并使用 GitHub OIDC + Cosign 无密钥签名;全部镜像成功后自动生成 GitHub Release。

已知限制

飞书官方 Go SDK v3.9.4 的 Start 在连接 context 取消后仍不会返回。MoonCode 会关闭实际连接并停止接收入站消息,但 SDK 的等待 goroutine 只能随 API 进程退出回收。频繁停用、启用或热更新飞书 Channel 后,建议重启 API 容器。

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages