跳转到主要内容

资料包格式

.crib 文件里有什么、怎样签名和校验、可信根与密钥策略,以及发布目录的布局、不可变规则和 HTTP 缓存要求。
说明

现在没有公开的资料包,也没有正式签名密钥。发布目录规划在 https://repo.pigsty.io/doc/,还没有上传。本页描述开发构建和构建工具 crib-pack 实现的格式。

文件

资料包是一个 ZIP 文件(支持 ZIP64,条目为 stored 或 DEFLATE),条目按名称排序,时间戳固定。2026-11-06 起新发布的资料包以 .crib 结尾;之前签发的目录和归档使用 .pgdocpack,这些已签名的路径继续有效。版本目录里的归档路径只接受这两种结尾,.CRIB、.crib.zip 等都会被拒绝。

App 还没有注册 .crib 文件类型,双击不能导入;请用资料库的“导入资料包…”。

一个手册资料包的内容:

pg/18.6-r4.crib

  • manifest.json清单:身份、版本、语言、文件列表与每个文件的哈希
  • manifest.sig对 manifest.json 原始字节的 Ed25519 签名
  • sources.json来源:上游修订、版次、修复记录和处理说明
  • content.sqlite文档、章节、精确名称键、双语对应、链接和搜索词元
  • documents/
    • en/英文 HTML 与资源
    • zh-Hans/简体中文 HTML 与资源
  • licenses/许可文本,按语言分目录

Wiki 资料包的页面在 documents/<语言>/wiki/<集合>/ 下,另外带有原始来源记录和许可说明 licenses/center-sources.json。

清单

format_version
资料包格式,现在是 1
schema_version
content.sqlite 的结构版本,现在是 1
analyzer_id
分词器标识 pgdash-han2-v1;旧名称属于格式身份,不随产品改名
pack_id
资料包身份,如 postgresql/manual/18、postgresql/wiki
project_id、branch、content_version、channel
项目、版本线、内容版本、发布渠道
pack_revision
修订号,同一 pack_id 跨内容版本单调递增
languages
["en", "zh-Hans"]
min_reader_version
能读取它的最低 Crib 版本
source_manifest_sha256
sources.json 的哈希
files
除清单和签名外每个文件的 path、bytes、sha256
licenses
许可文件路径
trust
签名类别;开发构建中是 development

清单之外出现未声明的文件,或任何文件与清单哈希不符,资料包都会被拒绝。Crib 用 manifest.json 原始字节的 SHA-256 标识一个已安装的资料包,链接里的 manifest 参数就是这个值。

签名与可信根

manifest.sig 是 {"key_id": "…", "signature": "<base64>"},签名对象是 manifest.json 的原始字节。目录 catalog.json 用同样的 Ed25519 签名。

公钥只来自 App 自带的 trust.json。资料包或服务器里的密钥都不会被信任。

{
  "development": false,
  "keys": { "<key_id>": "<base64 公钥>" },
  "key_policies": {
    "<key_id>": { "roles": ["pack", "catalog"], "not_after": "2027-12-31T00:00:00Z" }
  }
}
  • key_policies 可选。roles 取 pack、seed、catalog 的子集;not_after 必须是 YYYY-MM-DDTHH:MM:SSZ。没有列出的密钥可签所有用途、永不过期。
  • 未知字段、空的 roles、不规范的日期、指向不存在密钥的策略都会让整个可信根被拒绝。
  • 密钥过期只阻止获取(刷新目录、下载、导入)和发布端签名,已安装的内容照常可用。
  • 从可信根删除密钥等于吊销。要退役一把密钥,先设 not_after。

开发签名的内容只在两种情况下被接受:构建在 Info.plist 中声明 CribDevelopmentContent=true,或测试环境设置CRIB_ALLOW_DEVELOPMENT_CONTENT=1。这时资料库显示“非正式发布”。

导入与下载时的检查

解包之前,Crib 先完整检查整个 ZIP,拒绝符号链接、特殊文件、加密条目、分卷、路径穿越、大小写或 Unicode 规范化后重名的路径、多余的尾部字节。

上限值
条目数65,000
单个文件8 GiB
解包后总大小16 GiB
压缩文件20 GiB
压缩比1000:1

然后核对签名、每个文件的哈希、数据库结构和引用。同一 pack_id 同一修订号而内容不同的资料包会被拒绝。从目录下载时还要核对归档长度和 SHA-256、清单哈希和解包后大小,它们必须与目录记录一致。

发布目录

https://repo.pigsty.io/doc/(规划中)

  • catalog.json签名目录:别名、版本与状态、每个归档的路径、大小和哈希
  • pg/
    • 18.6-r4.crib
    • 17.11-r4.crib
    • 9.6.24-r4.crib
    • 20devel-r4.crib
  • pgwiki/
    • r5.crib

完整目录有 31 个手册归档和 1 个 Wiki 归档。文件名是内容版本加修订号。别名只写在 catalog.json 里,不复制文件,也不建符号链接。

catalog.json 是一个签名信封,解码后的载荷包含目录身份、修订号、签发和过期时间、默认别名、别名表和版本表:

{"format":"crib-signed-catalog-1","key_id":"…","payload":"<base64>","signature":"<base64>"}
{
  "format_version": 3,
  "catalog_id": "crib-docs",
  "revision": 2026102901,
  "default_alias": "pg",
  "aliases": {"pg": "pg18", "pg18": "[email protected]"},
  "releases": {
    "[email protected]": [{
      "pack_id": "postgresql/manual/18",
      "content_version": "18.6",
      "lifecycle": "default",
      "pack_revision": 4,
      "languages": ["en", "zh-Hans"],
      "archive_path": "pg/18.6-r4.crib",
      "manifest_sha256": "…",
      "archive_sha256": "…"
    }]
  }
}

这是节选,正式载荷还有 generated_at、expires_at、大小、结构版本等字段。版本状态 lifecycle 的含义见版本与别名。

客户端只使用目录给出的归档路径:一级目录加一个文件名,不接受绝对地址、查询串、片段、百分号转义、反斜杠和 ..,下载走与目录同源的 HTTPS。

不可变规则

  • 同一个 URL 的字节永远不变。内容有任何更正,都发新的内容版本或更高的修订号。
  • 修订号按 pack_id 单调递增,换内容版本也不重置:18.6-r4 之后发布 18.7,修订号至少是 r5。
  • 先上传并核对所有新归档,最后再替换 catalog.json。
  • 目录修订号只增不减。crib-pack distribute 的 --previous-catalog 要求新修订号更大;--validity 设定目录有效期,默认 720 小时,范围 24 小时到 400 天。

HTTP 缓存

这些是发布端的要求,还没有在真实服务器上配置和测试。

对象响应头
catalog.jsonCache-Control: no-cache
带版本和修订号的归档Cache-Control: public, max-age=31536000, immutable,Content-Length,强 ETag,支持 Range,不做内容转换

客户端续传时发送 Range 和 If-Range,规则见断点续传。