ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

一份600+条目的安全审计目录靠什么不乱?拆解 Trail of Bits publications 仓库

一份600+条目的安全审计目录靠什么不乱?拆解 Trail of Bits publications 仓库

一份600+条目的安全审计目录靠什么不乱?拆解 Trail of Bits publications 仓库

【免费下载链接】publicationsPublications from Trail of Bits项目地址: https://gitcode.com/GitHub_Trending/pu/publications

1300 行目录的头疼之处:每一条约束都是人肉维护的

你有没有手工维护过一份 1000 多行的 Markdown 目录?最难的部分从来不是写新条目,而是旧条目的整齐程度:日期列里 "Jul 2024" 和 "July 2024" 并存,产品名一会儿带 Labs 一会儿不带,有的表格行 6 个竖线,有的只有 5 个。

Trail of Bits 的 publications 仓库就是这种规模的东西:公司十余年的公开产出——30+ 篇学术论文、几百份审计报告、上百场会议演讲——全部以 PDF 加一份 1300 多行的README.md表格存着。没有数据库,没有站点构建,没有 CMS,"网站"就是仓库宿主直接渲染出来的 README。

有意思的不是内容,而是它怎么维护。约定分布在三个地方:顶层目录结构、每个演讲目录里的 frontmatter 元数据、以及一份写给 AI 协作者看的规则手册CLAUDE.md。下面按一次真实的"新增一条报告"操作,把这条链路走一遍。

一条新条目的完整路径:从文件名到表格行

第 1 步:文件先上对"货架"——目录即分类

先决定文件放哪。顶层目录就是分类,而且分类维度是"内容类型"而不是"主题":

papers/ 学术论文 reviews/ 审计报告 presentations/ 会议演讲,每场一个子目录 case-studies/ 客户案例 public-comments/ 给监管机构的公开评论 datasets/ 结构化数据集

为什么按类型分?因为每种类型在根 README 里对应不同的表格格式和命名习惯。按主题(比如blockchain/)分的话,一份报告横跨两个主题时就无处安放。

reviews/里的文件名一眼就能看出约定:

2024-07-uniswap-v4-core-securityreview.pdf 2023-12-curl-http3-securityreview.pdf 2025-03-scroll-euclidphase2-loa.pdf

日期前缀是稳定排序键:对 reviews/ 目录按文件名排序,等价于按时间排序。类型后缀(securityreview/fixreview/threatmodel/loa)承担了"文档类型"这个字段——它进了文件名,而不是表格列。这个决定有点反直觉,后面讲取舍时再展开。

第 2 步:演讲是自描述单元——frontmatter 元数据卡

演讲比 PDF 重:幻灯片、speaker notes、录像,还可能有多场会议的不同版本。约定于是变成"每场演讲一个子目录,目录里放一份README.md当元数据卡",格式在 CLAUDE.md 里有硬性规定。翻到一个真实样本:

--- title: "Swimming with the kubectl fish: The why, how, and what of the CNCF Kubernetes Assessment" date: 2019-09-12 authors: - Stefan Edwards conference: - Global AppSec DC 2019 resources: - label: Slides path: "OWASPGlobalDC.pdf" - label: Notes path: "OWASPGlobalDC.md" ---

注意resources的两种取值:path指向本地文件,url指向外部链接(本例恰好都是本地)。关键收益是元数据和产物同目录——要迁移或改名一整场演讲,git mv一次,元数据跟着走,不会碰任何别的文件。这就是"元数据贴在工件旁"相对中央索引表的最大好处:改动只触及一个目录,几乎不产生合并冲突。

目录命名同样死板:只放演讲标题,禁止带会议名和地点。"How to Fuzz Like a Pro" 在三个会场讲过,目录只有一个,三个版本的 PDF 并排放里面;根 README 允许表格里出现多行,指向同一个目录。

第 3 步:回到根表格——6 个竖线和一套 emoji 图例 🔖

最后回到 README.md 填一行。报告表格固定 5 列,竖线必须恰好 6 个。看一条真实的行:

| [Uniswap v4 Core](https://link.gitcode.com/i/8e7e0ae2216dae38c01701a6208dd8b6) |

中间那个| |是空的 Announcement 单元格,规则明确写了:空单元格补一个单空格,| |(两个空格)不行。

巧妙在 Report 列:emoji 就是文档类型。README 末尾的图例定义了 schema——📄 正式报告、✅ 修复复查、🔖 证明信(LoA)、📛 威胁建模、📰 白皮书、📖 案例。一个产品同时有正式报告和 LoA 时,两个 emoji 无空格连写在同一行:📄✅🔖。要是"文档类型"做成独立文本列,每行多出来 5~10 个字符,整张表直接开始换行。

行序是"新条目在上"——靠约定人工维持,没有任何代码参与。

第 4 步:CLAUDE.md——lint 规则是写给 AI 的

最后一个零件是那份 CLAUDE.md,140 来行,开头自称 "Guide for Claude when working with this repository",但它的实际身份是这个仓库的 lint 规则。摘几条:

### Date Formatting - Use 3-letter abbreviations for all month names to save space in the layout: - Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec - Do NOT use: January, February, ... #### Table Column Structure - Every row must have exactly 6 pipe characters (matching the header row) - Do not leave rows truncated with missing columns — pad with empty cells (`| |`)

里面有连传统 linter 都写不出来的判断型规则:Product 列只放产品名,"Offchain Labs X" 缩写成 "Offchain X",但会歧义时保留 "Labs";改格式时 "NEVER modify URLs or file paths"。每条规则一句话,都是一个可检查的断言——这正是它刻意用自然语言写的原因:主要编辑者已经是 AI agent 了,规则得让它能直接执行。

![Trail of Bits AI Maturity Matrix 各角色 AI 使用成熟度分级](https://raw.gitcode.com/GitHub_Trending/pu/publications/raw/89940dfbec07ad03b0989e67d78e84250765366b/presentations/How we made Trail of Bits AI-Native (so far)/ai_maturity_matrix.png?utm_source=gitcode_repo_files)

「How we made Trail of Bits AI-Native」演讲中的 AI Maturity Matrix:仓库的 AI 优先维护方式不是临时起意,是公司级成熟度计划的一部分。

约定里三个"反直觉"的选择,以及为什么

为什么拒绝建站、拒绝上数据库

最明显的问题是:几百条条目,做成能搜索、能筛选的站点不好吗?答案藏在他们如何定义瓶颈:这个项目的痛点在"编辑路径",不在"浏览路径"。README 的主要编辑者是工程师和 AI agent,读者只是顺便看看。纯 Markdown 表格任何编辑器、任何 agent 都能安全地改,构建成本为零。

代价是放弃了搜索、筛选和自动排序——排序靠人肉维持。我在 Wallet Reviews 表里确实翻到一条 Otim Smart Wallet 重复了两行,一字不差。CLAUDE.md 里有专门一条 "Remove duplicate entries",就是为这种漂移准备的。上数据库的话去重是一条查询的事,但整个仓库的形态、所有历史链接、所有 agent 的工作方式都得换。这里选了把复杂度全部压进"约定层",不是不会建站,是算过账。

为什么用 emoji 当文档类型字段

Markdown 表格的硬约束是行宽。CLAUDE.md 的优先级第一条就写着 "Priority: Keep security review table rows fitting on single lines"——一行折行,整张表的阅读性就崩了。文本列需要 "Security Review"、"Fix Review"、"LoA" 这样的完整词,emoji 只占一两个字符,还能无空格连写,是行宽预算下的最紧凑编码。

代价是 emoji 变成了第一类数据字段,底部图例就是它的 schema。以后新增一种文档类型,要同步改三处:图例、CLAUDE.md 的图标清单、实际使用的行。没有编译器检查这一步,全靠自觉。

为什么日期写进文件名

2024-07-uniswap-v4-core-securityreview.pdf里有日期,表格里也有日期,同一个事实写了两遍,看着冗余。

但两处用途不同:文件名里的日期是排序键,服务ls和文件树浏览;表格里的日期是展示字段,服务读者。两者唯一的耦合是"应该一致",而漂移真实存在——reviews/里有个2025.12-obsidiansync-securityreview.pdf用点号分隔月份,其余全是连字符。这是人工不变式的固有成本:没有强制手段,只有约定,漂移率比搭一套校验工具的低。

自己动手加一条:最短 3 步 + 一份提交前检查清单

假设你手上有一份新的 foo 项目安全评估报告。

先 clone:git clone https://gitcode.com/GitHub_Trending/pu/publications

第 1 步:按命名约定落文件。reviews/2026-10-foo-securityreview.pdf。是修复复查就用fixreview后缀,只有 LoA 就用loa。

第 2 步:在正确的表插行。找到该客户所在的 section(Offchain Labs、Scroll 这类大客户有独立小节),插在表头之后:

| [Foo](https://foo.example/) | Oct 2026 | 2 | | 📄 |

数竖线:6 个。空 Announcement 补| |(单空格);Effort 是小数就写2.5,别写.5——CLAUDE.md 里专门有条 ".2 should be 0.2",因为真有人踩过。

第 3 步:过一遍检查清单,CLAUDE.md 的 Editing Guidelines 可以直接当 checklist 用:

  • 除新行外,任何一行都不许动
  • 月份用三字母缩写,"Oct 2026" 而不是 "October 2026"
  • Product 列只有名字:不带 "Security Review",不带 "Labs"(除非会歧义)
  • 链接指向presentations/子目录时,路径里的空格必须写成%20,和目录名逐字符一致
  • 新开分支提 PR,禁止直接提交 master

最容易翻车的坑在第四条:从文件管理器复制目录名会带原始空格,直接贴进链接就是死链。"NEVER modify URLs" 那条规则,一半是在防这个。

动文件之前先看这 5 条约束

  • PDF 是不可变工件:发布后内容不改,文件名是唯一 ID。起错名字只能改名,所有引用它的现存链接全断;git 能跟踪 rename,但你的 PR 评审会很难看。
  • README 是单文件:1300 多行,两人同周改不同 section 必冲突。惯例是 PR 按 section 拆分,并遵守 "编辑后核对表格总行数不变"。
  • 唯一可机检的规则是竖线数:其余判断(产品名是否过长、announcement 链接是否官方)都靠人,自动化的成本高于一次人工 review。
  • 图例是 emoji 的唯一文档:新增图标时忘改图例和 CLAUDE.md,后续编辑者——包括 AI——会开始误用新图标。
  • PDF 体积大:reviews/一个目录就有数百个 PDF,全量 clone 很慢。只维护某个 section 的话,sparse checkout 对应目录即可。

继续深挖

  • CLAUDE.md:完整规则手册,只读一份文件就读它——这是这个仓库最接近"源码"的东西。
  • README.md:目录本体。对照看 Academic Papers 表(3 列)和 Major Clients 表(5 列),理解两套表格风格。
  • presentations/Swimming with the kubectl fish/:frontmatter 样本目录,README + 幻灯片 + 讲稿同目录存放的完整形态。
  • datasets/smart_contract_audit_findings/:仓库里少有的结构化数据集,CSV 带字段 schema(type / severity / difficulty / static / dynamic),适合做统计或当训练语料。
  • reviews/:命名约定的原样状态。按文件名排序,等于把公司十年的工作按时间轴过一遍。

【免费下载链接】publicationsPublications from Trail of Bits项目地址: https://gitcode.com/GitHub_Trending/pu/publications

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进