Help us shape the future of Go! Take the 2026 Go Developer Survey

gitserver

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 20, 2026 License: Apache-2.0 Imports: 34 Imported by: 0

Documentation

Overview

Package gitserver 是 git push(SSH) 与 webhook 两条部署触发入口的 daemon 侧实现(T2.19):

  • SSH 服务器(golang.org/x/crypto/ssh):认证 = 平台管理的 git 公钥 (state 层 git_keys 表,SHA256 指纹匹配);exec 白名单限定 git-receive-pack / git-upload-pack(防 shell 注入——git 直接 exec、 app 名严格校验);bare 仓库按 app 懒创建并生成 post-receive 钩子;
  • webhook(gateway 原生 HTTP handler 消费本包 Handler):强制 HMAC- SHA256 验签 + delivery ID TTL 防重放 + (app, sha) 幂等去重 + 拉源;
  • 两条入口汇入同一 DeployFromCommit:compose 真源在 git 对象库 (`git show <sha>:compose.{yaml,yml}`),不信任客户端传字节。

包纪律:不 import 任何框架类型(lynx.Service 壳在 cmd/fleetlyd);git 操作全部 exec 系统 git(宿主 git 为前置条件,不引入 go-git 等重框架)。

Index

Constants

View Source
const (
	// DefaultAddr 是 SSH git 面的缺省监听地址。
	DefaultAddr = "127.0.0.1:8424"
	// DefaultReplayTTL 是 webhook delivery ID 防重放缓存窗口(config
	// webhook.replay_ttl_seconds 缺省 900s = 15 分钟)。
	DefaultReplayTTL = 15 * time.Minute
	// TimestampWindow 是自定义投递方时间戳头(X-Fleetly-Timestamp)的
	// 接受窗口(±5 分钟)——绑定口径,不可配置。
	TimestampWindow = 5 * time.Minute
)

安全默认基线(architecture §4.2):SSH git 面默认只绑回环——VPS 上由 安装/文档指引改为对外;重放窗口默认 15 分钟。

Variables

View Source
var ErrBranchNotTracked = errors.New("branch is not tracked")

ErrBranchNotTracked 是分支过滤哨兵(H2:daemon 侧权威过滤):push 的 ref 非该 app 配置分支(空回落缺省 main)时 DeployFromCommit 不建部署、 返回它;api 面据此映射 skipped 回执,与 webhook 入口的 ignored 语义 对齐(webhook 路径在上游已同词形预过滤,不会命中)。

View Source
var ErrFetchFailed = errors.New("git fetch failed")

ErrFetchFailed 是拉源失败的包内哨兵。

View Source
var ErrSourceNotConfigured = errors.New("app source not configured")

ErrSourceNotConfigured 表示 app 未配置拉源 source(webhook 拉源前置)。

View Source
var WebhookPathPattern = regexp.MustCompile(`^/v1/apps/([a-z0-9][a-z0-9-]{0,62})/webhooks/(github|gitea)$`)

WebhookPathPattern 是原生端点的精确路径形态(provider 白名单内联—— 未知 provider 一律 404,豁免面不放宽)。gateway 侧根 handler 用同一线性 词形做分派(豁免面 = 分派面,cmd/fleetlyd/gateway.go 例外清单)。

Functions

func ValidAppName

func ValidAppName(name string) bool

ValidAppName 报告 app 名是否可用于 bare 仓库路径。

func ValidSHA

func ValidSHA(sha string) bool

ValidSHA 报告 commit 是否为 40 位十六进制。

Types

type Config

type Config struct {
	// Enabled 报告是否启用 SSH git 面(git.enabled;缺省 true)。
	Enabled bool
	// Addr 是 SSH 监听地址(git.addr;缺省 127.0.0.1:8424)。
	Addr string
	// Root 是 bare 仓库根目录(git.root;缺省与 state 库同目录下 git/,
	// 由装配方计算回落——本包不感知 db 路径)。
	Root string
	// HostKeyFile 是 SSH host key 文件路径(git.host_key_file;缺省
	// <root>/host_ed25519。首启不存在自动生成 ed25519 并持久化,二次
	// 启动复用——类比平台节点身份;私钥绝不打印)。
	HostKeyFile string
	// HookEndpoint 是 post-receive 钩子回调的控制面 HTTP 基址
	// (如 http://127.0.0.1:8420;装配方由 addr 键推导)。
	HookEndpoint string
	// ReplayTTL 是 webhook delivery ID 防重放窗口
	//(webhook.replay_ttl_seconds;缺省 15 分钟)。
	ReplayTTL time.Duration
}

Config 是 git 触发入口配置(config 键 git.* 与 webhook.* 归并承载—— webhook.* 只有重放窗口一键,随本配置节装配)。

func (Config) Normalize

func (c Config) Normalize() Config

Normalize 回落缺省值(装配期调用;Root 为空不在此兜底——它依赖 state 库路径,由 cmd/fleetlyd 装配点计算,此处仅在启用时校验非空)。

func (Config) Validate

func (c Config) Validate() error

Validate 启用态配置完整性检查(装配期 fail-fast)。

type DeployInput

type DeployInput struct {
	// App 是仓库对应的 app 名(compose name 与它不一致 → 拒绝——仓库
	// 路径即应用身份,跨名部署会被静默错置)。
	App string
	// SHA 是 40 位 commit。
	SHA string
	// Ref 是来源引用(refs/heads/<branch>;非配置分支在入口被过滤——
	// ErrBranchNotTracked,落库值恒为配置分支)。
	Ref string
	// AuditAction 是部署入队审计 action 词根。
	AuditAction string
	// ActorTokenID 是入队调用方 token(钩子 token id;webhook 进程内路径
	// 为空)。
	ActorTokenID string
	// DedupeSHA 置位时入队事务内做 (app, sha) 幂等复查(M3-4):该 sha
	// 已有 enqueued/active/succeeded 部署 → 整笔回滚返回
	// state.ErrDuplicateGitDeployment。仅 webhook 入口置位(受理侧的
	// check-then-insert 竞态在此闭合);SSH push 路径恒不置位——git push
	// 是显式用户动作,每次调用都建部署(幂等口径绑定,见上)。
	DedupeSHA bool
}

DeployFromCommit 是两条 git 触发入口的汇合点:compose 字节由服务端从 bare 仓库 `git show <sha>:compose.{yaml,yml}` 自取(真源在 git 对象库, 不信任客户端传字节),落临时文件走受控子集校验(与 API Deploy 同路径) 后入队部署,deployments.source_git_* 记录来源。

幂等口径(绑定):git push 是显式用户动作——每次调用都建部署记录(引擎 对同 spec 重放安全,Spike B2);(app, sha) 去重仅属 webhook 入口,受理侧 预查在 ServeHTTP、竞态兜底在本函数入队事务内(M3-4:DedupeSHA 置位时 COUNT 与 INSERT 同事务,命中返回 state.ErrDuplicateGitDeployment)。分支 过滤(push 到配置分支才触发部署)在 daemon 侧权威承载——见 checkBranchTracked。事件流复用既有 deployment.queued;审计 action 由入参区分(git.push_deploy / git.webhook_deploy),actor 恒 system (机器动作)。

type GitTriggers

type GitTriggers struct {
	// contains filtered or unexported fields
}

GitTriggers 是 git 触发入口的门面(命名口径 UBIQUITOUS_LANGUAGE §flagged-2: 承载触发面+拉源+部署入队,不只是一个「来源」,故弃 Source 旧名): bare 仓库管理与 post-receive 钩子、DeployFromCommit 入队、webhook 验签/防重放/去重/拉源、SSH 服务器。 它聚合 state 层(git keys/tokens/apps/deployments)与平台密钥盒 (webhook secret / 拉源认证材料的 envelope 加解密),对上暴露:

  • SSH:ListenAndServe(lynx.Service 壳在 cmd/fleetlyd 驱动)
  • HTTP:WebhookHandler(gateway 原生端点例外清单挂载)
  • API:DeployFromGitPush(DeployFromGit RPC 的端口实现——端口接口 定义在 internal/api,方向纪律:api 不感知本包类型)

func NewGitTriggers

func NewGitTriggers(cfg Config, st *state.Store, box *secrets.Box, log *slog.Logger) *GitTriggers

New 构造 Source(cfg 先经 Normalize;启用态完整性 Validate 由装配点 在 Init 阶段 fail-fast)。

func (*GitTriggers) CheckHealth

func (s *GitTriggers) CheckHealth() error

CheckHealth 报告 git 入口层健康:启用态配置完整性 + state 可达。SSH 监听失败属 Start 阶段显式失败,不在健康面二次上报(与 ingress 服务壳 同口径)。

func (*GitTriggers) Config

func (s *GitTriggers) Config() Config

Config 返回归一后的配置(只读投影)。

func (*GitTriggers) DeployFromCommit

func (s *GitTriggers) DeployFromCommit(ctx context.Context, in DeployInput) (state.DeployRecord, []compose.Warning, error)

DeployFromCommit 执行读源 → 校验 → 入队;返回 queued 部署记录与校验 期警告(非阻断标注,与 API Deploy 同面)。compose 违约(受控子集之外) 经 compose.Load 原样透传 E_COMPOSE_* 信封。

func (*GitTriggers) DeployFromGitPush

func (s *GitTriggers) DeployFromGitPush(ctx context.Context, app, sha, ref, actorTokenID string) (state.DeployRecord, []compose.Warning, error)

DeployFromGitPush 是 DeployFromGit RPC 的端口实现(git push 路径;每次 push 都建部署记录)。actorTokenID 记录钩子回调 token(可追溯)。

func (*GitTriggers) EnsureBareRepo

func (s *GitTriggers) EnsureBareRepo(ctx context.Context, app string) (string, bool, error)

EnsureBareRepo 懒创建 app 的 bare 仓库并确保 post-receive 钩子在位:

  • 仓库缺失 → git init --bare + 新钩子 token + 写钩子(0600 + POSIX 可执行位;明文 token 只写进钩子文件);
  • 仓库在、钩子缺失(仓库重建/手工误删)→ 轮换钩子 token(按名吊销 旧 token)+ 重写钩子——daemon 重建仓库时轮换的绑定语义。

幂等;返回仓库路径与是否发生了创建。E7③(S19):全程持 per-app 互斥 (stat 判定与 init/钩子写入/token 轮换之间的 TOCTOU 收口——并发同 app 调用方 SSH push/webhook 拉源/管理面交错时不再产生失配 token)。

func (*GitTriggers) FetchRemote

func (s *GitTriggers) FetchRemote(ctx context.Context, app string) error

FetchRemote 执行拉源:确保 bare 仓库在位 → 按计划 fetch。失败一律包装 ErrFetchFailed(调用方映射错误族信封;errors.Is 判定不受 B2 收口影响)。

B2(出站字节出口收口):全路径失败原文(git stderr、仓库路径、state/ 底层错误细节)只进 slog Warn;返回错误只保留哨兵 + 阶段词——调用方 (webhook 信封/审计)不再拼接原文,杜绝内部字节外泄。

func (*GitTriggers) ListenAndServe

func (s *GitTriggers) ListenAndServe(ctx context.Context, addr string) error

ListenAndServe 监听 SSH git 面(阻塞至 ctx 取消或监听错误);启用态由 lynx.Service 壳(cmd/fleetlyd)驱动。

func (*GitTriggers) SecretValues

func (s *GitTriggers) SecretValues(ctx context.Context, appID string) []string

SecretValues 实现 logs.SecretValuesSource(B3 脱敏值集扩面):钩子 token 的明文只落 post-receive 钩子文件(state 仅存哈希,无解密面)——从钩子 文件读取并入该 app 的日志脱敏值集。app 行/钩子文件缺失返回 nil(脱敏 面降级,不阻断采集)。

func (*GitTriggers) StartWebhookWorker

func (s *GitTriggers) StartWebhookWorker(ctx context.Context)

StartWebhookWorker 启动 webhook 后台 worker(D1):随 git.ssh 服务壳的 lynx Start 启动(webhook 面是 gateway 原生端点、独立于 SSH enabled 开关, 服务壳恒承担 worker 生命周期);ctx 取消后 worker 排空队列退出(排空 预算尽时剩余项转披露丢弃,X-6——见 webhookAuditInterrupted), StopWebhookWorker 是排空完成等待点。

func (*GitTriggers) StopWebhookWorker

func (s *GitTriggers) StopWebhookWorker(ctx context.Context) error

StopWebhookWorker 等待 worker 排空退出(D1);未启动为 no-op。

type WebhookHandler

type WebhookHandler struct {
	// contains filtered or unexported fields
}

WebhookHandler 是原生 webhook 端点处理器。

func NewWebhookHandler

func NewWebhookHandler(src *GitTriggers) *WebhookHandler

NewWebhookHandler 构造(src 提供验签材料/防重放缓存/拉源/入队)。

func (*WebhookHandler) ServeHTTP

func (h *WebhookHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP 实现 http.Handler(路径精确匹配 WebhookPathPattern)。

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL