|
1 | 1 | package controllers |
2 | 2 |
|
3 | 3 | import ( |
4 | | - "encoding/json" |
5 | 4 | "fmt" |
6 | 5 | "net/url" |
7 | 6 | "strconv" |
@@ -241,35 +240,36 @@ type ecosystemRow struct { |
241 | 240 | Count int `gorm:"count" json:"count"` |
242 | 241 | } |
243 | 242 |
|
244 | | -// return the number of affected packages by ecosystem |
245 | | -func (c VulnDBController) GetEcosystemDistribution(ctx shared.Context) error { |
246 | | - results := make([]ecosystemRow, 1024) |
| 243 | +// return the number of vulnerabilities in affected packages per ecosystem |
| 244 | +func (c VulnDBController) GetCVEEcosystemDistribution(ctx shared.Context) error { |
| 245 | + cveResults := make([]ecosystemRow, 0, 1024) |
| 246 | + maliciousPackageResults := make([]ecosystemRow, 0, 64) |
247 | 247 |
|
248 | | - // static sql to get amount of packages by ecosystem |
249 | | - sql := `SELECT ecosystem, COUNT(*) FROM affected_components GROUP BY ecosystem;` |
250 | | - err := c.affectedComponentRepository.GetDB(nil).Raw(sql).Find(&results).Error |
| 248 | + // get the amount of CVEs in affected packages per ecosystem |
| 249 | + cveSQL := `SELECT LOWER(b.ecosystem) as ecosystem, COUNT(*) FROM cve_affected_component a |
| 250 | + LEFT JOIN affected_components b ON b.id = a.affected_component_id |
| 251 | + GROUP BY LOWER(b.ecosystem);` |
| 252 | + err := c.affectedComponentRepository.GetDB(nil).Raw(cveSQL).Find(&cveResults).Error |
251 | 253 | if err != nil { |
252 | 254 | return echo.NewHTTPError(500, "could not fetch data from database").WithInternal(err) |
253 | 255 | } |
254 | 256 |
|
255 | | - // since ecosystem have tags behind the : character we want to group them by their prefix |
256 | | - jsonResults := buildResultsJSON(results) |
257 | | - |
258 | | - return ctx.String(200, jsonResults) |
259 | | -} |
260 | | - |
261 | | -// group ecosystem by prefix ecosystem string and return the equivalent json encoding |
262 | | -func buildResultsJSON(rows []ecosystemRow) string { |
263 | | - // map to deduplicate ecosystem with different tags |
264 | | - aggregatedResults := make(map[string]int) |
| 257 | + // do the same thing for malicious packages |
| 258 | + maliciousPackagesSQL := `SELECT LOWER(b.ecosystem) as ecosystem, COUNT(*) FROM malicious_packages a |
| 259 | + LEFT JOIN malicious_affected_components b ON a.id = b.malicious_package_id |
| 260 | + GROUP BY LOWER(b.ecosystem);` |
| 261 | + err = c.affectedComponentRepository.GetDB(nil).Raw(maliciousPackagesSQL).Find(&maliciousPackageResults).Error |
| 262 | + if err != nil { |
| 263 | + return echo.NewHTTPError(500, "could not fetch data from database").WithInternal(err) |
| 264 | + } |
265 | 265 |
|
266 | | - // fill the map with the value of the rows |
267 | | - for _, row := range rows { |
268 | | - before, _, _ := strings.Cut(row.Ecosystem, ":") |
269 | | - aggregatedResults[before] += row.Count |
| 266 | + // group the results in a map by cutting the ecosystem identifier before the ':' |
| 267 | + ecosystemToAmount := make(map[string]int, len(cveResults)) |
| 268 | + for _, row := range append(cveResults, maliciousPackageResults...) { |
| 269 | + key, _, _ := strings.Cut(row.Ecosystem, ":") |
| 270 | + ecosystemToAmount[key] += row.Count |
270 | 271 | } |
271 | 272 |
|
272 | | - // marshal to JSON with proper indentation |
273 | | - data, _ := json.MarshalIndent(aggregatedResults, "", config.PrettyJSONIndent) |
274 | | - return string(data) |
| 273 | + // convert the result in a map and return it |
| 274 | + return ctx.JSONPretty(200, ecosystemToAmount, config.PrettyJSONIndent) |
275 | 275 | } |
0 commit comments