安全公共GitHub发布
核心规则
公共信任优先于速度。优先使用干净的公共快照、发布分支PR/CI门禁、经过验证的GitHub Release制品、校验和,以及不可逆操作需经过维护者明确批准。
切勿直接从私有历史原地发布。如果仓库在创建时是干净的公共快照,仅因最终润色而保持私有,则在最终审查门禁通过后可切换为公开。仅当实际涉及Python包分发时,才使用PyPI/TestPyPI。
工作流程
- 首先检查:
git status -sb、远程仓库、当前分支、标签和相关工作流。- 使用
gh检查公共仓库可见性、默认分支、发布/标签状态以及GitHub环境。 - 检查现有文档中是否提及安装路径、发布、Homebrew、TestPyPI、PyPI、私有仓库、本地路径或交接文件。
- 界定公开面:
- 公开文档和包元数据可能提及公共所有者/仓库、包名、公共标签和官方安装命令。
- 公开文档不得提及私有仓库名、本地主目录路径、
HANDOFF.md、CONTINUITY.md、.local、.codex、令牌、密钥、原始内部记录或仅维护者可见的说明,除非重写为面向公众的指南。 - 对于仓库本地文档和媒体,优先使用相对README链接。在发布说明中使用绝对GitHub所有者/仓库URL是可以的,但在README中,它们可能会导致不必要的所有者耦合以及公开面审查检查中的误报。
- 准备GitHub发布门禁:
- 在进行远程变更之前,先在本地构建/测试。
- 默认情况下使用
release/vX.Y.Z-> PR -> CI -> 合并后再打标签。 - 当README或本地化README文件发生更改时,要求Aki在合并前对GitHub渲染的README进行视觉审批。
- 在上传Release制品前进行验证:预期的文件名、版本元数据、校验和、归档内容,以及平台特定的签名/公证检查(如适用)。
- 对于macOS
.appzip制品,在构建归档时禁用AppleDouble或Finder元数据。优先使用COPYFILE_DISABLE=1 zip或等效的归档命令,并拒绝包含__MACOSX、.DS_Store或._*文件的归档。这些额外文件可能会导致签名后的应用在解压缩后验证失败。 - 始终通过提取到临时目录、检查应用/包版本元数据、并对提取的有效负载运行相关签名/公证验证,来验证将要上传的确切归档。
- 按以下顺序发布GitHub Release:
- 重新获取
main,验证最新的CI为绿色,并确认本地工作树是干净的。 - 确认目标标签和GitHub Release尚不存在。
- 在验证过的
main提交上创建标签。 - 推送标签。
- 使用面向发布的基准名(而非
dist/...等本地路径)从最终上传文件创建校验和文件。 - 使用有意的说明和仅有的有意制品创建GitHub Release。
- 当校验和对制品类型有用时上传校验和文件,并在Release说明中包含校验和,以帮助用户验证下载。
- 重新获取
- 在GitHub发布后进行验证:
- 标签指向预期的提交。
- GitHub Release在预期的URL上可见。
- Release制品和校验和与本地验证的文件匹配。
- 将发布的Release制品下载到临时目录,并从下载的副本进行验证。对于基于校验和的归档,运行
shasum -a 256 -c <asset>.sha256;对于macOS.appzip,解压下载的制品并对提取的应用运行应用版本和codesign --verify --strict --deep检查。 - 公共README/文档与当前发布的版本和制品名称匹配。
可选的PyPI / TestPyPI小节
仅当GitHub发布同时发布Python包、CLI或uvx安装路径时,才使用此小节。
- 确保GitHub环境存在
testpypi和pypi。 - 让
pypi处于维护者批准保护下。 - 使用
id-token: write和PyPI受信任发布者,而不是存储的PyPI令牌。 - 按以下顺序发布:
- 从预期标签触发的仅构建工作流。
- 包含
SHA256SUMS和制品证明的GitHub Release归档。 - 发布到TestPyPI,然后进行安装冒烟测试。
- 仅在TestPyPI显示版本且安装冒烟测试通过后,才发布到PyPI。
- 更新文档,使实际安装路径成为主要路径。
- 发布后验证:
- PyPI/TestPyPI的JSON包含预期的版本。
uvx --from <package> <command> --help正常工作。- 重新上传相同版本被就绪检查阻止。
- 公共README/文档与实际安装路径匹配。
仅GitHub公共快照检查清单
当目标是GitHub仓库或应用发布(不含PyPI)时使用此清单。
- 在最终门禁通过之前,保持仓库私有。如果公共目标是一个独立的已公开仓库,切勿将私有历史复制进去;仅移动经过审查的快照内容。
- 默认情况下,对公共快照使用发布分支和PR:
- 在公共仓库中创建或更新
release/vX.Y.Z。 - 在该分支上提交准备好的快照和公共文档。
- 打开一个针对
main的PR并让CI运行。 - 当README或面向发布的文档发生更改时,也使用
readme-release-sync,以便公共副本保持可读、双语且与发布行为一致。 - 给Aki提供PR/分支的GitHub渲染README链接,并在合并前等待明确的视觉批准。本地Markdown预览、原始文件视图、截图或自动链接检查不能替代此门禁。
- 仅在CI为绿色且公开面审查通过后合并。
- 仅当Aki明确要求跳过PR门禁时,才直接推送到
main。
- 在公共仓库中创建或更新
- 审查跟踪的文件,而不仅仅是工作树:
- 密钥、本地路径、维护者名称、旧的私有仓库名、交接文件、生成的归档、过时的产品名称。
git ls-files检查意外的.mov、.mp4、构建输出、缓存和大二进制文件。
- 将README媒体视为公开面的一部分:
- 内嵌GIF是GitHub README演示最可靠的格式;将其保持在GitHub实际的图像/GIF限制内。
- 本地README
<video>嵌入和仓库本地MP4预览链接可能会失败或打开不稳定的GitHub文件预览页面。 - 仅在真正需要时,将可选的MP4演示放在GitHub Release制品中,并且如果产品不需要,则删除它们以及发布说明中的引用。
- 在创建标签或GitHub Release之前,重新获取:
- PR合并状态和合并后
main上的最新CI状态 git status -sb、git log --oneline -1、git tag --list和当前Release制品- 当仓库已公开时,通过GitHub内容API检查README和引用的图像路径
- 每个二进制上传的归档内容和提取制品验证结果
- PR合并状态和合并后
- 在切换可见性之前,重新获取:
gh repo view ... --json visibility,isPrivate,url,defaultBranchRef- 默认分支的最新Actions状态
- Release制品和Release说明
- 通过GitHub内容API检查README和引用的图像路径
- 仅在Aki明确表示要发布后才切换可见性,然后验证
visibility=PUBLIC、公共README URL可用性、Release制品和干净的工作树。
干净快照到公共仓库流程
当私有/内部仓库馈送到一个单独的公共仓库时,使用此流程。
- 在私有仓库中完成并验证功能。
- 根据公共文件允许列表创建一个临时快照文件夹。
- 在快照中应用公共命名并移除仅私有的表面。
- 审查快照中的密钥、私有路径、交接文件、旧产品名称、生成的归档和大的意外文件。
- 将审查后的快照复制到公共仓库的工作树中。
- 创建或切换到
release/vX.Y.Z。 - 在该分支上更新公共README、本地化README、变更日志、版本元数据、发布草稿说明和README媒体引用。
- 检查
git diff、README媒体链接、双语一致性、过时措辞和公开面扫描结果。 - 运行相关的本地构建/测试/打包检查。
- 在
release/vX.Y.Z上提交发布准备更改并推送分支。 - 打开一个针对
main的PR;暂时不要打标签或创建GitHub Release。 - 等待CI,在发布分支上修复失败,并重新运行检查。
- 向Aki发送PR/分支上
README.md和任何本地化README文件的GitHub渲染README URL。等待Aki明确视觉批准,确认README在GitHub上看起来正确。 - 仅在CI、审查门禁和Aki的GitHub渲染README视觉批准全部通过后,才合并PR。
- 重新获取
main并验证合并提交是干净且绿色的。 - 在创建
vX.Y.Z、上传制品或创建/发布GitHub Release之前,停下来等待Aki批准。
尚无公共仓库的流程
当项目从未有过公共仓库时,使用此路径。
- 不要将私有/内部工作仓库切换为公开。
- 创建一个新的干净发布仓库,并首先保持其私有。
- 仅从审查后的公共快照(而非私有历史)初始化它。
- 从一开始就使用面向公众的产品名称、包元数据、README文件、许可证、变更日志、发布草稿说明、截图/GIF和工作流。
- 对跟踪的文件运行相同的密钥/私有路径/大文件/公开面审查。
- 使用
release/vX.Y.Z-> PR -> CI -> Aki GitHub渲染README视觉批准 -> 合并,即使仓库仍然私有。 - 在可能的情况下,在仓库仍为私有状态时创建预期的标签和GitHub Release草稿,并在那里验证制品/校验和。
- 在更改可见性之前停下来等待Aki批准。
- 仅在最终审查、绿色CI、有意发布的制品和Aki明确批准后,才将可见性切换为公开。
- 可见性切换后,重新获取并验证公共README可用性、Release制品、标签、最新Actions状态和本地干净工作树。
重要经验教训
- GitHub Actions工作流定义取自用于调度工作流的引用(ref)。如果在添加新工作流输入或保护措施之前创建了标签,则从该旧标签调度时将不知道新输入。
- 未来的发布应在创建标签之前放置发布保护措施。然后使用受保护的输入从该标签进行调度。
- 如果一次性历史标签早于保护措施,不要猜测。运行本地就绪检查,首先验证TestPyPI,验证制品/证明,并记录异常。
- Release制品卫生很重要:在进行探索性上传后,最终的公共Release应仅包含有意的制品。在发布前删除不需要的制品及其SHA行或发布说明引用。
详细运行手册
阅读references/pypi-trusted-release-runbook.md获取逐步检查清单、命令模式和公共文档审计模式。