How OSV-Scanner License Scanning Works with SPDX Allowlists

OSV-Scanner evaluates package license expressions against user-provided SPDX allowlists using boolean logic, flagging violations when spdx.Satisfies returns false for any detected license identifier.

The google/osv-scanner CLI tool provides license compliance auditing by comparing detected package licenses against SPDX allowlists. This functionality parses complex SPDX expressions containing AND, OR, and WITH operators, validating them against standardized identifiers to identify policy violations during software composition analysis.

Parsing the --licenses Flag and Allowlist Validation

The license scanning workflow begins with CLI argument processing in cmd/osv-scanner/internal/helper/flags.go. The allowedLicencesFlag definition (lines 21-24) accepts either a boolean for summary mode or a comma-separated list of SPDX identifiers that constitute the allowlist.

When the scan initializes, GetScanLicensesAllowlist in cmd/osv-scanner/internal/helper/getters.go (lines 13-30) transforms the raw flag value into a Go []string. Before the actual scan begins, each identifier undergoes validation through spdx.Unrecognized in internal/spdx/verify.go (lines 5-13). This helper lower-cases entries and compares them against the built-in spdx.IDs map, causing an early error if any identifier is not a valid SPDX license ID.

The parsed allowlist is then stored in osvscanner.ScannerActions via GetCommonScannerActions (lines 35-48), populating the ScanLicensesAllowlist field that the core scanner will reference during analysis.

Evaluating SPDX Expressions Against Allowlists

For each detected package, OSV-Scanner extracts raw SPDX strings from lock-files and copies them into pkg.Licenses as models.License types within pkg/osvscanner/vulnerability_result.go (lines 17-22).

The critical evaluation logic resides in internal/spdx/satisfies.go. The Satisfies function (lines 52-62) tokenizes SPDX license expressions—for example MIT OR Apache-2.0—and builds an abstract syntax tree (AST). It then invokes node.satisfiedBy to check whether the parsed expression is satisfied by any identifier in the user-provided allowlist. This architecture supports complex logical operators including AND, OR, WITH, and parenthetical groupings.

Detecting and Recording License Violations

When Satisfies returns false for a license expression, the scanner appends the offending license to pkg.LicenseViolations (lines 28-33 of vulnerability_result.go). Packages containing at least one violation are automatically forced into the final results by setting includePackage = true, ensuring policy breaches cannot be filtered out accidentally.

After the scan completes, the allowlist and summary flag are stored in ExperimentalAnalysisConfig.Licenses (lines 89-96). This configuration object enables reporters to render compliance data appropriately. For instance, internal/output/table.go (lines 53-55) checks len(licenseConfig.Allowlist) > 0 to determine whether to display the "license allowlist" column in tabular output.

Practical Usage Examples

The following commands demonstrate common allowlist workflows:


# Generate a summary of all detected licenses without filtering

osv-scanner scan . --licenses

# Enforce an allowlist—only MIT or Apache-2.0 are permitted

osv-scanner scan . --licenses=MIT,Apache-2.0

# Combine allowlist validation with JSON output for CI pipelines

osv-scanner scan . \
    --format json \
    --licenses=MIT,Apache-2.0 \
    --output-file compliance-report.json

Under the hood, the comma-separated values become []string{"MIT", "Apache-2.0"}. The scanner evaluates each package's license expression against this slice, and the resulting JSON output includes a license_violations field for any package failing the check.

Summary

  • The --licenses flag accepts either a boolean for summary mode or a comma-separated list of valid SPDX identifiers.
  • Invalid SPDX IDs are rejected during initialization by spdx.Unrecognized before any scanning occurs.
  • SPDX expressions containing AND, OR, and WITH operators are parsed into an AST and evaluated against the allowlist via spdx.Satisfies.
  • Violations are recorded in pkg.LicenseViolations, forcing affected packages into the final output.
  • Results are enriched with ExperimentalAnalysisConfig.Licenses for rendering by table, JSON, HTML, and other reporters.

Frequently Asked Questions

What SPDX license formats does OSV-Scanner support?

OSV-Scanner supports standard SPDX license identifiers as defined in the SPDX specification, including simple identifiers like MIT or Apache-2.0, as well as complex expressions using AND, OR, and WITH operators with parenthetical grouping. The validator in internal/spdx/verify.go ensures all allowlist entries match the official SPDX ID registry.

How does the allowlist evaluate compound license expressions?

The spdx.Satisfies function in internal/spdx/satisfies.go tokenizes compound expressions and constructs an abstract syntax tree. For an expression like MIT OR Apache-2.0, the scanner returns true if either identifier appears in the allowlist. For MIT AND Apache-2.0, both must be present in the allowlist for the package to pass compliance.

What happens if I provide an invalid SPDX ID in the allowlist?

The command aborts during flag parsing with an error message. The GetScanLicensesAllowlist function calls spdx.Unrecognized to filter the provided identifiers against the spdx.IDs map, and any unrecognized values trigger an immediate exit before the scan begins.

Where do license violations appear in the output?

Violations appear in the license_violations field of the package data. When using the table reporter (internal/output/table.go), the output includes a dedicated column showing allowlist status when --licenses is configured with specific identifiers. JSON and HTML reporters read ExperimentalAnalysisConfig.Licenses to include both the configured allowlist and any detected violations in their respective formats.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →