aboutcode-org / aboutcode-org/univers

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

未關閉
#204 0 則留言 0 個 reaction 已指派 0 人 在 GitHub 檢視
主要語言
Python
星號
50
分支
29
PR 合併指標
30 天內沒有已合併 PR

描述

### 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.

貢獻指南

這個儲存庫沒有索引到貢獻指南

評估

這個 Issue 還沒有評估資料。

把新 issue 寄到你的電子郵件信箱

精選適合新手參與的 GitHub issue 摘要。