New vulnerability statistics records for previous vulnerability severity levels are initialized with negative values

Summary

When a vulnerability is updated, we call Vulnerabilities::BaseService#update_statistics which calls Vulnerabilities::Statistics::UpdateService#execute to create or update an entry in the vulnerability_statistics table.

If there are no entries in the vulnerability_statistics table for the given project, a new record is inserted, and the severity value corresponding to the vulnerability will be incremented.

For example, if a new vulnerability with severity level critical is created, the new vulnerability_statistics record will be the following:

id                 | 2652
created_at         | 2024-07-17 05:51:26.547461+00
updated_at         | 2024-07-18 01:15:43.464296+00
project_id         | 63
total              | 1
critical           | 1
high               | 0
medium             | 0
low                | 0
unknown            | 0
info               | 0
letter_grade       | 4
latest_pipeline_id | 870

However, if a vulnerability is updated, for example, the severity level changes from high to critical, then the new vulnerability_statistics record will be the following:

id                 |  2652
created_at         |  2024-07-17 05:51:26.547461+00
updated_at         |  2024-07-18 01:15:43.464296+00
project_id         |  63
total              |  0
critical           |  1
high               | -1
medium             |  0
low                |  0
unknown            |  0
info               |  0
letter_grade       |  4
latest_pipeline_id |  870

As you can see from the above table, the count of high severities is -1, and the total is 0, whereas these values should be 0 and 1, respectively.

We have code in place to prevent negative severity counts when vulnerability_statistics records are updated, but we don't have this same guard code when inserting new vulnerability_statistics records.

The result of this bug is that the severity level and total counts for the vulnerability_statistics table will be off by one

Steps to reproduce

See the test here.

What is the current bug behavior?

Severity level counts for the previous vulnerability severity level in the vulnerability_statistics table are initialized to -1, and the total is 0.

What is the expected correct behavior?

Severity level counts for the previous vulnerability severity level in the vulnerability_statistics table are initialized to 0, and the total is 1.

Possible fixes

/cc @minac

Edited Jul 24, 2024 by Adam Cohen
Assignee Loading
Time tracking Loading