klarlabs-studio/warden
GitHub: klarlabs-studio/warden
warden 是一个可配置的 Git 提交/推送门控工具,通过原生 hook 在隔离 worktree 中运行策略驱动的检查流水线,并生成密码学签名来源记录供 CI 验证和跳过。
Stars: 0 | Forks: 0
warden
一个可配置的 git commit/push 门控,作为**原生 git hooks** 安装——`git commit` 和 `git push` 本身就是受限指令,没有第二个远程仓库,也无需改变肌肉记忆。
Warden 在一个**一次性 worktree** 中运行由策略驱动的流水线(lint、test、review 等),因此运行过程永远不会触及你正在使用的检出,然后在一切通过后将你的真实分支快进合并,并自行执行推送。策略是一组可叠加的**规则**(基于分支、路径通配符和风险启发式算法进行匹配 → 覆盖),并且流水线可以通过类型化的 subprocess SDK 进行扩展。
基于 [`axi-go`](https://go.klarlabs.de/axi)(执行内核——类型化操作、受效门控的审批、防篡改的证据链)、[`fortify`](https://go.klarlabs.de/fortify)(弹性机制)、[`statekit`](https://go.klarlabs.de/statekit)(策略可视化)和 [`mcp-go`](https://go.klarlabs.de/mcp)(MCP 表面)构建。
## 为什么不直接用 Makefile / CI?
`make ci` 会运行你的检查——但只会在你**脏的工作树**中运行(“本地通过,CI 失败”),而且仅当你**记得**去运行它时才会执行,并且不会留下任何**痕迹**。
Warden 能做 Makefile 做不到的事:
- **干净运行。** 每次检查都在从提交内容生成的一次性 worktree 中运行,因此在 warden 中通过意味着在 CI 中也能通过——可复现。
- **不会被遗忘。** 原生 `git` hooks 会自动触发;不需要刻意遵守,也无需改变肌肉记忆。
- **留下证明。** 每个受门控的提交都会获得一个哈希链验证记录,并随仓库一起传输——因此 **CI 可以信任它并跳过重新运行检查**,从而节省时间和成本([provenance-skip](docs/ci-provenance-skip.md))。
- **随风险扩展。** 规则基于分支/路径/diff 大小进行匹配,因此繁重的检查和人工审批仅会在关键处生效。
它是对你现有检查的补充而不是替代:将 warden 指向你已经在运行的命令(`warden import` 会从你的 Makefile、npm scripts、lefthook 或 CI 中读取它们)。
## 安装
warden 是一个单一的静态二进制文件;选择你机器上已有的工具即可——不需要 Go 工具链。
```
# npx — 免安装(只要存在 Node 即可运行)
npx @klarlabs-studio/warden init
# curl (Linux/macOS)
curl -fsSL https://raw.githubusercontent.com/klarlabs-studio/warden/main/scripts/install.sh | sh
# Homebrew
brew install felixgeelhaar/tap/warden
# Go 开发者
go install go.klarlabs.de/warden@latest # or: go run go.klarlabs.de/warden@latest init
```
在 Windows 上:`irm https://raw.githubusercontent.com/klarlabs-studio/warden/main/scripts/install.ps1 | iex`。
`npx @klarlabs-studio/warden` 包是一个约 15 行代码的启动器:它为每个平台附带了预构建的二进制文件(即 [esbuild 模式](https://github.com/evanw/esbuild/tree/main/npm))并执行它。所有逻辑都存在于同一个 Go 二进制文件中;上述的每个渠道分发的都是同一个二进制文件。
## 使用一条命令接入现有仓库
```
cd your-repo
warden import --write # reads your Makefile / package.json / lefthook / CI into .warden.yaml
warden init # installs hooks + records the adoption point
```
单独运行 `warden init` 也可以——它会自动检测语言(Go、Rust、JS/TS、Python)并预填合理的 lint/test 命令。
在一个已有技术债的仓库中引入严格的 linter,或者在使用 warden 的同时结合 Copilot 审查和自动化 PR?请参阅[采用指南](docs/adoption-guide.md),了解如何门控这些更改(而不是历史记录),以及防止自动化 PR 阻塞的 CI/bot 设置。
## 快速开始
```
cd your-repo
warden init # installs pre-commit + pre-push hooks, writes .warden.yaml,
# records an adoption point at HEAD
warden policy explain # print the resolved effective policy for a hypothetical push
```
从此以后,`git commit` / `git push` 就会被门控。Warden 自身的推送会使用 `--no-verify` 运行,因此它永远不会重新触发 hook 并产生递归。
## 工作原理
- **pre-commit**(快速,本地):从 `HEAD` + 暂存的更改生成一个 worktree,运行快速步骤子集(默认:`lint`),并将任何自动修复重新应用到你的工作树中。通过 → 提交继续进行。
- **pre-push**(完整流水线):从分支尖端生成一个 worktree,运行解析后的流水线(`intent → rebase → review → test → document → lint`),在规则需要时于审批门处暂停,然后**快进你的本地分支并自行推送**,在 `refs/notes/warden` 下为每个通过验证的提交写入一条哈希链 provenance 记录。如果分支在运行期间发生了移动,快进将被中止,绝不强行合并。
pre-push hook 在成功时总是以非零状态退出——Warden 已经执行了推送,因此必须阻止 git 自身的(现已过期的)推送与其发生竞争。
### 签名的 provenance
每条验证记录都使用基于机器的 ed25519 密钥进行签名(在首次运行时生成,保存在你的用户 config 目录下——私钥永远不会离开本机)。签名者的公钥绑定在其自身的签名中,因此该记录不仅证明证据链完好无损,还证明了是由*特定的密钥*生成的。`warden verify` 会报告签名者;传入 `--key` 可要求特定的密钥:
```
warden key show # prints the fingerprint to pin
warden verify --key
# exit 0 only if signed by a trusted key
```
在 CI 中,这将 provenance-skip 从“有 warden 在这里运行过”变成了“**我信任的** warden 在这里运行过”——将 `key:` 传递给内置的 `warden-verify` 操作。记录无需固定即可保持可验证(链条 + 签名);`--key` 只是增加了信任门控。
每条记录还包含一个小型的 **SBOM**:验证时存在的每个依赖 lockfile(`go.sum`、`package-lock.json`、`Cargo.lock` 等)的 SHA-256 摘要。由于它是已签名、哈希链记录的一部分,因此通过验证的提交携带了其当时所拥有的确切依赖集的防篡改、已签名指纹——由 `warden why` 展示。
## 配置 (`.warden.yaml`)
```
extends: ../.warden.base.yaml # optional — inherit an org base config; this file overrides it
agent: auto
hooks: { pre_commit: true, pre_push: true }
commands:
lint: "golangci-lint run ./..."
test: "go test -race ./..."
# Agent 步骤(intent/review/document)运行为已解析的 agent 配置的
# 命令,并展开 {prompt}/{step}/{repo}。claude 和 codex 通过内置
# presets 开箱即用 — 你只需使用 agent_commands 来覆盖它们
# 或添加另一个 agent。无命令(且无 preset)→ advisory skip;Warden 绝不
# 猜测 agent 的 CLI。
agent_commands:
opencode: "opencode run {prompt}" # example: any other agent
steps:
pre_commit: [lint]
pre_push: [intent, rebase, review, test, document, lint]
parallel: true # default — run independent checks concurrently (see below)
timeouts: { test: "5m", review: "2m" } # kill + fail a step that hangs longer than this
notify: true # default — desktop notification when an interactive pre-push finishes
cache: { test: ["**/*.go", "go.mod", "go.sum"] } # skip a step when its declared inputs are unchanged
risk: { diff_lines_high: 400, files_touched_high: 15 }
pr: { enabled: true, comment: true } # open/update a PR on a passing push, post a gate-result comment
rules:
- match: { branch: main }
then: { require_approval: true, auto_fix: { test: 1 } }
- match: { paths: ["security/**", "auth/**"] }
then:
agent: { review: codex }
steps: { pre_push: { insert_after: lint, add: [security-scan] } }
- match: { risk: high }
then: { require_approval: true, agent: { review: claude } }
```
所有匹配的规则会叠加:对于每个字段,最具体的规则胜出(平局则按声明顺序决定);步骤的 `add`/`skip` 会被合并。`warden policy explain` 会打印结果——作为对门控配置错误规则的预期缓解措施——包括一条 `schedule:` 线,准确显示哪些步骤会同时运行。
### 并行步骤
默认情况下,Warden 会并发运行独立的、只读的检查,因此门控的耗时取决于最慢的检查,而不是所有检查时间的总和:
```
schedule: intent → rebase → [review ∥ test ∥ document ∥ lint]
```
当某个步骤写入 worktree 时,它会保持为**串行屏障**(按顺序单独运行):`rebase`(重写历史记录)以及任何被赋予 `auto_fix` 预算的步骤。屏障前后的步骤仍然会并行化。与 `lefthook` 的并行模式类似,并发运行的步骤不得修改被追踪的文件——如果需要修改,请给它一个 `auto_fix` 预算(这会使其串行化)。设置 `parallel: false` 可强制使用经典的一次一个步骤的流水线。
在交互式终端上,pre-push 运行会显示一个实时的 TUI:每个步骤都有一个加载动画和递增的计时器、每个运行中步骤流式输出的尾部日志,以及内嵌回答的审批门。
### 步骤缓存
在 `cache:` 下声明步骤的输入通配符,当所有匹配的文件与该步骤上次通过的运行状态达到字节级一致时,warden 将跳过该步骤——因此对于纯文档的推送,未更改的 `test` 不会重新运行。缓存存在于 `.git` 中(基于克隆,绝不提交);其键值还涵盖了步骤的命令,因此更改步骤运行的内容会使缓存失效。只有非变异性的步骤才可缓存,且正确性取决于是否声明了步骤的*所有*输入(与 bazel/turbo 的约定相同)。步骤首次命中缓存时会显示为 `test (cached — inputs unchanged)`。
## 命令
| 命令 | 描述 |
|---|---|
| `warden init [--hooks=pre-commit,pre-push]` | 初始化,安装 hooks,记录采用点 |
| `warden hooks enable\|disable ` | 更改 hook 选择 |
| `warden run ` | 运行门控(由 hook 垫片调用) |
| `warden policy explain [--hook h] [--branch b] [--paths glob,...] [--chart]` | 打印解析后的策略(或 XState 状态图) |
| `warden steps list` | 按 hook 列出内置 + 自定义步骤 |
| `warden import [--write]` | 从现有的 Makefile / package.json / lefthook / CI 生成 `.warden.yaml` |
| `warden status` | 显示门控状态:已启用的 hooks、采用点、已解析的步骤 |
| `warden doctor [--branch b]` | 审查自采用以来哪些提交带有验证记录 |
| `warden audit [--branch b] [--format text\|json\|md]` | 导出提交来源报告(合规性) |
| `warden verify [--commit c] [--key fp] [--quiet]` | 如果提交已通过 warden 验证则退出状态为 0 ——即 CI provenance-skip 原语 |
| `warden key show` | 打印本机的 provenance 签名密钥 + 指纹 |
| `warden why [commit]` | 根据记录解释门控为提交做了什么——匹配的规则、步骤、签名者 |
| `warden recipes [name]` | 列出 / 打印可粘贴的检查配方(gitleaks、semgrep、trivy、coverage-delta 等) |
| `warden watch` | 保存时重新运行快速检查——一个持续的开发反馈循环 |
| `warden attach` | 从另一个终端实时观看运行中的门控(Unix socket) |
| `warden ci [--branch b] [--wait]` | 报告(或轮询)分支 PR 的 CI 状态 |
| `warden axi ` | 纯 flag 的 agent 表面,TOON 输出 |
| `warden mcp serve` | 基于 stdio 的 MCP 服务器 |
## 自定义步骤
有两种方式,先从简单的开始。
### 1. 一个命令(无需代码)
为步骤提供一个名称和命令。任何具有 `commands.` 条目的步骤名称都会在 worktree 中运行该命令;非零退出将导致门控失败。这是最常见的情况——自定义检查仅仅是你已经在运行的命令。
```
commands:
security-scan: "nox scan . -severity-threshold high"
steps:
pre_push: [rebase, lint, security-scan, test]
```
### 2. 一个 subprocess 步骤(结构化发现)
当一个步骤需要返回基于文件的发现结果、请求批准或对早期步骤的发现做出反应时,请编写一个小程序,使用 `stepsdk` 包通过 stdin/stdout 交互 JSON 通信协议:
```
package main
import "go.klarlabs.de/warden/stepsdk"
func main() {
stepsdk.Run(func(in stepsdk.Input) stepsdk.Output {
// inspect in.RepoPath (the worktree), in.DiffSummary, in.PriorFindings...
return stepsdk.Pass()
})
}
```
将其构建为 `PATH` 上的 `warden-step-`,并在步骤列表中引用 ``。无论哪种方式,自定义步骤都作为隔离的子进程运行——没有任何由仓库编写的代码被加载到 daemon 中。
## 绕过 provenance (`warden doctor`)
`git ... --no-verify` 设计上可绕过任何 hook;Warden 并不阻止这种行为,而是让其在事后变得可见。每个经过验证的提交都会获得一条携带其 `axi-go` 证据链的 git 记录。`warden doctor` 会遍历自采用点以来的提交,并标记出任何没有匹配记录的提交——因此在共享分支上,每个贡献者都可以看到哪些提交实际上被验证过,而无需中央服务器。记录推送是尽力而为的:记录推送失败永远不会阻止推送本身。
## 开发
```
go build ./...
go test ./...
```
架构(六边形):`internal/domain`(策略模型)、`internal/policy`(规则解析)、`internal/application`(流水线 Runner + 端口)、`internal/infrastructure/{git,kernel,steps,hooks,explain}`(适配器)、`internal/service`(组合根)、`internal/cli` + `internal/mcp`(交付)、`stepsdk`(公共自定义步骤 SDK)。
## 贡献
欢迎贡献力量——请参阅 [CONTRIBUTING.md](CONTRIBUTING.md) 了解开发设置以及每次更改必须通过的 `make ci` 流水线。参与即表示你同意[行为准则](CODE_OF_CONDUCT.md)。发现了安全问题?请参阅 [SECURITY.md](SECURITY.md)——请不要发起公开的 issue。发布历史记录在 [CHANGELOG](CHANGELOG.md) 中。
## 许可证
MIT © Felix Geelhaar标签:EVTX分析, Git工具, Git钩子, 代码审查, 开发工作流, 日志审计, 网络安全研究