【免费下载链接】beads_rust
Fast Rust port of Steve Yegge's beads: local-first, non-invasive issue tracker storing tasks in SQLite with JSONL export for git collaboration
br(beads_rust)是 Steve Yegge 的 beads 的快速 Rust 移植版,一个本地优先(local-first)、非侵入式(non-invasive)的 issue 追踪器:任务存储在仓库内的 SQLite 数据库中,并通过 JSONL 导出实现 git 协作。相比云端工具,本地工具的最大隐患其实是"越权"和"损坏"——而 br 的安全设计恰恰围绕这两点展开。本文带你拆解它的 3 层防护:非侵入式原则、多进程写锁模型,以及发布签名验证。
一、为什么一个 CLI 工具需要"安全设计"?
很多人对命令行工具的安全认知停留在"别装来路不明的二进制"。但 br 的场景更复杂:
- 🗄️ 它长期驻留在你的仓库里(
.beads/目录),随时可能被其他进程(包括 AI agent 集群)并发访问; - 🔄 它要同步数据库和 git 中的 JSONL 文件,稍有不慎就可能破坏你的源代码或提交历史;
- 📦 它通过一键脚本和自更新命令分发布二进制,属于典型的供应链攻击面。
br 针对这三类风险,分别建立了下面三道防线。
二、非侵入式原则:br 承诺"永不越界" 🛡️
非侵入式(non-invasive)是 br 最核心的设计哲学,官方将其列为明确的设计非目标(non-goals)。
br sync 永远不会做的 6 件事
在 docs/SYNC_SAFETY.md 中,项目用一张"负面清单"划出了硬边界:
| # | 承诺 | 含义 |
|---|---|---|
| 1 | 不执行任何 git 命令 | 不 commit、不 push、不 stage,一切 git 操作由你手动完成 |
| 2 | 不修改允许清单外的文件 | 默认写入被限制在.beads/目录内 |
| 3 | 不安装 git hooks | 完全手动,绝不偷偷挂钩子 |
| 4 | 不运行后台守护进程 | 简单 CLI,无后台进程需要管理 |
| 5 | 不自动提交更改 | 每一次 git 操作都需要显式用户动作 |
| 6 | 不连接外部服务 | 离线优先,零网络调用 |
这张清单还配了配套的导出防护:空库防护(防止 0 条 issue 覆盖 N 条 JSONL)、过期数据库防护、未导入内容防护等,任何可能造成数据丢失的导出都会被默认拦截,必须显式--force才能突破。
写入范围被钉死在 .beads/ 目录
即使你指定了外部的 JSONL 路径,br 也会对它施加扩展名校验、符号链接防护、路径穿越防护和.git/目录隔离。换句话说:默认路径下,br sync 永远碰不到你的源代码;即便越出默认路径,也有一整套守卫把关。
README.md 中的 Limitations 章节把这条哲学总结得非常直白——自动 git 提交、hook 安装、后台守护进程都被"有意不支持",理由栏清一色写着:Non-invasive philosophy。
💡 对新手来说,这条原则的价值很实际:你可以放心让 AI agent 在仓库里高频调用
br,它不会在背后动你的 git 状态。
三、写锁模型:多进程并发下的数据库守护 🔒
当多个 br 进程(或 agent 集群)同时读写同一个 SQLite 数据库时,如何保证不出现半写状态和文件损坏?br 的答案是一套三层写锁体系。
三层锁各司其职
在 src/sync/mod.rs 中,br 定义了两种写权威(write authority):
- Workspace 写锁:基于规范路径的 sidecar 文件锁,负责在数据库尚未创建、或发生原子替换时,串行化不同工作区的写入;
- Database 写锁(src/sync/mod.rs#L444-L455):数据库文件存在后的最终写权威,把 workspace 锁和数据库 inode 锁组合在一起,防止同一个物理数据库通过硬链接获得两份独立写权限;
- JSONL 写锁:由于 JSONL 导出是"新建文件 → 原子 rename 覆盖",直接锁目标 inode 会在每次 flush 后失效,因此 br 改用基于规范路径哈希的 sidecar 权威锁,在 rename 之间保持稳定。
数据库 inode 锁:只锁 1 个字节 🎯
这是整个写锁模型里最精彩的一笔,实现在 src/sync/db_inode_lock.rs。
历史教训:v0.2.20 曾对数据库文件加整文件锁,结果在 macOS 上锁与 SQLite 引擎自身的锁冲突,导致"database is busy";在 Windows 上甚至让数据库 schema 都读不出来。根因是 SQLite 引擎会在 inode 的固定字节区间(0x40000000..0x40000200)上打自己的建议锁。
修复方案非常巧妙:
- 在
i64::MAX - 1这个字节偏移处只锁1 个字节——远超出 SQLite 锁字节区间,也超出任何真实数据库的文件大小; - Unix 上使用
F_OFD_SETLK打开文件描述锁,跨进程互斥,但永不与 SQLite 的锁区间重叠; - Windows 上对同一偏移做 1 字节
LockFileEx强制锁,语义上同样不会挡住引擎的 I/O。
正如模块注释所说:这个锁"锁住了数据库的 inode 本身",却"碰不到引擎的任何一个字节"。多进程竞争失败时,br 会返回带retryable标志的WriteLockTimeout错误,让调用方安全重试而不是硬闯。
未来演进方向(写合并队列)记录在 docs/WRITE_COMBINING_QUEUE_DESIGN.md:只有经过白名单审核的变更类命令才允许进入合并批次,读命令和带副作用的命令一律走直连路径。
四、发布签名验证:minisign + SHA256 双重校验 ✍️
本地优先不意味着"从官网随便下载"。br 的分发链路有完整的完整性校验。
强制 SHA256 校验:升级链路的默认行为
自 v0.4.1 起,每个发布资产(br-<version>-<platform>.tar.gz或.zip)都附带强制的.sha256sidecar。
- 一键安装脚本 install.sh 会自动下载校验和并验证,只有明确传入
--insecure-skip-checksum才允许跳过; - 内置的
br upgrade命令(src/cli/commands/upgrade.rs)在执行任何更新前,会下载对应的.sha256资产并逐字节比对哈希——缺少校验和资产时直接报错拒绝升级,而不是降级为"不校验继续装"。
minisign 签名:可手动验证的数字签名
README 的 "Verify Release Signatures" 章节给出了完整验证方式(README.md#L453-L473):
minisign -Vm br-<version>-<platform>.tar.gz \ -P 'RWTQoKUb0Ue4NsqTpPWnABCrIU0+m25zsMlbv6UcRClQ7jmRP3A7NmTB'几个值得注意的细节:
- 🔑 当前发布密钥 ID 为
36B847D11BA5A0D0,仓库内跟踪了对应的 Minisign 公钥 src/release_public_key.bin; - 🔄密钥轮换有据可查:v0.4.0 用的是一次性密钥,v0.4.1 起切换到可恢复的 DSR 密钥,v0.5.1 起在发布流程中上传前强制验证当前密钥——完整的密钥历史都写在 README 里,早期不可验证的签名被明确标注"应视为不可验证";
- 📦 资产命名有严格约定:只有
br-<version>-<platform>前缀的资产才是官方产物,其他前缀(比如带 Rust target 别名)的资产"不产自发布流程、不带签名、不受支持"。
这套"哈希管完整性、签名管来源"的双轨设计,意味着即使攻击者能污染下载通道,也拿不出能通过 minisign 公钥验证的合法签名。
五、CI 供应链防护:Actions 全部 SHA 锁定 🔗
发布安全还有一环容易被忽略:构建 br 的 CI 流水线本身。
docs/CI_SUPPLY_CHAIN.md 记录了这套机制:
- 所有外部 GitHub Action 在 workflow 中锁定到 40 位完整 commit SHA,禁止 tag 或短 SHA;
.github/action-pins.jsonl清单为每个锁定记录预期 SHA 和人工溯源说明;- 校验器刻意做到本地且确定性——不联网、不建 PR、不改文件,只做比对;
- 发布流程中的高危 shell 片段(校验和聚合、产物检测等)有专门的本地 harness 用 fixture 逐条覆盖,例如 tests/workflow_release_fragments.rs 会精确断言
minisign -Vm ... -x ... -P ...验证命令的存在。
一句话总结:连"构建 br 的流水线"也被纳入了 br 自己的安全模型。
六、总结:安全是"默认开启"的 🧠
| 防线 | 核心机制 | 防的是什么 |
|---|---|---|
| 🛡️ 非侵入式原则 | 负面清单 +.beads/写入域 + 导出防护 | 工具越权、误改源码、丢失数据 |
| 🔒 三层写锁模型 | workspace 锁 / inode 1 字节锁 / 路径哈希锁 | 多进程并发写入损坏数据库 |
| ✍️ 发布签名验证 | 强制 SHA256 + minisign 签名 + Action SHA 锁定 | 供应链投毒、二进制被篡改 |
br 的安全设计有一个共同特点:保护是默认行为,绕过必须显式声明——跳过校验和要传 flag,覆盖导出数据要--force,外部 JSONL 路径要 opt-in。对于新手来说,这意味着你只需要正常地使用br init、br create、br sync,安全边界就已经在你身后守好了。
更多细节可参阅:docs/SYNC_SAFETY.md、docs/ARCHITECTURE.md 与 docs/INSTALLING.md。
【免费下载链接】beads_rust
Fast Rust port of Steve Yegge's beads: local-first, non-invasive issue tracker storing tasks in SQLite with JSONL export for git collaboration
相关推荐
LSPosed模块签名验证:安全性与兼容性平衡
LSPosed模块签名验证:安全性与兼容性平衡 引言:模块安全的隐形守护者 Android生态中,模块框架面临着严峻的安全挑战。据XDA开发者论坛2024年安全
移动开发插件系统模型安全第一道防线:ONNX签名验证技术全解析
模型安全第一道防线:ONNX签名验证技术全解析 ONNX(Open Neural Network Exchange)作为机器学习互操作性的开放标准,为不同框架间
人工智能机器学习深度学习Webhook安全机制:触发器规则与签名验证
Webhook安全机制:触发器规则与签名验证 本文详细介绍了Webhook安全机制的核心组件,包括触发器规则配置、HMAC签名验证、IP白名单与访问控制以及参数
后端API网关
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考