Open-source license compliance
Before adding dependencies, identify copyleft, patent clauses, and notice obligations; produce allowlists and exception-approval paths.
The SKILL embeds an org-level allow / legal review / deny license table and requires scan output to match the lockfile; UNKNOWN or dual licensing needs human confirmation.
Binary distribution vs SaaS changes source-offer, copyright, and NOTICE aggregation requirements; the agent should separate delivery shape and list files that must ship with the artifact.
Tie to SBOM: license field changes trigger compliance review; model output must remind readers this is not legal advice—escalate major decisions to counsel.
- Do not mix GPL-family static linking with closed-source strategy without review.
- Keep third-party acknowledgements in docs and UI in sync with the dependency list.
- Record each policy exception and its re-review date.
Scan tool commands and CI blocking configuration
license-checker / FOSSA CLI scanning
# license-checker (Node.js projects)
npx license-checker --production \
--onlyAllow 'MIT;Apache-2.0;BSD-2-Clause;BSD-3-Clause;ISC;CC0-1.0' \
--excludePackages 'myapp@1.0.0' \
--json > license-report.json
# List all licenses (with dependency tree)
npx license-checker --production --csv > licenses.csv
# FOSSA CLI scan (requires FOSSA_API_KEY)
fossa analyze --branch main
fossa test --timeout 600 # non-zero exit means policy violation
# Python projects — pip-licenses
pip install pip-licenses
pip-licenses --format=json \
--with-urls \
--with-authors \
--output-file=licenses.json
# Auto-generate NOTICE file
npx license-checker --production \
--customFormat='{"name":"","version":"","licenses":"","copyright":""}' \
--out NOTICE \
--customPath notice-template.json
CI blocking for GPL libraries (GitHub Actions)
# .github/workflows/license-check.yml
name: License Compliance
on: [pull_request]
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: '20' }
- run: npm ci --production
- name: Check licenses (deny GPL)
run: |
npx license-checker --production \
--onlyAllow 'MIT;Apache-2.0;BSD-2-Clause;BSD-3-Clause;ISC;CC0-1.0;Unlicense' \
--excludePackages 'approved-exception@1.0.0' || \
(echo "::error::Disallowed license detected, check license-report.json" && exit 1)
- name: Upload report
uses: actions/upload-artifact@v4
with:
name: license-report
path: license-report.json
Compliance flow (lockfile → scan → SBOM)
[ Align lockfile / build graph with org allowlist ]
│
▼
┌─────────────┐ Parse SPDX License Expressions; flag UNKNOWN / OR / AND
│ Dependency scan │──── Conflicts: copyleft × closed-source distribution, patent grants, additional obligations
└─────────────┘
│
▼
┌─────────────┐ CycloneDX / SPDX JSON: licenseDeclared / licenseConcluded per component
│ SBOM output │──── Version drift: diff license fields → trigger compliance review ticket
└─────────────┘
│
▼
┌─────────────┐ NOTICE / source obligations / UI credits; exception log with expiry
│ Distribution │──── Not legal advice → escalate major risks to legal
└─────────────┘
When scanner-declared SPDX IDs conflict with package metadata, use traceable evidence (official LICENSE file, SPDX document) as the source of truth, and retain NOASSERTION or a note in SBOM until resolved.
License compatibility matrix
Common license usage constraints across different distribution scenarios (not legal advice—escalate major decisions to legal):
| License | Commercial closed-source use | Static linking distribution | SaaS (no binary distribution) | Key requirements |
|---|---|---|---|---|
MIT |
✅ | ✅ | ✅ | Retain copyright notice and license text |
Apache-2.0 |
✅ | ✅ | ✅ | Include NOTICE file; patent grant (bilateral) |
LGPL-2.1 |
⚠️ | ⚠️ Dynamic link or provide object files | ✅ | Closed-source apps may dynamically link; modifications to LGPL library itself must be open-sourced |
GPL-3.0 |
❌ Requires legal review | ❌ Requires entire program to be GPL | ⚠️ AGPL-3.0 stricter (network service also triggers) | Copyleft infects; distribution requires all source code to be open |
NOASSERTION: use as SBOM field placeholder when metadata is missing and not yet manually confirmed.- Scanner-output
UNKNOWNmust enter a review queue; must not be silently mapped to allowed.
License fields in SBOMs and review
CycloneDX licenses and SPDX JSON licenseDeclared / licenseConcluded should share provenance with CI scans and the lockfile; on merge, diff the previous SBOM’s license set.
Suggested automation
- Ship SPDX or CycloneDX with each release artifact, bound to image / artifact digest.
- Label or block merges on license changes (per org policy).
- Import SBOMs into vuln + license dashboards; unify UNKNOWN tickets.
Human / agent checks
- Under dual license, chosen terms match actual distribution.
- Transitive upgrades introducing copyleft are within the allow table.
- Exception records, re-review dates, and owners.
Allowlists, distribution shape, and NOTICE
Static vs dynamic linking, containers, and pure SaaS change “source offer—and “copyright notice—duties; the SKILL should list files that ship (LICENSE, NOTICE, third-party list) per delivery shape.
Version the org allow table and align it with pipeline gates; exceptions need ticket, approver, and re-review date. Generate “About / open source—pages from the SBOM or build-time credits—avoid hand-copy drift.
SPDX JSON package fragment lab
Fill coordinates and an SPDX license expression to produce a single packages[] element for SPDX 2.3 JSON (you still need document root SPDXID, relationships, etc.).
Illustrative only; a full SBOM also needs spdxVersion, dataLicense, document SPDXID, relationships, etc. CycloneDX users map licenses to components[].licenses.
---
name: license-compliance
description: Scan open-source licenses, generate NOTICE file, CI blocking for disallowed licenses, SBOM integration
---
# Steps
1. Run license-checker or FOSSA CLI: generate license-report.json
2. CI blocking: GitHub Actions deny GPL; block merge on policy violation
3. SPDX License Expression: parse AND/OR compound expressions, flag UNKNOWN for review
4. Compatibility matrix: check MIT/Apache/LGPL/GPL against distribution model (binary/SaaS)
5. NOTICE file: auto-generate from license-checker --customFormat; ship with release artifacts
6. SBOM integration: licenseDeclared / licenseConcluded field validation per component
7. Version diff: compare license field changes between SBOM versions; trigger review on new copyleft
8. Org allowlist: version-controlled; exceptions with ticket, approver, and re-review date
9. UNKNOWN handling: must enter review queue; do not silently map to allowed
10. Dual licensing: confirm which license applies to the actual use and distribution model
11. Static vs dynamic vs SaaS: LGPL static linking requires object files; GPL SaaS triggers AGPL
12. UI open-source notices page: generated from SBOM or build-time attribution file; avoid manual drift
# Anti-patterns
- Do NOT map UNKNOWN licenses to allowed without manual verification
- Do NOT use GPL libraries in commercial closed-source products without legal review
- Do NOT maintain open-source attribution page manually (sync with SBOM/build outputs)