aboutcode-org / aboutcode-org/univers

Empty string accepted as a valid version in Maven/NuGet/RubyGems, and sorts as minimum

Offen
#204 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen
Vorherrschende Sprache
Python
Sterne
50
Forks
29
PR-Merge-Kennzahlen
Keine gemergten PRs in 30 T.

Beschreibung

### Summary

`MavenVersion`, `NugetVersion` and `RubygemsVersion` accept the empty string `""` as a valid version, while `SemverVersion`, `PypiVersion` and others correctly raise `InvalidVersion`. Worse, the accepted empty version then **sorts below every real version**, so downstream range logic silently produces a confident but wrong answer rather than failing.

Tested with univers 32.0.1 on CPython 3.13.

### Reproducer

```python
from univers.versions import (
MavenVersion, NugetVersion, RubygemsVersion, SemverVersion, PypiVersion,
)

# Accepted (inconsistent):
MavenVersion("") # -> MavenVersion(string='')
NugetVersion("") # -> NugetVersion(string='')
RubygemsVersion("") # -> RubygemsVersion(string='')

# Correctly rejected:
SemverVersion("") # -> InvalidVersion
PypiVersion("") # -> InvalidVersion
```

Three different behaviours across schemes, none of them an error for the first group:

```python
MavenVersion("") < MavenVersion("0.0.1") # True -- sorts as minimum
RubygemsVersion("") < RubygemsVersion("0.0.1") # True -- sorts as minimum
NugetVersion("") < NugetVersion("0.0.1") # TypeError:
# '<' not supported between instances of 'NoneType' and 'Version'
```

So `NugetVersion` accepts the value at construction and then raises on comparison, which is a third distinct outcome.

### Why the silent ordering is the harmful part

Consider an OSV range built from a malformed advisory:

```json
{"type": "ECOSYSTEM", "events": [{"introduced": "0"}, {"fixed": ""}]}
```

Because `MavenVersion("")` is accepted *and* sorts as the minimum, the interval `[0, "")` evaluates to the **empty set**. Code comparing this against the advisory's previous range concludes, with no error and no warning, that the affected set was reduced to nothing — i.e. that the range was retracted.

We hit this in a measurement study over the git history of the GitHub Advisory Database. GHSA emitted schema-invalid `{"fixed": ""}` into 2,107 advisory revisions during a single week in March 2023. Because three of the ecosystems we needed silently accepted it, our comparator produced roughly **1,000 spurious "affected range narrowed" events** in Maven alone — a confidently wrong classification, not a crash we could catch. The npm/PyPI/Go paths were unaffected precisely because they raise `InvalidVersion`.

The general hazard: a caller cannot rely on "the version parsed successfully" as a validity check, and the failure is scheme-dependent, so it shows up only in some ecosystems and looks like real data.

### Suggested resolution

Whatever the decision on leniency, the three schemes should agree with each other and with the rest of the library. Options, in our order of preference:

1. Raise `InvalidVersion` for `""` in `MavenVersion`, `NugetVersion` and `RubygemsVersion`, matching `SemverVersion`/`PypiVersion`. An empty string is not a version in any of these ecosystems' specs.
2. If empty is to be accepted deliberately (see #10), make it consistent across all schemes **and** define its ordering explicitly rather than letting it fall out of the attribute tuple — the current `NugetVersion` `TypeError` on comparison shows the ordering is not well-defined today.

A test asserting identical `""` behaviour across every `Version` subclass would prevent the schemes drifting apart again.

### Related

- #10 `parse_version() should accept None and empty strings` — related but pointing the other way; this report is about the *inconsistency between schemes* and the silently wrong ordering, independent of which behaviour is chosen. The comment there that "None or empty would be the same... I am not sure this would make any sense" suggests option 1 is the intended direction.
- #203 `Do not allow creation of VersionRange with empty constraint` — same family of problem one level up, at the range rather than the version.

Happy to send a PR for option 1 plus the cross-scheme test if that is the direction you'd like.

Beitragsleitfaden

Für dieses Repository ist kein Beitragsleitfaden indexiert

Bewertung

Dieses Issue wurde noch nicht bewertet.

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.