licensecheck Integration with DefectDojo
licensecheck Integration with DefectDojo
licensecheck is an open source command-line tool for Python projects, maintained under the FHPythonUtils organization on GitHub. It lists the licence of every dependency a project uses and checks whether each licence is compatible with the project's own licence. By default it reads dependencies from pyproject.toml, can read requirements files instead, and writes its results as simple text, Markdown, HTML, CSV, ANSI, or JSON. DefectDojo imports the JSON format.
licensecheck Integration with DefectDojo
We added licensecheck to our Python builds because licence questions kept arriving late, usually from a legal reviewer days before a release. Feeding the licensecheck JSON report into DefectDojo turns each incompatible dependency into a High severity Finding on the Asset that ships it, with an owner and a due date, while compatible packages are kept as informational inventory. The licence conflict sits in the same queue as our vulnerability work instead of in a spreadsheet nobody reopens.
Why licensecheck Matters
A Python service can pull in dozens of transitive packages, and each one carries licence terms the team accepted without reading. licensecheck answers a narrower question than a plain licence inventory: does this dependency's licence conflict with ours?
- It makes a compatibility judgement per dependency against the project licence, rather than only listing licence names.
- It reads the dependency sources Python teams already maintain, so it fits into an existing build with little setup.
- A conflict is a distribution problem. Shipping the package may put the project out of line with its own licence terms.
- On its own, the report is a point-in-time list. It has no memory of which conflicts were reviewed, accepted, or fixed last quarter.
Advantages of This Integration
What changed once licensecheck output went through DefectDojo:
- Conflicts become work items. Incompatible licences import at High severity, so they pick up the SLA you have set for High findings and show up in the same triage views as security issues.
- Inventory without noise. Compatible dependencies import at Info. They are searchable when someone asks "where do we use this package?" but stay out of the way of remediation queues if you filter or set a minimum severity.
- Stable deduplication. DefectDojo hashes licensecheck findings on component name, component version, and the licence (stored as the tool's vulnerability ID), so a rescan of an unchanged lockfile does not create duplicates.
- A real lifecycle. Reimporting into the same Test mitigates conflicts that disappear when a package is replaced or upgraded, and reactivates any that return.
- A record of decisions. When legal approves a specific conflict, risk acceptance with an expiry date captures that decision on the Finding instead of in an email thread.
- Reporting by Asset. Licence conflicts roll up per Asset and Organization alongside vulnerability findings, which helps when a release review needs one view of open issues.
How This Integration Works
DefectDojo reads licensecheck reports with the Licensecheck Scan scan type.
1. Produce a JSON report. From the project root, run licensecheck with JSON output and capture it to a file:
licensecheck -f json > licensecheck.json
licensecheck also has an -o option for writing to a file directly, and -r to point it at requirements files when the project does not use pyproject.toml.
2. Import it. In the UI, open the Engagement, choose Import Scan Results, select Licensecheck Scan, and upload the file. For automation, the API works in Community Edition and DefectDojo Pro:
curl "https://YOUR_INSTANCE/api/v2/import-scan/"
-H "Authorization: Token $DD_API_TOKEN"
-F "scan_type=Licensecheck Scan"
-F "file=@licensecheck.json"
-F "product_name=billing-service"
-F "engagement_name=Licence Review"
-F "auto_create_context=true"
DefectDojo Pro users can run the same import from a pipeline with Universal Importer:
universal-importer import
--defectdojo-url "https://YOUR_INSTANCE.cloud.defectdojo.com/"
--scan-type "Licensecheck Scan"
--report-path "./licensecheck.json"
--product-name "billing-service"
--engagement-name "Licence Review"
--auto-create-context
3. Reimport on each dependency change. Send later reports to /api/v2/reimport-scan/ against the same Test, so replaced packages are mitigated and the Test keeps one continuous history.
The parser reads the packages array and the top-level project_license. Each package becomes one Finding, whether or not its licence is compatible.
Data Granularity: What Gets Imported
| DefectDojo Field | Source in licensecheck Report | Notes |
|---|---|---|
| Title | Package name, version, licence | Incompatible: "name version: license X incompatible with project"; compatible: "name version: X" |
| Severity | licenseCompat |
False becomes High; true becomes Info |
| Description | Package, licence, compatibility, project licence, homepage | Homepage only when the report has one |
| Mitigation | Fixed text | Incompatible only: replace the dependency or confirm the conflict is acceptable |
| Component Name | name |
Python package name |
| Component Version | version |
Installed version |
| Vulnerability ID from tool | license |
Set to UNKNOWN when no licence is reported |
| Finding type | Static | All findings are marked static |
| Deduplication | Hashcode | Component name, component version, vulnerability ID from tool |
licensecheck does not assign severity itself. The High and Info levels come from DefectDojo mapping its compatibility verdict, and the verdict comes from licensecheck's own compatibility rules, not from any policy configured in DefectDojo.
Use Cases
In a CI/CD pipeline: Each merge to main runs licensecheck and reimports the report. A new dependency with a conflicting licence appears as a new High Finding on the Asset, and the team can query the DefectDojo API for active High findings in that Test before tagging a release.
Before a commercial release: A product team preparing to distribute a Python application gives legal a filtered view of High licence findings for that Asset. Each one is either fixed by swapping the package or risk-accepted with a note recording who approved it.
For dependency inventory: Because compatible packages import at Info, security and legal can search DefectDojo for a specific package or licence across every Asset that runs licensecheck, without asking each team for a fresh report.
Across many repositories: An organization with many small Python services imports each into its own Asset. Security leads see licence conflicts by team in the same reports they already use for vulnerabilities.
Operational Tips
- Set
minimum_severity=Highon import if you only want conflicts, not inventory. You lose the Info records, so decide whether the inventory is worth keeping first. - If licensecheck reports a licence as unknown, the Finding's vulnerability ID becomes UNKNOWN. Treat those as review items, since an unknown licence is often as much of a problem as a conflicting one.
- Your licence policy may differ from licensecheck's compatibility matrix. Triage on the recorded licence after import and use false positive marking or risk acceptance for cases your policy allows.
- Use one Test per repository and reimport into it, so the open-to-mitigated history stays in one place.
- Tag imports with the release or branch (for example
tags=release-2.4) so a release review can filter to exactly what shipped. - Set the project licence correctly in
pyproject.toml. Every compatibility verdict depends on it, and the report records it in each Finding's description.