// License scanning integration
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 license requires legal review" }
};
}
if (_prohibited.Contains(license.SpdxIdentifier))
{
return new PolicyEvaluation
{
Status = PolicyStatus.Prohibited,
Issues = new[] { "Strong copyleft incompatible with proprietary distribution" }
};
}
return new PolicyEvaluation
{
Status = PolicyStatus.Unknown,
Issues = new[] { $"Unknown license: {license.SpdxIdentifier}" }
};
}
}
Attribution and NOTICE Files
// NOTICE file generator
public class NoticeFileGenerator
{
public string GenerateNotice(IEnumerable<PackageLicenseInfo> packages)
{
var sb = new StringBuilder();
sb.AppendLine("THIRD-PARTY SOFTWARE NOTICES AND INFORMATION");
sb.AppendLine("=============================================");
sb.AppendLine();
sb.AppendLine("This software includes the following third-party components:");
sb.AppendLine();
foreach (var pkg in packages.OrderBy(p => p.PackageId))
{
sb.AppendLine($"## {pkg.PackageId} ({pkg.Version})");
sb.AppendLine($"License: {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("License Text:");
sb.AppendLine(pkg.LicenseText);
sb.AppendLine();
}
sb.AppendLine("---");
sb.AppendLine();
}
return sb.ToString();
}
}
.NET Project Configuration
<!-- Enable license metadata in build -->
<PropertyGroup>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
</PropertyGroup>
<ItemGroup>
<!-- Include NOTICE file in package -->
<None Include="NOTICE.txt" Pack="true" PackagePath="" />
<!-- Set license expression for your package -->
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<!-- OR for file-based license -->
<PackageLicenseFile>LICENSE.txt</PackageLicenseFile>
</ItemGroup>
License Policy Template
Organizational License Policy
# Open Source License Policy
## 1. Purpose
This policy governs the use of open source software in [Organization] products.
## 2. License Categories
### 2.1 Approved Licenses (No Review Required)
- MIT
- Apache-2.0
- BSD-2-Clause
- BSD-3-Clause
- ISC
- Unlicense
- CC0-1.0
### 2.2 Requires Review
- LGPL-2.1, LGPL-3.0 (weak copyleft - usage context matters)
- MPL-2.0, EPL-2.0 (file/module-level copyleft)
- Creative Commons (varies by type)
- Dual-licensed packages
### 2.3 Prohibited
- GPL-2.0, GPL-3.0 (strong copyleft - unless project is GPL)
- AGPL-3.0 (network copyleft)
- SSPL (Server Side Public License)
- Any license with field-of-use restrictions
- Unknown or custom licenses without legal review
## 3. Process
### 3.1 New Dependency Addition
1. Check license using `dotnet-license-check` or equivalent
2. If Approved: Proceed, ensure attribution
3. If Requires Review: Submit to [email protected]
4. If Prohibited: Find alternative or request exception
### 3.2 Distribution
Before any release:
1. Run license audit
2. Generate NOTICE file
3. Include required attribution
4. Archive source code for copyleft compliance
## 4. Exceptions
Exceptions require written approval from Legal and CTO.
## 5. Compliance Verification
- Automated scanning in CI/CD pipeline
- Quarterly manual audits
- Annual policy review