Skip to content

Commit

Permalink
Improve CVE context (#55)
Browse files Browse the repository at this point in the history
Implements the following features:
- Allow viewing both resolved and unresolved issues in cve by distribution list
- Display of cve context in cve details

Part of gardenlinux/glvd#127
  • Loading branch information
fwilhe authored Nov 15, 2024
1 parent e867cfe commit 0b9fc4a
Show file tree
Hide file tree
Showing 7 changed files with 198 additions and 11 deletions.
10 changes: 9 additions & 1 deletion src/main/java/io/gardenlinux/glvd/GlvdService.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,17 @@ public class GlvdService {
@Nonnull
private final CveDetailsRepository cveDetailsRepository;

@Nonnull
private final CveContextRepository cveContextRepository;


Logger logger = LoggerFactory.getLogger(GlvdService.class);

public GlvdService(@Nonnull SourcePackageCveRepository sourcePackageCveRepository, @Nonnull SourcePackageRepository sourcePackageRepository, @Nonnull CveDetailsRepository cveDetailsRepository) {
public GlvdService(@Nonnull SourcePackageCveRepository sourcePackageCveRepository, @Nonnull SourcePackageRepository sourcePackageRepository, @Nonnull CveDetailsRepository cveDetailsRepository, @Nonnull CveContextRepository cveContextRepository) {
this.sourcePackageCveRepository = sourcePackageCveRepository;
this.sourcePackageRepository = sourcePackageRepository;
this.cveDetailsRepository = cveDetailsRepository;
this.cveContextRepository = cveContextRepository;
}

private Pageable determinePageAndSortFeatures(SortAndPageOptions sortAndPageOptions) {
Expand Down Expand Up @@ -108,4 +113,7 @@ public CveDetails getCveDetails(String cveId) {
return cveDetailsRepository.findByCveId(cveId);
}

public List<CveContext> getCveContexts(String cveId) {
return cveContextRepository.findByCveId(cveId);
}
}
26 changes: 25 additions & 1 deletion src/main/java/io/gardenlinux/glvd/UiController.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.gardenlinux.glvd;

import io.gardenlinux.glvd.db.SourcePackageCve;
import jakarta.annotation.Nonnull;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
Expand Down Expand Up @@ -39,16 +40,37 @@ public String getCveForDistribution(
@RequestParam(defaultValue = "DESC") final String sortOrder,
@RequestParam(required = false) final String pageNumber,
@RequestParam(required = false) final String pageSize,
@RequestParam(required = false, defaultValue = "true") final boolean onlyVulnerable,
Model model
) {
var sourcePackageCves = glvdService.getCveForDistribution(
gardenlinuxVersion, new SortAndPageOptions(sortBy, sortOrder, pageNumber, pageSize)
);
).stream().filter(SourcePackageCve::isVulnerable).toList();
model.addAttribute("sourcePackageCves", sourcePackageCves);
model.addAttribute("gardenlinuxVersion", gardenlinuxVersion);
model.addAttribute("onlyVulnerable", onlyVulnerable);
return "getCveForDistribution";
}

@GetMapping("/getCveForDistributionAll")
public String getCveForDistributionAll(
@RequestParam(name = "gardenlinuxVersion", required = true) String gardenlinuxVersion,
@RequestParam(defaultValue = "baseScore") final String sortBy,
@RequestParam(defaultValue = "DESC") final String sortOrder,
@RequestParam(required = false) final String pageNumber,
@RequestParam(required = false) final String pageSize,
@RequestParam(required = false, defaultValue = "true") final boolean onlyVulnerable,
Model model
) {
var sourcePackageCves = glvdService.getCveForDistribution(
gardenlinuxVersion, new SortAndPageOptions(sortBy, sortOrder, pageNumber, pageSize)
);
model.addAttribute("sourcePackageCves", sourcePackageCves);
model.addAttribute("gardenlinuxVersion", gardenlinuxVersion);
model.addAttribute("onlyVulnerable", onlyVulnerable);
return "getCveForDistributionAll";
}

@GetMapping("/getCveForPackages")
public String getCveForPackages(
@RequestParam(name = "gardenlinuxVersion", required = true) String gardenlinuxVersion,
Expand Down Expand Up @@ -90,7 +112,9 @@ gardenlinuxVersion, cveId, new SortAndPageOptions(sortBy, sortOrder, pageNumber,
@GetMapping("/getCveDetails")
public String getCveDetails(@RequestParam(name = "cveId", required = true) String cveId, Model model) {
var cveDetails = glvdService.getCveDetails(cveId);
var cveContexts = glvdService.getCveContexts(cveId);
model.addAttribute("cveDetails", cveDetails);
model.addAttribute("cveContexts", cveContexts);
return "getCveDetails";
}

Expand Down
75 changes: 75 additions & 0 deletions src/main/java/io/gardenlinux/glvd/db/CveContext.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package io.gardenlinux.glvd.db;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;

import java.util.List;

@Entity
@Table(name = "cve_context")
public class CveContext {
@Id
@Column(name = "cve_id", nullable = false)
private String cveId;

@Column(name = "dist_id", nullable = false)
private String distId;

@Column(name = "create_date", nullable = false)
private String createDate;

@Column(name = "context_descriptor", nullable = false)
private String contextDescriptor;

@Column(name = "score_override", nullable = true)
private Float scoreOverride;

@Column(name = "description", nullable = true)
private String description;

@Column(name = "is_resolved", nullable = true)
private Boolean isResolved;

public CveContext() {
}

public CveContext(String cveId, String distId, String createDate, String contextDescriptor, Float scoreOverride, String description, Boolean isResolved) {
this.cveId = cveId;
this.distId = distId;
this.createDate = createDate;
this.contextDescriptor = contextDescriptor;
this.scoreOverride = scoreOverride;
this.description = description;
this.isResolved = isResolved;
}

public String getCveId() {
return cveId;
}

public String getDistId() {
return distId;
}

public String getCreateDate() {
return createDate;
}

public String getContextDescriptor() {
return contextDescriptor;
}

public Float getScoreOverride() {
return scoreOverride;
}

public String getDescription() {
return description;
}

public Boolean getResolved() {
return isResolved;
}
}
12 changes: 12 additions & 0 deletions src/main/java/io/gardenlinux/glvd/db/CveContextRepository.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package io.gardenlinux.glvd.db;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.query.Param;

import java.util.List;

public interface CveContextRepository extends JpaRepository<CveContext, String> {
List<CveContext> findByCveId(
@Param("cve_id") String cve_id
);
}
10 changes: 10 additions & 0 deletions src/main/resources/templates/getCveDetails.html
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,15 @@ <h2>Affected Linux Versions</h2>

</table>

<h2>CVE Context</h2>

<!-- FIXME not yet clear how this information is properly displayed as we have have many entries for each cve.. for now just dump the info here. -->
<div th:each="context: ${cveContexts}">
<p th:text="${context.description}"/>
<p th:text="${context.createDate}"/>
<p th:text="${context.getResolved}"/>
<p th:text="${context.scoreOverride}"/>
</div>

</body>
</html>
20 changes: 11 additions & 9 deletions src/main/resources/templates/getCveForDistribution.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,33 +6,35 @@
<link href="style.css" rel="stylesheet" media="screen" />
</head>
<body>
<h1 th:text="|Vulnerabilities list for Garden Linux ${gardenlinuxVersion}|" />
<h1 th:text="|Vulnerabilities list for Garden Linux ${gardenlinuxVersion} (ignoring resolved issues)|" />

<p th:text="|Found ${#lists.size(sourcePackageCves)} potential security issues|"></p>

<a th:href="@{/getCveForDistributionAll(gardenlinuxVersion=${gardenlinuxVersion},onlyVulnerable=false)}">Show all potential issues</a>

<table>
<thead>
<tr>
<th>CVE ID
<a th:href="@{/getCveForDistribution(gardenlinuxVersion=${gardenlinuxVersion},sortBy=cveId,sortOrder=ASC)}">&uarr;</a>
<a th:href="@{/getCveForDistribution(gardenlinuxVersion=${gardenlinuxVersion},sortBy=cveId,sortOrder=DESC)}">&darr;</a>
<a th:href="@{/getCveForDistribution(gardenlinuxVersion=${gardenlinuxVersion},sortBy=cveId,sortOrder=ASC,onlyVulnerable=true)}">&uarr;</a>
<a th:href="@{/getCveForDistribution(gardenlinuxVersion=${gardenlinuxVersion},sortBy=cveId,sortOrder=DESC,onlyVulnerable=true)}">&darr;</a>
</th>

<th>CVE Base Score
<a th:href="@{/getCveForDistribution(gardenlinuxVersion=${gardenlinuxVersion},sortBy=baseScore,sortOrder=ASC)}">&uarr;</a>
<a th:href="@{/getCveForDistribution(gardenlinuxVersion=${gardenlinuxVersion},sortBy=baseScore,sortOrder=DESC)}">&darr;</a>
<a th:href="@{/getCveForDistribution(gardenlinuxVersion=${gardenlinuxVersion},sortBy=baseScore,sortOrder=ASC,onlyVulnerable=true)}">&uarr;</a>
<a th:href="@{/getCveForDistribution(gardenlinuxVersion=${gardenlinuxVersion},sortBy=baseScore,sortOrder=DESC,onlyVulnerable=true)}">&darr;</a>
</th>

<th>Vector String</th>

<th>CVE Published Date
<a th:href="@{/getCveForDistribution(gardenlinuxVersion=${gardenlinuxVersion},sortBy=cvePublishedDate,sortOrder=ASC)}">&uarr;</a>
<a th:href="@{/getCveForDistribution(gardenlinuxVersion=${gardenlinuxVersion},sortBy=cvePublishedDate,sortOrder=DESC)}">&darr;</a>
<a th:href="@{/getCveForDistribution(gardenlinuxVersion=${gardenlinuxVersion},sortBy=cvePublishedDate,sortOrder=ASC,onlyVulnerable=true)}">&uarr;</a>
<a th:href="@{/getCveForDistribution(gardenlinuxVersion=${gardenlinuxVersion},sortBy=cvePublishedDate,sortOrder=DESC,onlyVulnerable=true)}">&darr;</a>
</th>

<th>Source Package
<a th:href="@{/getCveForDistribution(gardenlinuxVersion=${gardenlinuxVersion},sortBy=sourcePackageName,sortOrder=ASC)}">&uarr;</a>
<a th:href="@{/getCveForDistribution(gardenlinuxVersion=${gardenlinuxVersion},sortBy=sourcePackageName,sortOrder=DESC)}">&darr;</a>
<a th:href="@{/getCveForDistribution(gardenlinuxVersion=${gardenlinuxVersion},sortBy=sourcePackageName,sortOrder=ASC,onlyVulnerable=true)}">&uarr;</a>
<a th:href="@{/getCveForDistribution(gardenlinuxVersion=${gardenlinuxVersion},sortBy=sourcePackageName,sortOrder=DESC,onlyVulnerable=true)}">&darr;</a>
</th>

<th>Version</th>
Expand Down
56 changes: 56 additions & 0 deletions src/main/resources/templates/getCveForDistributionAll.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>GLVD: List vulnerabilities in distro</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link href="style.css" rel="stylesheet" media="screen" />
</head>
<body>
<h1 th:text="|Vulnerabilities list for Garden Linux ${gardenlinuxVersion} (showing resolved issues)|" />

<p th:text="|Found ${#lists.size(sourcePackageCves)} potential security issues|"></p>

<a th:href="@{/getCveForDistribution(gardenlinuxVersion=${gardenlinuxVersion},onlyVulnerable=true)}">Show only unresolved potential issues</a>

<table>
<thead>
<tr>
<th>CVE ID
<a th:href="@{/getCveForDistributionAll(gardenlinuxVersion=${gardenlinuxVersion},sortBy=cveId,sortOrder=ASC,onlyVulnerable=false)}">&uarr;</a>
<a th:href="@{/getCveForDistributionAll(gardenlinuxVersion=${gardenlinuxVersion},sortBy=cveId,sortOrder=DESC,onlyVulnerable=false)}">&darr;</a>
</th>

<th>CVE Base Score
<a th:href="@{/getCveForDistributionAll(gardenlinuxVersion=${gardenlinuxVersion},sortBy=baseScore,sortOrder=ASC,onlyVulnerable=false)}">&uarr;</a>
<a th:href="@{/getCveForDistributionAll(gardenlinuxVersion=${gardenlinuxVersion},sortBy=baseScore,sortOrder=DESC,onlyVulnerable=false)}">&darr;</a>
</th>

<th>Vector String</th>

<th>CVE Published Date
<a th:href="@{/getCveForDistributionAll(gardenlinuxVersion=${gardenlinuxVersion},sortBy=cvePublishedDate,sortOrder=ASC,onlyVulnerable=false)}">&uarr;</a>
<a th:href="@{/getCveForDistributionAll(gardenlinuxVersion=${gardenlinuxVersion},sortBy=cvePublishedDate,sortOrder=DESC,onlyVulnerable=false)}">&darr;</a>
</th>

<th>Source Package
<a th:href="@{/getCveForDistributionAll(gardenlinuxVersion=${gardenlinuxVersion},sortBy=sourcePackageName,sortOrder=ASC,onlyVulnerable=false)}">&uarr;</a>
<a th:href="@{/getCveForDistributionAll(gardenlinuxVersion=${gardenlinuxVersion},sortBy=sourcePackageName,sortOrder=DESC,onlyVulnerable=false)}">&darr;</a>
</th>

<th>Version</th>
<th>Is Vulnerable?</th>
</tr>
</thead>
<tr th:each="item: ${sourcePackageCves}">
<td><a th:href="@{/getCveDetails(cveId=${item.cveId})}"> <div th:text="${item.cveId}"/> </a></td>
<td th:text="${item.baseScore}" />
<td th:text="${item.vectorString}" />
<td th:text="${item.cvePublishedDate}" />
<td th:text="${item.sourcePackageName}" />
<td th:text="${item.sourcePackageVersion}" />
<td th:text="${item.isVulnerable}" />
</tr>
</table>

</body>
</html>

0 comments on commit 0b9fc4a

Please sign in to comment.