☰
Liam 开源依赖许可证审计:LicenseFinder 报告、决策机制与许可证兼容性实践
2026/10/13 2:15:35 网站建设 项目流程
  • 数据可视化
  • 数据库
  • 前端
  • CLI

【免费下载链接】liam

Automatically generates beautiful and easy-to-read ER diagrams from your database.

项目地址:https://gitcode.com/GitHub_Trending/li/liam
点击查看免费下载

在依赖动辄上千个的 JavaScript Monorepo 中,如何系统性地核查每一个第三方包的开源许可证,并保证它们与项目自身的 Apache-2.0 许可证兼容,是每个开源团队都要面对的合规问题。Liam(一个“从数据库自动生成 ER 图”的开源项目)在仓库中维护了一份由 LicenseFinder 自动生成的依赖许可证审计报告 docs/packages-license.md,并配套了 config/license_finder.yml 与 config/dependency_decisions.yml 两份决策配置。读完本文,你将理解这份报告的结构与生成方式、permit/approve两类人工决策的差异、以及项目如何为误检许可证、Public Domain、GPL 家族依赖等边界情况建立可追溯的例外记录。

审计基线:Liam 自身是 Apache-2.0 项目

一切许可证兼容性判断的出发点,是项目自身的许可证。仓库根目录的 LICENSE 文件完整收录了 Apache License Version 2.0 的条款,版权方为 ROUTE06, Inc.(2024)。README.md 中的 License 章节也明确声明:

Liam ERD is licensed under the Apache License Version 2.0. Licenses for third-party packages can be found in docs/packages-license.md.

这意味着两件事:

  1. 兼容性基线是 Apache-2.0。所有第三方依赖的许可证必须能与 Apache-2.0 共存。宽松型许可证(MIT、ISC、BSD 系列、Unlicense、CC0 等)天然兼容,而强 Copyleft(如 GPL)则需要特别评估——这一点在下面的“边界情况”一节有实例。
  2. 依赖许可证清单是一份正式的仓库文档,直接放在docs/目录下并由 README 链接引用,供使用者与下游项目在引入 Liam 时做合规核查。

审计报告的构成:Summary 与逐包 Items

docs/packages-license.md 是一份约 1.9 万行的机器生成报告,由两大块组成。

Summary:许可证分布总览

报告开头的 Summary 小节按许可证名称聚合了全部被审计依赖的数量,当前快照为:

许可证依赖数量
MIT1414
Apache 2.0131
ISC85
New BSD40
Simplified BSD25
Mozilla Public License 2.08
BlueOak-1.0.05
CC0 1.0 Universal4
Unknown3
MIT OR Apache-2.02
The Unlicense2
MIT-01
LGPL-3.0-or-later1
Apache-2.0 AND MIT1
Python-2.01
CC-BY-4.01
Artistic-2.01
Eclipse 2.01
Public Domain1
(MIT AND Zlib)1
(BSD-2-Clause OR MIT OR Apache-2.0)1
(MIT AND BSD-3-Clause)1
CC-BY-3.01
BSD Zero Clause License1
(MIT OR CC0-1.0)1

从分布可以直观读出项目的依赖生态画像:MIT 占绝对多数(1414 个),其次是 Apache 2.0 与 ISC,其余为零星的双许可证(如MIT OR Apache-2.0)、公共领域类(CC0、Unlicense、Public Domain)以及少数需要人工介入的条目(Unknown、Python-2.0、LGPL-3.0-or-later)。表格中所有许可证均为宽松型(permissive)许可或与 Apache-2.0 共存的许可,Unknown仅 3 个且全部有对应的人工批准记录——这正体现了决策机制兜底的作用。

Items:逐包明细的固定格式

Summary 之后是 Items 部分,按包名排序逐个列出。每个条目格式固定,例如报告中zod的条目:

<a name="zod"></a> ### zod v3.25.76 #### ##### Paths * /home/runner/work/liam/liam MIT permitted

各部分含义:

  • ### <包名> v<版本>:被审计的依赖及其精确版本。同一包可能出现多个版本(如yallist v3.1.1与yallist v5.0.0并存),因为它们来自 workspace 中不同子包的依赖链。

  • ##### Paths:该依赖被引入的仓库路径。报告中统一为/home/runner/work/liam/liam,这是 CI 环境(GitHub Actions runner)中的工作目录,即本次审计扫描的是整个仓库根目录。

  • <许可证> permitted:自动判定结果——该许可证在“允许列表”中,无需人工干预。

  • <许可证> manually approved:未进入自动允许列表,由人工批准(approve),并附带一段引用说明与批准人、时间,例如argparse v2.0.1的条目:

    ### argparse v2.0.1 ##### Paths * /home/runner/work/liam/liam Python-2.0 manually approved >Python 2.0 license is compatible with Apache-2.0. But License Finder does >not support the name "Python-2.0". ><cite> OSPO @masutaka 2024-11-28</cite>

这份报告是静态产物:当pnpm-lock.yaml变化、依赖版本更新后,重新运行 LicenseFinder 即可重新生成,从而保证清单与锁文件一致。

配置侧的真相:license_finder.yml 与 dependency_decisions.yml

报告只是“输出”,真正定义审计规则的是config/下的两份文件。

config/license_finder.yml:工具行为配置

--- decisions_file: 'config/dependency_decisions.yml' enabled_package_managers: - pnpm

内容极简但信息量完整:

  • decisions_file指定决策记录文件的相对路径(相对于仓库根目录);
  • enabled_package_managers只启用pnpm——与仓库的实际情况一致:根目录 package.json 声明"packageManager": "pnpm@10.18.3",pnpm-workspace.yaml 将 workspace 包定义为frontend/apps/*、frontend/packages/*、frontend/packages/__mocks__/*、frontend/internal-packages/*。LicenseFinder 只解析 pnpm 的锁文件与依赖树,避免重复或漏检。

config/dependency_decisions.yml:人工决策台账

这份文件是许可证审计的“治理中枢”,当前包含 22 条记录,每条记录的结构为:

- - :permit # 动作:permit(许可证级)或 approve(包级) - MIT # 针对的许可证名或包名 - :who: OSPO @masutaka # 决策人 :why: Compatible with Apache-2.0 license. # 决策理由 :versions: [] # 限定的版本列表;[] 表示该包的所有版本 :when: 2024-11-22 08:47:26.167960000 Z # 决策时间

两类动作有本质区别:

动作作用对象语义典型场景
permit一种许可证该许可证下任何包、任何版本都视为可接受MIT、Apache 2.0、ISC、BSD 各条款、Unlicense、CC0 1.0 Universal、Mozilla Public License 2.0、Eclipse 2.0、LGPL-3.0-or-later、Zlib、Artistic-2.0、CC-BY-3.0、CC-BY-4.0、MIT-0 等
approve某个具体包(可限定版本)该包被点名批准,记录理由与版本范围工具误检或许可证名无法识别的个例

permit决策的理由高度一致:几乎每一条:why都是 "Compatible with Apache-2.0 license." 的变体,并附上许可证的官方说明出处——这正是“审计基线为 Apache-2.0”这一原则在配置层的落地。值得注意的是:versions: []表示不限版本,与approve中显式列出versions: [2.0.1]的写法形成对照:许可证级豁免是全局的,而包级批准往往只针对出问题的特定版本。

人工批准实例:工具误检的四种典型处理

config/dependency_decisions.yml 中的approve记录,对应报告 Items 部分的 4 处manually approved条目。逐个复盘,能看清 LicenseFinder 这类自动化工具的能力边界与正确的人工兜底方式。

1.argparse v2.0.1:许可证名不被工具识别

Python 的argparse2.x 采用 "Python Software Foundation License"(报告中记为 Python-2.0)。LicenseFinder 不认识这个许可证名称(:why字段引用了上游 LicenseFinder 的一个 pull request 佐证),于是审计会失败。处理方式:对该包approve,理由写明 "Python 2.0 license is compatible with Apache-2.0"。同一个包名下argparse v1.0.10是 MIT,仍走自动permitted通道——同一包不同版本可以走完全不同的判定路径,这就是版本级approve的价值。

2.jsonify v0.0.1:Public Domain 不是软件许可证

jsonify标记为 Public Domain,但 Public Domain 是权利放弃声明而非 SPDX 意义上的软件许可证,工具无法自动放行。决策记录写明 "Public Domain is compatible with Apache-2.0. But it is not a software license",并附了一条项目 issue 链接作为决策背景。人工批准解决。

3.spawndamnit v3.0.1:许可证字段写法导致误检

该包实际是 MIT,但license字段写成SEE LICENSE IN LICENSE这类间接指代,工具无法解析出实际许可证,报告中标记为Unknown manually approved。approve理由直接说明 "Its license is MIT, but it is mis-detected"。这类Unknown条目是审计时必须逐个清零的红项,任何一条无解释的 Unknown 都意味着合规盲区。

4.@browserbasehq/sdk与@vercel/gatsby-plugin-vercel-builder:Apache-2.0 却没被识别出来

这两个包的许可证就是Apache-2.0,但工具未能从包元数据中提取到(报告中均显示Unknown manually approved)。决策记录分别为 "The license is Apache-2.0. License Finder failed to identify the license." 与 "The license is Apache-2.0."。此外url-template v2.0.8也有一条approve:该包使用 BSD-3-Clause,但 2.0.8 版本的许可证标注错误(:why字段引用了上游的修复 PR),属于上游元数据错误导致的误检,同样以版本级批准兜底。

五个案例覆盖了自动审计的主要失败模式:许可证名缺失、非软件许可声明、间接指代、元数据标注错误。处理原则始终一致——人工判定实际许可证、记录理由与出处、限定影响范围(版本),让每一次例外都可追溯。

边界情况:Copyleft 与宽松许可的混排

Summary 中还有几个值得单独讨论的条目。

LGPL-3.0-or-later:对应@img/sharp-libvips-linux-x64(sharp 的 libvips 预编译二进制),这是报告中唯一一条 GPL 家族依赖。决策文件对LGPL-3.0-or-later做了permit,理由同样是 "Compatible with Apache-2.0 license"。需要注意其适用前提:LGPL 是弱 Copyleft,其约束主要针对对 LGPL 代码本身的修改与再分发;作为独立动态/预编译二进制被依赖时,与 Apache-2.0 项目共存的合规风险远低于 AGPL/GPL。团队以permit形式把这一判断固化进了配置,属于“人工评估后放行”而非“工具自动放行”。

双/多许可证条目:MIT OR Apache-2.0(2 个)、Apache-2.0 AND MIT(1 个)、(BSD-2-Clause OR MIT OR Apache-2.0)、(MIT AND BSD-3-Clause)、(MIT OR CC0-1.0)、(MIT AND Zlib)等。OR表示下游可任选其一(实践中选 MIT/Apache-2.0 即可),AND表示需同时满足两份条款(所列组合均相互兼容且宽松)。这类条目的存在提醒:许可证字符串本身可能是 SPDX 表达式,审计时不能只按“名字”匹配,必须理解表达式语义。

The Unlicense / CC0 1.0 Universal:两者都是公共领域奉献工具,对 Apache-2.0 完全兼容,报告中分别出现 2 个和 4 个依赖,配置里也都有对应permit。

版本并存:同一包名出现多行(如yallist同时有 v3.1.1 与 v5.0.0)是因为 pnpm workspace 下不同子包声明了不同版本区间。审计以“包名+版本”为最小单位,这正是 Monorepo 场景下依赖清单与单包项目最大的不同——它天然容纳了版本分叉。

如何阅读与使用这份审计报告

对不同类型的读者,docs/packages-license.md 的使用方式不同:

  1. 使用者/下游项目:若你的产品集成了 Liam(例如使用@liam-hq/cli),这份报告告诉你 Liam 的依赖树中不存在 GPL/AGPL 等强 Copyleft 许可证,且所有例外都有书面决策依据。结合 LICENSE(Apache-2.0)即可做出引入决策。
  2. 贡献者:当你升级或新增依赖后,如果报告重新生成出现新的 Unknown 或不在permit列表中的许可证,你需要按既有格式向 config/dependency_decisions.yml 追加一条:permit(新许可证)或:approve(个例包),:who、:why、:versions、:when四要素缺一不可。
  3. 合规审查者:manually approved的引用块(含决策人、日期、理由)就是审计证据链。当前报告中恰好 3 条Unknown(@browserbasehq/sdk、@vercel/gatsby-plugin-vercel-builder、spawndamnit)加上 2 条有名字的例外(Python-2.0、Public Domain),每一条都能在决策文件中找到一一对应的记录,无悬空项。

小结

Liam 的依赖许可证审计方案可以概括为三层:

  • 声明层:LICENSE 确立 Apache-2.0 基线,README.md 把报告作为正式文档链接出去;
  • 配置层:config/license_finder.yml 限定 LicenseFinder 只审计 pnpm 依赖树;config/dependency_decisions.yml 以permit(许可证级、不限版本)与approve(包级、可限定版本)两类带署名的决策记录,把“兼容性判断”变成可复核的数据;
  • 报告层:docs/packages-license.md 以 25 种许可证分类的 Summary + 逐包 Items 明细呈现结果,permitted/manually approved两种状态让任何一条依赖的合规来源都能一眼追溯。

这套“自动审计 + 人工决策台账 + 全量报告”的组合,对任何以宽松许可证发布、依赖规模上千的 Monorepo 项目都具备直接可复用的参考价值:先明确自己的许可证基线,再让工具做全量扫描,最后用一份结构化的决策文件把所有例外钉死在证据链上。

  • 数据可视化
  • 数据库
  • 前端
  • CLI

【免费下载链接】liam

Automatically generates beautiful and easy-to-read ER diagrams from your database.

项目地址:https://gitcode.com/GitHub_Trending/li/liam
点击查看免费下载

相关推荐

上一篇:DataLink数据连接神器:高效数据交换的终极解决方案
下一篇:如何快速搭建智能在线考试系统?学之思开源平台完整指南

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询