When a legal team asked whether a product contained any GPL-licensed dependencies, the answer wasn’t immediately clear. Scanning thousands of transitive packages across Node and Python services revealed a gap: no fast, offline method existed to confirm compliance. Existing tools either depended on cloud APIs, required user accounts, or left license strings unclassified. To solve this, a lightweight command-line utility was built to read metadata directly from local folders and categorize each license into actionable risk tiers.
The problem: license ambiguity in dependency chains
Most dependency scanners fall into two categories. Some, like license-checker—the npm default with nearly a million weekly downloads—are effectively unmaintained and return raw license text without interpretation. Others, such as Snyk, FOSSA, or Black Duck, offer detailed reports but require network access, API tokens, and user sign-ups before they can analyze a project already present on disk.
In both cases, the critical question—whether a GPL-licensed package could inadvertently trigger copyleft obligations—remains unanswered until the scan completes. And by then, the package may have already been installed.
How the tool works: scan local files, classify risks
The solution, called licsniff, operates entirely offline. It reads package metadata from standard files that every dependency already ships: package.json in Node projects and METADATA files in Python wheels. Instead of uploading data to a server, it performs a local scan and immediately categorizes each license into one of five tiers:
- permissive – Licenses like MIT, ISC, BSD, Apache-2.0, 0BSD, Unlicense, or CC0 allow unrestricted use without obligations.
- weak-copyleft – Licenses such as LGPL, MPL-2.0, EPL, or CDDL require limited compliance, typically related to linking or file redistribution.
- strong-copyleft – Licenses including GPL and AGPL can compel open-sourcing of the entire application under certain conditions.
- proprietary – Packages marked as
UNLICENSEDorSEE LICENSE IN …are not open source and may impose usage restrictions. - unknown – Missing or unrecognized license strings represent the highest risk, as the legal implications are undefined.
Normalizing real-world license expressions
Real-world metadata rarely uses clean identifiers. Developers regularly encounter variations such as GPL-3.0, GPLv3, GPL-3.0-only, (MIT OR Apache-2.0), or GPL-3.0 AND MIT. licsniff normalizes these into standardized SPDX expressions and evaluates boolean logic correctly:
- For
ORexpressions, the least restrictive option is selected, so(MIT OR GPL-3.0)becomespermissive. - For
ANDexpressions, the most restrictive option applies, makingGPL-3.0 AND MITstrong-copyleft.
This prevents false positives that could gate CI pipelines for the wrong reasons.
Enforcing compliance in CI with a single flag
The tool’s most practical feature is the --fail-on flag, which turns any scan into a compliance gate. For example:
licsniff --fail-on strong-copyleftThis command exits with a non-zero status as soon as any dependency reaches or exceeds the strong-copyleft tier, blocking a GPL package from entering the build. Additional flags like --summary provide counts of each tier, while --json outputs structured data for further processing.
Cross-ecosystem support with identical logic
Because many teams use both Node and Python, licsniff is available for both ecosystems with consistent behavior:
- For Node projects, run
npx licsniffto scan thenode_modulesdirectory. - For Python projects, use
pipx run licsniffto scansite-packages, leveraging only standard library modules.
Both versions implement the same license classifier, tested against identical vectors, ensuring that a license like LGPL-2.1 is tiered identically whether detected in a JavaScript or Python project. The Python version also reads the modern License-Expression field introduced in PEP 639 for newer wheels.
Design choices that ensure reliability and safety
Under the hood, licsniff is built around a single pure function, classifyLicense(idOrName) → {tier, spdx}, which contains no I/O, no network calls, and no mutable state. The CLI is essentially a thin wrapper that reads directories and calls this function. This design allows the Node and Python implementations to be proven equivalent—they share the same test suite and classification logic.
The tool is intentionally offline and read-only. It never writes files, modifies directories, or opens network sockets, making it safe for air-gapped environments and client machines.
Try it, test it, contribute
The project is open source under the MIT license and available for both ecosystems:
- Node version: github.com/jjdoor/licsniff
- Python version: github.com/jjdoor/licsniff-py
If you encounter an unusual license string that isn’t classified correctly, the maintainer invites contributions—paste the offending entry from your node_modules or site-packages and help expand the classifier. For teams that haven’t yet implemented automated license audits, this tool offers a fast, no-setup path to compliance confidence.
The next time legal counsel asks for proof that no GPL code is present, the answer can be immediate—and automated.
AI summary
Kapalı kaynak kodlu projelerinizdeki GPL ve diğer lisans risklerini yerel olarak tarayan licsniff aracıyla, bağımlılıklarınızın yasal uyumluluğunu anında kontrol edin. Net, hızlı ve kullanımı kolay çözüm.