go-licenses不能直接判断GPL冲突,它仅提取许可证声明(如GPL-3.0、MIT)并原样输出,不进行兼容性推理;合规判定需人工或额外规则引擎基于实际LICENSE文件、源码注释等可信来源完成。

go-licenses 能否直接判断 GPL 冲突?
go-licenses 本身不进行许可证兼容性推理,它只做事实性提取:从模块的 go.mod、go.sum、源码注释、LICENSE 文件中读取声明的许可证文本或标识符(如 GPL-3.0、MIT),然后原样输出。它不会自动告诉你 github.com/some/pkg 的 GPLv3 是否与你项目的 Apache-2.0 不兼容。
所以别指望运行完 go-licenses save 就能拿到“合规/不合规”红绿灯结果。它给的是原材料——一份带来源路径和许可证字符串的清单,后续分析得靠人或额外规则引擎。
- 它可能把
License: GPL-3.0解析成GPL-3.0,但也可能只抓到模糊字段如License: See LICENSE,这时得手动打开对应文件确认 - 某些模块没声明许可证,
go-licenses会标为Unknown,不能默认为“可自由用”,反而要重点核查 - 如果模块用了
replace指向私有 fork,go-licenses默认不会去扫描那个 fork 的 LICENSE,除非你把它也作为独立模块传入
go list -m all 输出的 License 字段可靠吗?
不可靠,基本不能信。
go list -m -json all 返回的 JSON 中确实有 License 字段,但 Go 官方明确说明:这个字段是模块作者**自行填写**的,无校验、无规范、无强制格式。现实中常见情况包括:
立即学习“go语言免费学习笔记(深入)”;
- 填空:
"License": "" - 乱填:
"License": "Free to use"或"License": "MIT or Apache"(这不是有效 SPDX ID) - 过时:
go.mod里写的是MIT,但实际 LICENSE 文件早已换成AGPL-3.0
因此,仅依赖 go list 的 License 字段做合规决策,等于拿一张手写的便签当法律文书。真正可信的来源只有:模块根目录的 LICENSE / LICENSE.md 文件内容、源码头部注释、或其上游发布页(如 GitHub tag 页面)明确标注的许可证。
如何定位某个 GPL 模块是否被实际编译进二进制?
很多团队误以为“只要没在 import 语句里写它,就不算使用”。错。间接依赖一样构成法律意义上的“分发”行为,尤其当它被链接进最终可执行文件时。
验证是否真被编译进去,最轻量的方式是检查符号表:
go build -o myapp .<br>nm myapp | grep 'some_gpl_symbol' | head -5
更稳妥的做法是结合 go mod graph 和 go mod why:
-
go mod graph | grep gpl-module-name看它被谁引入 -
go mod why -m gpl-module-name看 import 链是否真实存在(返回main开头路径才表示被主模块路径触发) - 若
go mod why返回(main module does not need this module),说明它只是indirect且未被任何活跃 import 触达,理论上可安全剔除(用go mod tidy)
注意:静态链接的 C 依赖(如 CGO 调用的 GPL 库)无法通过 Go 工具链检测,必须人工审查 build/cgo 相关代码和链接参数。
CI 流程中该拦截哪些许可证?
别一刀切禁所有 GPL。要分场景:
- 内部工具类 CLI:用
GPL-3.0通常无风险,只要不对外分发二进制,就不触发“传染性”条款 - SaaS 服务端:多数法务接受
GPL-2.0及以上,因 SaaS 不属于“分发”,但AGPL-3.0明确覆盖网络服务,必须规避 - 闭源商业产品 SDK:禁止一切
GPL、AGPL、SSPL、CPAL,MIT/Apache-2.0 是底线
CI 脚本里建议用 go-licenses csv 导出后,用 awk 或短脚本过滤高危项:
go-licenses csv . | awk -F, '$3 ~ /AGPL|SSPL|CPAL|GPL.*3\.0/ {print $1,$3}'
真正容易被忽略的是:某些模块许可证在小版本升级中变更(比如 v1.2.0 是 MIT,v1.3.0 改成 MPL-2.0)。所以 go.sum 锁定的版本号,必须和许可证扫描结果严格绑定,不能只扫 latest。


















