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 摘要。