22vers: a mostly universal version range specifier
33======================================================
44
5- This specification is an attempt to standardize on a subset of existing
6- notations to reliably communicate software package version ranges as used in
7- package dependencies and vulnerabilities advisories.
5+ This specification is a new syntax for dependency and vulnerable version ranges.
86
97
108Context
@@ -27,20 +25,20 @@ interest. But in practice, all the versions may not yet exist when defining an
2725open version range such as "v2.0 or later".
2826
2927Therefore, a version range is a necessary, compact and practical way to
30- reference multiple versions rather that listing all the versions.
28+ reference multiple versions rather than listing all the versions.
3129
3230
3331Problem
3432--------
3533
36- Several version range syntaxes exist and have evolved separately to serve the
34+ Several version range notations exist and have evolved separately to serve the
3735specific needs of each package ecosystem, vulnerability databases and tools.
3836
39- There is no (mostly) universal syntax for version ranges and there is no
37+ There is no (mostly) universal notation for version ranges and there is no
4038universal way to compare two versions, even though the concepts that exist in
4139most version range notations are similar.
4240
43- Each package type or ecosystem may define their own range syntax and version
41+ Each package type or ecosystem may define their own ranges notation and version
4442comparison semantics for dependencies. And for security advisories, the lack of
4543portable notation for vulnerable package version ranges means that these ranges
4644may be either ambiguous or hard to compute and are typically replaced by
@@ -49,7 +47,7 @@ complete enumerations of all versions, such as the NVD CPEs.
4947Because of this, expressing and resolving a version range is often a complex, or
5048error prone task.
5149
52- In particular the need for common syntax for version has emerged based on the
50+ In particular the need for common notation for version has emerged based on the
5351usage of Package URLs referencing vulnerable package version ranges such as in
5452vulnerability databases like VulnerableCode.
5553
@@ -66,8 +64,7 @@ in use:
6664 https://dart.dev/tools/pub/versioning provides a comprehensive coverage of the
6765 topic of versioning. But version resolution is using its own algorithm.
6866
69- - Python uses its own syntax and version ranges notation specific to Python
70- https://www.python.org/dev/peps/pep-0440/
67+ - Python uses its own version ranges notation https://www.python.org/dev/peps/pep-0440/
7168
7269- Debian and Ubuntu use their own notation
7370 https://www.debian.org/doc/debian-policy/ch-relationships.html
@@ -90,31 +87,38 @@ in use:
9087- Go modules https://golang.org/ref/mod#versions use semver versions with
9188 specific version resolution algorithms.
9289
90+ - Haskell Package Versioning Policy https://pvp.haskell.org/ provides a notation
91+ similar to this specification based on a modified semver with extra notations
92+ such as star and caret.
93+
94+
9395Note that there is a closely related problem: the way two versions are compared
9496as equal, lesser or greater is complex and package types may have evolved their
9597own peculiar version comparison procedure. Semver is a prominent specification
96- in this domain but this is just one of the many versioning schemes. Semver, Debian,
97- RPM, PyPI, Rubygems, and Composer all have their own subtly different ways of
98- comparing two versions even though they may seem highly similar at first glance.
98+ in this domain but this is just one of the many versioning schemes. Semver,
99+ Debian, RPM, PyPI, Rubygems, and Composer all have their own subtly different
100+ ways of comparing two versions even though they may seem highly similar at first
101+ glance.
99102
100103
101104Solution
102105---------
103106
104- A solution to the many version ranges syntaxes is to design a new syntax to
107+ A solution to the many version range syntaxes is to design a new notation to
105108unify them all with:
106109
107- - a mostly universal and minimalist syntax to express the version range notations from many different package types and ecosystems.
110+ - a mostly universal and minimalist notation to express the version range
111+ notations from many different package types and ecosystems.
108112
109113- the package type-specific definitions to normalize existing range expressions
110- to this common syntax .
114+ to this common notation .
111115
112116- the designation of which algorithm or procedure to use when comparing two
113117 versions such that it is possible to resolve if a version is within or
114118 outside of a version range.
115119
116120We call this solution "version range specifier" or "vers" and it is described
117- here .
121+ in this document .
118122
119123
120124Version range specifier
@@ -139,7 +143,7 @@ constraint such as::
139143Or a composite constraint grouping multiple ``<version-constraint> `` joined by
140144an ampersand such as:
141145
142- <comparator:version>&<comparator:version>...
146+ <comparator:version>&<comparator:version>...
143147
144148The comma is a logical `OR ` and the ampersand is a logical `AND `.
145149
@@ -148,9 +152,8 @@ A version range specifier is therefore an "OR of ANDs". This is also called a
148152See https://en.wikipedia.org/wiki/Disjunctive_normal_form for details.
149153
150154``vers `` is the URI-scheme and is an acronym for "VErsion Range Specifier". It
151- has been selected because it is short, obviously about version and available in
152- the IANA URI-schemes registry for a future formal registration for this URI-
153- scheme.
155+ has been selected because it is short, obviously about version and available
156+ for a future formal registration for this URI-scheme at the IANA registry.
154157
155158
156159``<versioning-scheme> ``
@@ -159,15 +162,15 @@ scheme.
159162The ``<versioning-scheme> `` (such as ``semver ``,
160163``debian ``, etc.) determines:
161164
162- - the specific syntax and conventions used for a version string encoded in this
163- scheme. Versioning schemes often specify a version segments separator and
165+ - the specific notation and conventions used for a version string encoded in
166+ this scheme. Versioning schemes often specify a version segments separator and
164167 the meaning of each version segments, such as [major.minor.patch] in semver.
165168
166169- how two versions compare as greater or lesser to determine if a version is
167170 within or outside a range.
168171
169- - how a versioning scheme-specific range syntax can be transformed in the
170- ``vers `` syntax defined here.
172+ - how a versioning scheme-specific range notation can be transformed in the
173+ ``vers `` notation defined here.
171174
172175Note: the ``<versioning-scheme> `` does not define which symbols to use to
173176compare versions, and how to compose these as this is the substance of this
@@ -204,27 +207,34 @@ The ``<comparator>`` is one of these comparison operators:
204207 strings and is not versioning scheme-specific.
205208
206209- "!=": Version exclusion or inequality comparator. This means a version must
207- not be equal to the provided version and is excluded from the range. For
208- example: "!=1.2.3".
210+ not be equal to the provided version and this version must be excluded from
211+ the range. For example: "!=1.2.3" means that version "1.2.3" is not part of
212+ the range.
209213
210214- "<", "<=": Less than or less-or-equal version comparators points to all
211215 versions less than or equal to the provided version. For example "<=1.2.3"
212- means less than or equal to "1.2.3". The way two version strings are compared
213- using these comparators is implied by the versioning scheme.
216+ means less than or equal to "1.2.3".
214217
215- - "< ", "< =": Greater than or greater-or-equal version comparators points to
218+ - "> ", "> =": Greater than or greater-or-equal version comparators points to
216219 all versions greater than or equal to the provided version. For example
217220 ">=1.2.3" means greater than or equal to "1.2.3".
218221
219222- The way two version strings are compared using these comparators is defined
220223 by the ``<versioning-scheme> ``.
221224
222- - The syntax of a version such as "1.2.3" is defined by the
223- ``<versioning-scheme> ``.
225+ - The structure and meaning of a version string such as "1.2.3" is defined by
226+ the ``<versioning-scheme> ``. For instance, ``semver `` defines three
227+ dot-separated segments name major, minor and patch.
224228
225229- The special star "*" ``<version-constraint> `` matches any version. This star
226- constraint must be used **alone ** in a version range specifier.
227- For example "vers:debian/\* " would resolve to any version.
230+ constraint must be used **alone ** in a version range specifier, exclusive of
231+ any other constraint. For example "vers:debian/\* " resolves to any version.
232+
233+
234+ Examples
235+ ~~~~~~~~~
236+
237+ TODO.
228238
229239
230240Normalized or canonical representation
@@ -237,10 +247,9 @@ Normalized or canonical representation
237247 "!=1.2.3" and " ! = 1.2. 3" are equivalent. And so are "1.2.3 & < = 2.0.0" and
238248 "1.2.3&<=2.0.0"
239249
240- - Version ranges specifiers are case-insensitive and lowercase in their
241- canonical form.
250+ - A version range specifier is case-insensitive and lowercase in canonical form.
242251
243- - The ordering of multiple ``<version-constraint> `` in a specifier is not
252+ - The ordering of multiple ``<version-constraint> `` in a range specifier is not
244253 significant. The canonical ordering is by sorting these by lexicographical
245254 order applied with this approach:
246255
@@ -249,8 +258,9 @@ Normalized or canonical representation
249258
250259- A version in a ``<version-constraint> `` can only contain printable ASCII
251260 characters excluding the special characters used as separators and comparators
252- ``><=!,&* ``. If required (which should be rare in practice) the version
253- in a constraint must be quoted using the URL quoting rules.
261+ ``><=!,&* ``. If it contains special characters (which should be rare in
262+ practice) the version string in a constraint must be quoted using the URL
263+ quoting rules.
254264
255265
256266Using version range specifiers
@@ -265,19 +275,21 @@ outside of the range specifier.
265275
266276Some important usages derived from this primary usage include:
267277
268- - resolving a version range specifier to a list of concrete versions. In this
269- case, the input is the set of known versions of a package (typically obtained
270- from some package repository or registry). Each version is then tested
271- individually to check if it is within or outside the ranges. For example, this
272- can be used to determine which existing package versions are affected by a
273- known vulnerability version range specifier.
278+ - **Resolving a version range specifier to a list of concrete versions. **
279+ In this case, the input is the set of known versions of a package (typically
280+ obtained from some package repository or registry). Each version is then
281+ tested individually to check if it is within or outside the ranges. For
282+ example, this can be used to determine which existing package versions are
283+ affected by a known vulnerability if they match the vulnerability version
284+ range specifier.
274285
275- - selecting one of several versions that are within a range specifier.
286+ - ** Selecting one of several versions that are within a range. **
276287 For example, package management tools need to determine what are the dependent
277- package versions of a package instance. This usually requires deploying
278- heuristics and algorithms (often complex such as sat solvers) that are
279- versioning-scheme- and tool-specific and outside of the scope for this
280- specification.
288+ package versions of a package instance based the acceptable version ranges
289+ provided with each dependency. This usually requires deploying heuristics and
290+ algorithms (possibly complex such as sat solvers) that are versioning-scheme-
291+ and tool-specific and outside of the scope for this specification; ``vers ``
292+ scope is limited to provide an input to the resolution process.
281293
282294
283295Parsing version range specifiers
@@ -406,20 +418,33 @@ Implementations
406418- Yours!
407419
408420
409- Why not reuse existing version ranges syntaxes ?
421+ Why not reuse existing version range notations ?
410422~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
411423
412- Most existing version ranges syntaxes are tied to a specific version syntax and
413- are therefore not readily applicable to other contexts such as tilde and caret
414- ranges as used in Ruby or Dart. The inclusion of additional comparators is a
415- result of the history and evolution in a package ecosystem.
424+ Most existing version range notations are tied to a specific version string
425+ syntax and are therefore not readily applicable to other contexts. For example,
426+ the use of elements such as tilde and caret ranges in Ruby or Dart notations
427+ implies that a certain structure exists in the version string (semver or semver-
428+ like). The inclusion of these additional comparators is a result of the history
429+ and evolution in a given package ecosystem to address specific needs.
416430
417431In practice, the unified and reduced set of comparators and syntax defined for
418- ``vers `` has been designed such that all these notations can be
419- converted to a ``vers `` and back from a ``vers `` to the original notation. There
420- are likely to be a few rare cases where round tripping may not be possible, and
421- in anycase round tripping to and from ``vers `` may only produce equivalent
422- results and not strictly the same original strings.
432+ ``vers `` has been designed such that all these notations can be converted to a
433+ ``vers `` and back from a ``vers `` to the original notation.
434+
435+ In contrast, this would not be possible with existing notations. For instance,
436+ the Python notation may not work with npm versions and reciprocally.
437+
438+ There are likely to be a few rare cases where round tripping from and to
439+ ``vers `` may not be possible, and in anycase round tripping to and from ``vers ``
440+ may only produce equivalent results and not strictly the same original strings.
441+
442+ Another issue with existing version range notations is that, they are primarily
443+ meant to be used for dependency constraints and may not readily be reused for
444+ vulnerable ranges. In particular, a vulnerability may exist for multiple
445+ "branches" of a given package (such as Django 2, 3 and 4) which may not be
446+ possible to express with a notation designed exclusively for dependent versions
447+ resolution.
423448
424449
425450Why not use the NVD CPE Ranges?
@@ -447,20 +472,21 @@ https://github.com/npm/node-semver#ranges
447472The node semver is very similar to this spec (this is also an OR of ANDs) but it
448473has a few practical issues:
449474
450- - The space means "AND" and significant whitespaces in a single string makes
451- normalization more complicated and may be a source of confusion or errors.
452- The explicit ampersand "AND" operator specified here improves clarity.
475+ - The space means "AND" and significant whitespace in a single string makes
476+ normalization more complicated and may be a source of confusion or errors. The
477+ explicit ampersand used an "AND" operator specified here improves clarity.
453478
454- - There is no negation "!=" operator meaning that some version constraints
455- are difficult to express and require combining < and > comparators. For
456- instance stating that a vulnerability affects babel 6.2 or later but not
457- babel 7.0 is possible but difficult.
479+ - There is no negation "!=" operator meaning that some version constraints are
480+ difficult to express and require combining < and > comparators. For instance
481+ stating that a vulnerability affects babel 6.2 or later but not babel 7.0 is
482+ possible but difficult.
483+
484+ - The advanced range syntax has grown to be rather complex using hyphen, stars,
485+ carets and tilde constructs are all tied to the JavaScript and npm ways of
486+ handling versions in their specific ecosystem and furthermore are bound to the
487+ semver semantics. These are not readily reusable elsewhere. And these multiple
488+ comparators and modifiers make the grammar and parsing more complex.
458489
459- - The advanced range syntax has grown to be rather complex using hyphen,
460- stars, carets and tilde constructs all tied to the JavaScript and npm ways
461- of handling versions in their specific ecosystem and furthermore bound to
462- semver. These are not readily reusable elsewhere. And these multiple
463- comparators and modifiers make the grammar and parsing more complex.
464490
465491Why not use Python pep-0440 ranges?
466492#####################################
@@ -475,16 +501,17 @@ This specification is mostly compatible with and is similar to this ``vers``
475501spec, but has a richer notation with some aspects specific to the version used
476502only in the Python ecosystem.
477503
478- - In particular pep-0440 uses tilde, triple equal and wildcard star operators
479- that are specific to how two Python versions are compared.
504+ - In particular pep-0440 uses tilde, triple equal and wildcard star operators
505+ that are specific to how two Python versions are compared.
506+
507+ - The comma separator between constraints is a logical "AND" rather than an
508+ "OR". The "OR" does not exist in the syntax making some version ranges
509+ harder to express, in particular for vulnerabilities that may affect several
510+ exact versions or version ranges such as when there are multiple release
511+ branches that exist in parallel. For instance a statement such as: Django 1.2
512+ or later, or Django 2.2 or later or Django 3.2 or later is difficult to
513+ express without an "OR" logic.
480514
481- - The comma separator between constraints is a logical "AND" rather than an
482- "OR". The "OR" does not exist in the syntax making some version ranges
483- harder to express, in particular for vulnerabilities that may affect
484- several exact versions or version ranges such as when there are multiple
485- release branches that exist in parallel. For instance a statement such as:
486- Django 1.2 or later, or Django 2.2 or later or Django 3.2 or later is
487- difficult to express without an "OR" logic.
488515
489516Why not use Rubygems requirements notation?
490517##############################################################
0 commit comments