Create a new GraphQL type & resolver to return vulnerability grades
What does this MR do?
Before FCV(Fist class vulnerabilities) we were using a RESTish endpoint to fetch all the vulnerable projects and their respective vulnerability stats and frontend application was calculating the letter grades based on the payload given by the backend.
There was no pagination in the old endpoint but since we have the builtin pagination on GraphQL we can not return all the vulnerable projects with their statistics at once so we decided to introduce a new type and move the logic to backend.
With this new type, clients will be able to retrieve the vulnerability letter grade information for group & instance-level security dashboards.
API Changes
Example query;
fragment letterGradeFields on VulnerabilityLetterGrade {
count
projects {
nodes {
name
}
}
}
fragment gradeFields on VulnerabilityGrades {
a { ...letterGradeFields }
b { ...letterGradeFields }
c { ...letterGradeFields }
d { ...letterGradeFields }
f { ...letterGradeFields }
}
query getGroup($fullPath: ID!) {
group(fullPath: $fullPath) {
name
vulnerabilityGrades {
...gradeFields
}
}
}
Model Changes
This MR introduces 2 new models;
-
Vulnerabilities::Stats
is a read model based onvulnerabilities
table which supports access to vulnerability statistics of a specific project. Currently we are calculating the data on the fly which can be later calculated by a trigger or application layer logic to be persisted into its own database table to improve the performance. -
Vulnerabilities::LetterGrade
is a read model as well based on the data we have inVulnerabilities::Stats
model.
SQL Queries
Vulnerability stats of a project
SELECT
"vulnerabilities"."project_id",
COUNT(*) AS count_all,
COUNT(*) FILTER (WHERE severity = 1 AND state IN (1,4)) as info,
COUNT(*) FILTER (WHERE severity = 2 AND state IN (1,4)) as unknown,
COUNT(*) FILTER (WHERE severity = 4 AND state IN (1,4)) as low,
COUNT(*) FILTER (WHERE severity = 5 AND state IN (1,4)) as medium,
COUNT(*) FILTER (WHERE severity = 6 AND state IN (1,4)) as high,
COUNT(*) FILTER (WHERE severity = 7 AND state IN (1,4)) as critical
FROM "vulnerabilities"
WHERE "vulnerabilities"."project_id" = $project_id
GROUP BY "vulnerabilities"."project_id"
LIMIT 1
Letter grades of a group
SELECT
count(*) filter (where critical = 0 and high = 0 and unknown = 0 and medium = 0 and low = 0) as a,
count(*) filter (where critical = 0 and high = 0 and unknown = 0 and medium = 0 and low > 0) as b,
count(*) filter (where critical = 0 and high = 0 and unknown = 0 and medium > 0) as c,
count(*) filter (where critical = 0 and (high > 0 or unknown > 0)) as d,
count(*) filter (where critical > 0) as f
FROM ($similar_to_previous_query) as stats
/related to #213623 (closed)
Does this MR meet the acceptance criteria?
Conformity
-
Changelog entry -
Documentation (if required) -
Code review guidelines -
Merge request performance guidelines -
Style guides - [-] Database guides
-
Separation of EE specific content
Availability and Testing
- [-] Review and add/update tests for this feature/bug. Consider all test levels. See the Test Planning Process.
- [-] Tested in all supported browsers
- [-] Informed Infrastructure department of a default or new setting change, if applicable per definition of done
Security
If this MR contains changes to processing or storing of credentials or tokens, authorization and authentication methods and other items described in the security review guidelines:
- [-] Label as security and @ mention
@gitlab-com/gl-security/appsec
- [-] The MR includes necessary changes to maintain consistency between UI, API, email, or other methods
- [-] Security reports checked/validated by a reviewer from the AppSec team