news 2026/9/13 14:55:28

Ruffle 开源协议深度解析:MIT/Apache-2.0 双许可体系与第三方依赖许可证审计

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Ruffle 开源协议深度解析:MIT/Apache-2.0 双许可体系与第三方依赖许可证审计

Ruffle 开源协议深度解析:MIT/Apache-2.0 双许可体系与第三方依赖许可证审计

【免费下载链接】ruffleA Flash Player emulator written in Rust项目地址: https://gitcode.com/GitHub_Trending/ru/ruffle

本文以 Ruffle 仓库中的 web/LICENSE.md 为蓝本,完整解析这个用 Rust 编写的 Flash Player 模拟器是如何通过 “MIT 或 Apache-2.0” 双许可(dual-licensing)机制发布代码的、如何在 Cargo workspace 中统一声明许可证、如何以 400+ 条目的表格形式登记全部第三方依赖的许可证归属,以及如何借助 deny.toml 中的 cargo-deny 策略对依赖许可进行自动化审计。读完本文,你将掌握在大型 Rust 项目中落地双许可声明、继承式 license 配置与依赖许可合规检查的完整方法。

一、双许可声明:MIT 或 Apache-2.0,由使用者选择

web/LICENSE.md 开篇即给出了 Ruffle 项目的核心许可声明(文件第 1~8 行):

Ruffle is licensed under either of

  • Apache License, Version 2.0
  • MIT license at your option.

这也就是业界所称的dual-licensing(双许可/可选许可):每一部分代码同时被两种许可证覆盖,下游使用者可以任意选择其中一种来使用、修改和再分发 Ruffle 的代码。Ruffle 主版权所有者为 “Copyright (c) 2018-2021 Michael R. Welsh 和 Ruffle contributors”(见 web/LICENSE.md 第 12 行)。

为什么很多高性能 Rust 项目(Ruffle 的 workspace 版本为 0.6.0,见 Cargo.toml 第 51 行)倾向于这种模式?两种许可证的定位差异如下:

维度MIT(web/LICENSE.md)Apache-2.0(web/LICENSE.md)
授予的权利无限制地使用、复制、修改、合并、发布、分发、再许可和出售版权许可 +显式专利许可(第 3 节 Grant of Patent License)
专利条款无显式专利授权贡献者授予不可撤销的专利许可;若你对 Work 发起专利诉讼,该专利许可自起诉之日终止
再分发义务保留版权声明与许可声明四项义务(第 4 节):附带许可副本、修改文件需显著标注、保留版权/专利/商标/署名通知、NOTICE 文件随附
商标未涉及第 6 节明确不授予商标使用权,仅限描述作品来源的合理使用
责任限制AS IS,免除一切默示担保,作者不承担合同/侵权/其他责任AS IS(第 7 节),全面免除直接/间接/特殊/附带/后果性损害(第 8 节)
额外责任无对应条款第 9 节允许再分发者以自己名义提供担保/支持/赔偿,但必须对所有贡献者进行无过错补偿(indemnify)

从 web/LICENSE.md 第 106~127 行可以看到 Apache-2.0 的专利条款细节:各贡献者授予的专利许可仅覆盖 “其 Contribution 单独或与 Work 结合所必然侵犯的专利权利要求”,这是该条款保护下游不被贡献者专利追索的关键设计。

双许可带来的直接好处:

  • 对于只想要极简条款的用户,MIT 的三行式许可几乎零负担;
  • 对于需要明确专利保护的企业用户(例如将 Ruffle 编译进商业产品或浏览器扩展),可以改走 Apache-2.0,获得显式专利授权;
  • Ruffle 自身代码同时满足两类宽松许可(permissive license),不会与大多数主流 OSS 依赖发生传染式冲突。

二、在 Cargo workspace 中统一声明许可证

web/LICENSE.md 是 web 端(浏览器构建)的许可文件,但真正的机器可读许可声明位于 Cargo 配置中。Ruffle 在 workspace 根 Cargo.toml 第 45~51 行集中声明:

[workspace.package] authors = ["Ruffle LLC <ruffle@ruffle.rs>"] edition = "2024" homepage = "https://ruffle.rs" license = "MIT OR Apache-2.0" repository = "https://github.com/ruffle-rs/ruffle" version = "0.6.0"

关键点在于许可表达式的写法:license = "MIT OR Apache-2.0"。这里使用的是 SPDX 许可表达式语法,OR表示 “二选一”,与 web/LICENSE.md 中 “licensed under either of … at your option” 的表述严格对应。

各成员 crate 并不重复书写许可信息,而是通过 workspace 继承复用同一份声明。例如:

  • core/Cargo.toml 第 6 行:license.workspace = true
  • web/Cargo.toml 第 7 行:license.workspace = true
  • swf/Cargo.toml 第 8 行:license.workspace = true
  • desktop/Cargo.toml 第 6 行:license.workspace = true
  • render/Cargo.toml 第 6 行:license.workspace = true

这种 “workspace 统一定义、成员继承” 的模式保证几十个 crate 的许可元数据永不漂移,也是 crates.io 发布时自动识别MIT OR Apache-2.0的依据。

值得注意的是 swf/ 子目录(SWF 文件解析/写出库)额外携带了两份独立许可文件 swf/LICENSE-APACHE 与 swf/LICENSE-MIT。这种 “子目录附带 LICENSE-XXX 文件” 的布局是 MIT/Apache 双许可项目的标准做法:打包工具(cargo package、发布脚本)可以把对应文本直接放入产物中,满足 MIT “保留声明” 与 Apache-2.0 第 4(a) 条 “向接收者提供许可副本” 的义务。

三、第三方依赖许可证登记表:406 个 crate 逐条列证

web/LICENSE.md 第 218 行起是 “Third-Party Libraries” 章节,以三列表格逐条登记 Ruffle 依赖树中的第三方库:

含义
Library Namecrate 名称(多数附原始仓库链接)
License该 crate 实际采用的许可证(可多选,如 Apache-2.0/MIT 双许可)
Authors/Notes版权声明,用于再分发时保留署名

统计该表(第 224~630 行,共 406 个条目)中出现的许可证标注,可以清楚看到 Ruffle 依赖树的许可构成以宽松许可为绝对主体:

许可证标注出现次数
MIT(含 “Apache-2.0/MIT” 组合)747
Apache-2.0(含 “Apache-2.0/MIT” 组合)284
Unlicense(公共领域放弃)20
BSD-3-Clause14
Zlib12
ISC9
MPL-2.05
BSD-2-Clause4
0BSD / CC0-1.0 / BSL-1.0 / Custom ISC-style各 1~2

表中几个对 Ruffle 功能至关重要的条目值得单独说明:

  • wgpu/wgpu-core/wgpu-types:标注MPL-2.0,Copyright (c) wgpu developers——它是 Ruffle GPU 渲染管线(见 render/wgpu/)的底层,属于文件级弱 Copyleft,修改其源文件需以 MPL-2.0 发布该文件,整体项目仍保持 MIT/Apache-2.0;
  • symphonia:MPL-2.0,用于音频解码(见 video/ 模块);
  • nellymoser-rs:MIT,且备注写明其派生自 MIT 许可的 nelly2pcm 与 FFmpeg 项目——SWF 音频使用的 Nellymoser 编码,这正是 “Authors/Notes” 列保留来源说明的典型价值;
  • swf一行指向 ruffle-rs 自己的仓库,标注 Apache-2.0/MIT,与第二节中独立的 swf crate 相呼应;
  • ringwebpki两行许可证列为空(第 500、608 行)——这正是第四节中 cargo-denyclarify规则存在的原因:这类 crate 没有机器可读的 SPDX 声明,需要人工补充说明。

四、cargo-deny 策略:许可证白名单与人工澄清

表格是给人看的,deny.toml 是给 CI 机器看的。Ruffle 使用 cargo-deny 对依赖许可做强制审计,核心配置有三块:

1. 许可白名单(deny.toml 第 9~25 行):

[licenses] version = 2 # List of explicitly allowed licenses allow = [ "MIT", "Apache-2.0", "Apache-2.0 WITH LLVM-exception", "Zlib", "BSD-2-Clause", "BSD-3-Clause", "ISC", "Unicode-3.0", "MPL-2.0", "BSL-1.0", "CC0-1.0", "OFL-1.1", "Ubuntu-font-1.0", "CDLA-Permissive-2.0", "bzip2-1.0.6", ]

任何不在白名单中的许可证都会使cargo deny check licenses失败——这实际上把 web/LICENSE.md 第三部分 “Licenses of Third-Party Libraries” 收录的 0BSD、Apache-2.0、BSD-2-Clause、BSD-3-Clause、CC0-1.0、ISC、MIT、MPL-2.0、Unlicense、Zlib 十类许可全文(文件第 632~1421 行)转化成了可执行的合规边界。

2. 人工澄清条目(deny.toml 第 33~53 行):对缺少机器可读许可信息的 crate 手工指定表达式。例如 NihAV 系列(视频解复用/解码,供 FLV/视频路径使用)由作者重新以 MIT 授权,配置为:

[[licenses.clarify]] name = "nihav_core" expression = "MIT" license-files = []

ring被澄清为expression = "MIT AND ISC AND OpenSSL",并校验其 LICENSE 文件哈希{ path = "LICENSE", hash = 0xbd0eed23 }——哈希校验保证 “人工声明的许可” 与上游文件内容一致,防止上游悄悄更换许可证而 CI 无感知。

3. 依赖来源管控(deny.toml 第 75~87 行):

[sources] unknown-registry = "deny" unknown-git = "deny" [sources.allow-org] # github.com organizations to allow git sources for github = [ "ruffle-rs", ]

即所有依赖必须来自 crates.io 官方 registry,git 源只允许 ruffle-rs 官方组织。许可合规与供应链安全在此合一。

五、各许可证再分发义务速查(以 web/LICENSE.md 收录文本为准)

web/LICENSE.md 第 632 行之后收录了十类第三方许可证的全文,它们也是使用者再分发 Ruffle 相关代码时最直接的义务清单:

许可证文件锚点核心再分发义务
MITweb/LICENSE.md所有副本或实质部分须包含版权声明与许可声明
Apache-2.0web/LICENSE.md提供许可副本、修改处显著标注、保留各类通知、NOTICE 随附
BSD-2-Clauseweb/LICENSE.md源码形式保留声明;二进制形式在文档/材料中复现声明
BSD-3-Clauseweb/LICENSE.md在 BSD-2 基础上增加第 3 条:未经书面许可不得用版权方名义为衍生产品背书/宣传
0BSDweb/LICENSE.md无任何条件,仅免责声明
CC0-1.0web/LICENSE.md版权及相关权利放弃进入公共领域;含公共许可回退条款(第 3 节)与商标/专利不豁免条款
ISCweb/LICENSE.md全部副本中保留版权与许可声明
MPL-2.0web/LICENSE.md源形式分发须告知接收者许可条款(3.1 节);可执行形式须能以不高于分发成本的方式提供源码(3.2 节);不得删改许可通知(3.4 节);附 Exhibit A 标准声明
Unlicenseweb/LICENSE.md无义务,版权明示献予公共领域
Zlibweb/LICENSE.md不得歪曲来源;修改版须显著标记;源分发不得移除本声明

其中 MPL-2.0 与 Apache-2.0 是最值得细读的两类:前者第 5 节规定了违规后权利自动终止与 30/60 天通知后的恢复机制,后者第 3 节专利许可的终止条件是 “对 Work 提起专利侵权诉讼”。这两段直接决定了下游商业用户在何种情形下会丧失使用资格。

六、集成 Ruffle 时的合规实操清单

综合 web/LICENSE.md、Cargo.toml 与 deny.toml,将 Ruffle 相关代码纳入自己项目时的可执行步骤:

  1. 选定许可轨道:使用 Ruffle 代码(含 core/、swf/、render/ 等 crate)时,在文档中明确你走 MIT 还是 Apache-2.0;二者义务差异很小,但需要专利保护时选 Apache-2.0。
  2. 保留声明:保留所有被修改文件的版权/许可头;发布二进制时在产品文档或随附 LICENSE 中放入对应许可全文(可参照 swf/LICENSE-APACHE、swf/LICENSE-MIT 的 “LICENSE-后缀” 命名惯例)。
  3. NOTICE 随附:若分发的 Work 中包含 NOTICE 文件,按 Apache-2.0 第 4(d) 条将相关归属通知放入衍生作品的 NOTICE、源文档或界面中。
  4. 依赖许可核查:在自己的仓库复制 deny.toml 的[licenses]/[sources]配置段,运行cargo deny check,把依赖许可白名单纳入 CI;对ring这类无机器可读声明的 crate 使用[[licenses.clarify]]补全并校验文件哈希。
  5. 尊重特殊授权:例如 NihAV 相关 crate 是作者 “kindly relicensed for us under MIT”(见 deny.toml 第 31~32 行注释),此类特例的许可以澄清条目为准,不要直接采用上游声明。
  6. 商标边界:Apache-2.0 第 6 节不授予 “Ruffle” 名称/商标的使用权,仅限描述作品来源的合理使用——再分发时不要暗示官方背书。

七、小结

web/LICENSE.md 虽然位于 web 子目录下,但它实际上承载了 Ruffle 项目三层合规信息:面向使用者的MIT OR Apache-2.0 双许可全文(第 1~216 行)、面向审计者的406 条第三方依赖许可登记表(第 218~630 行)、面向再分发者的十类第三方许可证全文(第 632~1421 行)。它与 Cargo.toml 中 workspace 级的license = "MIT OR Apache-2.0"声明、各 crate 的license.workspace = true继承,以及 deny.toml 的白名单/澄清/来源管控共同构成了一个 “声明—登记—机器校验” 闭环,是 Rust 生态大型项目中依赖许可治理的完整范本。

【免费下载链接】ruffleA Flash Player emulator written in Rust项目地址: https://gitcode.com/GitHub_Trending/ru/ruffle

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/13 14:55:09

Spring Cloud服务连不上Redis和数据库?整套排查思路与实战复盘

Spring Cloud 服务突然连不上 Redis 和数据库&#xff1f;这套排查思路送给你前两周我这边一套 Spring Cloud 微服务在下午高峰期突然开始连环报错&#xff0c;日志里同时出现 Redis 连接失败、MyBatisSystemException、Failed to obtain JDBC Connection 三兄弟&#xff0c;新…

作者头像 李华
网站建设 2026/9/13 14:54:04

某度翻译Acs-Token算法逆向分析与安全机制解析

1. Acs-Token算法背景与应用场景某度翻译作为国内领先的机器翻译服务提供商&#xff0c;其API接口采用了名为Acs-Token的安全验证机制。这种算法本质上是一种动态签名技术&#xff0c;主要用于&#xff1a;防止未授权调用翻译API限制接口滥用和恶意爬取实现请求来源的身份验证保…

作者头像 李华
网站建设 2026/9/13 14:51:14

LeetCode-Go 题解 18. 4Sum:三种去重方案实现四数之和

LeetCode-Go 题解 18. 4Sum&#xff1a;三种去重方案实现四数之和 【免费下载链接】LeetCode-Go ✅ Solutions to LeetCode by Go, 100% test coverage, runtime beats 100% | LeetCode 题解 项目地址: https://gitcode.com/GitHub_Trending/le/LeetCode-Go 本篇文章以 …

作者头像 李华
网站建设 2026/9/13 14:50:43

Gleam 编译器版本发布全流程指南:从版本号更新到 CI 自动发布

Gleam 编译器版本发布全流程指南&#xff1a;从版本号更新到 CI 自动发布 【免费下载链接】gleam ⭐️ A friendly language for building type-safe, scalable systems! 项目地址: https://gitcode.com/GitHub_Trending/gl/gleam 本篇指南围绕 Gleam 编译器仓库根目录下…

作者头像 李华
网站建设 2026/9/13 14:49:54

RoboMaster硬件实战:PCB设计、调试与嘉立创EDA工程落地

1. 这份讲义不是“教材”&#xff0c;而是电控组新人上手前必须拆开的三块电路板你拿到《Robomaster硬件基础讲义V0.2.1》时&#xff0c;大概率正坐在实验室长桌前&#xff0c;面前摆着一块刚焊完但没亮灯的主控板&#xff0c;旁边是半盒散落的0402电阻和一卷被烫弯的杜邦线。讲…

作者头像 李华