2. 许可证识别基础

在开源合规工作中,许可证识别不是“看一眼 LICENSE 文件”这么简单。一个真实项目里,许可证信息可能分散在仓库根目录、子模块、包管理器元数据、源文件头注释、构建脚本甚至文档中,而且不同位置的信息可能互相矛盾。本节的目标是建立一套可复用的定位与验证方法:先知道去哪里找,再知道怎么读,最后知道如何判断“这个标识符是否可信”。

一、许可证信息的四个主要来源

从工程实践看,许可证信息通常出现在以下四类位置,它们的权威性和用途各不相同。

  • 仓库根目录的许可证文件:最常见的是 LICENSE、LICENSE.txt、LICENSE.md、COPYING、COPYING.LESSER。这是项目整体授权声明的主要载体,通常包含完整许可证正文。
  • 包管理器元数据:如 npm 的 package.json 中的 license 字段、Python 的 pyproject.toml 或 setup.py 中的 license、Maven 的 pom.xml 中的 <licenses>、Rust 的 Cargo.toml 中的 license 字段。这些字段通常使用 SPDX 标识符,便于机器读取。
  • 源文件头部的版权与许可声明:例如 /* SPDX-License-Identifier: MIT */ 或 // Copyright 2023 Example Corp. Licensed under Apache-2.0.。这类声明粒度最细,能反映单个文件的授权情况。
  • 项目文档与 README:README 中常出现“本项目采用 MIT 许可证”等描述,但它是叙述性文字,权威性低于 LICENSE 文件和 SPDX 标识符,只能作为线索。
识别顺序建议:先看包管理器元数据中的 SPDX 标识符,再核对仓库根目录的 LICENSE 正文,最后抽查源文件头声明是否一致。三者一致时可信度最高。

二、SPDX 标识符的读取与验证

SPDX(Software Package Data Exchange)标识符是许可证的“标准缩写”,例如 MIT、Apache-2.0、GPL-3.0-only、BSD-3-Clause、MPL-2.0。它的价值在于消除歧义:同样是“GPL”,GPL-2.0-only、GPL-2.0-or-later、GPL-3.0-only 的法律含义完全不同。

读取 SPDX 标识符时,要特别注意以下几种写法:

  • 带 -only 与 -or-later:GPL-2.0-only 表示仅限该版本;GPL-2.0-or-later 表示可使用该版本或任何后续版本。后者对使用者更宽松,但合规义务的版本选择需要明确。
  • 带 + 的旧式写法:如 GPL-2.0+,在 SPDX 中应规范化为 GPL-2.0-or-later。
  • 复合表达式:如 MIT OR Apache-2.0、Apache-2.0 AND MIT、GPL-2.0-only WITH Classpath-exception-2.0。这里的 OR、AND、WITH 是逻辑运算符,含义不同:OR 表示可任选其一,AND 表示需同时满足,WITH 表示附加例外条款。
  • 非标准写法:如 MIT License、Apache 2、GPLv3。这些不是合法 SPDX 标识符,需要人工映射到标准标识符后再判断。

验证 SPDX 标识符是否有效,可以对照 SPDX 官方许可证列表。一个实用的检查流程是:先确认标识符是否在官方列表中;再确认表达式语法是否正确;最后确认该标识符与 LICENSE 正文是否匹配。例如,元数据写 MIT,但 LICENSE 文件正文是 Apache-2.0 的完整条款,这就属于典型的不一致,需要以 LICENSE 正文为准并进一步排查。

三、OSI 认证与“开源”判断

OSI(Open Source Initiative)维护着开源定义(OSD)并认证许可证。看到某个许可证名称时,不要默认它就是 OSI 认证的开源许可证。例如,SSPL、BSL 等常被误认为开源,但它们并未通过 OSI 认证,商业使用限制明显。判断一个许可证是否属于 OSI 认证,应查询 OSI 官方许可证列表,而不是依赖项目自我描述。

需要区分三个层次:OSI 认证说明该许可证符合开源定义;SPDX 收录说明该许可证有标准标识符,便于机器处理;FSF 自由许可证则从自由软件角度评估。三者有交集但不完全等同。合规判断中,通常以 SPDX 标识符作为机器可读入口,以 OSI 认证状态作为“是否开源”的初步依据,再结合具体条款评估商业使用风险。

四、定位与验证的实操路径

下面给出一条可直接执行的检查路径,适用于对一个新引入的依赖或代码仓库做许可证识别。

  1. 在仓库根目录查找 LICENSE*、COPYING* 文件,记录文件名与正文首行。
  2. 打开包管理器元数据,提取 license 或 licenses 字段,记录原始字符串。
  3. 随机抽取 3~5 个源文件,查看头部是否有 SPDX-License-Identifier 或版权声明。
  4. 将元数据中的标识符与 LICENSE 正文比对,确认是否一致。
  5. 若标识符为复合表达式,拆解 OR/AND/WITH 结构,明确可选路径与附加义务。
  6. 查询 SPDX 与 OSI 官方列表,确认标识符合法性与开源认证状态。
  7. 记录不一致项、缺失项和待确认项,形成初步识别结论。

例如,某 npm 包的 package.json 中写 "license": "MIT",仓库根目录存在 LICENSE 文件,正文为 MIT 标准条款,源文件头部有 SPDX-License-Identifier: MIT。三者一致,可初步判定为 MIT。若元数据写 "license": "GPL-3.0",而 LICENSE 正文是 GPL-3.0 完整文本,但源文件头写 SPDX-License-Identifier: GPL-2.0-only,则存在版本冲突,需要进一步确认项目实际授权意图,不能直接按元数据下结论。

许可证信息定位与验证关系图 仓库根目录 LICENSE / COPYING 完整许可证正文 包管理器元数据 package.json / pom.xml SPDX 标识符字段 源文件头声明 SPDX-License-Identifier 单文件粒度授权 README / 文档 叙述性许可描述 仅作线索,权威性低 提取原始许可证字符串 记录来源位置与原文,不做主观改写 SPDX 规范化与表达式解析 -only / -or-later / OR / AND / WITH SPDX 官方列表校验 标识符是否存在、语法是否合法 与 LICENSE 正文是否匹配 OSI 认证状态查询 是否通过 OSI 认证 是否属于开源许可证 形成识别结论与待确认项 一致 / 冲突 / 缺失 / 需人工复核

五、常见不一致与处理原则

实际项目中最容易出问题的是“元数据与正文不一致”。常见情形包括:元数据写 MIT,LICENSE 正文却是 BSD-3-Clause;元数据写 Apache-2.0,但源文件头写 GPL-2.0-only;元数据写 ISC,仓库中根本没有 LICENSE 文件。处理原则是:以更具体、更正式的授权文本为准,同时记录冲突。LICENSE 正文通常比元数据字段更正式;源文件头声明在涉及单文件授权时具有独立意义。若冲突无法通过项目文档解释,应视为高风险项,进入人工复核。

不要仅凭 README 中的“本项目使用 MIT 许可证”就下结论。README 是叙述性材料,可能过时或与 LICENSE 正文不一致。合规判断应以 LICENSE 正文和 SPDX 标识符为主要依据。

六、识别记录表示例

为了让识别结果可追溯,建议对每个依赖或仓库维护一份简表。以下为示例结构,字段可根据团队需要增减。

检查项 示例值 判断要点
仓库 LICENSE 文件 LICENSE(MIT 正文) 是否存在、正文首行是否可识别
包管理器 license 字段 "license": "MIT" 是否为合法 SPDX 标识符
源文件头 SPDX SPDX-License-Identifier: MIT 抽查文件是否一致
SPDX 表达式 MIT OR Apache-2.0 拆解 OR/AND/WITH 结构
OSI 认证 是 查询 OSI 官方列表确认
一致性结论 一致 一致 / 冲突 / 缺失 / 待复核

完成上述定位与验证后,你得到的不只是一个许可证名称,而是一条可追溯的证据链:信息来自哪里、原始字符串是什么、是否经过 SPDX 规范化、是否通过 OSI 认证、是否存在冲突。这条证据链是后续商业使用风险判断的基础。下一阶段的工作,才是基于这些识别结果去分析具体义务与风险。