Skip to content

feat(datasource): 新增 Git 仓库数据源连接器与 push webhook 自动同步 - #2747

Open
lurj7988 wants to merge 5 commits into
Tencent:mainfrom
lurj7988:main
Open

feat(datasource): 新增 Git 仓库数据源连接器与 push webhook 自动同步#2747
lurj7988 wants to merge 5 commits into
Tencent:mainfrom
lurj7988:main

Conversation

@lurj7988

Copy link
Copy Markdown

概述

新增 Git 仓库(git_repo)数据源连接器,支持从任意 git 服务(内网 GitLab / Gitea / GitHub 等)同步文档;并为 git_repo 数据源增加 GitLab / GitHub push webhook 自动触发同步

变更内容

1. Git 仓库数据源连接器(d536a00f

  • 通用 git 同步:基于 go-git 本地克隆,不依赖平台 API,适用于任意 git 服务(含私有化部署)
  • 增量同步:commit 游标比对 + git diff --name-status,仅处理变更文件;force-push / 历史重写自动降级全量重枚举
  • 完整变更语义:新增 / 修改 / 删除 / 重命名(重命名先删旧路径再发新路径);删除条目走现有 SyncDeletions 按数据源范围隔离删除逻辑
  • 图片内联:Markdown / HTML 相对路径图片自动转 data: URI 内联,随文档入库
  • 健壮性:按数据源/仓库/分支哈希隔离克隆目录、并发互斥、每仓库 checkpoint(超时续传);仅同步 6 种纯文本格式,避免独立图片成为噪音文档
  • 前端:数据源编辑表单支持配置仓库列表(URL / 分支 / 目录)

2. Push Webhook 自动触发(7c87b560

  • 公开端点 POST /api/v1/datasource/webhooks/git/:id(认证中间件之前注册,同 IM 回调模式)
  • 双平台鉴权:GitLab X-Gitlab-Token 常量时间比对;GitHub X-Hub-Signature-256(及旧版 sha1)HMAC 验签
  • 密钥两级配置:数据源 settings.webhook_secret > 环境变量 GIT_REPO_WEBHOOK_SECRET;均未配置时 fail-closed(403)
  • 匹配保护:载荷仓库 URL 归一化匹配(容忍 scheme / .git 后缀 / host 大小写)+ 分支过滤;分支删除 / 非分支推送 / 仓库不匹配返回 200 忽略(避免平台重试)
  • 服务层ManualSync 重构出 enqueueSync(trigger),新增 WebhookSync;审计与日志记录 trigger 来源(manual / webhook / scheduled)
  • 前端:git_repo 数据源编辑页展示 webhook 回调 URL 提示卡(一键复制,密钥不回显)

3. 文档(6b5e9d26

  • website-docs/03-features/10-datasource.md:能力对比表补 GitLab / Git Repo 两列,注册说明更正为 9 类型,新增 GitLab / Git Repo 连接器详解与「Push Webhook 自动触发」章节
  • website-docs/04-api/02-api-infra.md:公开 webhook 端点说明(鉴权、响应码、curl 示例)
  • .env.example:登记 GIT_REPO_WEBHOOK_SECRETGIT_REPO_STORAGE_BASE_DIR
  • internal/datasource/README.md:API 端点清单补 webhook 小节

测试验证

  • go build ./... 全量编译通过
  • 涉改包测试通过:handler(含 10 个 webhook 用例)、router、application/service、datasource/connector/git_repo、container、docs(swagger 契约)
  • 前端 vue-tsc type-check 通过
  • 三个 commit 各自可独立编译

备注

  • swagger 三件套(docs/swagger.{json,yaml,go})由 make docs 重新生成,含 /datasource/webhooks/git/{id};其中顺带补齐了上游近期已改注释但未再生成的路由(memory / mcp 等),PR diff 中 swagger 文件较大属此原因

支持从任意 git 服务(内网 GitLab/Gitea/GitHub 等)同步文档:
- go-git 本地克隆,按数据源/仓库/分支哈希隔离目录,并发互斥
- commit 游标增量:新增/修改/删除/重命名,force-push 降级全量
- Markdown/HTML 相对路径图片内联为 data URI
- 每仓库 checkpoint,超时重试续跑;仅同步 6 种纯文本格式
- 公开端点 POST /api/v1/datasource/webhooks/git/:id(Auth 前注册,同 IM 回调模式)
- GitLab X-Gitlab-Token 常量时间比对;GitHub X-Hub-Signature-256 HMAC 验签
- 密钥两级:settings.webhook_secret > GIT_REPO_WEBHOOK_SECRET,未配置 fail-closed
- URL 归一化匹配(容忍 scheme/.git 后缀/大小写)+ 分支过滤
- 分支删除/非分支推送/仓库不匹配返回 200 忽略,防平台重试
- ManualSync 重构出 enqueueSync(trigger),新增 WebhookSync;审计记录 trigger 来源
- 前端数据源编辑页展示 webhook 回调 URL 提示卡(复制按钮,密钥不回显)
- 10-datasource.md:能力对比表补 GitLab/Git Repo 两列,注册说明更正为 9 类型,
  新增 GitLab/Git Repo 连接器详解与「Push Webhook 自动触发」章节
- 02-api-infra.md:新增公开 webhook 端点说明(鉴权头、密钥配置、响应码、curl 示例)
- swagger 三件套由 make docs 重新生成(含 /datasource/webhooks/git/{id})
- .env.example:登记 GIT_REPO_WEBHOOK_SECRET 与 GIT_REPO_STORAGE_BASE_DIR
- internal/datasource/README.md:API 端点清单补 webhook 小节
@lurj7988

Copy link
Copy Markdown
Author

Suggestion from adding this connector: lower the cost of adding a new datasource connector

I just went through the full flow of adding a new connector (git_repo) in this PR, and wanted to share a concrete observation about extension friction — hopefully useful for the maintainers.

What's already good: the Connector / StreamingConnector abstraction and initConnectorRegistry() are clean, and the extension-point docs are excellent. I don't think we should move to Go plugins (too many toolchain/platform constraints) or a sidecar process for every connector.

The friction I hit: adding one connector touched 4 separate places and required recompiling the whole binary:

  1. new internal/datasource/connector/<type>/ package
  2. metadata entry in internal/datasource/connector.go (ConnectorMetadataRegistry)
  3. manual registry.Register(...) in internal/container/container.go (initConnectorRegistry())
  4. frontend metadata (icon, i18n keys, editor form) — easy to forget any one of these

For a repo that explicitly positions datasource connectors as an extension point, 3-4 manual edit sites + a full rebuild feels heavier than necessary.

Two pragmatic improvements that would keep the current architecture while lowering the cost:

  1. Build-tag optional connectors — gate each connector package with a build tag (e.g. //go:build with_git_repo, default on). Self-hosted deployments can then strip connectors they don't use (smaller binary, smaller attack surface). git_repo / web crawler / IMAP are natural first candidates.

  2. Registry auto-discovery — since ConnectorMetadataRegistry already enumerates all connectors, initConnectorRegistry() could iterate it and auto-register implementations by Type() (a ConnectorFactory map per type), so adding a connector becomes: package + metadata entry, without hand-editing the wiring in container.go.

  3. Connector contract checklist / frontend metadata as part of the interface — make the frontend registration (icon, i18n, editor form) a documented part of the connector contract, or drive it from backend metadata, so it can't be silently forgotten.

Happy to help draft any of these if the maintainers are interested.

@lyingbug

Copy link
Copy Markdown
Collaborator

感谢提供此数据源,是否有充分进行测试,已经相关可用截图,方便我们审核

@lurj7988

lurj7988 commented Aug 20, 2026

Copy link
Copy Markdown
Author
image image image image image image image 可以正常识别基于vuepress编写的知识库内容,其中markdown执行的相对路径的图片也完成了处理并且能够正常显示

@lurj7988

Copy link
Copy Markdown
Author

感谢提供此数据源,是否有充分进行测试,已经相关可用截图,方便我们审核

image 直接同步了vuepress的git仓库,提交git即可通过webhook发起同步操作

// credentials go in the access_token credential field); an absolute local path
// is allowed so tests can clone from a throwaway bare repo and local checkouts
// can be synced directly.
func normalizeRepoURL(raw string) (string, error) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

repo_url 需要增加 ValidateURLForSSRF,对应的transport也要尽可能使用 datasource/httpclient.go 的 SSRF 安全客户端

Comment thread .env.example
# GIT_REPO_WEBHOOK_SECRET=
# git_repo 数据源:本地克隆存储根目录覆盖(默认 LOCAL_STORAGE_BASE_DIR/git-repos)。
# GIT_REPO_STORAGE_BASE_DIR=
# 统一文件大小限制(MB,默认 50)。影响单文件上传、docreader gRPC 消息、frontend Nginx请求体、浏览器客户端校验。属部署期配置:Go/Nginx/docreader/浏览器四层启动时读一次,运行中改不生效,改后须同步重启四层。

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

感觉不需要增加默认的环境变量配置,直接按空间租户隔离

评审意见:repo_url 需要增加 ValidateURLForSSRF,对应 transport 尽可能使用
datasource/httpclient.go 的 SSRF 安全客户端。

- normalizeRepoURL 对归一化后的 URL 调用 utils.ValidateURLForSSRF,私网/回环/
  link-local/云元数据等目标在配置期即被拒绝,内网 git 服务器可经
  SSRF_WHITELIST/SSRF_WHITELIST_EXTRA 放行
- ensureSSRFTransport 通过 go-git 传输注册表将 http/https 协议替换为
  datasource.NewConnectorHTTPClient 的客户端(拨号期+重定向二次校验,防
  DNS 重绑定),clone/fetch/ls-remote 全部走 SSRF 防护
- 新增 ssrf_test.go;webhook/handler 测试 fixture 改用公开域名以通过校验
- 文档与 .env.example 补充 SSRF 校验说明
…_DIR

评审意见:不需要增加默认的环境变量配置,直接按空间租户隔离。

- 删除 GIT_REPO_STORAGE_BASE_DIR,克隆统一落在
  <LOCAL_STORAGE_BASE_DIR>/git-repos/<租户ID>/<数据源ID>/<sha1(url+branch)>/
- repoStorageBase 直接读 LOCAL_STORAGE_BASE_DIR(默认 /data/files),
  目录隔离由 cloneDirFor 按 tenantID/dsID 保证
- .env.example 与 datasource 文档同步更新;connector_test 改用
  LOCAL_STORAGE_BASE_DIR 重定向临时存储
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants