Skip to content

Add a formal semver 2.0.0 version type #371

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 57 commits into
base: feature-PR371-semver2.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
c50a136
Add a formal semver 2.0.0 version type
darakian Dec 9, 2024
bec099b
Add an example for discussion
darakian Jan 22, 2025
20f9b39
Add some text for the parameters and remove markdown horizontal break
darakian Jan 22, 2025
e637776
Expand example to show inclusive/exclusive bounds and single version …
darakian Jan 30, 2025
fffd0cd
Add explainer
darakian Jan 30, 2025
16680d2
Add examples of single sided ranges. ex < 1.0.0 or >= 9.0.0 to allow …
darakian Feb 19, 2025
208980b
Add status back as a parameter after sync chat in QWG meeting on 2025…
darakian Feb 20, 2025
0ce6601
Stub new properties
darakian Mar 5, 2025
62db169
Add pattern regex
darakian Mar 5, 2025
34af2ae
and trim newline
darakian Mar 5, 2025
046dadd
Add an attempt at json schema options for semver 2.0.0
darakian Mar 6, 2025
484ca76
Add valid forms of semver-2.0.0 usage
darakian Mar 12, 2025
3527158
trim extra comma
darakian Mar 12, 2025
b037e53
Switch from anyOf to oneOf
darakian Mar 12, 2025
226158a
Update build.js to reference current schema location
darakian Mar 12, 2025
e264318
Add missing comma
darakian Mar 12, 2025
ddf4895
Double slash seems to be the correct approach
darakian Mar 13, 2025
7b77630
Fix typo to allow stand alone inclusive lower bound
darakian Mar 13, 2025
bf48730
Add validation of schemas to the workflow
darakian Mar 14, 2025
e333f53
Prefer test over validate for symmetry with invalid test to come
darakian Mar 14, 2025
992e9c3
Be strict about versionType value
darakian Mar 14, 2025
9226d60
Add invalid test for missing versionType
darakian Mar 14, 2025
3f33ceb
Break tests out for easier long term managment
darakian Mar 14, 2025
eb4fd2f
Add test case for mixing exactly with a range
darakian Mar 14, 2025
36a22ee
Add test case for duplicate upper bounds
darakian Mar 14, 2025
fd0d7e1
Add test case for duplicate lower bounds
darakian Mar 14, 2025
745cc6f
Add semver tests to the workflow
darakian Mar 14, 2025
a0ff77b
Remove test
darakian Mar 14, 2025
9f839d6
Removing this test for now. Unclear why it fails
darakian Mar 14, 2025
5cc921e
Move semver regex out to a single def and reference it
darakian Apr 1, 2025
9a4ad63
stub idea for changes block
darakian Apr 1, 2025
50d0e12
Add a test to ensure asterisk usage fails
darakian Apr 18, 2025
a72e5b8
Update schema with working concept of reusing old parameters. Adds tw…
darakian Apr 30, 2025
9d53824
Update positive tests. IMO they are less readable than before
darakian Apr 30, 2025
30bd0de
Check for invalid format in semver 2.0.0 rather than invalid version …
darakian Apr 30, 2025
10c83ec
Clean up language on usage of the two new parameters
darakian May 1, 2025
fc8b7b8
Typo fix 🤦
darakian May 1, 2025
6135668
Remove missing version test since not specifying is valid and the use…
darakian May 8, 2025
43e4f17
Update negative tests
darakian May 8, 2025
1e91117
ref instead of duplicate regex
darakian May 11, 2025
0dc04e2
remove overconstraint I guess. This lets two tests pass (mixedRange1 …
darakian May 11, 2025
da94093
Stub rfd from template
darakian Jun 14, 2025
5ac7c5f
Stage draft RFD
darakian Jun 16, 2025
a3f5748
Update success metrics
darakian Jun 17, 2025
b8b9afd
Update migration
darakian Jun 17, 2025
85af8eb
update impact
darakian Jun 17, 2025
97f14c2
Remove blank line
darakian Jun 17, 2025
b800796
typo plus a +
darakian Jun 26, 2025
69aba3f
Better impact
darakian Jun 26, 2025
c9fde50
Remove the word new
darakian Jul 16, 2025
bc077f5
Update verbiage
darakian Jul 16, 2025
64774b5
Update examples
darakian Jul 16, 2025
4d091a0
Mention that not adopting is an option
darakian Jul 16, 2025
7ba977b
Remove template text for supporting data/research
darakian Jul 16, 2025
1bb151e
Delete some trailing commas
darakian Jul 17, 2025
4427021
Provide symmetry in parameter requirements
darakian Jul 17, 2025
c6e12cb
Delete two more trailing commas
darakian Jul 18, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/validate-schema.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,7 @@ jobs:
ajv validate -c ajv-formats -s "${CVE_SCHEMA_DIR}/docs/CVE_Record_Format_bundled.json" -d "${CVE_SCHEMA_DIR}/docs/full-record-advanced-example.json"
ajv validate -c ajv-formats -s "${CVE_SCHEMA_DIR}/docs/CVE_Record_Format_bundled_cnaPublishedContainer.json" -d "${CVE_SCHEMA_DIR}/docs/cnaContainer-advanced-example.json"
ajv validate -c ajv-formats -s "${CVE_SCHEMA_DIR}/docs/CVE_Record_Format_bundled_cnaPublishedContainer.json" -d "${CVE_SCHEMA_DIR}/docs/cnaContainer-basic-example.json"
# Run semver 2.0.0 tests
ajv test -c ajv-formats -s "${CVE_SCHEMA_DIR}/docs/CVE_Record_Format_bundled.json" -d "${CVE_SCHEMA_DIR}/support/tests/valid/valid-semver-2-0-0/*.json" --valid
ajv test -c ajv-formats -s "${CVE_SCHEMA_DIR}/docs/CVE_Record_Format_bundled.json" -d "${CVE_SCHEMA_DIR}/support/tests/invalid/invalid-semver-2-0-0/*.json" --invalid

81 changes: 81 additions & 0 deletions rfds/0000-formalize-semver-version-type.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Add a formal semver 2.0.0 version type

| Field | Value |
|:-----------------|:-------|
| RFD Submitter | Jon Moroney |
| RFD Pull Request | [RFD #0000](https://github.com/CVEProject/cve-schema/pull/371) |

## Summary
[summary]: #summary

Introduce a new semantic versioning version type for the machine readable `versions` array. The goal of this addition is to provide consumers of CVE records with version information which is interoperable with off the shelf semantic versioning compatible tools. The proposed change includes schema based validation to ensure submitted records conform to the semver specification as well as tests to ensure conformity.

## Problem Statement
[problem-statement]: #problem-statement

Today the `versions` array allows for a number of typed version fields which should inform the reader how to interpret the data. Alas, there is no validation that a record producer must conform to and as a result the version types have been used inconsistently. A consumer reading the semantic versioning type in particular has about a [44% chance of the data conforming to the semantic versioning specification](https://darakian.github.io/2025/06/04/parsing-semver-from-cve.html).

As a result consumers of CVE records cannot build reliable automation from the data in the record itself. Multiple sub-patterns do exist, but there is canonical list of them nor is there any guarantee of their stability. This leads to increased operational complexity in vulnerability management and potentially to vulnerabilities going unresolved.

Failing to adopt stricter datatypes will keep maintain the status quo which is generally accepted to be lacking.

## Proposed Solution
[proposed-solution]: #proposed-solution

The proposed change adds a new "semver-2.0.0-version" pattern and two new properties for expressing version ranges. The two new properties `greaterThan`, and `greaterThanOrEqual` allow for the expression of an either exclusive, or inclusive upper bound on a version range. The new pattern "semver-2.0.0-version" is used to validate payloads which may be provided in the `version`, `lessThan`, `lessThanOrEqual`, `greaterThan`, and `greaterThanOrEqual`.

## Examples
[examples]: #examples

Examples are provided as tests and may be viewed in the valid and invalid semver-2-0-0 subdirectories here:
https://github.com/CVEProject/cve-schema/tree/0dc04e2a9adb9e3d50409051ce1d006d79b57a90/schema/support/tests

## Impact Assessment
[impact-assessment]: #impact-assessment

This proposal has been designed to be very low impact. In the base case both record producers and record consumers can simply ignore the new data type. Adoption of the new data type into systems that process CVE records should be quite straight forward as semantic versioning is well supported across many languages. Once records begin to be produced with `semver-2.0.0` values a record consumer will be able to build reliable vulnerability managment automation based on the data.

## Compatibility and Migration
[compatibility-and-migration]: #compatibility-and-migration

This change adds one new, optional, value to the `versions` array and should be completely backwards compatible as no prior data formats are altered. The version type is currently arbitrary and so record providers are free to populate anything in that field, however no currently published records have used `semver-2.0.0`.

Both consumers are producers will need to update their code/process in order to make use of the new field. Should there be a desire to coordinate a migration an addition could be made to this RFD with guidance both for record producer and consumers, but off the shelf, semver compatible tools are expected to work.

Existence of the new version type should be communicated to stakeholders upon the RFDs acceptance.

## Success Metrics
[success-metrics]: #success-metrics

6+ months after the acceptance and adoption of this RFD process, the QWG should conduct a review of published CVE records to assess usage of the new version type. Additionally the QWG should solicit a survey to QWG members and outside CVE stakeholders about the perceived value of the new type. If there is low/no usage as well as a poor qualitative perception then the effort should be considered a failure and discussion of a rollback should be considered.

If there is consistent measured usage as well as positive qualitative perception then the effort should be considered a success. Anything between these two polls will require more qualitative analysis, but it is the RFD author's opinion that if there is a lack of consensus then the effort should by default be considered a failure.

A roll back of this RFD would consist of a removal of the `semver-2.0.0` version type and associated tests.

## Supporting Data or Research
[supporting-data-or-research]: #supporting-data-or-research


## Related Issues or Proposals
[related-issues-or-proposals]: #related-issues-or-proposals

This change originated out of a conversation detailing the shortcomings of the current versioning system here:
https://github.com/CVEProject/cve-schema/issues/362

An alternative to adopting this RFD would be to not adopt it.

## Recommended Priority
[recommended-priority]: #recommended-priority

Medium

## Unresolved Questions
[unresolved-questions]: #unresolved-questions

None currently.

## Future Possibilities
[future-possibilities]: #future-possibilities

Other common versioning types could have new, validated versions provided via subsequent RFDs.
41 changes: 38 additions & 3 deletions schema/CVE_Record_Format.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,11 @@
"minLength": 1,
"maxLength": 1024
},
"semver-2.0.0-version": {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since a PATCH is backwards compatible.

Suggested change
"semver-2.0.0-version": {
"semver-2.0-version": {

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I may be incorrect, but I don't see this definition referenced anywhere. Is this intentional?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe we've resolved this point in QWG discussions since this comment was posted. "2.0" is not a valid SemVer version, and it would be awkward to version our SemVer version type with a version which is not itself a valid SemVer version.

"description": "A semver 2.0.0 compatible version",
"type": "string",
"pattern": "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$"
},
"status": {
"description": "The vulnerability status of a given version or range of versions of a product. The statuses 'affected' and 'unaffected' indicate that the version is affected or unaffected by the vulnerability. The status 'unknown' indicates that it is unknown or unspecified whether the given version is affected. There can be many reasons for an 'unknown' status, including that an investigation has not been undertaken or that a vendor has not disclosed the status.",
"type": "string",
Expand Down Expand Up @@ -299,12 +304,32 @@
"maxProperties": 3
},
{
"required": ["version", "status", "versionType", "lessThan"]
"required": ["status", "versionType", "lessThan"]
},
{
"required": ["status", "versionType", "lessThanOrEqual"]
},
{
"required": ["version", "status", "versionType", "lessThanOrEqual"]
"required": ["status", "versionType", "greaterThan"]
},
{
"required": ["status", "versionType", "greaterThanOrEqual"]
}
],
"if": {
"properties": {
"versionType": {"const": "semver-2.0.0"}
Copy link
Collaborator

@david-waltermire david-waltermire May 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since a PATCH must be backwards compatible.

Suggested change
"versionType": {"const": "semver-2.0.0"}
"versionType": {"const": "semver-2.0"}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I said here (https://github.com/CVEProject/cve-schema/pull/371/files#r2210891519) I believe we've resolved this in QWG discussions, determining that "2.0.0" is correct.

}
},
"then": {
"properties": {
"version": { "$ref": "#/definitions/semver-2.0.0-version" },
"lessThan": { "$ref": "#/definitions/semver-2.0.0-version" },
"lessThanOrEqual": { "$ref": "#/definitions/semver-2.0.0-version" },
"greaterThan": { "$ref": "#/definitions/semver-2.0.0-version" },
"greaterThanOrEqual": { "$ref": "#/definitions/semver-2.0.0-version" }
}
},
"properties": {
"version": {
"description": "The single version being described, or the version at the start of the range. By convention, typically 0 denotes the earliest possible version.",
Expand Down Expand Up @@ -336,6 +361,14 @@
"description": "The inclusive upper limit of the range. This is the greatest version contained in the range. Only one of lessThan and lessThanOrEqual should be specified. For example, `{version: 1.0, lessThanOrEqual: 1.3}` covers all versions from 1.0 up to and including 1.3.",
"$ref": "#/definitions/version"
},
"greaterThan": {
"description": "The exclusive lower limit of the range. This is the lowest version NOT in the range. Used only for ranges which extend to positive infinity.",
"$ref": "#/definitions/version"
},
"greaterThanOrEqual": {
"description": "The inclusive lower limit of the range. This is the lowest version in the range. Used only for ranges which extend to positive infinity.",
"$ref": "#/definitions/version"
},
"changes": {
"type": "array",
"description": "A list of status changes that take place during the range. The array should be sorted in increasing order by the 'at' field, according to the versionType, but clients must re-sort the list themselves rather than assume it is sorted.",
Expand All @@ -349,7 +382,9 @@
"properties": {
"at": {
"description": "The version at which a status change occurs.",
"$ref": "#/definitions/version"
"oneOf": [
{"$ref": "#/definitions/version"}
]
},
"status": {
"description": "The new status in the range starting at the given version.",
Expand Down
72 changes: 72 additions & 0 deletions schema/docs/versions.md
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,78 @@ Now that we know how to encode version objects, that would be written as:
}
]

### Version Types

#### Semantic versioning 2.0.0

Type identifier: `semver-2.0.0`
Formally specified here at https://semver.org/spec/v2.0.0.html
`semver-2.0.0` is type introduced to formally specify usage of semantic versioning.

`semver-2.0.0` in its simplest form is a dot separated triple. eg `1.2.3`. The three parts have names with the first being the `MAJOR`, the second being `MINOR` and the third `PATCH`. The [Semantic](https://en.wikipedia.org/wiki/Semantics) meaning of each is described as
1. MAJOR version when you make incompatible API changes
2. MINOR version when you add functionality in a backward compatible manner
3. PATCH version when you make backward compatible bug fixes
This triple can be extended with either a `-` or a `+` or with both for `pre-release` and `build` identifiers.
The triple can only be populated with non-negative integers and must not contain leading zeros.
Ordering of the triple is determined by the first difference when comparing each of these identifiers from left to right as follows: Major, minor, and patch versions are always compared numerically.
Full ordering for pre-releases and builds are described in the semver document [here](https://semver.org/spec/v2.0.0.html#spec-item-11).
While the triple can only contain numeric values the `pre-release` and `build` are free to be alpha numeric.
A complete definition of this version type can be viewed here
https://semver.org/spec/v2.0.0.html#backusnaur-form-grammar-for-valid-semver-versions

The `semver-2.0.0` version type has five possible parameters which may be used to define either a single version or a continuous range. The parameters are `version`, `lessThan`, `lessThanOrEqual`, `greaterThan`, and `greaterThanOrEqual`. The use of `version` alone defines a single version when used alone or an inclusive bound when used with one of the other parameters. Each parameter must be a valid semver triple with optional pre-release/build extensions.

##### Example

```
"affected": [
{
"vendor": "Example.org",
"product": "Example Enterprise",
"versions": [
{
"versionType": "semver-2.0.0",
"status": "affected",
"version": "1.2.3-alpha",
"lessThan": "2.3.4+build17"
}
{
"versionType": "semver-2.0.0",
"status": "unaffected",
"greaterThan": "3.4.5-beta",
"version": "4.5.6+assembly88"
}
{
"versionType": "semver-2.0.0",
"status": "affected",
"version": "5.6.7-gamma",
}
{
"versionType": "semver-2.0.0",
"status": "affected",
"version": "6.7.8-delta",
}
{
"versionType": "semver-2.0.0",
"status": "affected",
"lessThan": "1.0.0",
}
{
"versionType": "semver-2.0.0",
"status": "unknown",
"greaterThanOrEqual": "9.0.0",
}
],
}
],
```

#### Explainer

A `semver-2.0.0` version is expressed as either a range or as a single exact version. Chaining multiple `semver-2.0.0` versions can be done to express more complex ranges. A `semver-2.0.0` range must begin with a lower bound which is followed by an upper bound. Each bound may be either inclusive or exclusive. These terms map as `exclusiveUpperBound` to `<`, `inclusiveUpperBound` to `<=`, `exclusiveLowerBound` to `>`, `inclusiveLowerBound` to `>=` and `exactly` to `=`. Thus the first example above could be rewritten as `>= 1.2.3-alpha, < 2.3.4+build17`.


## Version Status Changes

As presented in the previous section,
Expand Down
2 changes: 1 addition & 1 deletion schema/support/Node_Validator/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const path = require("path")
const Ajv = require('ajv').default;
const standaloneCode = require("ajv/dist/standalone").default
const addFormats = require('ajv-formats').default;
const schema = require("../../docs/CVE_JSON_bundled.json")
const schema = require("../../docs/CVE_Record_Format_bundled.json")

function reduceSchema(o) {
for(prop in o) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
{
"dataType": "CVE_RECORD",
"dataVersion": "5.1",
"cveMetadata": {
"cveId": "CVE-1900-1234",
"assignerOrgId": "b3476cb9-2e3d-41a6-98d0-0f47421a65b6",
"state": "PUBLISHED"
},
"containers": {
"cna": {
"providerMetadata": {
"orgId": "b3476cb9-2e3d-41a6-98d0-0f47421a65b6"
},
"problemTypes": [
{
"descriptions": [
{
"lang": "en",
"description": "CWE-78 OS Command Injection"
}
]
}
],
"affected": [
{
"vendor": "Example.org",
"product": "Example Enterprise",
"versions": [
{
"versionType": "semver-2.0.0",
"status": "affected",
"version": "1.2.*"
}
],
"defaultStatus": "unaffected"
}
],
"descriptions": [
{
"lang": "en",
"value": "OS Command Injection vulnerability parseFilename function of example.php in the Web Management Interface of Example.org Example Enterprise on Windows, MacOS and XT-4500 allows remote unauthenticated attackers to escalate privileges.\n\nThis issue affects:\n * 1.0 versions before 1.0.6\n * 2.1 versions from 2.16 until 2.1.9."
}
],
"references": [
{
"url": "https://example.org/ESA-22-11-CVE-1900-1234"
}
]
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
{
"dataType": "CVE_RECORD",
"dataVersion": "5.1",
"cveMetadata": {
"cveId": "CVE-1900-1234",
"assignerOrgId": "b3476cb9-2e3d-41a6-98d0-0f47421a65b6",
"state": "PUBLISHED"
},
"containers": {
"cna": {
"providerMetadata": {
"orgId": "b3476cb9-2e3d-41a6-98d0-0f47421a65b6"
},
"problemTypes": [
{
"descriptions": [
{
"lang": "en",
"description": "CWE-78 OS Command Injection"
}
]
}
],
"affected": [
{
"vendor": "Example.org",
"product": "Example Enterprise",
"versions": [
{
"versionType": "semver-2.0.0",
"status": "affected",
"version": "1.2.3",
"greaterThan": "1.2.4",
"greaterThanEqualTo": "1.2.4"
}
],
"defaultStatus": "unaffected"
}
],
"descriptions": [
{
"lang": "en",
"value": "OS Command Injection vulnerability parseFilename function of example.php in the Web Management Interface of Example.org Example Enterprise on Windows, MacOS and XT-4500 allows remote unauthenticated attackers to escalate privileges.\n\nThis issue affects:\n * 1.0 versions before 1.0.6\n * 2.1 versions from 2.16 until 2.1.9."
}
],
"references": [
{
"url": "https://example.org/ESA-22-11-CVE-1900-1234"
}
]
}
}
}
Loading