跳转到主要内容

这是本节的多页打印视图。 .

返回本页常规视图.

设计注记

关于 PIG 关键决策、取舍与实现边界的设计注记。

设计注记解释 PIG 的决策与提案。每篇都列出日期、状态、范围、备选方案与依据。 提案介绍正在讨论的方向;已实现、已发布的记录说明已经完成的对应工作。

查命令语法与操作步骤,请读 PIG 文档;查各版本的变更,请读发布注记。

1 - 从面向人类到 Agent-Native:PIG 的 CLI 契约

PIG 如何分别提供终端文本、结构化结果、执行计划与环境上下文。

决策日期: 2026-02-12
状态: 随 pig v1.1.0 发布,之后随命令层演进调整。下述验收修订已实现(Implemented),纳入 v1.10.0 候选版本,尚未发布。
当前参考: pig 命令总览
范围: PIG 命令的自动化接口,以及外部工具的原生透传接口。

决策

PIG 为终端用户提供文本,为自动化提供结构化结果。产生稳定数据的命令提供 JSON 或 YAML 与状态码, 支持计划的工作流还提供执行计划。pig pt 等透明透传命令保留外部工具的输出、提示与退出码。

背景

PIG 最初是一套便捷的软件包管理 CLI。随着它扩展到 PostgreSQL、Patroni、pgBackRest、 Pigsty 与软件仓库操作,纯面向人的接口出现了几个问题:

  • 自动化只能抓取带颜色的自然语言文本;
  • 外层进程退出为零时,内层操作仍可能已经失败;
  • 破坏性工作流在执行前无法被审阅;
  • Agent 需要连续调用许多发现命令才能理解当前主机;
  • 包装器容易把子进程输出与结构化结果混在一起。

v1.1.0 引入了全局输出选择、稳定结果对象、执行计划与 pig context 快照。 后续重构明确了各命令支持的输出方式。

考虑过的方案

考虑过以下方案:

  1. 解析人类文本。 文案、翻译、颜色与上游工具变化都会让它失效。
  2. 把所有子进程输出捕获进 JSON。 这会破坏交互程序、流式输出、终端控制与原生退出语义。
  3. 设计一个万能结果模式。 软件包事务、恢复计划、指标和环境快照拥有不同的稳定语义,强行拍平只会丢失信息。

契约

长期有效的契约是:

  • 文本是面向人的默认接口;
  • 只有在 PIG 拥有稳定结果时,命令才声明支持结构化输出;
  • 结构化 stdout 只包含一个可解析结果,诊断与被包装工具的输出进入 stderr;
  • 计划描述动作、范围、风险和预期效果,但不执行动作;
  • PIG 自己拥有的破坏性操作在缺少确认时默认失败;
  • 状态码区分用法、确认、环境、依赖与执行失败;
  • pig context 提供有边界的环境快照,不要求调用方自行拼接;
  • 透明透传命令保持上游契约。

2026-10-16 修订将同一契约应用于 pig ext:

  • 可用性判断与各格式摘要共用矩阵优先级、架构别名及元数据回退规则。 macOS 只报告声明支持的 PostgreSQL 版本,不承诺存在安装包。 这里描述的是目录中的包快照;默认构建目标仍按版本元数据与本机安装规则选择, 不受包矩阵影响。
  • 部分导入失败必须返回失败,同时保留已解析、已下载和未解析的条目。 已完成的下载留在磁盘上,操作不承诺全有或全无事务。
  • pig pe 将 HTTP 4xx/5xx 视为失败。错误详情只包含状态码与标准说明, 不包含响应体或服务端自定义的状态描述。
  • pig license issue 明确交付新签发的凭据,成功时在结构化结果的 data.captured_output 中保留 Token。参数中省略签名私钥,私钥加载的原始错误在命令内部 替换为固定文案。参数错误和不含私钥的签名密钥诊断在所有输出格式中保持可读。 其他敏感命令包装器继续隐藏捕获输出与错误详情。

影响

这种分离让脚本更可靠,也让 Agent 能够依据风险与输出能力选择命令。与此同时,每个结构化字段都需要保持兼容, stdout 纯净性需要测试,包装器也不能承诺比被委托工具更高的稳定性。

输出方式由命令决定:PIG 操作使用 PIG 结果,转发工具使用原生输出。

验证与演进

v1.10.0 已提交修订的固定源码与回归测试证据包括: 可用性与计数、 部分导入失败、 exporter HTTP 失败。这些提交不构成版本发布证据。

最初框架随 v1.1.0 发布。 命令层整合提交 fb93602 随后删除重复包装器, 统一计划与输出处理。Patroni 后来改为透明透传,直接使用上游接口。

当前测试覆盖结构化 stdout 隔离、结果渲染、计划、确认门与环境上下文采集。

当前状态

按具体命令选择其支持的输出方式。结构化结果与透传行为见 pig 参考文档。

2 - 先编译和校验,再提交:原生 sty conf 流水线

pig sty conf 如何校验模板、修改配置、保护凭据,并原子写入 Inventory。

决策日期: 2026-02-18;生产契约于 2026-08-14 定稿。
状态: 已实现并随 pig v1.8.0 发布。
当前参考: pig sty conf
范围: 从受信 Pigsty 模板生成一份经过校验的静态 Inventory,不是任意 YAML 转换器。

决策

pig sty conf 应当像一台小型编译器:解析一个安全模板,读取结构,应用一组有边界的结构化变更, 校验完整候选文件,并且只在所有必要阶段成功后原子提交输出。

命令不调用旧 configure 脚本,也不回退到原始 Shell 执行。 结构化结果报告选中的输入、实际选择、变更类型与告警,但不返回生成的凭据值。

背景

模板配置看似简单,直到路径、符号链接、多 IP 占位符、固定版本模板、镜像、代理环境、生成凭据与部分有效 YAML 同时出现。文本替换流水线可能级联替换 IP,修改无关域名,泄露秘密,或在最终校验失败后截断目标文件。

输出 Inventory 可能包含管理员凭据,因此文件处理与结果渲染都属于安全边界。

考虑过的方案

  • 调用现有 Shell configure 脚本。 解析、校验和结果语义仍在 PIG 控制之外。
  • 使用全局搜索替换。 IP 与域名需要精确占位符边界和同时映射。
  • 先写文件再校验。 失败候选可能替换仍然可用的 Inventory。
  • 接受任意绝对模板路径。 命令应编译已知 Pigsty mode,而不是成为特权文件复制器。
  • 为了方便返回生成密码。 结构化日志与 Agent 轨迹不是秘密交付通道。

契约

  • 模板通过安全相对名称解析到 Pigsty 配置树下;
  • 拒绝绝对路径、目录穿越、路径逃逸,以及直接路径、符号链接父目录或硬链接造成的源/输出别名;
  • 解析与 IP 冲突检查先于外部预检;
  • 占位 IP 同时映射,无关地址保持不变;
  • 域名替换只匹配精确模板 token;
  • profile、region、proxy、locale 与 PostgreSQL 版本变更都是有边界的结构化操作;
  • 每个已知凭据标识符只生成一个随机值,结果只暴露标识符;
  • 完整候选接受原生校验,并可选执行有超时边界的 Ansible 解析;
  • 任一失败都不改变目标文件;
  • 成功结果以 0600 权限原子写入。

影响

使用 sty conf 从已知模板生成新 Inventory。编辑已有 Inventory 时,使用无损的 pig inventory 工作流。

固定版本模板保留原版本;请求了冲突的版本时,命令给出告警。

验证与演进

原生 configure 方案最早记录于 2026-02-18,生产实现收敛于 74e084e, 最终契约同步提交为 adc4260。 测试覆盖目录穿越与别名、同时 IP 映射、域名边界、交互与关闭输入选择、版本处理、代理和区域变更、 凭据生成与脱敏、预检顺序、校验失败、权限与原子写入。

当前状态

使用 pig sty conf 从 Pigsty 模板生成新 Inventory,使用 pig inventory 查看或编辑已有声明。 当前参数、mode 与预检行为维护在 pig sty 参考文档中。

3 - 七成正确的调优器:界定 pig pg tune 的边界

pig pg tune 如何根据硬件与工作负载计算 PostgreSQL 初始参数。

决策日期: 2026-03-21
状态: 2026-03-23 实现,随 pig v1.3.2 发布。
当前参考: pig pg tune
范围: 根据硬件、PostgreSQL 版本与工作负载类型生成初始配置。

决策

pig pg tune 计算 PostgreSQL 核心参数,输出结果供用户审阅。命令探测 CPU、内存与磁盘容量, 接受用户指定的覆盖值,并按选定的工作负载类型计算。文本输出展示生成的参数;JSON 和 YAML 输出 包含输入条件与参数。用户审阅结果后,选择需要的参数,通过现有配置系统应用。

原名“七成正确的调优器”表达的是实用的起点,并非测得的准确率。

背景

新安装的数据库尚无工作负载数据,也需要一套初始配置。小型开发机与大型数据库服务器无法 共用一份固定配置。根据硬件计算参数,可以提供可复现、便于检查和调整的基线。

考虑过的方案

  • 发布一份固定配置。 内存与并行参数需要随主机规模变化。
  • 构建自适应调优器。 这需要工作负载数据、实验与反馈循环。
  • 自动应用参数。 用户需要先审阅结果,再通过现有配置流程决定如何部署。
  • 计算全部 PostgreSQL 参数。 复制、安全与可用性设置还取决于硬件探测无法确定的业务要求。

契约

  • 使用探测到的硬件,或用户明确指定的 CPU、内存与磁盘值。
  • 通过 oltp、olap、tiny、crit 选择计算公式。
  • 相同的实际输入与 PostgreSQL 版本产生相同参数。
  • 结构化结果包含实际采用的工作负载类型、硬件与 PostgreSQL 版本。
  • 文本参数按固定顺序输出,标题注明 SSD 假设。
  • 校验输入范围,并省略所选 PostgreSQL 版本不支持的参数。
  • 保持配置文件与运行中的服务器不变。

影响

用户可以将输出用于新安装或初步容量规划。先审阅参数,通过现有配置系统应用,再测量真实 工作负载。后续调整应依据查询并发、检查点行为、存储延迟与复制要求。

验证与演进

初始实现为 60eecfe。 v1.3.2 首次发布参数生成功能。 当前实现 返回结果供输出层渲染。 tune_test.go 覆盖工作负载公式、资源边界、覆盖值与版本相关参数。

当前状态

参数生成功能已经发布。 输入与输出示例见 pig pg 参考文档。

4 - 为什么 PIG 保持扁平的 Cobra 命令层

一个顶层命令对应 cmd 中一个文件,具体行为进入 cli 与 internal 包的源码布局决策。

决策日期: 2026-06-30
状态: 已实现;新命令继续采用此布局。
当前参考: pig 命令总览与源码仓库
范围: Go 源码归属与命令注册方式,而不是公开命令分类本身。

决策

cmd 包保持扁平。一个顶层命令对应一个顶层 Go 文件:pg.go、pb.go、pt.go、 pe.go、sty.go、do.go、repo.go 等。即使命令树很复杂,也继续留在这个入口文件中, 除非另有明确的布局决策。

文件可以很长,但只应包含 Cobra 关注点:名称、别名、注解、参数、实参校验、帮助、注册和选项映射。 具体工作放入 cli/*、internal/* 或其它实现包。

背景

早期命令增长产生了很多以子命令命名的小文件,也出现了多套确认、结构化输出、计划渲染和旧接口包装实现。 一些简单问题因此难以回答:顶层命令在哪里注册,某个别名由谁拥有,两段辅助代码是否在执行同一策略?

PIG 的命令族很大,但它们的公开语法是一个整体。把语法集中在一个位置更容易审查冲突, 实现包则继续按职责拆分。

考虑过的方案

  • 在 cmd 下为每个命令建目录。 普通命令不采用,因为一个公开语法会散落在多个包中,也容易把业务逻辑放到 Cobra 附近。
  • 每个子命令一个文件。 注册、别名和继承参数将难以作为整体审阅。
  • 把所有逻辑都放进 cmd。 操作逻辑依赖 Cobra 状态后,测试与复用都会变差。
  • 抽象每一行重复代码。 猜测式框架会遮蔽命令语法;只有已经稳定、跨命令复用的辅助逻辑才应共享。

契约

  • cmd/root.go 负责根命令、全局参数和顶层注册;
  • cmd/utils.go 负责共享的命令层辅助函数;
  • 每个普通顶层命令有一个对应的顶层源码文件,可以配同名测试文件与专项测试文件;
  • Cobra 层校验语法和映射选项,但不执行具体操作;
  • 确认、注解、结构化输出与计划辅助逻辑只有一套实现;
  • 实现包接收普通选项并返回类型化结果或错误,不依赖 Cobra 全局状态。

影响

部分命令文件会有意保持较长。这个取舍是可接受的,因为公开接口可以作为整体审阅,而实现仍然在下层拆分。 规则也减少了别名或参数移动时的文件变动,为 Agent 提供确定的阅读起点。

审查重点是职责分工。操作逻辑应放在实现包中,闭包内的逻辑也遵循这一规则。

验证与演进

约定记录在 9eb70db, 随后由大型命令面整合提交 fb93602 落实。 Guard 测试检查别名冲突与命令注册,实现层行为则由各包测试验证。

当前状态

这仍是新工作的仓库规则。公开命令文档统一放在本站;源码布局约束继续靠近代码保留, 确保贡献者与编码 Agent 在修改前就能看到。

5 - 为什么 PIG 默认构建调试包

将 RPM debuginfo/debugsource 与 DEB dbgsym 从显式启用改为显式退出的构建策略决策。

决策日期: 2026-09-03
状态: Released(已发布),随 v1.8.1 交付。
当前参考: pig build
范围: pig build ext 与 pig build pkg 的调试包策略;单个包的产物仍以其配方为权威。

决策

pig build ext 与 pig build pkg 默认请求平台的正常调试包产物。普通构建时,PIG 不再传入禁用参数;只有需要更小或更快产物集合的用户,才显式使用 --nodbg 退出。

在 RPM 系统上,普通构建保留发行版的 debuginfo 与 debugsource 机制;--nodbg 把 debug_package 定义为空。在 Debian 与 Ubuntu 上,--nodbg 会在保留已有选项的同时, 向 DEB_BUILD_OPTIONS 追加 noautodbgsym。旧的 -s|--symbol 继续作为弃用的兼容空操作 被接受,因为调试产物已经不需要额外启用。

背景

旧命令通过 --symbol 显式启用 RPM 调试产物,否则主动注入 debug_package %{nil}。 这与平台惯例相反,也让默认产物不利于事后故障分析。Debian 的 Debhelper 已经在满足条件时 默认创建自动 dbgsym 包,并提供 noautodbgsym 作为显式退出机制。

调试包会增加构建时间、存储和仓库容量,但这些成本可见且可管理。等到精确源码、编译器和二进制 已经变化后,再重建匹配符号通常困难得多。

考虑过的方案

  • 继续用 --symbol 显式启用。 不采用,因为发布质量的产物默认就应保留匹配的诊断材料。
  • 强制所有构建都必须有调试包。 不采用,因为快速本地构建和受限产物流仍需要明确的退出方式。
  • 由 PIG 改写包配方。 不采用,因为 spec 与 debian/rules 负责包内容;运行时改写既意外又难审计。
  • 用 nostrip 退出 DEB 调试包。 不采用,因为它会改变主二进制,而不只是省略独立的自动调试包。

契约

  • 未指定 --nodbg 时,PIG 不添加任何禁用调试包的宏或环境选项;
  • RPM 上,--nodbg 为 rpmbuild 添加 --define "debug_package %{nil}";
  • DEB 上,--nodbg 向 DEB_BUILD_OPTIONS 追加 noautodbgsym,且不丢弃已有的 parallel=N、nocheck 等值;
  • --symbol 为兼容继续可解析,但被隐藏、弃用且不再有必要;
  • 结构化命令结果新增 nodbg,并保留 symbol 作为实际行为的反向值;
  • 普通安装包仍是构建成功的判据;调试包是附加产物,不能替代主包;
  • 纯 SQL、noarch 或其它不满足条件的构建无需生成空调试包;
  • 包配方或操作者提供的构建环境中的显式决定仍然具有最终权威。命令默认值是一项策略请求, 不是改写配方的许可。

影响

包含编译产物的扩展通常会生成更多文件,占用更多构建与仓库存储。作为回报,默认构建可以直接用于 栈回溯、core 分析和符号服务,不必再做一次重建。已有的 --symbol 脚本仍能运行;有意保留旧式 精简产物集合的脚本应改用 --nodbg。

配方仓库应删除那些不代表具体包约束的全局调试禁用语句。这必须作为独立改动审查,因为部分包是 架构无关包、无法完成调试信息提取,或使用自定义构建系统。

验证与演进

已被取代的显式启用行为可在此前固定版本的 build 参数注册 和 rpmbuild 命令构造 中复核。替代实现由 1c6f524 固定。命令测试保证 --nodbg 可见、兼容参数已弃用;构建器测试保证默认 RPM argv 不含禁用宏、 退出模式包含该宏,并保证 DEB 环境保留已有选项且只追加一次 noautodbgsym。

平台验证应在一个 EL builder 与一个 DEB builder 上各抽样一个含编译产物的扩展,同时检查默认 调试产物以及使用 --nodbg 后不再生成调试产物。配方级例外必须单独报告,不能据此声称 PIG 忽略了自己的参数。

当前状态

已随 v1.8.1 发布。 用法与平台要求见文首链接的当前参考文档。

6 - 危险操作只有一套语法:PIG 运维 CLI 安全契约

PIG 如何分离底层原语与编排器、显式表达破坏性意图,并防止别名或结构化输出改变操作含义。

决策日期: 2026-07-02
状态: pg、pb、pt、pitr 已于 v1.5.0 交付;2026-08-29 的 do 与 build proxy 修订已随 v1.8.1 发布。下述验收修订已实现(Implemented),面向 v1.10.0;源码证据见验证章节,尚未发布。
当前参考: pig pg、pig pb、pig pitr、pig do 与 pig build
范围: PIG 实现的运维命令;透明上游命令继续采用上游的确认与退出行为。

决策

操作便利性不能模糊操作含义。PIG 明确区分底层原语与多阶段编排器,显式表达破坏性意图, 谨慎分配别名,并要求计划与结构化结果描述的动作必须和文本模式真正执行的动作一致。

最重要的例子是恢复:pig pb restore 是 pgBackRest 原语,pig pitr 则协调 Patroni、 PostgreSQL 停止、恢复、重新启动与恢复后指引。任何别名都不能让这两条路径看起来可以互换。

背景

第一代便利别名积累了不一致的位置参数、确认参数、输出处理与服务语义。 restart、restore、promote、failover 等相似词在不同层次代表完全不同的操作。 跨越层次的短别名可能把看似无害的调用变成缺少编排保护的破坏性原语。

自动化还暴露出假成功问题:包装器输出、子进程输出和结果渲染可能使用不同的成功定义。

考虑过的方案

  • 尽可能增加短别名。 冲突和跨层同义词带来的风险高于节省几个字符的价值。
  • 给所有看起来危险的单词都加确认。 对透传命令不成立,因为提示与语义必须由上游工具拥有。
  • 让编排器成为原语的便利别名。 恢复编排拥有额外的停止、验证与重启不变量,不能合并。
  • 启动内层命令后立即返回成功。 结果必须反映 PIG 拥有的完整工作流。
  • 将维护命令的库名限制为 ASCII 标识符。 这会拒绝原本支持的空格和非 ASCII 名称。 只拒绝 libpq 连接串语法,并在生成命令时保留位置参数边界。

契约

  • 同级命令名称与别名唯一;
  • 子命令别名不能遮蔽另一个顶层命令;
  • PIG 实现的破坏性操作要求显式确认,并在有意义时提供无副作用计划;
  • 命令层在产生副作用前拒绝错误或多余的位置参数;
  • 命令专用名称遵循下游 Pigsty 契约;下游 Playbook 没有显式语法时,只采用有文档说明的最窄安全边界;
  • 结构化输出与文本模式共享同一个结果和成功定义;
  • 含凭据的值不进入诊断输出;就绪或连通性失败必须保持命令失败,不能只记警告后返回成功;
  • 底层 restore 不声称管理 Patroni 或 HA 路由;
  • PITR 编排器按需停止管理器,检查 PostgreSQL 已停止,执行恢复,可选启动 PostgreSQL, 并有意保持 Patroni 停止,等待运维人员验证;
  • 额外原生参数只通过明确记录的边界传递。

2026-10-16 至 2026-10-17 的修订将相同边界用于 v1.10.0 候选版本:

  • 跨用户 DBSU 写入以排他方式创建私有临时文件,使用 0600 和执行 DBSU 的属主,拒绝符号链接与 非普通文件目标,精确替换目标路径,失败时清理暂存。Linux 使用精确目标重命名;macOS 使用系统 Perl 的 rename 系统调用,避免 BSD mv 将源文件移入目录的语义。
  • repo rm 在变更前校验完整参数列表。只有零参数代表全量备份; all 仍只表示 node、pgsql、infra。 requested_modules 保留原始请求,removed_repos 描述展开后的执行动作。 repo add、repo set、repo info 同样整次拒绝显式空名称和逗号空项;只有省略参数 才保留 add/set 默认选择 all 的行为。 add/set 还会在初始化仓库管理器前校验模块名格式。不安全名称使整次请求失败;格式正确但 不存在的名称仍保留添加模式的部分成功行为,替换模式则在变更前整次拒绝。
  • 显式指定 pg -D 时,SQL 操作和数据库枚举绑定到该目录记录的端口与 socket,元数据不明确时先失败。 省略 -D 时保留原生客户端的默认连接方式;实例操作的默认目录仍为 /pg/data。 显式空字符串或纯空白的 -D 在配置初始化和操作前失败。 计划、确认重试和验证命令保留相同的目标与操作选项,包括显式的 -D /pg/data。 VACUUM FULL 计划与执行一样要求确认。 2026-10-17 的维护命令修订要求在计划、确认和执行前拒绝连接串形式的数据库参数,且不回显原值。 否则 libpq 连接串仍能覆盖所选主机和端口,并将凭据带入输出。 vacuum、analyze、freeze 在维护任何数据库前,先校验枚举出的完整库名列表。 生成的 vacuum 和 repack 命令将全部选项放在 -- 之前、库名放在其后, 保证 --all 这样的库名仍表示单个数据库。
  • 覆盖非空非托管 fork 目标必须有明确记录目标的匹配元数据,普通非 PGDATA 目录也不例外。 空目标仍可使用,托管 fork 必须按名称替换。私有路径以 DBSU 解析;无法解析的别名仍直接失败。 2026-10-17 的复核撤销额外的 /pg/data 禁令,按目标归属、源目标关系和运行状态决定是否允许操作。 约定路径既不能识别所有主库,也可能是合法的 fork 目标。 保留受管孤儿目录的强制清理契约。 非托管 fork 删除的本地路径检查遇到权限不足时,以所选 DBSU 重试;确认目标为目录且不是 符号链接后,才允许继续删除。
  • 不能仅凭 EPERM 放行 pg init --force 或 PITR 恢复。独立的可执行程序身份可证明 PID 已被复用; 身份无法确认时仍为未知。向存活 PID 发信号或使用其连接元数据执行 SQL 前,必须确认它属于 PostgreSQL。 未知状态不提供可用于强制停止升级的 PID,fork start 也不能写入成功状态;列表显示 unknown 并在结构化结果中设置 runtime_unknown: true。 角色检测在运行状态不明时同样失败;文件中的角色证据不能推翻已确认的停止状态。 强制初始化分别报告探测失败与正在运行的冲突。 计划前置检查将无法确认的运行状态报告为 unknown,不能以 PID 零标记为检查通过。 状态查询区分权限失败(130201,退出码 3)与其他探测失败(130808,退出码 1); 两类失败中的部分数据均不能证明实例已停止。
  • 时间线查询将 SQL 绑定到所选目录有效 PID 元数据中的端口与 socket。无法解析时,使用该目录的 pg_controldata 或报告未知时间线;promote 执行过程及必须确认主库角色的成功判据保持不变。
  • PITR 取消确认或遇到 EOF 时,在停服务、恢复与启动之前返回确认缺失(161001,退出码 7)。 验收必须执行真实确认路径,并检查生命周期操作的副作用为零。
  • PIG_NON_INTERACTIVE 和结构化执行关闭提示 stdin,并加上 sudo -n,旧式结构化包装也遵循 此规则。原生透传与显式数据 stdin 保留各自契约。
  • 敏感捕获输出和错误详情保持私有,签发密钥加载失败不回显输入。文档规定的原始导出通道仍然可用。

影响

部分历史缩写被移除,一些脚本需要采用 cluster-first 或显式目标语法。 作为回报,命令名称保留了层次边界,计划对应真实动作,恢复自动化也不会悄悄用原语替换编排器。

计划列出受影响的资源与动作,供用户在执行恢复前审阅。

验证与演进

v1.10.0 已提交修订的固定源码与回归测试证据包括: 运行身份与 SQL 目标、 fork 归属与私有路径、 PITR 取消与未知状态、 计划目标保留、 状态错误分类。这些提交不构成版本发布证据。 后续的维护数据库名与 -- 操作数边界修订 包含 Cobra 参数重解析测试与真实 libpq 目标边界回归测试。 仓库参数预检 在准备密钥或写入仓库前拒绝 不安全模块名,并保留格式正确但模块不存在时的添加部分成功行为。

规范命令契约在 c62c0f5 中进入仓库。 后续提交继续统一别名、早期校验、恢复目标、服务语义与角色检测。 Guard 测试遍历 Cobra 树,拒绝同级与跨层别名冲突;恢复测试覆盖计划、确认、停止升级、旁路恢复、 重启行为与结构化失败结果。 维护命令的回归检查应使用 Cobra 重新解析生成的命令,并让真实 libpq 客户端访问受控本地端点; 仅检查参数列表中包含 -h 和 -p 不足以证明目标绑定正确。

Patroni 后来改成透明透传,这仍遵循同一原则:PIG 只为自己拥有的工作流提供安全保证。

同一契约在 3e1603b 中扩展到 pig do 的名称与集群校验,并在 a880485 中封闭 Ansible 内置目标。软件包驱动、凭据安全且如实报告失败的 build proxy 设置进入 220ef9c, 随后由 74cb128 补齐结构化参数遮盖与机器注解,并在 de7ffd0 中把可选参数同步到机器语法。这些修改均在 Ubuntu 24.04 与 Rocky Linux 9 ARM64 Farrow 客体中完成实机测试,并在 v1.8.1 CI 通过后,从源码提交 1c6f524 正式发布。

当前状态

明确需要 pgBackRest 原语时使用 pig pb restore;需要受控恢复流程时使用 pig pitr。 当前语法与平台要求见对应命令参考页。

7 - 编辑声明,保留文档:无损 Pigsty Inventory

为什么 pig inventory 将 YAML 语义与源字节分离,让局部编辑能够保留注释、顺序、锚点与格式。

决策日期: 2026-07-18
状态: 已实现并随 pig v1.6.0 发布。 下述验收修订已实现(Implemented),纳入 v1.10.0 候选版本,尚未发布。
当前参考: pig inventory
范围: 静态 Pigsty Inventory 的查看、局部编辑、校验、比较与安全写入。

决策

PIG 同时把 pigsty.yml 视为配置声明和人工维护的源文档。语义解析器负责判断 Inventory 的含义, 原始字节则决定它的书写方式。局部编辑只替换指定的源范围,并在原子写入前重新解析完整候选文件。

这样可以避免 YAML 工具常见的失败模式:逻辑上正确的一次编辑,却悄悄重写整份文件的注释、键顺序、 引号、锚点、块标量或换行风格。

背景

Pigsty Inventory 是长期存在的运维资产,包含拓扑、调优、凭据、注释、示例、锚点和本地有意义的顺序。 普通的“解析—修改—序列化”流程可能生成有效但无法审阅的差异,并改变运维人员没有选择的结构。

另一方面,没有语义校验的纯文本编辑又可能把无效或自相矛盾的配置写入磁盘。 设计必须同时获得源文件格式与整份配置的正确性。

考虑过的方案

  • 使用一个 YAML 序列化器完整往返。 在真实 Pigsty 语料上,没有选定的序列化器能够逐字节保留完整源契约。
  • 用正则表达式处理 YAML。 引号、注释、别名、块标量和嵌套集合让纯文本语义判断不安全。
  • 只编辑规范化生成副本。 活跃 Inventory 属于运维人员,仍会与生成表示发生漂移。
  • 允许替换所有节点类型。 锚点、别名、标签与块标量需要比普通映射和标量更严格的处理。

契约

  • 拒绝重复键与多文档 YAML;
  • selector 只定位一个无歧义的声明片段;
  • 语义解码与源范围发现是两项独立职责;
  • 编辑从确定的源文件版本开始,文件被并发修改时失败;
  • 编辑片段只进行插入上下文所必需的规范化;
  • 提交前重新解析并校验完整候选文件;
  • 写入使用同目录临时文件、sync、rename 与目录 sync;
  • 拒绝符号链接与不安全路径变化;
  • 成功编辑后移除组和其他用户的权限,保留所有者原有的读写权限;
  • 除非命令明确属于原始文本输出接口,诊断、diff、计划与结构化结果都不输出声明值。

2026-10-16 的验收修订保留 pg_users[].roles 的角色名字符串与结构化授权对象兼容。 编辑、序列化和 CMDB 导出必须保留 YAML 1.1 字符串语义,包括 "1:30";"010" 是回归对照, 不代表此前必然存在损坏。 2026-10-17 的修订进一步要求:作为字符串传入的日期与时间戳,经 PyYAML 加载后仍为字符串。 已有时间戳值作为不透明标量保留原始内容,不增加日期运算,也不归一化整个文档。 验收使用独立 YAML 解析器检查写出后的类型,不能仅依赖 PIG 自身的往返解析。

sty deploy 与 do 使用配置层已经解析的 Inventory 路径。 参数和环境中的相对路径以调用者 cwd 为基准,带引号的 ~/ 使用用户主目录,默认来源在执行时 也保持显式。来源缺失不得回退。静态检查仍不执行动态来源;执行边界继续由 Ansible 负责。

影响

编辑器比普通 YAML marshal 更复杂;当无法证明源文件保真时,一些语法有效的片段也会被有意拒绝。 换来的结果是可审阅差异:未选择部分逐字节稳定,无效 YAML 无法落盘,并发修改不会被静默覆盖。

Inventory 可以包含自定义凭据字段,无法仅凭字段名可靠脱敏。 因此,show 输出所选声明的原始文本;元数据与校验命令则省略声明值。

验证与演进

v1.10.0 已提交修订的固定源码与回归测试证据包括: 来源解析与角色授权、 日期形式字符串保留、 独立 YAML 消费端验收。这些提交不构成版本发布证据。

根级 Inventory 契约与既有 CMDB 边界建立于 ba6e678,实现落地于 ea43858。测试覆盖真实 Pigsty 配置语料、逐字节往返、 局部替换、受保护 YAML 形式、并发变更拒绝、原子写失败、selector、校验和无敏感值诊断。

后续重构移除了旧选项并分离校验阶段,但没有改变源文件保真模型。

当前状态

静态 Inventory 仍是主要配置来源。selector、校验 profile、结构化输出与明确标记为实验性的 CMDB 桥接, 均以当前 pig inventory 参考文档为准。

8 - 复用 Pigsty 已经拥有的 CMDB

PIG 如何复用 Pigsty 既有 PostgreSQL CMDB,并撤销重复的版本存储设计。

决策日期: 2026-07-18
状态: 适配器随 v1.6.0 发布,仍为实验功能;早期版本存储设计已被取代。
当前参考: pig inventory cmdb
范围: 与 Pigsty 既有 CMDB 交换声明,而不是再设计一个配置数据库。

决策

PIG 必须复用 Pigsty 已经提供的 CMDB。它的职责是有边界的适配:校验静态 Inventory, 将声明装载到既有表中,导出既有投影,检查一致性,并安全切换 Ansible 的静态与动态数据源。

PIG 不拥有第二套 schema、迁移历史、快照账本、CAS revision store、三方合并引擎或数据库回滚系统。

背景

早期设计把 CMDB 支持当成一个全新后端,提出独立 schema、不可变快照、revision token、合并与回滚、 备份 bundle 和数据源切换记录。方案内部逻辑完整,但出发点错误:Pigsty 已经拥有 pigsty 与 pglog schema、装载脚本、动态 Inventory 投影和数据源切换行为。

再建一套控制面会复制事实、制造同步问题,并让 PIG 对另一个项目拥有的数据模型负责。

考虑过的方案

  • 把新 revision store 保留为高级模式。 即使可选,两套权威仍然是两套权威。
  • 在新旧 schema 之间双向镜像。 冲突处理与迁移会成为永久产品责任。
  • 只用 Shell 包装既有脚本。 PIG 仍需要有边界的超时、安全连接处理、结构化计划与原子数据源切换。
  • 完全删除 CMDB 支持。 一个小型原生适配器仍能提供有价值的校验与自动化,而不重新定义 schema。

契约

  • Pigsty 既有 schema 与投影是数据模型权威;
  • PIG 通过显式数据库目标、环境配置或 service=meta 连接;
  • 凭据、DSN、SQL 正文与声明值不得进入计划或诊断;
  • check 只读;
  • init 用匹配版本的基线替换 pigsty 与 pglog schema,并要求确认;操作前先备份现有数据库;
  • load 在事务内替换声明行,并要求显式确认;
  • dump 在没有 force 时拒绝意外覆盖;
  • enable 与 disable 只修改能够识别的 Ansible Inventory source 形式,并原子写入;
  • 无法识别的可执行 Inventory source 一律拒绝,不擅自重写;
  • 整个命令族继续明确标记为实验功能。

影响

修订移除了重复的版本存储实现,也减少了维护工作。

保留下来的适配器更小、更容易审计,也与现有 Pigsty 运维方式兼容。 它同时继承既有系统的限制:init 需要运维人员自行备份,装载声明属于替换操作,而不是协同版本控制。

验证与演进

纠正后的边界记录在 ba6e678。 废弃实现由 e0f73ed 删除, 其中包括平行 schema、snapshot、merge、revision 与 rollback 机制。 保留路径的测试覆盖 PostgreSQL 兼容性、连接信息脱敏、事务失败、摘要绑定确认、dump 安全和原子数据源切换。

当前状态

既有 CMDB 适配器已随 v1.6.0 发布,但仍为实验功能。 初始化或替换前先备份 CMDB。操作流程见 pig inventory 文档。

9 - 用有边界的 Grafana 客户端替代仪表盘脚本

pig sty grafana 如何通过原生 HTTP 客户端管理仪表盘与偏好设置。

决策日期: 2026-07-18
状态: 随 v1.6.0 发布;v1.6.2 加入仪表盘 schema v2 支持。
当前参考: pig sty grafana
范围: 仪表盘导入、导出、清理,以及部分组织与用户偏好设置。

决策

PIG 使用原生 HTTP 客户端管理 Grafana 仪表盘。本地 JSON 路径选择单个仪表盘、一个文件夹或 完整仪表盘目录。装载、导出与清理采用同一套选择规则,破坏性操作可以先预览。

默认目录是 Pigsty 仪表盘集合,用户也可以选择其他符合格式的目录。 清理默认按本地文件声明的仪表盘 UID 选择目标;显式指定 clean --all 时, 目标是当前 Grafana 组织中的全部仪表盘与文件夹。

背景

旧 Shell 脚本依赖本地文件布局,对部分失败的说明有限。将这些操作纳入 PIG 后, 可以统一超时、认证、路径校验与结果输出。本地声明也为默认清理提供了明确范围。

考虑过的方案

  • 继续把 Shell 脚本作为公开接口。 网络限制、脱敏与结构化结果仍会分散在各脚本中。
  • 开放任意 Grafana API 调用。 PIG 只需要仪表盘操作与少量偏好设置。
  • 按文件夹名称选择清理目标。 名称可能重复。本地 JSON 提供仪表盘 UID,文件夹仅在清空后删除。
  • 内置默认密码。 凭据应由用户配置。

契约

  • 限制请求时间与响应大小,拒绝不安全的重定向。
  • 认证前检查公开健康端点。没有密码时,info 可以仅返回健康状态。
  • 凭据来自显式输入、环境或 Inventory;诊断与结构化结果不包含凭据和响应正文。
  • list 列出当前组织的全部仪表盘。
  • load 校验并导入所选本地文件,不删除远端仪表盘。
  • boot 将已有的 pigsty 仪表盘设为首页并收藏,将组织命名为 Pigsty。
  • init 装载完整仪表盘目录,全部成功后才执行 boot。
  • dump 将所选远端内容导出为确定性的 JSON,并原子写入文件。
  • clean 删除本地声明的 UID,再删除空文件夹。--all 显式选择整个当前组织。 两种模式都显示计划,并要求确认。
  • lang 与 style 修改组织和当前用户的对应偏好。样式 auto 映射为 Grafana 的 system。
  • 读写时统一处理受支持的 schema v1 与 v2 仪表盘格式。

影响

装载与清理使用同一份本地声明,用户可以只操作一个仪表盘或文件夹。 UID 匹配用于定位目标,不代表该仪表盘最初由 PIG 创建。执行清理前应审阅计划, 尤其是使用 --all 时。

数据源配置、插件安装与用户管理继续使用 Grafana 自身工具。

验证与演进

原生工作流落地于 3060485, 67f6e3b 加入仪表盘 schema v2 支持。 已发布测试 覆盖仅查健康状态、认证、装载范围、初始化顺序、导出稳定性、偏好更新、本地 UID 清理、 显式全量清理与计划变更拒绝。HTTP 客户端测试覆盖超时、重定向、响应限制与脱敏。

当前状态

仪表盘工作流已经发布。路径选择、凭据与清理示例见 pig sty grafana。

10 - 让 Patronictl 自己说话

为什么 pig pt 不再镜像 Patronictl 命令树,而是只保留少量 PIG 本地辅助功能的透明启动器。

决策日期: 2026-07-21
状态: 已实现并随 pig v1.6.0 发布。
当前参考: pig pt
范围: Patronictl 集群命令,以及 PIG 拥有的配置选择、参数设置、服务、状态和日志辅助功能。

决策

pig pt 是已安装 patronictl 的透明启动器。PIG 选择配置并分派少量本地辅助命令; 其它命令词及其后的所有参数原样传递,保留原生提示、终端行为、输出格式与退出码。

PIG 不再维护一份持续变化的 Patronictl 命令树副本。

背景

镜像 Patronictl 要求 PIG 复制命令、参数、位置语法、确认方式、格式和版本相关行为。 上游接口持续演进,PIG 的副本必然漂移。同一个操作通过 patronictl 与 PIG 调用时可能出现不同语义。

包装器在 Pigsty 环境中仍有价值:以数据库操作系统用户选择正确配置,提供本地服务和日志工作流, 并把一小段参数设置便利语法翻译为一次原生 edit-config 调用。

考虑过的方案

  • 继续镜像全部上游命令。 必然滞后,并重复 Patronictl 已经拥有的校验。
  • 只允许经过测试的命令白名单。 新上游命令仍要等待 PIG 发布后才能使用。
  • 把原生输出捕获成 PIG JSON。 会破坏交互编辑、流式输出、提示、终端保真和上游 schema。
  • 完全删除 pig pt。 确定性配置选择与本地 Pigsty 辅助能力仍然有价值。

契约

  • 第一个非选项命令词决定本地分派还是透传;
  • set、本地服务快捷命令、status 与 log 由 PIG 拥有;
  • 其它命令和剩余参数原样转发;
  • pig pt -- COMMAND ... 显式绕过本地名称冲突;
  • 包装器参数必须出现在原生命令词之前;
  • 原生 help 可以在没有本地 Patroni 配置时运行;
  • Patronictl 拥有交互提示、原生 --format 和退出码;
  • 会产生原生参数歧义的 PIG 全局结构化输出被明确拒绝;
  • 配置按确定顺序解析,进程以数据库系统用户运行。

影响

自动化需要采用 Patronictl 的集群名在前的位置参数语法与原生输出参数。 部分 PIG 专有别名和结果 schema 被移除。换来的好处是:新 Patronictl 功能无需等待 PIG 发布, 行为也不再依赖滞后的包装器实现。

本地 set 辅助功能有意保持很小:它只分类 Patroni 标量键与 PostgreSQL 参数,然后执行一次原生 edit-config。

验证与演进

重写提交为 6cbc23b。 测试覆盖 token 边界、argv 原样保留、配置优先级、数据库用户执行、原生退出码、无配置 help、 输出模式拒绝、-- 逃逸与本地辅助命令冲突。最终 help 路径修正在 v1.6.0 前完成。

当前状态

透传命令语法以 Patronictl 自身文档为准;PIG 的配置选择与本地辅助功能以 pig pt 为准。 透传命令需要 JSON 输出时,使用 Patronictl 原生 --format json 参数。

11 - PIG 2.0 产品方向

PIG 2.0 提案:统一 Pigsty 初始化入口,校验 Catalog,固定项目所用版本,并保留独立部署步骤。

决策日期: 2026-08-13
状态: 提案,待审议,尚未实现。
当前参考: PIG 文档与发布历史
范围: 未来 PIG 2.0 / Pigsty 5.0 的候选产品边界与验证门槛。

决策

提案方向是让 PIG 成为从空白控制节点到经过校验、可以部署的 Pigsty Inventory 的统一初始化入口。 PIG 负责 Catalog 选择与解析、执行计划、流程编排、结构化结果与脱敏执行记录; 软件包事务、配置应用与基础设施状态继续委托给 DNF/APT、Ansible 和未来的基础设施工具。

提案有意保留 PIG 的独立价值:repo、ext、install 在没有 Pigsty 项目时也必须可用。 它也保留独立部署步骤:未来的 pig sty setup 可以下载、引导与生成配置,但不能在用户没有单独调用部署时 自动执行多节点 deploy。

背景

到 v1.8.0,PIG 已经能够下载 release、原生引导控制节点、编译 Inventory、管理仓库与扩展, 并执行部分运维操作。产品仍有以下问题:

  • 仓库、包别名、扩展、路由与 Pigsty 元数据可以独立变化;
  • 项目没有明确 Catalog 身份,无法防止后续解析受全局更新影响;
  • 路由选择与仓库安全还不是一套可见产品契约;
  • 初始化路径上的执行结果还没有形成持久、脱敏的执行记录;
  • PIG、Pigsty、Catalog schema、操作系统与 Ansible 的兼容性需要统一发布矩阵,而不是分散假设。

提案将 2.0 的重点放在元数据一致性与可重复的初始化流程上。

考虑过的方案

  • 把 PIG 变成单体配置与状态引擎。 Inventory、Catalog 编写工具、包管理器、Ansible 与基础设施工具 已经分别拥有不同事实,因此否决。
  • 让 Pigsty 运行时依赖 PIG 或 pgext checkout。 Pigsty release 必须依靠版本化生成产物独立工作。
  • 让 setup 自动部署。 生成并校验配置与修改远程节点属于不同的同意边界。
  • 重新实现 DNF/APT failover 或 Ansible 执行。 PIG 应选择输入并解释结果,而不是成为另一个包管理器或配置引擎。
  • 让 Vagrant/Terraform 统一阻塞 2.0。 实验环境工具的状态语义不同,也不决定核心初始化路径。
  • 立即发明万能 sty plan。 至少两个 PIG 自有工作流证明同一计划 schema 可复用后再讨论。

契约

如果获得批准,产品方向将遵循以下边界:

  • 每类事实只有一个权威:Inventory 负责集群声明,Catalog 编写来源负责产品元数据, 项目锁定文件负责选中的快照身份,执行记录负责观测结果,基础设施工具负责实时状态;
  • PIG 拥有 Catalog schema、校验、客户端、解析器与选择逻辑,但不拥有所有元数据编写数据库;
  • sty setup 组合既有 init、boot、配置流程,不复制实现;
  • setup 在 Inventory 校验后停止,deploy 继续显式执行;
  • 独立命令跟踪兼容 Catalog 发布通道,Pigsty 项目在成功 setup 或 conf 提交后锁定当时的快照;
  • 普通命令不隐式改写已有项目锁定文件;
  • 路由选择来自显式配置或有边界的首次判断,不构建持续 GeoIP、云 IMDS 或后台测速服务;
  • 软件包下载重试与下载端点切换由 DNF/APT 负责;
  • 执行产物按版本管理并脱敏,raw 上游模式保持原生输出流与退出语义;
  • doctor 保持诊断角色,不获得默认修复权限;
  • 未来 lab 支持只做薄适配,PIG 不拥有 Terraform state。

影响

提案会让首次使用路径更清晰,也让元数据选择可以审计。与此同时,它会新增快照身份、 项目锁定文件、迁移规则、信任策略、执行记录和兼容矩阵等持久契约。 这些契约会显著增加测试与发布负担,不能作为松散功能各自交付。

Ansible 事件桥接需要先通过脱敏与兼容实验。诊断与支持包、实验环境适配器推迟到首版发布之后; EL7 支持级别仍待决定。

验证与演进

提案成为发布契约前需要以下证据:

  • 覆盖声明支持的 Linux 平台,验证原生初始化流程;
  • Catalog 签名、过期、回滚、混装与离线场景的对抗测试;
  • 证明 Pig、Pigsty、pgext 生成消费者不会漂移的语义差异检查;
  • no_log 与秘密零泄露的 Ansible 回调实验;
  • 全球、中国、代理和受限网络环境的路由选择测试;
  • 修改安全默认值前的仓库签名矩阵;
  • 1.x 到 2.0 的布局、lock 与混合版本迁移演练;
  • 与明确兼容矩阵绑定的 schema 和结构化输出测试样例。

这份提案采用的实现基线是 v1.8.0。 该版本已经包含原生 boot 与 configure,但没有实现提案中的 Catalog v2、项目版本锁定、setup 命令、 事件执行记录或 2.0 迁移契约。

当前状态

提案仍待审议。Catalog 安全机制、覆盖规则、路径、EL7 支持与 Ansible 事件桥接需要继续决策。 已发布命令的用法见当前文档。

12 - Catalog v2 提案:不可变的分类快照

用分类数据文件组成可验证的 Catalog 快照,支持原子激活、项目版本锁定与离线导入。

决策日期: 2026-08-13
状态: 提案;安全机制、覆盖规则、打包方式与路径布局待定。
当前参考: pig ext 与 pig repo
范围: PIG 2.0 产品元数据的发布与读取模型。

决策

Catalog v2 将产品元数据分成多个有类型的数据文件,组成一份不可变、可验证的快照。 清单文件(manifest)记录平台、仓库、路由、包别名、扩展、兼容性、Pigsty 版本与公钥数据的 长度和哈希。所有文件一起校验,通过同一个指针激活,避免混用不同版本的仓库与扩展矩阵。

快照以内容摘要标识。系统、用户、便携环境与项目都选择完整快照,并从各自的存储位置读取。

背景

v1 Catalog 的相关信息分布在内嵌 CSV、仓库 YAML、Pigsty 变量、生成站点与更新流程中。 部分字段可以推导,却仍需重复维护;扩展矩阵也把项目、版本与包等不同对象压在同一条记录里。 独立更新后,很难确认这些数据来自同一次发布。

Catalog v2 要解决的是数据如何一起发布、校验和启用。

考虑过的方案

  • 扩大 extension.csv 或改用一个大 YAML。 不同数据类型需要独立的结构和校验规则。
  • 立即使用 SQLite、protobuf 或定制二进制格式。 当前数据量尚不需要增加这类运行和调试成本。
  • 按字段合并系统、用户与项目基础快照。 合并结果缺少单一发布者、摘要、兼容声明与签名。
  • 只在缓存中保存当前快照和项目锁定版本。 清理缓存会破坏持久选择。
  • 让用户文件覆盖官方信任根。 用户偏好不应削弱系统的安全策略。
  • 后台静默更新并启用。 元数据变化会改变包解析结果,用户需要知道何时发生了更新。

契约

提案规定:

  • 清单与小型数据文件使用确定性的 UTF-8 JSON,大型稀疏数据使用 JSONL。
  • 直接校验清单原始字节,以及数据文件的长度和哈希,避免重新序列化产生歧义。
  • 清单包含格式版本、单调递增的安全版本、创建与过期时间、发布通道及 PIG/Pigsty 兼容范围。
  • 内嵌一份可用于恢复的基础快照。
  • 将包管理器维护的基础快照、持久快照存储、可变状态指针与下载缓存分开存放。
  • Linux 遵循 FHS/XDG,macOS 使用 Application Support 与 Caches。便携模式下的 PIG_HOME 也分别存放配置、数据、状态、缓存与运行文件。
  • 项目锁定文件记录快照身份与有序覆盖层;项目自身持久保存已验证的快照数据。
  • 将“选择哪个摘要”与“到哪里读取对应数据”分成两个步骤。
  • 用户与项目只能收紧系统安全策略。
  • 更新先下载到私有暂存目录,逐层校验并同步到磁盘,再移入按内容寻址的存储,最后原子替换激活指针。
  • 更新失败保留原快照;用户或系统通道更新不改变项目锁定版本。
  • 离线导出包含验证元数据和公开信任材料,不包含私钥。
  • 在一个兼容周期内,ext reload 与 repo reload 可以映射到完整快照更新;各数据文件统一激活。

Inventory、凭据、实时探测、已安装包状态、Ansible 事件、基础设施状态、操作确认与短期指标 继续由各自的系统管理。

影响

分类数据文件便于确定维护职责和校验规则,内容寻址便于回滚与离线导入。 项目自带所需快照后,部署不再依赖某个用户的全局缓存。系统软件包更新基础快照时, 用户已选择的快照保持不变。

这需要同时设计密钥轮换、过期、回滚保护、垃圾回收、路径权限、迁移、包管理器生命周期、 覆盖冲突与跨仓库生成流程。

扩展模型还需区分 SQL 扩展、上游项目、构建单元、发布版本、操作系统软件包、目标平台可用性 与展示规则。平台支持汇总、required_by 等派生字段由生成器计算。

验证与演进

实现前需比较 go-tuf 与最小签名清单方案,记录安全机制的选择。 两者均需通过错误签名、元数据过期、回滚、文件替换、快照混装、下载截断与离线验证测试。

其余测试覆盖各平台路径、root 与普通用户权限、只读目录、符号链接替换、磁盘写满、并发激活、 包升级与卸载、删除全局缓存后的项目运行,以及现有扩展和可用性数据的完整迁移。

本提案形成时的源码基线为 v1.8.0。 v1.9.0 仍使用内嵌与可独立更新的 v1 Catalog。

当前状态

Catalog v2 尚未实现。安全机制、路径与覆盖规则需要先完成决策和验证。 如果覆盖层的冲突与信任规则尚不成熟,可以先采用完整的自定义签名通道。 当前用法见 pig ext 与 pig repo。

13 - 一键配置 Xray 客户端与服务端

以现有可工作的客户端与服务端为参考,为 build proxy 增加配套的 VLESS、REALITY 与 Vision 初始化能力。

决策日期: 2026-10-05
状态: Released(已发布),随 v1.9.0 交付。 下述验收修订已实现(Implemented),纳入 v1.10.0 候选版本,尚未发布。
当前参考: pig build、运维安全契约与发布历史
范围: 一键配置 Xray 客户端与服务端;Linux 客户端和服务端,以及 macOS 客户端。共享 Nginx 入口仍是独立部署边界。

决策

为 pig build proxy 增加明确的 client 与 server 子命令。新工作流采用 VLESS + RAW + REALITY + xtls-rprx-vision。服务端首次设置生成配套凭据,重复设置保留 已有客户端连接契约,并提供相同的标准 URI; 客户端直接接收 URI 或命令行参数、安装 Xray、配置本地监听、启动服务,并验证连接。 文件传递是可选方式,不是初始化的前提。

保留现有命令路径与 x 别名。无参数调用改为安装或确认 Xray。兼容期内,历史形式 id@host:port [local] 继续通过 V2Ray 使用 VMess,并保留默认端口。

背景

此前实现 安装 vray,将 HTTP 到 VMess 的配置写入 /etc/v2ray.json,赋予 v2ray 组读取权限, 写入 Shell 别名,重启 v2ray,再检查 HTTPS 请求。现有测试覆盖参数解析、包管理器选择与凭据脱敏。

已检查的参考配对使用 Xray 26.3.27。运行中的 macOS 客户端在回环地址的 8888 端口同时提供 HTTP 与 SOCKS,出站使用 VLESS/RAW/REALITY/Vision,采用 Chrome 指纹、关闭 multiplexing, 并启用 ML-DSA-65 验证。检查期间 HTTP 与 SOCKS 请求均成功;客户端 UUID、short ID 与 SNI 匹配服务端相应字段。

参考 Linux 服务端监听回环地址的 9443 端口。Nginx 占用公网 443,按 SNI 选择后端, 并转发 PROXY protocol 头。Xray 接收该头,连接 REALITY target,使用 freedom 出站, 阻断匹配 geoip:private 的目的地址。此部署由 Nginx 提供公网入口。

检查过的 Pigsty RPM 与 DEB 制品覆盖两种架构,均提供 /usr/bin/xray、权限为 0640 且归属 root:xray 的 /etc/xray.json、xray:xray 服务账户、xray.service,以及 /usr/share/xray 中的地理数据。安装脚本只重载 systemd,不自动启动或启用服务。 公开仓库索引列出了 26.3.27-1PGSTY。运行测试范围见下文。

考虑过的替代方案

  • 只替换 V2Ray 名称,继续只支持 VMess。 无法满足服务端初始化与参考协议需求。 旧模板可以通过 Xray 配置校验,但 Xray 会输出 VMess 弃用警告。
  • 建设通用代理管理器。 暂缓:订阅、协议目录、TUN、透明代理、流量统计与任意配置导入 超出了本次配套初始化需求。
  • 立即新增顶层命令。 暂缓:现有 build proxy 可以容纳两个角色,无须变更根命令语法或维护第二套实现。
  • 原样复制参考服务端。 否决:要求 PROXY protocol 的回环监听不能直接接收公网连接, 也必须尊重现有 Nginx 对端口的占用。
  • 要求客户端必须通过文件初始化。 否决:粘贴一条 URI 或直接指定参数是主要用法; 受保护文件与标准输入仍适用于自动化。
  • 在普通成功输出中打印生成的凭据。 否决:结构化结果和日常日志应可以安全保留; 显式请求的导出可以将 URI 交付到终端。

契约

已经实现的角色语法如下:

# 在 Linux 服务端执行,显式打印连接 URI 供复制。
pig build proxy server --host proxy.example.com --target www.example.net:443 --export -

# 在 Linux 或 macOS 客户端粘贴服务端返回的 URI。
pig build proxy client 'vless://[email protected]:443?encryption=none&security=reality&type=tcp&flow=xtls-rprx-vision&sni=www.example.net&fp=chrome&pbk=PUBLIC_KEY&sid=SHORT_ID&pqv=VERIFY_KEY'

# 也可以逐项指定连接参数。
pig build proxy client --server proxy.example.com:443 --id UUID --sni www.example.net --public-key PUBLIC_KEY --short-id SHORT_ID --pqv VERIFY_KEY

# 可选的受保护文件输入。
pig build proxy client --from ./client.uri

# 复用运行中 Linux 服务端的凭据,不改变它的部署。
pig build proxy server --host proxy.example.com --export-only --export -

# 使用默认客户端监听 127.0.0.1:12345 做无变更预览。
pig build proxy client --from ./client.uri --plan

# 显式使用已检查的本地客户端监听地址。
pig build proxy client --from ./client.uri --listen 127.0.0.1:8888

# 位于已配置可信入口后的 Xray 后端,默认监听 127.0.0.1:9443。
pig build proxy server --host proxy.example.com --target www.example.net:443 --proxy-protocol --export ./client.uri

服务端输入与默认值。 必须指定对外公布的 --host 与 REALITY --target。 公网 --port 默认 443,直连模式默认在所有 IPv4 接口监听该端口。 首次设置指定 --proxy-protocol 时,改为默认监听 127.0.0.1:9443。 显式 --listen 改变绑定地址,不改变公布的公网端口。重复设置未指定 --listen 时,保留已有 受支持配置的监听地址,不使用首次设置的默认值替换它。首次设置时,除非指定 --sni,否则从 target 主机名推导 SNI;重复设置保留已有 SNI,不重新推导替代值。应用配置前检查 target 的 TLS 兼容性, 不静默选择无关的伪装站点。

生成 UUID、X25519 密钥对、随机八字节 short ID,以及独立的 ML-DSA-65 seed 与验证密钥。 重复设置复用已有 PIG 管理的材料,普通重跑不轮换凭据。轮换与多用户管理需要后续明确契约。 使用 warning 日志、关闭访问日志、decryption: none、Vision flow,并明确阻断私网目的地址。 地理数据环境变量指向软件包提供的资源目录。

服务端幂等。 用相同输入重复设置,必须让已有客户端继续可用,无须修改客户端配置。 保留 UUID、X25519 私钥及对应客户端认证材料、short ID、ML-DSA seed 与验证密钥、SNI,以及 协议默认值。公布的 host 与公网端口相同时,导出同一条规范 URI。只在首次创建服务端配置时 生成凭据,不能因为再次执行设置而重新生成。

已有受管理配置和服务设置满足请求,且服务已运行并启用时,只执行检查,不重写文件或重启服务。 若仅服务停止或自动启动被关闭,则使用原有凭据恢复请求的服务状态。已有认证材料缺失、损坏或 存在歧义时必须报错,不能通过静默重新生成凭据来修复。新输入与已有认证或 SNI 契约冲突时, 普通设置拒绝执行;此类变更需要明确的迁移或轮换契约,不能作为普通重跑处理。

复用已有服务端。 server --export-only --host HOST --export DESTINATION 读取现有软件包 服务端配置,使用当前 UUID、SNI、short ID,以及派生的客户端验证材料,导出连接 URI。 公布的公网端口仍默认 443,不能从回环后端端口推断。要求存在唯一、无歧义且受支持的 VLESS/REALITY 入站、客户端账户、SNI 与 short ID;遇到歧义或错误材料时拒绝,不任意选择条目。 此模式不安装、不重写服务端或服务配置、不重启、不启用服务、不轮换凭据;显式请求的文件导出 是唯一持久写入。在进程内派生验证材料,避免将已有私钥或 seed 放入子进程参数。 这个分支执行只读查询与显式凭据导出;共享的 server 命令保留保守的 action 注解。

客户端输入与默认值。 主要用法是直接传入一个带引号的 vless:// 位置参数。 同时支持参数模式:--server host:port、--id、--sni、--public-key、--short-id; 服务端使用 ML-DSA 验证时,通过 --pqv 提供验证密钥。参数模式指定连接字段,REALITY、RAW、 Vision 与 Chrome 采用下述默认值。所有输入形式进入同一份经过验证的连接模型与配置生成器。 保留 --from FILE 与 --from -,作为可选的文件与标准输入方式。拒绝混用不同连接输入, 不静默用 flags 覆盖 URI 字段;--listen 等本地选项可用于所有输入方式。

client.uri 是普通 UTF-8 文本文件,内容只有一条标准 vless:// URI,可带结尾换行; 文件名可以任意指定,它不是新的 PIG 配置格式。 只支持参考组合 REALITY + Vision + TCP/RAW。URI 中的 type=tcp 映射为 JSON network: raw,pbk 映射为 password,sid 映射为 shortId,pqv 映射为 mldsa65Verify。保留 ML-DSA 验证字段,不静默丢弃。拒绝重复参数,以及会改变连接语义的 不支持参数。映射遵循上游分享链接规范。

首次设置使用 socks 入站,默认绑定 127.0.0.1:12345,沿用现有 PIG 客户端默认地址。 可通过 --listen 127.0.0.1:8888 显式使用已检查的本地客户端地址。重复设置未指定 --listen 时, 保留已有受管理客户端的监听地址。同一端口提供 HTTP,启用 UDP,关闭 multiplexing。 出站使用 encryption: none、Vision flow、Chrome 指纹与 spiderX: /。 上游 Socks 参考明确说明支持 HTTP。 分别验证 HTTP 与 SOCKS,不能仅以 TCP 端口开启认定代理工作。

命令行字段与现有参考配置的对应关系如下。客户端路径相对于 VLESS 出站,服务端路径相对于 VLESS 入站。

命令行字段 客户端配置 服务端配置或导出
服务端 --host、--port;客户端 --server settings.vnext[0].address 与 .port URI 对外连接地址,不一定是绑定地址
各角色的 --listen 本地入站的 listen 与 port VLESS 入站的 listen 与 port
客户端 --id settings.vnext[0].users[0].id 匹配 settings.clients[0].id
--sni streamSettings.realitySettings.serverName 属于 streamSettings.realitySettings.serverNames
客户端 --public-key streamSettings.realitySettings.password 从 streamSettings.realitySettings.privateKey 派生
客户端 --short-id streamSettings.realitySettings.shortId 属于 streamSettings.realitySettings.shortIds
客户端 --pqv streamSettings.realitySettings.mldsa65Verify 从 streamSettings.realitySettings.mldsa65Seed 派生
服务端 --target 没有直接对应字段,SNI 需兼容 streamSettings.realitySettings.target
服务端 --proxy-protocol 无对应字段 streamSettings.rawSettings.acceptProxyProtocol: true

参考服务端保持 realitySettings.xver: 0:接收 Nginx 的 PROXY 头,与向 REALITY target 发送 PROXY 头是不同设置。模板默认值保留参考配对的 flow、传输安全、日志、关闭 multiplexing、 服务端私网目的地址阻断,以及客户端指纹。公网连接地址、绑定地址与 target 各自承担不同角色。

平台与服务所有权。 Linux 使用已经配置的软件仓库,以及上述软件包账户、配置路径与 unit。 macOS 客户端使用 Homebrew Xray、权限为 0600 的用户配置 ~/.config/xray/pig-proxy.json, 以及专用用户 LaunchAgent com.pigsty.xray-proxy;不接管其它 Xray daemon 或 Homebrew 服务。 Linux 设置需要 root 与运行中的 systemd;macOS 客户端使用普通用户,并需要已有 Homebrew。macOS 服务端不属于本次变更范围。

新角色设置明确启动服务并启用自动启动;仅安装时不启动或启用服务。Linux 下,PIG 管理有边界的 pig-proxy.conf systemd drop-in,用于资源目录和 capabilities。直接绑定特权端口时, 先清空 bounding 与 ambient 集合,再按需授予 CAP_NET_BIND_SERVICE,避免 systemd 将正向设置 与软件包 unit 的权限叠加;回环地址上的非特权端口后端 不需要该能力。不能依赖宽松的主机 sysctl,也不能为了监听 443 改为以 root 运行 Xray。

应用与恢复。 变更前完成参数解析,检查路径、端口所有权、服务冲突与已有配置。 通过完整的受支持配置形态识别 PIG 管理的配置,不能只凭一个入站 tag 判断。 替换不同或不支持的客户端配置需要 --replace --yes。不支持的服务端配置,以及使用其他账户、显式指定其他服务组或加载额外配置的服务 unit 会被拒绝。 --plan 支持预览,不安装、不生成凭据、不写文件、不重启服务。

通过 Go 序列化生成 JSON。暂存受保护的候选配置,以实际服务身份执行 Xray 校验,再原子应用 配置和服务变更。判断是否需要应用变更时,同时检查内容、所有权与权限。 macOS 将持久禁用状态与已加载状态分别检查,启动时启用自己的 LaunchAgent,失败时恢复两种状态。 保存原始内容、所有权、权限、服务启用状态与运行状态,用于有边界的回滚。 服务健康与连通性检查通过后,才交付 Shell 别名或连接导出。客户端要求 HTTP 与 SOCKS 访问 https://www.google.com/generate_204 均返回 HTTP 204,因此服务端外网访问该端点是验收条件。 应用失败返回非零,并说明哪些 恢复步骤成功;安装过的软件包可能保留。

不删除或自动停止 V2Ray。端口冲突在预检阶段停止,并给出迁移指引;保留原 V2Ray 配置供操作者 控制回滚。保留 po、px、pck 便利命令,同时覆盖构建工具需要的小写代理环境变量。 当前 Shell 激活仍需要 source 生成的 Shell 文件并执行 po;子进程不能修改父 Shell 的环境。

秘密与导出。 --export FILE 将显式请求的连接导出写入权限为 0600 的文件, 不包含服务端私钥或 ML-DSA seed。--export - 明确将一条完整 URI 交付到标准输出, 非秘密的初始化诊断写入标准错误。凭据导出模式要求文本输出,与 JSON/YAML 同时指定时在变更前 拒绝,不把 URI 放进结构化结果。普通初始化输出仍脱敏。允许命令行输入,同时明确调用者的 Shell 历史或进程检查可能保留这些凭据;需要避免留存时仍可选择文件或标准输入。

将整个 URI 视为凭据,包括 UUID 与认证字段。默认日志、计划、JSON/YAML 结果与失败详情只包含 脱敏摘要及导出路径。密钥材料在进程内生成和派生。校验器输出必须私下捕获:上游配置错误 可能直接包含错误的秘密值,不能将通用子进程输出捕获视为安全凭据边界。重复导出到已有受保护文件时,若内容是 同一条规范 URI,则成功返回而不重写;内容不同时报告冲突,不能静默覆盖或在诊断中打印原内容。

入口与验证边界。 一键服务端设置默认使用直连模式。显式 --proxy-protocol 后端模式 要求绑定回环地址,并已有可信前端。本次不重写 Nginx 或防火墙、云安全组规则。 公网端口已被占用时明确失败,不停止端口拥有者。后端就绪不能证明公网入口正常;服务端设置 分别报告本机检查,并将外部可达性保持为待验证,直到客户端握手与 HTTPS 请求实际成功。

生成等价的 Xray 配置应覆盖参考配对的全部协议与认证字段。复现完整参考部署还需要 Nginx 的 SNI map、接收 PROXY 头的网站后端,以及操作系统特定的服务注册。当前实现管理 Xray 及其服务设置, 不宣称可从一个服务端 URI 还原这套 Nginx 组合。配置等价不要求逐字节保留 tag、字段顺序或安装专属名称。

2026-10-16 的兼容修订接受旧渲染器生成、配置与二进制路径匹配的完整无 marker macOS plist。 管理注释本身不足以证明归属。修改过或外来的文件需要显式替换;Linux 识别也限制为完整生成的 两种 capability 配置。一次性迁移注释后,相同执行必须保留运行中的服务。

无 marker 测试样例来自实际执行旧渲染函数。其源文件与公开可访问的 v1.9.0 源码 9eb54888 逐字节相同。这证明旧源码格式,不代表验证了某个已发布二进制。

影响

用户通过一条标准 URI 衔接两次初始化操作,或直接指定客户端参数,配套参数自动生成, 无须手改 JSON,也无须创建连接文件。 新客户端与历史 VMess 形式首次设置都默认使用 127.0.0.1:12345。直连服务端默认在所有 IPv4 接口监听公网端口,PROXY protocol 后端默认监听 127.0.0.1:9443。重复设置未指定 --listen 时 保留已有监听地址。配置与服务管理明确区分角色、操作系统、所有权和外部入口。

实现保留在 cmd/build.go 与 cli/build 下的聚焦文件中,复用现有计划、输出、确认、特权写入 与日志辅助函数。

验证与演进

v1.10.0 已提交修订的固定源码与回归测试证据包括: 完整旧服务定义识别。这些提交不构成版本发布证据。 下列 v1.9.0 运行验证针对原始实现。

实现提交为 d090b7c, 5d8660c 补齐文件归属与服务状态恢复。测试覆盖角色语法、输入形式等价、脱敏、监听默认值、凭据复用、 导出冲突、受保护文件、capabilities 选择与执行计划。完整 Go 测试、vet、静态分析、死代码与 复杂度检查,以及命令/build 包重复竞态测试均在本地通过。

运行测试使用 Xray 26.3.27:

环境 已验证行为
全新 Debian 13 ARM64 客户端 软件包安装;以 xray 身份运行;HTTP/SOCKS 健康检查;重复设置保持配置和 PID;错误 UUID 后回滚
全新 Debian 服务端 直连特权端口;0640 配置与 0600 导出;重复设置保持凭据、文件与 PID;导出失败后回滚
macOS 已有 Homebrew Xray 独立 LaunchAgent;HTTP/SOCKS 连通性;无变更重跑;失败后恢复配置与持久禁用状态
已有参考服务端 只读导出与客户端测试期间,配置哈希和 PID 保持不变

新服务端导出的 URI 成功建立 REALITY/Vision 连接,并使用 ML-DSA 验证。 HTTP 与 SOCKS 访问可达的 TLS 网站均返回 HTTP 200。该服务器的网络无法访问 Google 健康检查端点, 因此这组配对的完整客户端设置失败并回滚。完整客户端设置在连接已有参考服务端时通过, 使用的是该服务端已有的 Nginx/PROXY 入口。

运行测试未覆盖 RPM 安装、全新 Homebrew 安装、UDP 转发、其他 Xray 版本或新建 PROXY protocol 前端。

当前状态

已随 v1.9.0 发布。 Nginx 入口自动化与凭据轮换留待后续设计。

14 - 把 Pigsty 控制节点引导设计成可恢复事务

为什么 pig sty boot 在提权前解析来源、分离硬失败与收尾告警,并在软件源准备失败时恢复仓库定义。

决策日期: 2026-08-14
状态: 已实现并随 pig v1.8.0 发布。
当前参考: pig sty boot
范围: 准备 Pigsty 控制节点及其软件来源,不包括部署数据库集群。

决策

pig sty boot 应当是一套原生、能够处理失败的控制节点引导工作流。 它在提权前解析显式来源,准备在线或离线仓库,只安装必要的控制节点软件包,证明 Ansible 真正可用, 并执行有边界的收尾检查。

仓库替换具有事务语义:软件包准备失败时恢复原有仓库定义。 可选便利功能可以告警,但无效的显式输入、软件包失败和最终不可用的 Ansible 环境属于硬失败。

背景

旧命令把工作委托给 Shell bootstrap 脚本,来源选择、下载、sudo 边界、仓库回滚、错误分类与结构化自动化都难以观察。 仅仅存在 ansible-playbook 二进制也可能产生假就绪,因为它使用的 Python 环境可能缺少必要模块。

离线安装还带来另一种歧义:控制节点已经可用时,仍可能需要为后续节点准备本地仓库。

考虑过的方案

  • 继续调用旧脚本。 PIG 无法拥有事务,也无法可靠解释部分失败。
  • 要求整个命令一开始就以 root 运行。 显式下载与来源校验不需要权限,应在一次有边界的提权前完成。
  • 把 Ansible 二进制存在视为就绪。 可执行文件使用的 Python 环境可能缺少必要模块。
  • Ansible 已就绪时跳过仓库工作。 用户明确指定离线来源时,仍需要准备该仓库。
  • 把所有收尾检查设为硬失败。 locale 便利、本机 SSH 修复或目录初始化失败,不一定让控制节点不可用。

契约

  • 显式本地路径和 URL 必须校验,失败时不能悄悄回退到在线模式;
  • 自动发现的离线来源必须通过所有者与权限检查;
  • 已提交的本地仓库可以优先于选定的软件包;
  • 下载与受限归档解压使用原生有边界实现;
  • 离线包必须包含 pigsty/repo_complete 完成标记;附加根目录先预检并在 pigsty 前 rename, 冲突与中断残留都会使操作停止,由用户检查并清理;
  • 来源解析完成后只进行一次提权,并可禁止或要求非交互提权;
  • 软件包准备失败时,被替换的仓库定义可以恢复;
  • 就绪检查实际执行 Ansible,并验证它会使用的 Python 模块;
  • 结果区分 ready、offline、online 与 existing 模式;
  • 硬失败和收尾告警使用不同结构化字段;
  • bootstrap 不声称 Pigsty 部署已经成功。

影响

原生工作流比脚本启动器更大,但副作用与回滚状态可见。 它能够在已经可用的控制节点上继续准备离线内容,也能为自动化提供稳定结果而不隐藏可选问题。

控制节点准备好后,生成 Inventory、部署所选服务,再检查服务状态。

验证与演进

原生实现落地于 222616e, 并在 74e084e 中继续收敛。 测试覆盖来源优先级、权限检查、受限解压、sudo 自重启、仓库回滚、locale 修复、Ansible/Python 就绪、 本机 SSH、初始化、告警分类与结构化结果。v1.8.0 发布页记录了交付状态。

离线包改进提交 8fa3abb 保留多个通过校验的顶层仓库,继续使用 repo_complete 完成标记。 该改进已随 v1.8.1 发布。

当前状态

pig sty boot 准备控制节点。配置 Inventory 后,单独执行部署。 来源模式、环境控制与后续步骤见 pig sty 文档。

15 - 自动安装 Pigsty 仓库公钥

配置 Pigsty 仓库时准备内嵌公钥,明确默认失败处理与显式密钥要求。

决策日期: 2026-10-04
状态: Released(已发布),随 v1.9.0 交付。
当前参考: pig repo
范围: 配置仓库时安装已有的内嵌 Pigsty 公钥。

决策

当所选模块包含当前平台可用的 pigsty-infra 或 pigsty-pgsql 仓库时,先准备内嵌 Pigsty 公钥,再修改仓库定义。该逻辑放在共享配置流程中,使 repo add、repo set 以及复用此流程的调用方保持一致。已有公钥文件直接复用,自动安装尽最大努力; 所选仓库元数据显式引用签名密钥时,安装失败才必须终止。

背景

基线实现 只在调用方指定 GPGCheck 时安装公钥,原生 sty boot 使用了这一选项。 因此,普通 repo add/set 没有安装 PIG 已经内嵌的公钥。

两个 Pigsty 仓库都使用此公钥,而它们分布在 pigsty、infra、pgsql 和默认的 all 选择中。只检查命令参数是否包含字面量 pigsty 会遗漏正常用法。

APT 不会自动发现 /etc/apt/keyrings 中的文件,仓库必须通过 signed-by 引用准备好的 公钥,否则即使文件写入成功,刷新缓存时仍会出现 NO_PUBKEY 警告。

降级时删除 signed-by,可能与保留的同源 APT 定义冲突,因此成功和失败时都保持默认引用一致。 显式元数据指定的是它实际需要的密钥,准备一个无关的默认文件不能满足要求。

备选方案

  • 运行时下载默认公钥。 现有内嵌发布输入已经提供公钥,支持离线使用,无须增加网络或外部工具依赖。
  • 每次仓库操作都安装公钥。 无关仓库不应触发 Pigsty 公钥写入,应先解析模块成员与平台可用性。
  • 自动安装公钥失败就阻止仓库操作。 可选的公钥准备不应阻止已有兼容模式工作,因此拒绝这种处理。 显式签名密钥元数据仍是严格边界。
  • 同时开启所有签名校验。 发布者身份、RPM 包签名和 APT 元数据认证是不同的契约。 自动安装公钥不能证明所有软件包或镜像都具备对应签名。

契约

  • 安装前校验请求的模块。被拒绝的仓库替换请求不会安装公钥或移动仓库文件。
  • 检查展开后模块中的两个 Pigsty 仓库标识符,包括自定义模块;不凭 URL 主机名选择签名身份。
  • EL 写入 /etc/pki/rpm-gpg/RPM-GPG-KEY-pigsty,Debian/Ubuntu 写入 /etc/apt/keyrings/pigsty.asc;仅在需要安装时写入内嵌公钥,权限为 0644。
  • 先检查公钥普通文件是否存在,包括能解析到普通文件的符号链接;存在时复用,不修改内容或权限。 存在性检查失败时仍尝试安装。
  • 父目录缺失时使用已有 sudo 回退机制创建,并通过原子文件写入逻辑安装。 检查目标时遇到权限不足,仍应进入提权安装并再次检查目标。目标被目录或悬空符号链接占用属于安装错误。
  • 未显式指定密钥时,安装失败只告警并继续;仅所选 Pigsty 定义降级为 APT trusted=yes, 或 RPM gpgcheck=0 与 repo_gpgcheck=0。成功和失败时均补齐默认的 gpgkey 或 signed-by 引用,不通过改写已保留的仓库文件实现降级。
  • 显式密钥准备针对实际引用。APT 的 signed-by 接受已有普通密钥文件的绝对路径,多个路径以 逗号分隔;显式引用默认路径时可安装内嵌公钥。EL 按需准备显式引用的默认公钥文件,再把 gpgkey 中的路径或不含变量的 URL 交给原生 rpm --import。
  • 显式密钥准备失败会在备份、写入仓库、刷新缓存之前终止。保留其引用,绝不降级该定义。 有效自定义密钥不依赖默认路径;其他所选仓库的默认密钥失败只使对应的默认定义降级。
  • 普通操作成功准备公钥后保留签名校验设置。sty boot 在公钥准备成功时请求启用校验, 默认公钥失败时采用同样的降级规则。
  • 降级警告同时写入 stderr 和 repo add/set 的 data.warnings,sty boot 也保留在自身告警中。 默认安装不导入 RPM 数据库,EL 显式密钥配置会导入;两种情况都不修改 APT 全局信任库。
  • 仓库回滚恢复仓库定义,已经安装或导入的公钥保留。

影响

添加 Pigsty 仓库时会一并尝试准备公钥文件,离线主机也适用。默认公钥失败不再阻止仓库配置。 降级会关闭这些 Pigsty 定义的签名校验,并明确报告。存在性检查成功后保留管理员已有文件, 不校验其内容;第三方仓库的信任策略保持不变。 密钥不可用时,APT 可能告警并沿用此前认证过的索引,因此仓库配置成功不能证明每个索引都刚刚下载。 当前默认行为和路径以仓库参考页为准。

验证与演进

自动公钥准备实现 与仓库回归测试 已记录在源代码提交 56f7353 中。本地回归测试覆盖 EL、Debian、Ubuntu 及两种支持的架构,并检查默认选择、组合模块、已有公钥复用、存在性检查被拒、自定义模块、 不可用仓库、默认公钥降级,以及显式密钥安装失败时不修改仓库。已有仓库替换测试继续验证回滚行为。

本地 EL9、EL10、Debian 12 和 Ubuntu 24 ARM64 虚拟机中的实际 CLI 测试使用独立挂载命名空间,验证普通用户通过 sudo 创建缺失的密钥目录、内嵌公钥字节与权限一致、重复执行、组合模块、可解析的结构化输出, 以及默认公钥失败时告警并继续、显式密钥失败时在替换仓库之前停止。测试使用真实 DNF/APT, 使用隔离缓存,并查询生成索引中的可用包。APT 还验证成功安装后的密钥引用 消除了 NO_PUBKEY 警告,以及显式配置 signed-by 与 trusted=no 时能完成元数据认证。 这些检查不安装软件包,也不验证 RPM 包签名。虚拟机原有仓库定义、公钥与缓存保持不变。

后续回归补充了保留旧 APT 源与已认证缓存、自定义密钥缺失时阻止添加和替换、默认路径不可用时 有效自定义密钥仍能工作,以及显式与默认密钥混合配置的场景。权限测试禁止普通用户遍历密钥目录, 验证提权安装和隐藏符号链接拒绝行为。RPM 导入测试使用虚拟机 RPM 数据库的隔离副本。

当前状态

已随 v1.9.0 发布。 用法与平台要求见文首链接的当前参考文档。

16 - 官网与 CLI 统一按目录条目计数

官网、扩展列表、可用性摘要和目录刷新结果统一统计全部目录记录。

决策日期: 2026-10-16
状态: Implemented(已实现),纳入 v1.10.0 候选版本,尚未发布。
当前参考: pig ext 目录计数
范围: 目录总数与默认列表成员;包安装和 SQL 启用方式仍由各条目定义。

决策

统一用目录记录数表示扩展总数,包括已打包的 SQL 工具与保留的生命周期记录。 CLI 根据实际加载或下载的目录计算总数。

背景

目录同时服务于软件包发现和 PostgreSQL 扩展发现。已打包的 SQL 工具即使没有控制文件, 不支持 CREATE EXTENSION,也仍然有用。将它从默认列表和总数中排除,会让 CLI 与 官网、目录文件的统计不一致,即使按名称搜索仍能找到它。

考虑过的方案

  • 只统计被分类为 PostgreSQL 扩展的记录。 不采用,因为同一目录会在 CLI 与官网产生不同总数。
  • 为每种条目类型新增独立的公开计数。 当前列表契约不需要这些额外字段。
  • 在 CLI 中写死对外公布的总数。 不采用,因为下载的目录可能与内嵌目录不同。

契约

  • 无筛选的默认列表包含全部目录记录,包括 SQL 工具和已移除记录。
  • 文本行数与 JSON/YAML 的 data.count 等于实际返回的记录数。
  • 搜索统计匹配条目;--pkg 继续统计主导包记录。
  • 全局可用性文本摘要使用完整目录总数。
  • 目录刷新结果的 data.extension_count 和消息使用实际下载的记录数。
  • 官网总数跟随内嵌目录;更新后的下载目录可以有不同总数。
  • 计入总数不会改变条目的 DDL 要求、生命周期状态或平台可用性。

影响

SQL 工具同时出现在默认列表和按名称搜索的结果中。输出字段的名称和类型保持稳定。 调用方应将扩展总数理解为目录覆盖范围;它不表示某个数据库已启用的扩展数, 也不表示某台主机可以安装的扩展数。

验证

v1.10.0 已提交修订的固定源码与回归测试证据包括: 目录条目计数与可用性。这些提交不构成版本发布证据。

此前的分类规则保留在 v1.9.0 目录源码 中。验收检查将解析得到的记录数与默认列表、可用性摘要、目录刷新结果逐一比较, 覆盖已打包的 SQL 工具和已移除记录,并确认搜索和包计数仍对应各自返回的行。

状态

此决策于 2026-10-16 接受,已实现并包含回归测试。v1.10.0 候选版本内嵌 603 条记录,尚未发布。 计数契约见当前参考,版本边界见发布注记。