开源许可证合规Skill license-compliance

本技能提供开源许可证合规的全面指导,涵盖许可证兼容性分析、义务跟踪和合规工作流,帮助开发者和组织在软件开发中确保遵守开源许可证规定,适用于依赖评估、政策制定和合规实施。关键词:开源许可证、合规、兼容性分析、义务跟踪、工作流、软件开发、许可证管理。

合规管理 0 次安装 1 次浏览 更新于 3/11/2026

name: license-compliance description: 开源许可证合规,包括兼容性分析、义务跟踪和合规工作流 allowed-tools: Read, Glob, Grep, Write, Edit, Task

开源许可证合规

在开发前后提供开源许可证合规的全面指导。

何时使用此技能

  • 为新项目评估开源依赖项
  • 检查包之间的许可证兼容性
  • 理解分发义务
  • 创建归属声明和NOTICES文件
  • 为您的组织建立许可证政策

许可证类别

宽松许可证

允许使用、修改和分发,限制最少。

许可证 义务 商业使用 专利授权
MIT 归属
BSD-2-Clause 归属
BSD-3-Clause 归属,无背书
Apache-2.0 归属,声明变更,NOTICE文件
ISC 归属

Copyleft许可证

要求衍生作品使用相同许可证。

许可证 Copyleft范围 SaaS触发 分发义务
GPL-2.0 源代码披露
GPL-3.0 源代码披露,反Tivo化
LGPL-2.1 弱(库) 库源代码,允许链接
AGPL-3.0 强 + 网络 网络使用时源代码披露
MPL-2.0 文件级 修改文件源代码
EPL-2.0 模块级 修改模块源代码

弱Copyleft vs 强Copyleft

强Copyleft (GPL):
┌──────────────────────────────────────────┐
│  您的应用程序(变为GPL)          │
│  ┌──────────────────────────────────┐   │
│  │  GPL库(链接/包含)   │
│  └──────────────────────────────────┘   │
└──────────────────────────────────────────┘

弱Copyleft (LGPL):
┌──────────────────────────────────────────┐
│  您的应用程序(任何许可证)          │
│  ↓ 动态链接                          │
│  ┌──────────────────────────────────┐   │
│  │  LGPL库(保持LGPL)     │
│  └──────────────────────────────────┘   │
└──────────────────────────────────────────┘

许可证兼容性

兼容性矩阵

输入许可证 → 输出许可证兼容性

FROM ↓ / TO →  | MIT | Apache | BSD | LGPL | MPL | GPL | AGPL
---------------|-----|--------|-----|------|-----|-----|------
MIT            |  ✓  |   ✓    |  ✓  |  ✓   |  ✓  |  ✓  |  ✓
Apache-2.0     |  ✗  |   ✓    |  ✗  |  ✓   |  ✓  |  ✓* |  ✓*
BSD-3-Clause   |  ✓  |   ✓    |  ✓  |  ✓   |  ✓  |  ✓  |  ✓
LGPL-2.1       |  ✗  |   ✗    |  ✗  |  ✓   |  ✗  |  ✓  |  ✓
MPL-2.0        |  ✗  |   ✗    |  ✗  |  ✗   |  ✓  |  ✓  |  ✓
GPL-2.0        |  ✗  |   ✗    |  ✗  |  ✗   |  ✗  |  ✓  |  ✗
GPL-3.0        |  ✗  |   ✗    |  ✗  |  ✗   |  ✗  |  ✓  |  ✓
AGPL-3.0       |  ✗  |   ✗    |  ✗  |  ✗   |  ✗  |  ✗  |  ✓

✓ = 兼容,✗ = 不兼容
* 仅GPL-3.0(Apache-2.0与GPL-2.0不兼容)

常见兼容性问题

问题 示例 解决方案
GPL + 专有 在闭源中使用GPL库 使用LGPL替代或开源
Apache + GPL-2.0 结合Apache-2.0与GPL-2.0 升级到GPL-3.0
AGPL + SaaS 在Web服务中使用AGPL 开源您的代码或使用替代
冲突Copyleft 同一二进制中GPL + EPL 分离为不同程序

按用例的义务分析

仅内部使用

许可证类型 义务 需要跟踪
宽松 最小
弱Copyleft 最小
强Copyleft 无(无分发) 最小
AGPL 网络服务时源代码可用

分发(桌面/移动)

许可证类型 义务
MIT, BSD, ISC 在分发中包含许可证/版权
Apache-2.0 包含许可证、NOTICE文件、声明变更
LGPL 提供库源代码,允许重新链接
GPL 提供完整源代码
MPL 提供修改文件源代码

SaaS(无二进制分发)

许可证类型 义务
宽松 无(无分发)
GPL, LGPL 无(无分发)
AGPL 必须向用户提供源代码

许可证合规实施

.NET依赖分析

// 许可证扫描集成
public class LicenseComplianceChecker
{
    private readonly IPackageMetadataProvider _packageProvider;
    private readonly LicensePolicy _policy;

    public async Task<ComplianceReport> AnalyzeProject(
        string projectPath,
        CancellationToken ct)
    {
        var packages = await _packageProvider.GetPackages(projectPath, ct);
        var report = new ComplianceReport();

        foreach (var package in packages)
        {
            var license = await _packageProvider.GetLicense(package, ct);

            var evaluation = _policy.Evaluate(license);

            report.Packages.Add(new PackageLicenseInfo
            {
                PackageId = package.Id,
                Version = package.Version,
                License = license.SpdxIdentifier,
                LicenseUrl = license.Url,
                Category = license.Category,
                Status = evaluation.Status,
                Obligations = evaluation.Obligations,
                Issues = evaluation.Issues
            });
        }

        return report;
    }
}

public class LicensePolicy
{
    private readonly HashSet<string> _approved = new()
    {
        "MIT", "Apache-2.0", "BSD-2-Clause", "BSD-3-Clause", "ISC"
    };

    private readonly HashSet<string> _requiresReview = new()
    {
        "LGPL-2.1", "LGPL-3.0", "MPL-2.0", "EPL-2.0"
    };

    private readonly HashSet<string> _prohibited = new()
    {
        "GPL-2.0", "GPL-3.0", "AGPL-3.0"
    };

    public PolicyEvaluation Evaluate(LicenseInfo license)
    {
        if (_approved.Contains(license.SpdxIdentifier))
        {
            return new PolicyEvaluation
            {
                Status = PolicyStatus.Approved,
                Obligations = GetObligations(license.SpdxIdentifier)
            };
        }

        if (_requiresReview.Contains(license.SpdxIdentifier))
        {
            return new PolicyEvaluation
            {
                Status = PolicyStatus.RequiresReview,
                Obligations = GetObligations(license.SpdxIdentifier),
                Issues = new[] { "Copyleft许可证需要法律审查" }
            };
        }

        if (_prohibited.Contains(license.SpdxIdentifier))
        {
            return new PolicyEvaluation
            {
                Status = PolicyStatus.Prohibited,
                Issues = new[] { "强Copyleft与专有分发不兼容" }
            };
        }

        return new PolicyEvaluation
        {
            Status = PolicyStatus.Unknown,
            Issues = new[] { $"未知许可证: {license.SpdxIdentifier}" }
        };
    }
}

归属和NOTICES文件

// NOTICES文件生成器
public class NoticeFileGenerator
{
    public string GenerateNotice(IEnumerable<PackageLicenseInfo> packages)
    {
        var sb = new StringBuilder();

        sb.AppendLine("第三方软件声明和信息");
        sb.AppendLine("=============================================");
        sb.AppendLine();
        sb.AppendLine("本软件包含以下第三方组件:");
        sb.AppendLine();

        foreach (var pkg in packages.OrderBy(p => p.PackageId))
        {
            sb.AppendLine($"## {pkg.PackageId} ({pkg.Version})");
            sb.AppendLine($"许可证: {pkg.License}");
            sb.AppendLine($"URL: {pkg.LicenseUrl}");
            sb.AppendLine();

            if (!string.IsNullOrEmpty(pkg.Copyright))
            {
                sb.AppendLine(pkg.Copyright);
                sb.AppendLine();
            }

            if (!string.IsNullOrEmpty(pkg.LicenseText))
            {
                sb.AppendLine("许可证文本:");
                sb.AppendLine(pkg.LicenseText);
                sb.AppendLine();
            }

            sb.AppendLine("---");
            sb.AppendLine();
        }

        return sb.ToString();
    }
}

.NET项目配置

<!-- 在构建中启用许可证元数据 -->
<PropertyGroup>
  <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
</PropertyGroup>

<ItemGroup>
  <!-- 在包中包含NOTICES文件 -->
  <None Include="NOTICES.txt" Pack="true" PackagePath="" />

  <!-- 为您的包设置许可证表达式 -->
  <PackageLicenseExpression>MIT</PackageLicenseExpression>
  <!-- 或基于文件的许可证 -->
  <PackageLicenseFile>LICENSE.txt</PackageLicenseFile>
</ItemGroup>

许可证政策模板

组织许可证政策

# 开源许可证政策

## 1. 目的
本政策管理[组织]产品中开源软件的使用。

## 2. 许可证类别

### 2.1 批准许可证(无需审查)
- MIT
- Apache-2.0
- BSD-2-Clause
- BSD-3-Clause
- ISC
- Unlicense
- CC0-1.0

### 2.2 需要审查
- LGPL-2.1, LGPL-3.0(弱copyleft - 使用上下文重要)
- MPL-2.0, EPL-2.0(文件/模块级copyleft)
- Creative Commons(类型各异)
- 双重许可包

### 2.3 禁止
- GPL-2.0, GPL-3.0(强copyleft - 除非项目是GPL)
- AGPL-3.0(网络copyleft)
- SSPL(服务器端公共许可证)
- 任何有使用领域限制的许可证
- 未经法律审查的未知或自定义许可证

## 3. 流程

### 3.1 新依赖添加
1. 使用`dotnet-license-check`或等效工具检查许可证
2. 如果批准:继续,确保归属
3. 如果需要审查:提交至legal@company.com
4. 如果禁止:寻找替代或请求例外

### 3.2 分发
在发布前:
1. 运行许可证审计
2. 生成NOTICES文件
3. 包含所需归属
4. 为copyleft合规存档源代码

## 4. 例外
例外需要法律和CTO的书面批准。

## 5. 合规验证
- CI/CD管道中的自动扫描
- 季度手动审计
- 年度政策审查

SPDX标识符

常见SPDX标识符

宽松许可证:
MIT, Apache-2.0, BSD-2-Clause, BSD-3-Clause, ISC, Unlicense, CC0-1.0

弱Copyleft:
LGPL-2.1-only, LGPL-2.1-or-later, LGPL-3.0-only, LGPL-3.0-or-later
MPL-2.0, EPL-2.0, OSL-3.0

强Copyleft:
GPL-2.0-only, GPL-2.0-or-later, GPL-3.0-only, GPL-3.0-or-later
AGPL-3.0-only, AGPL-3.0-or-later

复合表达式:
(MIT OR Apache-2.0)  - 选择
(LGPL-2.1-only AND MIT)  - 两者适用
GPL-2.0-only WITH Classpath-exception-2.0  - 例外

CI/CD集成

许可证扫描管道

# GitHub Actions示例
name: 许可证合规检查

on:
  pull_request:
    paths:
      - '**/*.csproj'
      - '**/packages.lock.json'

jobs:
  license-check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5

      - name: 设置.NET
        uses: actions/setup-dotnet@v4
        with:
          dotnet-version: '10.0.x'

      - name: 安装许可证检查器
        run: dotnet tool install --global dotnet-project-licenses

      - name: 检查许可证
        run: |
          dotnet-project-licenses -i . \
            --allowed-license-types "MIT;Apache-2.0;BSD-2-Clause;BSD-3-Clause" \
            --output license-report.json \
            --output-type json

      - name: 上传许可证报告
        uses: actions/upload-artifact@v4
        with:
          name: license-report
          path: license-report.json

      - name: 在禁止许可证时失败
        run: |
          if grep -q "GPL-" license-report.json; then
            echo "::error::检测到禁止许可证"
            exit 1
          fi

许可证合规检查清单

开发前

  • [ ] 为项目定义许可证政策
  • [ ] 识别项目分发模型(SaaS/桌面/库)
  • [ ] 确定您的代码的输出许可证
  • [ ] 建立依赖审查流程

开发期间

  • [ ] 在添加每个依赖前检查许可证
  • [ ] 在NOTICES文件中维护归属
  • [ ] 记录任何例外
  • [ ] 在CI中运行许可证扫描

发布前

  • [ ] 完成许可证审计
  • [ ] 生成最终NOTICES文件
  • [ ] 验证所有归属已包含
  • [ ] 为copyleft合规存档源代码
  • [ ] 如果需要,法律签署

交叉引用

  • SBOM: sbom-management 用于依赖跟踪
  • 安全: security-frameworks 用于安全供应链
  • 数据隐私: 考虑依赖项中的数据

资源