ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Wasmtime 代码贡献规范实战:从 rustfmt、Clippy 到 cargo vet 与 unsafe 审查

Wasmtime 代码贡献规范实战:从 rustfmt、Clippy 到 cargo vet 与 unsafe 审查 Wasmtime 代码贡献规范实战从 rustfmt、Clippy 到 cargo vet 与 unsafe 审查【免费下载链接】wasmtimeA lightweight WebAssembly runtime that is fast, secure, and standards-compliant项目地址: https://gitcode.com/gh_mirrors/wa/wasmtime本指南以 Wasmtime 仓库的 docs/contributing-coding-guidelines.md 为骨架系统讲解向 Wasmtime 提交代码时必须遵守的工程规范代码格式化、编译器警告与 lint 策略、Clippy 的按需启用机制、MSRV最低支持 Rust 版本政策、基于cargo vet的供应链安全审查流程、仓库的 crate 组织方式以及unsafe代码的使用准则。读完本文你将掌握 Wasmtime 的代码质量门槛与 CI 检查逻辑能够独立判断一个 PR 在格式、lint、依赖审查三个维度上是否符合合入要求。Wasmtime 与 Cranelift 大体遵循通用的 Rust 惯例和 PR 工作流但在此基础上还额外约定了一批需要特别留意的工程规范。这些规范并非停留在纸面它们被落地为仓库根目录 Cargo.toml 的 workspace lint 配置、CI 工作流中的强制检查以及supply-chain/目录下真实存在的审计记录。本文将在继承原文档全部内容的基础上结合仓库源码与配置文件逐条印证。统一格式化rustfmt 是硬性门槛所有 PR 必须通过 rustfmt 格式化并且这一要求在持续集成测试中被强制检查。在仓库根目录本地执行cargo fmt即可完成全仓库代码格式化。rustfmt 的配置集中在仓库根目录的 rustfmt.toml 中目前仅有edition 2024即整个仓库统一使用 Rust 2024 edition 的格式化规则。这意味着无论哪个 crate 的代码格式化风格完全一致diff 中不会出现因为不同开发者编辑器设置不同而产生的噪音改动。值得说明的是Wasmtime 仓库很大cargo fmt会遍历整个 workspace涵盖crates/、cranelift/、winch/、pulley/等所有子 crate因此在提交 PR 前在仓库根目录执行一次cargo fmt是最省事的做法。rustfmt 也支持编辑器集成保存时自动格式化可在开发阶段就避免格式问题。编译器警告与 Lint本地宽容、CI 从严Wasmtime 在 CI 中把所有编译器警告提升为错误这意味着main分支在 CI 所测试的 Rust 版本下不存在任何编译器警告。不过编译器警告会随 Rust 版本变化而增减因此使用任意 Rust 版本构建时并不保证零警告——如果你在自己版本的 Rust 下遇到新警告欢迎提交 PR 修复它们。本地开发时情况则宽松很多警告只是警告构建和测试依然可以成功。这在重构中途特别有用——重构过程中警告往往大量涌现本地开发不受阻碍但提交 PR 时所有警告必须解决否则 CI 失败、PR 无法合入。lint 由仓库根目录 Cargo.toml 中的[workspace.lints.rust]表统一控制。仓库实际启用了如下默认允许的 lint均设为warn[workspace.lints.rust] unused_extern_crates warn trivial_numeric_casts warn unstable_features warn unused_import_braces warn unused_lifetimes warn unused_macro_rules warn此外仓库还专门配置了[workspace.lints.rust.unexpected_cfgs]通过check-cfg白名单声明项目自用的自定义cfg避免这些cfg触发未知配置警告[workspace.lints.rust.unexpected_cfgs] level warn check-cfg [ cfg(pulley_tail_calls), cfg(pulley_assume_llvm_makes_tail_calls), cfg(pulley_disable_interp_simd), cfg(arc_try_new), # 由 cargo fuzz 构建模糊测试时启用 cfg(fuzzing), # 启用后触发激进的 GC 调试断言 cfg(gc_zeal), ]可见这些cfg对应的是 Pulley 解释器的尾调用特性、模糊测试fuzzing以及 GC 调试模式等真实存在的功能开关。lint 也可以按 crate 单独启用例如在某个src/lib.rs中放置#![warn(trivial_numeric_casts)]使用warn级别允许本地开发继续推进同时 CI 会将该警告提升为错误——这是本地宽松、CI 从严策略在 lint 层面的直接体现。如果你认为某个默认关闭的 lint 对仓库有价值欢迎在 workspace 或 crate 级别启用它。Clippy全部默认关闭按需逐个启用所有 PR 都以cargo clippy对全部 workspace crate 和目标通过为门槛。但与一般项目不同Wasmtime 把 Clippy 的全部 lint 默认设为 allow关闭理由是默认的 Clippy lint 集合太吵无法有效使用其他 lint。项目采用选择性开启的 opt-in 策略。workspace 级别通过[workspace.lints.clippy]控制仓库实际的配置Cargo.toml如下[workspace.lints.clippy] # Clippy 默认 lint 集合被视为太吵因此默认全部关闭按需开启以下 lint。 all { level allow, priority -1 } clone_on_copy warn map_clone warn uninlined_format_args warn unnecessary_to_owned warn manual_strip warn useless_conversion warn unnecessary_mut_passed warn unnecessary_fallible_conversions warn unnecessary_cast warn allow_attributes_without_reason warn from_over_into warn redundant_field_names warn multiple_bound_locations warn extra_unused_type_parameters warn其中all { level allow, priority -1 }是关键它把全部 Clippy lint 的默认级别降为 allow且优先级为 -1低于具体 lint 条目随后列出的具体 lint 再逐个提升为warn。这样既保证了默认集合不产生噪音又能精准启用对 Wasmtime 代码库有价值的 lint。lint 同样可以在单个 crate 或模块级别启用#![warn(clippy::manual_strip)]与原文档一致Wasmtime 认为默认 Clippy lint 集合噪音过大因此采用 allow-by-default 的行为但对所有 crate 或单个 crate/模块有用的 lint 仍被鼓励通过 workspace 或 crate 级配置启用。与编译器警告同理所有 Clippy 警告在 CI 中都会被提升为错误因此main分支在 CI 同版本编译器通常是当前 stable Rust下cargo clippy零警告。需要特别注意的是如果你在 workspace 层面启用了新的 Clippy lint就必须修复 workspace 内所有crate 的该 lint 问题才能让 PR 通过 CI。本地运行 Clippy 的命令是cargo clippy --workspace --all-targets--workspace检查所有工作区 crate--all-targets则把 tests、benches、examples 等所有目标类型也纳入检查——这与 CI 的检查范围一致避免只在src下通过却在测试代码中触雷。MSRV支持最近三个稳定版 RustWasmtime 和 Cranelift 支持 Rust 的最近三个稳定版本。举例来说若最新稳定版是 1.72.0则 Wasmtime 支持 1.70.0、1.71.0、1.72.0CI 默认用 1.72.0 测试同时有一个 job 在 Linux x86_64 上用 1.70.0 跑完整测试套件。部分 CI job 依赖 nightly Rust例如用 nightly 特性跑 rustdoc但这些 job 使用 CI 中固定并定期更新的 pinned 版本整个仓库本身不依赖 nightly 特性。更新 MSRV 的方式是修改 workspace 根 Cargo.toml 中的rust-version字段。仓库当前的实际配置为edition 2024 # Wasmtime 的现行政策该数字不能大于当前 stable Rust 版本减 2。 rust-version 1.96.0注意文件中的注释直接印证了支持最近三个稳定版的政策rust-version取值为当前 stable 减 2恰好覆盖最近三个版本。该政策未来可能调整比如扩展到更多 rustc 版本如果您的使用场景需要更宽的 MSRV 窗口可以通过 issue、Wasmtime 会议或 Zulip 联系维护者提出诉求。Wasmtime 现有用户并不需要一个更大的 MSRV 窗口来支撑相应的维护成本。依赖与供应链安全cargo vet 审查门槛Wasmtime 和 Cranelift 在添加依赖方面比默认门槛更高所有依赖都必须通过cargo vet工具进行审查vet。这一要求在 CI 中被检查并会在Cargo.lock的任何修改上运行。需要澄清一个常见误解Wasmtime 的 vet 并不是对依赖做一丝不苟的正确性代码审查而是声明该 crate 不含恶意代码、在开发和可选用户运行 Wasmtime 时是安全的。Wasmtime 的 vet 记录同时被其他组织复用反过来 Wasmtime 也引用其他组织的 vet 记录从而不必事事亲力亲为。所有的配置集中在仓库的 supply-chain 目录包含四个文件supply-chain/config.tomlcargo vet 的配置包括导入的第三方审计源、各 crate 的审查政策以及[[exemptions]]豁免列表supply-chain/audits.tomlWasmtime 自己产出的审计记录[[audits]]条目每条都带有审计者who信息supply-chain/imports.lock第三方审计源的锁定快照supply-chain/README.md说明文档。从 supply-chain/config.toml 可以看到 Wasmtime 导入了五个第三方审计源包括 Embark Studios、Google、ISRG、Mozilla 和 Spin Framework 的 audits 记录。这正是原文档所说Wasmtime 使用其他组织的 vet 条目的实际落点。supply-chain/audits.toml 中的记录格式大致为[[audits.xxx]]who 审计者姓名 邮箱即每条 vet 记录都明确归属到具体审计者多为 Wasmtime 核心维护者保证可追溯。这些文件通常不需要手工编辑而是通过cargo vet工具自身管理。注意supply-chain/audits.toml中还包含表明作者被信任trusted的条目这种条目针对的是受信任作者的 crate可以降低其版本升级时的审查负担。综合起来任何更新或新增依赖的贡献默认情况下无法直接合入CI 会失败。这是项目配置的预期行为处理方式见下文。需要强调的是这套流程的目的不是阻止新依赖或依赖更新而是确保 Wasmtime 的开发建立在经过可信方审查的可信代码之上。看到 CI 中cargo vet失败时不必惊慌欢迎提交依赖更新和新功能。cargo vet 的分角色操作流程面向贡献者如果你是 Wasmtime 的贡献者修改依赖集合时请遵循以下原则优先精简依赖添加新依赖时值得先尝试削减所需范围或完全避免该依赖。在合理的前提下避免新增依赖是最佳选择但并非总是可行这交由作者和审查者判断。更新依赖要有明确目的依赖更新应当与当前 PR 的目的直接相关。例如 PR 实现新功能则依赖更新应服务于该功能否则最好把依赖更新拆成独立 PR。单纯为了更新而更新也是允许的但更希望作为独立 PR 提交。不要自行运行 cargo vet 或改动 supply-chain 目录依赖的增改需要维护者采取行动因此请把cargo vet的执行和supply-chain目录的更新交给维护者。维护者会审查你的 PR 并亲自完成 vet 记录通常会另开一个 PR 添加 vet 条目待其合入后你的 PR 进入合入队列。面向维护者维护者必须明确审查并批准所有依赖更新和对 Wasmtime 依赖集合的修改。审查 PR 时应确保贡献者没有自己修改supply-chain目录除非这些提交出自其他维护者。添加 vet 条目通常有三种途径维护者自改自审当维护者本人修改依赖时cargo vet条目可直接内联在该 PR 中审查者已知该作者就是维护者。独立的纯依赖更新 PR这类 PR 随时可以提交可以为未来功能或未来贡献者做准备处理方式与前一类基本相同。代贡献者补录对于不应自行添加 vet 条目的贡献者维护者审查 PR 后在独立 PR 中或直接在贡献者 PR 内添加 vet 条目。独立 PR 的做法是检出该分支 → 运行cargo vet→ rebase 掉贡献者的提交 → 只推送自己的cargo vet提交去合入。对于直接推送到贡献者 PR 的情形务必注意贡献者后续推送的更新要么包含、要么不要覆盖你的 vet 条目如果 PR 分支被 rebase 或 force-push要核对你先前推送的 vet 细节不变例如版本没有被提升、描述性理由保持一致。若既要推送 vet 提交又要求更多修改请让贡献者以追加提交的方式完成修改而不是 force-push 重写历史从而保证你已有的 vet 提交不被触碰。这些约定都是为了便于验证 vet 记录未被篡改。添加 cargo vet 条目的政策该政策的目标是既不让依赖更新沉重到无人问津又能获得cargo vet在抵御供应链攻击方面的主要收益。政策分两条日均下载量 ≥ 10,000 次的 crate以 crates.io 数据为准可以直接在 supply-chain/config.toml 的[[exemptions]]中添加条目无需仔细审查甚至完全不用审查。其假设是对热门 crate 的供应链攻击在统计上会较快被发现Wasmtime 的发布流程保证对main的修改至少 2 周后才发布热门 crate 遭受攻击大概率在此期间暴露。仓库中确实存在大量[[exemptions]]条目例如addr2line、aes、base64ct、criterioncriteria 为safe-to-run等且大多标注criteria safe-to-deploy。这一政策也大幅降低了升级常见热门依赖时维护者的负担。其他依赖必须进行手动 vet。cargo vet工具会引导你查看 crates.io 上发布的源码。手动审查的目标是确认没有恶意行为——例如检查unsafe代码、对环境系统能力的调用std::fs、std::net、std::process以及构建脚本build scripts。注意审查的不是正确性而仅仅是是否存在供应链攻击的迹象。该政策旨在平衡可用性与安全性。在可能的情况下始终推荐添加 vet 条目但上面第一条只适用于exemptions条目——当使用热门阈值时不要添加 vet 条目因为该 crate 实际上并未被 vet必须走[[exemptions]]通道。仓库 crate 组织monorepo 的布局规则Wasmtime 仓库是一个包含大量内部 crate 的 monorepo。不同 crate 的定位与待遇不同新增 crate 时大致遵循如下约定Wasmtime 相关 crate位于crates/foo/Cargo.tomlcrate 名通常是wasmtime-foo或wasmtime-internal-foo。仓库中可以看到crates/wasmtime、crates/wasi、crates/wasi-http、crates/environ等大量符合此模式的目录。Cranelift 相关 crate位于cranelift/foo/Cargo.tomlcrate 名为cranelift-foo例如 cranelift/codegencranelift-codegen、cranelift/frontend、cranelift/isle 等。例外项目Winch、Pulley、Wiggle 是上述规则的例外分别位于 winch、pulley 和 crates/wiggle。内部 crate有些 crate 仅用于 crate 组织目的如可选依赖的组织、代码组织不面向公众消费仅供wasmtimecrate 或其他公开 crate 内部使用。这类 crate 应命名为wasmtime-internal-foo并位于crates/foo。仓库根 Cargo.toml 的[workspace.dependencies]指令会在 workspace 内部使用时将其重命名为wasmtime-foo即 internal 字样只在 crates.io 上对外可见。新增 crate 的完整流程从占位发布到 trusted publishing向 workspace 添加新 crate 需要格外小心。Wasmtime 使用crates.io trusted publishing可信发布即所有 crate 都由 CI 中的特定工作流发布。这意味着新 crate 在从 Wasmtime workspace 首次发布之前必须已经存在于 crates.io 上并配置好 trusted publishing。新增流程如下在 PR 中添加新 crate通常一开始并不会读到本文档。CI 的verify-publishjob 会因该 crate 在 crates.io 上不存在而失败。PR 作者先在 crates.io 上发布一个占位 crate。在 crates.io 的 Settings → Trusted Publishing 下点击 Add填写字段PublisherGitHubRepository OwnerbytecodeallianceRepository namewasmtimeWorkflow filenamepublish-to-cratesio.ymlEnvironment namepublish勾选要求所有发布都使用 trusted publishing 工作流。邀请wasmtime-publish用户加入该 crate。Wasmtime 维护者可访问 BA 1password vault以wasmtime-publish身份登录 crates.io 接受邀请并复核所有设置、移除原 crate 所有者使wasmtime-publish成为唯一所有者。上述第 4 步引用的发布工作流在仓库中真实存在见 .github/workflows/publish-to-cratesio.yml。这套机制确保在发布时 crate 已在 GitHub 侧被保留发布工作流必然成功首次发布后该 crate 由 Wasmtime 维护者管理。unsafe 代码使用准则Wasmtime 包含unsafeRust 代码同时被用于安全关键场景因此这些unsafe代码的正确性格外重要。本节概述在 Wasmtime 中使用unsafe的指导原则。理想情况下 Wasmtime 不应有任何unsafe代码且大型组件中这一点已经基本实现——以下组件几乎没有unsafe代码Cranelift编译 WebAssembly 模块Winch编译 WebAssembly 模块Wasmparser校验 WebAssemblywasmtime-wasi/wasmtime-wasi-httpWASI 的实现。没有unsafe安全漏洞的可能性大幅降低最危险的情况不过是 panic 造成的 DoS 向量通常被视为低严重性问题。但受 Wasmtime 的本质所限100% 移除unsafe实际上不可能问题在于如何找到正确平衡、如何与unsafe共处。有些unsafe块本质上无法消除。例如Wasmtime 必然要把 Cranelift 的输出转换为函数指针并调用它此时unsafe块的正确性依赖于 Cranelift 本身的正确性以及 WebAssembly 到 Cranelift 翻译的正确性——这是 Wasmtime 项目的基本属性无法缓解。其余unsafe块则应尽量自包含、隔离在 Wasmtime 的小范围内。对这些代码Wasmtime 遵循四条准则公开 API 不应要求unsafewasmtimecrate 公开 API 的用户永远不应需要unsafe。无论与安全的 Rust 代码如何组合wasmtime的 API 都应该是健全sound且安全的。虽然允许新增unsafe但必须用精确的契约清楚记录究竟哪里不安全、调用方必须维持什么。例如Module::deserialize明确记录其可能导致任意代码执行因此传入任意字节是不安全的而此前序列化的字节总是安全的。unsafe fn必须有清晰的文档将函数声明为unsafe时应在函数声明处附带文档说明该函数为何不安全并清楚列出调用方为安全调用所需维持的全部契约。虽然无法验证文档是否正确但这对审查者和读者都是有用的警示促使其对这些函数更加警惕。函数内的unsafe块前要有前置注释解释该块为何是安全的并且这种解释应能通过局部推理验证例如只需考虑当前函数或模块内的少量代码。这意味着应能几乎不费力地把被调用函数要求的契约unsafe块存在的原因与周围代码关联起来——可以借助当前函数本身是unsafe相当于转发被调用方的契约或局部推理完成。功能实现不应产生过量的unsafe在权衡两个设计方案时不需要强制选择零unsafe的方案而是应当偏好少量 unsafe胜过完全 unsafe的方案。一个例子是 Wasmtime 对 GC 提案的实现采用沙箱化堆sandboxed heap堆上的数据永不被信任。这在宿主侧付出了轻微的理论性能损失但换来实现内所有函数都是安全的。这类设计权衡难以固化成条文但总体原则是只要假设性的性能牺牲不过分就应倾向更安全的实现。最后需要坦承Wasmtime 是一个相对庞大且历史悠久的代码库既有代码并不完美遵循上述准则。不符合准则的代码被视为必须偿还的技术债Wasmtime 通过维护已知问题清单wasmtime:unsafe-code标签来逐步消耗这份清单。新功能允许向清单添加条目但必须明确说明将来如何偿还这些新增条目。提交 PR 前的本地检查速查综合上述规范向 Wasmtime 提交 PR 前建议在仓库根目录依次执行cargo fmt # 统一格式化 cargo clippy --workspace --all-targets # 全部 crate 与目标的 Clippy 检查零警告 cargo build --workspace # 确认构建无警告 cargo test # 运行测试可选取决于改动范围涉及依赖变更时还需预期cargo vet在 CI 中失败并交由维护者处理supply-chain目录的更新而不是自行修改。遵循以上规范你的 PR 将顺利通过格式、lint 与供应链审查三道关卡。【免费下载链接】wasmtimeA lightweight WebAssembly runtime that is fast, secure, and standards-compliant项目地址: https://gitcode.com/gh_mirrors/wa/wasmtime创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表