NautilusTrader 发布流水线安全架构:威胁模型、信任根与工件验证实战指南
【免费下载链接】nautilus_traderProduction-grade Rust-native trading engine with deterministic event-driven architecture项目地址: https://gitcode.com/GitHub_Trending/na/nautilus_trader
NautilusTrader 是一个生产级的 Rust 原生交易引擎(事件驱动、确定性架构),其发布安全模型覆盖从源码提交到包索引、容器镜像与 GitHub Release 的完整链路。本文以 安全架构文档 为核心,结合仓库内 SECURITY.md、发布指南、CI/CD 总览 及.github/workflows/与scripts/ci/中的真实实现,系统讲解 NautilusTrader 的发布威胁模型、信任根、发布时序、工件完整性/出处记录,以及面向消费者的端到端验证命令。读完本文,你将掌握如何独立校验 Python wheel/sdist、PyPI 发布出处、Rust crates 与 Docker 镜像的真实性与完整性,并理解其背后的 OIDC Trusted Publishing、Sigstore 与 SLSA 设计。
一、发布流水线的安全目标
NautilusTrader 的发布流水线有四个核心安全目标,全部围绕"可审计、可验证、最小化长期凭据"展开:
- 每个官方工件都必须来自经过评审的仓库提交(reviewed repository commit),确保"代码即事实"。
- 发布 Python 与 Rust 包时不得使用长期有效的包注册表令牌,通过 PyPI / crates.io Trusted Publishing 以 OIDC 短期身份替代。
- 在发布 GitHub Release 之前,先附加校验和、清单与出处证明(provenance),使完整性记录先于公开可见。
- 向用户提供足够的公开数据,使其能验证下载的工件与发布内容一致,即消费者侧可复现 CI 的校验结论。
GitHub Release 是整个链路完整性的锚点(anchor):稳定版发布时,wheels 与 sdist 会先以资产形式挂到draft(草稿)GitHub Release上,然后才开始向包索引发布;流水线随后发布包索引、并对照 GitHub Release 资产逐一核验索引内容,最后附加最终完整性资产并正式发布 GitHub Release。这种"先挂草稿、后发索引、再验索引、最后发布"的时序,配合 GitHub 对已发布 Release 资产与标签的不可变性,构成了完整性的闭环。
二、威胁模型:防御什么,不防御什么
2.1 流水线主动防御的威胁
| 威胁 | 防御机制 | 仓库证据 |
|---|---|---|
| 第三方 GitHub Actions 被入侵或可变 | Actions 全部以完整 commit SHA固定版本 | build.yml 中step-security/harden-runner@05e31511...、actions/checkout@3d3c42e...等均带 SHA 与注释标签;OVERVIEW.md 要求外部 Action 注明来源 URL、记录对应 release tag,且发布至少两周后才可采纳 |
| 从错误的 workflow / 分支 / 环境误发布 | OIDC publisher 严格绑定仓库nautechsystems/nautilus_trader、build.yml与release环境 | 见下方"信任根"一节 |
| 长期包注册表令牌失窃 | PyPI 与 crates.io 均启用 Trusted Publishing,无持久 token | 发布作业仅需id-token: write,见 build.yml 的publish作业权限声明 |
| 注册表传播延迟或部分重跑导致状态不一致 | 发布与校验脚本幂等且容忍重试 | 见 verify-published-registries.bash(跳过已存在版本、等待 sparse index 同步) |
| 注册表被替换或上传漂移 | 将 PyPI / crates.io 工件与发布清单及注册表元数据逐项比对 | 见 verify-published-registries.bash 与dist-manifest.json、crates-manifest.json |
| 静默手工恢复 crate | 强制显式声明CRATES_IO_MANUAL_PUBLISH_EXCEPTIONS,并在crates-manifest.json中记录例外 | 见 verify-published-registries.bash 对例外条目的校验逻辑 |
2.2 流水线明确不防御的范围
文档明确划定了边界,避免虚假安全感:
- 有权修改发布 workflow 并审批发布的恶意维护者(信任模型不防内部恶意的最终权威);
- GitHub、PyPI、crates.io 或 Sigstore信任根自身被攻破(可伪造用户依赖的信任根);
- 用户机器在验证执行前已被入侵;
- 交易所、券商、数据提供商或用户交易策略的运行时被攻破;
- wheels/sdist 的逐位可复现构建漂移——当前保证的是出处(provenance)与摘要验证,而非可复现构建(reproducible builds)。
三、信任根(Trust Roots)
流水线依赖以下六类信任根,层层递进:
- GitHub 仓库规则(rulesets):保护受审源码、发布分支与发布标签;受保护的
master分支与不可变的v*发布标签是相关记录。对应实现见 CODEOWNERS 与仓库 rulesets。 - GitHub Actions OIDC 颁发者:从
https://token.actions.githubusercontent.com提供短期工作流身份。 - GitHub
release部署环境:限制部署仅针对master,并要求评审者审批,是所有包发布与 Release 审批的门禁。 - PyPI Trusted Publishing:发布 wheels 与 sdist 无需持久 token,绑定仓库
nautechsystems/nautilus_trader、workflowbuild.yml、环境release。 - crates.io Trusted Publishing:绑定 owner
nautechsystems、仓库nautilus_trader、workflowbuild.yml、环境release。crates.io 各 crate 的发布配置要求见 releases.md 中的表格(Owner / Repository / Workflow / Environment 四字段)。 - Sigstore Fulcio / Rekor / TUF:将工件绑定到 OIDC 身份与透明日志。GitHub artifact attestations、PyPI publish attestations 与 Docker cosign 签名均依赖此根。
- GitHub Release 不可变性:已发布的 Release 资产与 release tag 不可替换,防止发布后被篡改。
补充实现事实:部署环境隔离不仅用于
release,还扩展了r2-develop、r2-nightly两个发布环境,见 OVERVIEW.md;发布/包发布作业使用作用域化的部署环境,使发布凭据与 OIDC trusted-publisher 身份与测试、lint、纯构建作业隔离。
四、发布流程(Release Flow)
security.md给出了完整的 mermaid 时序图,本文以文字形式完整保留并补充源码依据:
流程关键点与源码对照:
- 先审后发:
master分支上的发布提交进入build.yml,先跑发布门禁——Rust 测试套件、cargo-deny、cargo-vet、Cargo publish 预检与 docs/features 预检(见 releases.md 的稳定发布工作流)。同时 security-audit.yml 以workflow_call方式被build.yml调用,作为发布门禁的一部分。 - 门禁顺序约束:
tag-release必须依赖security-audit,保证审计失败时不能继续打稳定版标签(见 releases.md 的时序规则清单)。 - 先草稿后发布:先创建 tag 与 draft GitHub Release,wheels 与 sdist 资产必须先挂到 draft 上,再向
packages.nautechsystems.io、PyPI、crates.io 发布;发布完成后由publish-release-integrity先生成清单、再对照清单核验注册表、核验通过后才附加最终完整性资产;publish-github-release必须是稳定发布的最后一个作业,发布后校验 GitHub 的 release attestation(同一节中列出了全部时序约束)。 - Docker 独立但同模型:Docker 工作流(docker.yml)与包发布工作流相互独立,但采用相同的身份模型——镜像签名与 SBOM attestation 将镜像 digest 绑定到预期的 GitHub Actions workflow 身份。
五、工件记录(Artifact Records)
不同工件类别使用不同的完整性与出处记录组合:
| 工件 | 发布目标 | 完整性记录 | 出处记录 |
|---|---|---|---|
| Python wheels | GitHub Releases、PyPI、Nautech Systems 包索引(packages.nautechsystems.io) | SHA256SUMS、每资产.sha256文件、dist-manifest.json | GitHub artifact attestations、PyPI publish attestations、.sigstore包、.intoto.jsonlDSSE 信封 |
| Python sdist | GitHub Releases、PyPI | 与 wheels 相同的记录 | 与 wheels 相同;但不发布到仅限 wheel 的包索引 |
| Rust crates | crates.io | crates.io checksum、crates-manifest.json | crates.iotrustpub_data(除非存在显式手工例外) |
| Docker 镜像 | GitHub Container Registry | 镜像 digest | Sigstore cosign 签名、SPDX SBOM attestation |
| GitHub Release 记录 | GitHub Releases | 已发布资产 + 不可变 tag | GitHub release attestation |
关于crates-manifest.json的生成,可从源码确认:脚本 verify-published-registries.bash 会读取 crates.io API 的trustpub_data(provider / repository / sha)与本地校验和,逐 crate 生成 JSONL 并汇总为crates-manifest.json,其中每项包含trusted_publishing与release_status(例如manual_token_publish)字段。
六、消费者验证映射(Consumer Verification Map)
security.md声明"详细命令位于 SECURITY.md 的 Verifying releases 一节"(仓库中对应 SECURITY.md),并给出每类消费者应验证的公开数据清单与示例命令。以下完整继承并补全。
6.1 Python wheels 与 sdist
应验证:
- 工件 digest 与
SHA256SUMS、每资产.sha256文件或dist-manifest.json一致; - GitHub artifact attestation 身份匹配
nautechsystems/nautilus_trader/.github/workflows/build.yml的master或nightly分支; - PyPI publish attestation 报告仓库
nautechsystems/nautilus_trader、workflowbuild.yml、环境release。
示例命令(完整保留原文档脚本,并补充环境变量说明):
: "${VERSION:?Set VERSION to the Python package version}" : "${ARTIFACT:?Set ARTIFACT to the release asset filename}" TAG="v$VERSION" REPO=nautechsystems/nautilus_trader ISSUER=https://token.actions.githubusercontent.com IDENTITY='^https://github\.com/nautechsystems/nautilus_trader/\.github/workflows/build\.yml@refs/heads/(master|nightly)$' # 1) 从 GitHub Release 下载资产与其 .sha256 侧车文件 gh release download "$TAG" --repo "$REPO" --pattern "$ARTIFACT" --pattern "$ARTIFACT.sha256" # 2) 校验本地摘要与发布记录一致 sha256sum -c "$ARTIFACT.sha256" # 3) 校验 Sigstore 出处:身份必须来自 build.yml 且分支为 master 或 nightly gh attestation verify "$ARTIFACT" \ --repo "$REPO" \ --cert-identity-regex "$IDENTITY" \ --cert-oidc-issuer "$ISSUER"SECURITY.md 补充了两点实用细节:GitHub CLI 默认从 GitHub API 拉取 attestations,也可改用--bundle <artifact>.sigstore校验本地下载的 Sigstore bundle;gh attestation verify每次调用只接受一个 subject,因此多个 wheel 应循环验证(该文件中给出了for whl in nautilus_trader-*.whl的循环写法)。
6.2 PyPI 发布出处
应验证:
- PyPI 文件哈希与
dist-manifest.json一致; - PyPI provenance 暴露预期的 GitHub publisher 身份;
pypi-attestations verify接受下载文件的 URL。
示例命令:
: "${VERSION:?Set VERSION to the Python package version}" : "${ARTIFACT:?Set ARTIFACT to the release asset filename}" # 从 PyPI JSON API 解析出对应文件名的下载 URL PYPI_URL=$(curl -sS "https://pypi.org/pypi/nautilus_trader/$VERSION/json" | \ jq -r --arg artifact "$ARTIFACT" '.urls[] | select(.filename == $artifact) | .url') # 用隔离环境中的 pypi-attestations 校验出处(仓库将 pypi-attestations 固定为 0.0.30,见 tools.toml) uv run --no-project --no-build --with pypi-attestations -- \ pypi-attestations verify pypi \ --repository https://github.com/nautechsystems/nautilus_trader \ "$PYPI_URL"6.3 Rust crates
应验证:
- crates.io 版本的 checksum 与下载的
.crate文件一致; trustpub_data.provider为github;trustpub_data.repository为nautechsystems/nautilus_trader;published_by为null,除非crates-manifest.json记录了显式的manual_token_publish例外。
示例命令:
CRATE=${CRATE:-nautilus-core} : "${VERSION:?Set VERSION to the crate version}" REPO=nautechsystems/nautilus_trader # 从 crates.io API 取版本元数据,提取 checksum 与 trustpub_data VERSION_JSON=$(curl -sS "https://crates.io/api/v1/crates/$CRATE/versions" | \ jq -c --arg version "$VERSION" '.versions[] | select(.num == $version)') CRATE_SHA256=$(printf '%s\n' "$VERSION_JSON" | jq -r '.checksum') # 断言:Trusted Publishing 身份正确且非手工 token 发布 printf '%s\n' "$VERSION_JSON" | jq -e --arg repo "$REPO" \ '.trustpub_data.provider == "github" and .trustpub_data.repository == $repo and .published_by == null' # 下载 .crate 并比对摘要 curl -sSL "https://static.crates.io/crates/$CRATE/$CRATE-$VERSION.crate" -o "$CRATE-$VERSION.crate" test "$(sha256sum "$CRATE-$VERSION.crate" | cut -d ' ' -f 1)" = "$CRATE_SHA256"6.4 Docker 镜像
应验证:
- 可变 tag 解析到你想运行的 digest;
- cosign 签名身份匹配 Docker workflow;
- SPDX SBOM attestation 绑定到同一镜像 digest。
示例命令:
export IMAGE_BASE=ghcr.io/nautechsystems/nautilus_trader # 关键:先把可变 tag 解析为不可变 digest,后续 pull/run/校验均基于同一 digest export DIGEST=$(crane digest "$IMAGE_BASE:latest") export IMAGE=$IMAGE_BASE@$DIGEST export ISSUER=https://token.actions.githubusercontent.com export IDENTITY='^https://github\.com/nautechsystems/nautilus_trader/\.github/workflows/docker\.yml@refs/heads/(master|nightly)$' # 校验 cosign 签名(证明镜像由 NautilusTrader CI workflow 构建) cosign verify "$IMAGE" --certificate-identity-regexp "$IDENTITY" --certificate-oidc-issuer "$ISSUER" # 校验 SPDX SBOM attestation 绑定同一 digest cosign verify-attestation \ --type https://spdx.dev/Document/v2.3 \ "$IMAGE" \ --certificate-identity-regexp "$IDENTITY" \ --certificate-oidc-issuer "$ISSUER"SECURITY.md 补充:GitHub CLI 也能校验 SBOM attestation(gh attestation verify "oci://${IMAGE}" --predicate-type https://spdx.dev/Document/v2.3 ...),但它不检查cosign 镜像签名,因此只能作为cosign verify的补充而非替代。
七、手工恢复姿态(Manual Recovery Posture)
正常发布只走 Trusted Publishing。手工发布(带 token 发布)是部分发布失败后的最后兜底恢复路径,且受到严格约束:
- 优先重跑:注册表或 Sigstore 验证器失败时,优先重跑失败的 job 或 workflow,而不是手工干预;
- 发布后不可变更:不得替换已发布的 release tag 或 GitHub Release 资产;
- 禁止静默接受:不得静默接受手工发布的 crate;
- 显式声明例外:若必须用 token 恢复某 crate,须将每个
crate@version列入CRATES_IO_MANUAL_PUBLISH_EXCEPTIONS; - 记录例外:在发布说明与
crates-manifest.json中记录,release_status设为"manual_token_publish"。
从实现看,脚本对例外条目的校验是双向的:格式非法或未被使用的例外条目都会使作业失败(见 verify-published-registries.bash),且后发布验证只有在 crates.io 显示该 crate 版本由本仓库 trusted-published 时才视为previously_published,否则即使列入例外,也需要逐项核对(见 releases.md 的 crates.io publishing 一节)。
结论:没有任何常规发布路径依赖长期有效的 PyPI 或 crates.io token。
八、事件响应姿态(Incident Response Posture)
security.md为每类可检测异常定义了明确的响应动作:
| 检测到的异常 | 响应动作 |
|---|---|
| PyPI publisher 漂移 | 由 PyPI provenance 验证器发现;停止发布、修复 PyPI Trusted Publisher、重跑验证 |
| crates.io publisher 漂移 | 由 trusted-publishing 检查或注册表验证器发现;修复 crate publisher 设置并重跑;仅在部分恢复时使用手工例外 |
| GitHub Release 资产不匹配 | 由校验和或清单验证发现;发布前停止发布,若资产已随发布外发则发布安全通告(advisory) |
| Sigstore / Rekor / TUF 延迟 | 表现为可重试的透明日志错误;有界退避重试,若延迟持续则暂停发布密封(release sealing) |
| Sigstore 信任根疑虑 | 当 attestation 验证变得不明确时出现;暂停发布、对照注册表记录核验、在支持时轮换信任根 |
| Workflow 身份不匹配 | 由 GitHub、PyPI 或 cosign 身份检查发现;在审查完成前按配置漂移或入侵处理 |
| 手工 crate 发布例外 | 当 crates.io 显示published_by而非trustpub_data时发现;记录显式例外、记录受影响的 crates、保留审计线索 |
九、SLSA 姿态(SLSA Posture)
- Python 发布工件通过GitHub artifact attestations 与 PyPI publish attestations携带构建出处;
- Docker 镜像携带Sigstore 签名与 SPDX SBOM attestation;
- Rust crates 依赖crates.io Trusted Publishing 元数据与发布时的
crates-manifest.json。
文档明确:本文不对所有工件类别断言某一具名 SLSA 级别。任何未来的 SLSA 级别声明都必须引用本架构、指明其覆盖的工件类别,并在 CI 中加入验证——即校验已发布出处可解析为所声明的 predicate 类型。这是一条"先验证、后声明"的严谨边界。
十、从源码看:发布安全的实现支柱
除security.md本身外,仓库中的以下文件是上述安全设计的落地证据,可继续深入阅读:
- SECURITY.md:消费端完整验证命令(含 wheel 循环验证、Docker SBOM 的
gh attestation补充校验)、漏洞报告流程、OpenSSF Scorecard、依赖冷却期(Python 7 天exclude-newer、Rust 3 天冷却)、no-build-packagewheel-only 安装、运行时密码学选型(TLS 与多数运行时密码学使用aws-lc-rs,Ed25519 使用ed25519-dalek,AWS-LC 以非 FIPS 模式运行的原因)以及已处理的第三方 advisory 记录。 - releases.md:三分支模型(
develop/nightly/master)、稳定发布工作流的完整 mermaid 时序、crates.io Trusted Publishing 配置字段表、发布清单与发布说明规范。 - .github/OVERVIEW.md:CI 侧约束——CODEOWNERS 评审要求、Action 采用冷却期、Docker 基础镜像与 service container 的 digest 固定、最小权限
GITHUB_TOKEN、网络出口白名单(step-security/harden-runner默认egress-policy: block)、SECURITY_GATE_OVERRIDE门禁覆盖机制(格式<UTC expiry>@<full commit SHA>、过期时间不得超过未来两小时、失败关闭)。 - deny.toml:
cargo-deny配置——只允许 crates.io 作为注册表(unknown-registry = "deny"、unknown-git = "deny")、禁止通配符版本、多版本重复检测、LGPL-3.0 兼容许可证白名单与带理由的 advisory 忽略清单。 - security-audit.yml:zizmor(GitHub Actions 审计)+ supply-chain 双作业的变更感知审计(path-filtered),
audit-result聚合门禁,cargo audit、cargo-deny、cargo-vet、pip-audit、OSV-Scanner、Zizmor 全部纳入。 - verify-published-registries.bash:
crates-manifest.json的实际生成与注册表核验逻辑(trustpub_data解析、CRATES_IO_MANUAL_PUBLISH_EXCEPTIONS双向校验、逐 crate 生成 JSONL 清单)。 - tools.toml 与 rust-toolchain.toml:工具链版本固定(含
pypi-attestations 0.0.30、nightly/miri 固定版本),支撑可复现的 CI 与验证环境。
结语
NautilusTrader 的发布安全架构用一句话概括:以"受审提交 + OIDC 短期身份 + 草稿 Release 先行 + 注册表对照核验 + Sigstore/SLSA 出处记录 + GitHub Release 不可变性"组成纵深防御链。对消费者而言,核心理念是"先验后用"——通过本文第六节的四组命令,任何人无需信任发布方即可独立确认所获工件的完整性与出处。若需进一步阅读,可依次查阅 SECURITY.md(消费端命令全集)、releases.md(发布时序约束)与 .github/OVERVIEW.md(CI 控制细节)。
【免费下载链接】nautilus_traderProduction-grade Rust-native trading engine with deterministic event-driven architecture项目地址: https://gitcode.com/GitHub_Trending/na/nautilus_trader
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考