License scanning is reading the license of every package your app depends on, including the packages those packages pull in from npm or PyPI, and flagging the ones whose terms your product cannot meet. An app assembled with an AI assistant gains dependencies nobody picked by name, and a buyer’s reviewer asks for the license report all the same.

What license scanning is, and what the audit produces

License scanning reads the license of every dependency, including the ones your dependencies pull in, and produces two artifacts: a license report with a decision per flagged package and a software bill of materials. The scan is quick to run; the audit is the decisions, one per copyleft or unlicensed package.

The audit is one of the engineering standards for AI-assisted teams, and its output ends up in the pack a reviewer reads during startup technical due diligence. It has nothing to do with the ID scanners that read a driver’s license at a front desk: everything here is about software dependencies.

ArtifactWhat it containsWho asks for it
License reportEvery dependency, its license, its license class, and a recorded decision for each flagged packageAn investor’s or buyer’s technical reviewer during due diligence
Software bill of materials (SBOM)A machine-readable inventory of the components, with versions and licenses, in SPDX or CycloneDX formatA buyer’s reviewer or a contract; in the US, federal software procurement guidance

To generate a dependency license report, run the listing command for your stack (the commands are further down) and add one column: the decision. The command alone gives you an inventory; the decision column is what turns it into an audit. Dated, those rows double as your open source license compliance checklist, because each one names a package, its license, its class, what you decided and when.

The license half of an open source code audit reads package metadata and license files, not the code you wrote. An open source software audit run for a buyer goes wider and also asks whether the packages are still maintained and whether they carry known vulnerabilities, which the next section sorts out.

In the Production Hardening Sprint this audit is deliverable 10.11: we inventory the licenses of every dependency, flag copyleft or unlicensed packages, and replace or approve each one.

Copyleft uses copyright to make modified versions carry the same terms. Permissive licenses ask for the notice, weak copyleft covers changes to the licensed library or its files, strong copyleft covers larger works that include it when distributed, and the AGPL treats network use as distribution for a modified version. No license generally means no permission.

The difference between copyright and copyleft starts with the default. Copyright applies whether or not anyone writes a license: GitHub’s licensing docs say that without one, “the default copyright laws apply, meaning that you retain all rights to your source code and no one may reproduce, distribute, or create derivative works from your work.” A copyleft license keeps that copyright and grants the permissions anyway, with a condition attached, and that condition is the practical meaning of copyleft: you may use, change and share the code, and its terms travel with what you share.

The table groups six common licenses into classes. The class names are my grouping; the conditions are the labels Choose a License’s license summaries list for each license, copied as written.

License classExamplesWhat Choose a License lists as its conditionsSource
PermissiveMIT, Apache-2.0MIT: License and copyright notice. Apache-2.0: License and copyright notice; State changesChoose a License
Weak copyleftLGPL-3.0, MPL-2.0LGPL-3.0: Disclose source; License and copyright notice; Same license (library); State changes. MPL-2.0: Disclose source; License and copyright notice; Same license (file)Choose a License
Strong copyleftGPL-3.0Disclose source; License and copyright notice; Same license; State changesChoose a License
Network copyleftAGPL-3.0Disclose source; License and copyright notice; Network use is distribution; Same license; State changesChoose a License
No licenseNoneNo permission: a package without a license “generally means you have no permission from the creators of the software to use, modify, or share the software”Choose a License’s no-permission page; GitHub’s licensing docs

Two of those labels carry the distribution condition in Choose a License’s own definitions. Disclose source means “Source code must be made available when the licensed material is distributed,” and Same license means “Modifications must be released under the same license when distributing the licensed material.” The site calls MPL-2.0 a weak copyleft license, GPL-3.0 a strong one and AGPL-3.0 the strongest, and it adds one sentence to the AGPL-3.0 that no other row has: “When a modified version is used to provide a service over a network, the complete source code of the modified version must be made available.” That sentence is why the AGPL row is the one a hosted product reads twice.

Every open source copyleft license in the table, from LGPL-3.0 to AGPL-3.0, is on the Open Source Initiative’s license list, alongside MIT and Apache-2.0. Licenses on code an assistant reproduced from another repository, rather than pulled in as a package, are a different question with its own owner: the software due diligence checklist.

What goes wrong without it

Each failure below has a first check you can run today.

SymptomLikely causeFirst check
The reviewer asks for the license report and there is nothing to sendNo scan was ever run, or its output was never keptRun the listing command for your stack and save the output with the date
An AGPL-3.0 package sits inside a hosted product with no decision recordedIt arrived through another dependency, and nobody read its licenseFind it in the SBOM and follow the dependency entries back to the package you installed on purpose
A package with no license sits deep in the treeThe author never added one, or the package metadata carries noneOpen the package’s own folder and look for a license file; license-checker and pip-licenses print these as UNKNOWN

If an investor has asked about dependency licenses and there is no report to send, the reviewer notes the gap, and what investors look for in code covers how that note is read. The fix is a listing, a decision column and a date.

Take the second row as a case. An investor’s reviewer asks for the dependency license report during diligence. The first scan finds an AGPL-licensed library, pulled in through another dependency, inside a closed-source SaaS, and nobody has recorded a decision about it. A license nobody chose still arrives with its conditions, and the report with a recorded decision is what the reviewer reads.

I split open source risks into three: the license, packages nobody maintains any more, and known vulnerabilities. Each open source software risk is its own topic: licenses are this page, abandoned packages are part of tech debt, and vulnerabilities belong to the npm audit command. None of the dangers of open source software on that list means avoiding packages; each one is a check you can run and date.

How to run the scan on the common stacks

How to audit npm package licenses comes down to one listing command plus the decision column, Python has an equivalent, and a paid tool earns its cost later, if at all. The commands, flags and outputs below are taken from each tool’s own documentation, not from a run on your project.

npm and pnpm

npm sbom is npm’s own command. Its docs say it “generates a Software Bill of Materials (SBOM) listing the dependencies for the current project” and that “SBOMs can be generated in either SPDX or CycloneDX format.” The command has a page in the npm 9, 10, 11 and 12 docs and none in the npm 8 docs, so I’d treat npm 9 as the minimum. Its format setting defaults to null, so name the format on the command line. In the example outputs on that page, every package carries its license, under “licenses” in CycloneDX and “licenseDeclared” in SPDX, and a “dependencies” section in CycloneDX (“relationships” in SPDX) records which package depends on which. That section is how you trace a package your package.json never names back to the one that pulled it in, and the same file is your license inventory, so it is the natural first step of SBOM generation on an npm project.

npm’s docs describe the command against npm’s own package lock and installed tree, so on a pnpm project I’d use pnpm’s own listing instead. pnpm’s docs describe pnpm licenses list as “List licenses for installed packages”, with --json for JSON output and --prod to check only dependencies and optionalDependencies.

The community tool license-checker is a third option. Its README lists --summary to “output a summary of the license usage” and --onlyunknown to “only list packages with unknown or guessed licenses.” Its sample output shows some modules as licenses: UNKNOWN, and an asterisk next to a license name “means that it was deduced from an other file than package.json (README, LICENSE, COPYING, …)”. Treat every UNKNOWN and every asterisk as a flag for the report.

# npm 9 or later: every dependency, with its license
npm sbom --sbom-format cyclonedx > bom.json

# pnpm: licenses of installed packages, as JSON
pnpm licenses list --json > licenses.json

# license-checker (community tool, installed globally)
npm install -g license-checker
license-checker --summary
license-checker --onlyunknown

Python

pip-licenses describes itself as a way to “Dump the software license list of Python packages installed with pip.” Install and run it inside the app’s own virtual environment, because by default it “finds the packages from the environment pip-licenses is launched from.” Run from a global Python, it would list whatever that environment happens to hold. The default output is plain text with Name, Version and License columns; --format=csv, --format=json and --format=markdown are among the other formats. Some packages declare their license only in Trove Classifiers, and for those the README points to --from=mixed, which it says “works well and looks for licenses.” A package with no metadata comes out as UNKNOWN, which goes on the report as a flag like any other.

# inside the app's virtual environment
pip install pip-licenses
pip-licenses --from=mixed --format=csv > licenses.csv

Add the same decision column to that CSV that the npm report gets.

When to pay for a tool

Black Duck, Snyk, FOSSA and Mend are vendors of open source license management software. I name them in no order and make no claim about their features; a company comparing open source license compliance tools across many repositories should compare them on their own documentation. A black duck audit is something else again: Black Duck’s own audit service, which its site describes as software due diligence work. For one app, my working rule is that the free listing plus a decision column is the audit. What a single app does need is repetition: the gate that runs the listing on every pull request belongs with CI/CD best practices, and a new dependency is a line in the code review checklist.

What to do with a copyleft hit

A copyleft hit has four steps: confirm the license from the package itself, decide whether your use triggers its conditions, then replace the package, isolate it, or comply, and record the decision with a date. None of those steps is legal advice; before a sale, I’d treat a lawyer’s reading as the safer route.

  1. 01 Confirm the license from the package's own license file, not the registry summary. Evidence: the file path and the first line of the license text.
  2. 02 Decide whether your use triggers its conditions. A tool that only runs at build time is a different case from a library shipped inside the product. Evidence: one sentence in the report saying how the package is used.
  3. 03 Replace it with a permissively licensed equivalent, isolate it as a separate service, or comply with its conditions. Evidence: the pull request that removes it, the service boundary, or the published source.
  4. 04 Record the decision and the date in the license report. Evidence: the dated row, with the name of whoever decided.

Step 2 is my reading of how the conditions apply, not the license’s wording. The conditions themselves are the ones in the classes table, and for an AGPL-3.0 package the extra question is the one in its network sentence: whether a modified version of it is used to provide a service over a network. Choose a License’s own advice for a package with no license is to ask the maintainers to add one, not to use it, or to negotiate a private license.

The SBOM: SBOM example and what a buyer or an auditor will accept

A software bill of materials is a nested inventory of the components that make up a piece of software, with versions and licenses, in a machine-readable format such as SPDX or CycloneDX. A buyer’s reviewer can work from either; which one a contract asks for is the contract’s call.

The “nested inventory” wording is CISA’s: “An SBOM is a nested inventory, a list of ingredients that make up software components.” In npm’s own example the app is the top component, and each OSS component listed beneath it carries its own license entry.

FormatWho publishes itWhat the example on npm’s page carries
SPDXThe SPDX project on spdx.dev, a Linux Foundation site; an international open standard, ISO/IEC 5962:2021; current version 3.0spdxVersion, documentNamespace, creationInfo with a created time, and a packages list with licenseDeclared on each
CycloneDXDeveloped by the OWASP Foundation and Ecma International; standardized as ECMA-424; current version 1.7, released 2025-10-21bomFormat, specVersion, serialNumber, a metadata timestamp, and a components list with licenses on each

This excerpt is trimmed from CycloneDX’s own open-source licensing example, cut to one component with its evidence block removed:

{
  "bomFormat": "CycloneDX",
  "specVersion": "1.7",
  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
  "version": 1,
  "components": [
    {
      "type": "library",
      "name": "Library A",
      "version": "3.7.1",
      "licenses": [{ "license": { "id": "Apache-2.0", "acknowledgement": "concluded" } }]
    }
  ]
}

The acknowledgement field is the part an audit fills in. The CycloneDX specification supports declared, observed and concluded licenses, and a concluded license is “the result of a comprehensive analysis of the project’s codebase to identify and confirm the actual licenses of the components used.” The SBOM file itself is conventionally named bom.json for CycloneDX JSON, or anything matching *.cdx.json. The SPDX specification is the other format, and npm sbom writes either.

Where a written requirement exists, it is narrow. In the US, Executive Order 14028 of May 2021 directed the Commerce Department, through NIST, to issue software supply chain guidance that “shall include standards, procedures, or criteria regarding” a list of practices, item (vii) of section 4(e) being “providing a purchaser a Software Bill of Materials (SBOM) for each product directly or by publishing it on a public website.” That is guidance for software the federal government buys. For a private SaaS sale, none of these sources states a requirement, and a buyer may ask for one anyway; that is my reading, not legal advice.

Four related terms, one line each. SCA vs SBOM is a tool against its output: software composition analysis is the scan, and the SBOM is one of the things it produces (my gloss). CycloneDX uses SaaSBOM for a bill of materials that inventories “services, endpoints, and data flows and classifications that power cloud-native applications.” An SBOM solution or SBOM manager is a product that stores and compares SBOMs across many products, which one app with one file in its repository does not need (my reading). SBOM compliance for a single app, as I use the term, means the file exists, matches the current lockfile and is regenerated on each release.

How to verify it

A license audit is done when every flag in the report has a recorded decision: open a few packages’ license files at random, read the recorded decision on any copyleft entry, and regenerate the report to confirm it matches the copy you hand over.

  1. Pick a few packages from the report at random, open each one’s license file, and check that its first line matches the license the report names.
  2. Read the decision row for every copyleft and UNKNOWN entry. Each needs a decision, a reason and a date.
  3. Regenerate the SBOM and the listing from the current lockfile, then compare package names, versions and licenses with the copy you are handing over.

Compare those three fields, not the whole file. In the example outputs on npm’s page, a CycloneDX SBOM carries a “serialNumber” (a urn:uuid) and a “timestamp”, and an SPDX one carries a “documentNamespace” with a UUID and a “created” time. Two SBOMs of the same tree therefore never match as plain text, which is my reading of those examples, so a raw text diff tells you nothing.

In the sprint, deliverable 10.11 is verified this way: include the license report in the due diligence pack with zero unresolved flags.

Where the sprint does this

The license report sits in the technical due diligence pack that our handover includes, which bundles the readiness report, architecture diagram, data model, security checklist and capacity statement into one PDF. Deliverable 10.11 is also recorded in the production readiness report, which accounts for all 123 IDs, keeps failures visible until resolved and explains genuine non-applicable items. The full list of deliverables is in the published scope.

Common questions about copyleft and SBOMs

Is copyleft a real thing?

Yes. Copyleft is a licensing method, and copyleft licenses such as GPL-3.0, AGPL-3.0, LGPL-3.0 and MPL-2.0 are all on the Open Source Initiative’s list of approved licenses, which it approves against its Open Source Definition.

Can you give me an example of a copyleft license?

GPL-3.0 is a copyleft license, and one of the two popular licenses Choose a License features on its home page. The site describes it as a strong copyleft license whose permissions are conditioned on making complete source code of licensed works and modifications, including larger works using it, available under the same license. The AGPL-3.0, which the site calls the strongest copyleft license, adds a network condition; the LGPL-3.0 and MPL-2.0 are narrower copyleft licenses.

Is SBOM legally required?

Not in general. In the US, Executive Order 14028 put SBOMs into the guidance for federal software procurement, as something a supplier provides to the purchaser. For a private sale, none of the sources here states a requirement, though a contract can ask for one. This is not legal advice.

SPDX and CycloneDX. SPDX is published as ISO/IEC 5962:2021 and CycloneDX as ECMA-424, and npm sbom writes either one. I have no measure of which is used more, so I don’t rank them.

Is GPL 3.0 free for commercial use?

Yes, with conditions. Choose a License lists commercial use as a GPL-3.0 permission, alongside the conditions Disclose source, License and copyright notice, Same license and State changes, and it defines Disclose source as applying when the licensed material is distributed. This is not legal advice.