anistark / anistark/feluda

bug: SBOM writers discard license expressions longer than 100 characters

Ouverte
#257 1 commentaire 0 réactions 0 personnes assignées Voir sur GitHub
bug difficulty: easy
Langage dominant
Rust
Étoiles
471
Forks
27
Merge moyen
17 h 14 min
PR mergées (30 j)
5

Description

## Description

Both SBOM writers discard any license expression longer than 100 characters and emit `NOASSERTION` in its place. The direct scan resolves the license correctly, so the loss happens only on the way into a generated document.

The cap has no basis in the specification. SPDX 2.3 places no length limit on a license expression, and neither does CycloneDX. The effect is worst on the packages most likely to carry compliance risk, because an expression is long precisely when a package aggregates many licensed components. On a stock `fedora:41` root filesystem, `libgomp` has a 744 character expression containing `GPL-3.0-or-later`, and the SBOM records it as `NOASSERTION`.

## Steps to Reproduce

Any scan source reproduces it. The smallest case is a single npm dependency:

```sh
mkdir -p app/node_modules/longlic
echo '{"name":"app","version":"1.0.0","dependencies":{"longlic":"1.0.0"}}' > app/package.json
echo '{"name":"longlic","version":"1.0.0","license":"MIT AND Apache-2.0 AND BSD-3-Clause AND ISC AND Zlib AND MPL-2.0 AND GPL-2.0-or-later AND LGPL-2.1-or-later AND CC0-1.0"}' > app/node_modules/longlic/package.json

feluda --path app --json # license resolves correctly, 119 characters
feluda sbom spdx --path app --output s.json
grep licenseDeclared s.json # NOASSERTION
```

Observed on a `fedora:41` root filesystem via `--filesystem`, on a Debian package via a `copyright` file, and on the npm case above, so it is independent of the scan source.

## Root cause

The length test in the structural constraint block of `convert_to_spdx_license_expression`, at src/sbom/spdx.rs:161:

https://github.com/anistark/feluda/blob/2e0d5d5/src/sbom/spdx.rs#L160-L166

The correlation is exact. Across the 124 packages of a `fedora:41` root filesystem, every expression over 100 characters was replaced with `NOASSERTION` and every expression under it was preserved. The shortest one dropped was 116 characters, the longest one kept was 96, and no other rule in the function fired for any of them.

CycloneDX is affected through the same path, because it converts from the SPDX document rather than from `LicenseInfo`:

https://github.com/anistark/feluda/blob/2e0d5d5/src/sbom/cyclonedx.rs#L225-L226

It records `{"license": {"name": "NOASSERTION"}}` for the same components.

## Environment

- feluda 1.15.0, commit 2e0d5d5
- Reproduced on macOS 15.3, and independent of platform since the check is a plain string length test

## Additional Context

Introduced in c5cb0ba (#163), which added the character validation and structural checks around it. The other rules in that function guard against genuinely malformed or unsafe input, so this is specifically about the arbitrary length bound rather than the validation as a whole.

Two things worth deciding alongside a fix:

- Whether a long but structurally valid expression should ever be discarded, given that the same function already rejects forbidden characters and template patterns separately.
- Whether an expression that genuinely cannot be represented should fall back to `LicenseRef-feluda-*` with the text in `hasExtractedLicensingInfos`, which is the mechanism the SBOM ingest enrichment already uses for free-form registry titles, rather than to `NOASSERTION`.

## Acceptance criteria

- A structurally valid license expression of any length survives into both `spdx` and `cyclonedx` output.
- The 14 packages of a stock `fedora:41` root filesystem that currently report `NOASSERTION` carry their real expressions.
- `feluda sbom validate` still passes with zero errors on the result.
- A regression test covers an expression over 100 characters.

Guide de contribution

Ouvrir le guide de contribution

Évaluation

Cette issue n'a pas encore été évaluée.

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.