Skip to content

Commit 77acfb4

Browse files
authored
Add image-based view (#170)
Add view and api for 'image-based' cve view Part of gardenlinux/glvd#189
1 parent 8e3cfe0 commit 77acfb4

File tree

17 files changed

+930
-14
lines changed

17 files changed

+930
-14
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,6 @@ out/
3838

3939
### Unbase OCI ###
4040
*.oci
41-
glvd.sql
41+
42+
# DB Dump for DevDb container image
43+
/glvd.sql

DevDb.Containerfile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
FROM ghcr.io/gardenlinux/glvd-postgres:latest
2+
3+
COPY glvd.sql /docker-entrypoint-initdb.d/glvd.sql

README.md

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,26 +32,32 @@ To build the app, ensure the test database is running:
3232

3333
## Running the Application Locally
3434

35-
1. Start the application database:
35+
1. Get a dump of the Database (this needs the GitHub `gh` cli and `jq`)
36+
37+
```bash
38+
./download-db-dump.sh
39+
```
40+
41+
2. Start the application database:
3642

3743
```bash
3844
./start-db-for-app.sh
3945
```
4046

41-
2. Build and run the Spring Boot app:
47+
3. Build and run the Spring Boot app:
4248

4349
```bash
4450
./gradlew bootRun
4551
```
4652

47-
3. After startup, check readiness:
53+
4. After startup, check readiness:
4854

4955
```
5056
curl http://localhost:8080/readiness
5157
# Should return status code 200
5258
```
5359

54-
4. Open http://localhost:8080 in your web browser to use the UI
60+
5. Open http://localhost:8080 in your web browser to use the UI
5561

5662
## Example Requests
5763

download-db-dump.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#!/bin/bash
2+
3+
LATEST_RUN_ID=$(gh run list --repo gardenlinux/glvd-data-ingestion --branch main --workflow 02-ingest-dump-snapshot.yaml --json databaseId --limit 1 | jq -r '.[0].databaseId')
4+
gh run download $LATEST_RUN_ID -n glvd.sql --repo gardenlinux/glvd-data-ingestion

src/docs/asciidoc/index.adoc

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,25 @@ Example response:
7171

7272
include::{snippets}/getCveForDistro/http-response.adoc[]
7373

74+
=== List CVEs by Image
75+
76+
Retrieve all CVEs for a given Garden Linux image and version.
77+
This applies a filter for the packages in the specified image.
78+
79+
Supported images are currently:
80+
81+
- `ali-gardener_prod`
82+
- `aws-gardener_prod`
83+
- `azure-gardener_prod`
84+
- `gcp-gardener_prod`
85+
- `openstack-gardener_prod`
86+
87+
include::{snippets}/getCveForImage/curl-request.adoc[]
88+
89+
Example response:
90+
91+
include::{snippets}/getCveForImage/http-response.adoc[]
92+
7493
=== List CVEs for Packages by Distribution
7594

7695
Retrieve all CVEs for a list of packages in a specified distribution.

src/main/java/io/gardenlinux/glvd/GlvdController.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,20 @@ gardenlinuxVersion, new SortAndPageOptions(sortBy, sortOrder, pageNumber, pageSi
3535
);
3636
}
3737

38+
@GetMapping("/cves/{gardenlinuxVersion}/image/{gardenlinuxImage}")
39+
ResponseEntity<List<ImageSourcePackageCve>> getCveImage(
40+
@PathVariable final String gardenlinuxVersion,
41+
@PathVariable final String gardenlinuxImage,
42+
@RequestParam(defaultValue = "cveId") final String sortBy,
43+
@RequestParam(defaultValue = "ASC") final String sortOrder,
44+
@RequestParam(required = false) final String pageNumber,
45+
@RequestParam(required = false) final String pageSize
46+
) {
47+
return ResponseEntity.ok().body(glvdService.getCveForImage(
48+
gardenlinuxImage, gardenlinuxVersion, new SortAndPageOptions(sortBy, sortOrder, pageNumber, pageSize))
49+
);
50+
}
51+
3852
@GetMapping("/cves/{gardenlinuxVersion}/packages/{packageList}")
3953
ResponseEntity<List<SourcePackageCve>> getCvePackages(
4054
@PathVariable final String gardenlinuxVersion,

src/main/java/io/gardenlinux/glvd/GlvdService.java

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ public class GlvdService {
3333
@Nonnull
3434
private final SourcePackageRepository sourcePackageRepository;
3535

36+
@Nonnull
37+
private final ImageSourcePackageCveRepository imageSourcePackageCveRepository;
38+
3639
@Nonnull
3740
private final CveDetailsRepository cveDetailsRepository;
3841

@@ -62,9 +65,10 @@ public class GlvdService {
6265

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

65-
public GlvdService(@Nonnull SourcePackageCveRepository sourcePackageCveRepository, @Nonnull SourcePackageRepository sourcePackageRepository, @Nonnull CveDetailsRepository cveDetailsRepository, @Nonnull CveContextRepository cveContextRepository, @Nonnull DistCpeRepository distCpeRepository, @Nonnull NvdExclusiveCveRepository nvdExclusiveCveRepository, @Nonnull DebSrcRepository debSrcRepository, @Nonnull KernelCveRepository kernelCveRepository, @Nonnull KernelCveDetailsRepository kernelCveDetailsRepository, @Nonnull NvdCveRepository nvdCveRepository, @Nonnull TriageRepository triageRepository) {
68+
public GlvdService(@Nonnull SourcePackageCveRepository sourcePackageCveRepository, @Nonnull SourcePackageRepository sourcePackageRepository, @Nonnull ImageSourcePackageCveRepository imageSourcePackageCveRepository, @Nonnull CveDetailsRepository cveDetailsRepository, @Nonnull CveContextRepository cveContextRepository, @Nonnull DistCpeRepository distCpeRepository, @Nonnull NvdExclusiveCveRepository nvdExclusiveCveRepository, @Nonnull DebSrcRepository debSrcRepository, @Nonnull KernelCveRepository kernelCveRepository, @Nonnull KernelCveDetailsRepository kernelCveDetailsRepository, @Nonnull NvdCveRepository nvdCveRepository, @Nonnull TriageRepository triageRepository) {
6669
this.sourcePackageCveRepository = sourcePackageCveRepository;
6770
this.sourcePackageRepository = sourcePackageRepository;
71+
this.imageSourcePackageCveRepository = imageSourcePackageCveRepository;
6872
this.cveDetailsRepository = cveDetailsRepository;
6973
this.cveContextRepository = cveContextRepository;
7074
this.distCpeRepository = distCpeRepository;
@@ -108,6 +112,22 @@ private Pageable determinePageAndSortFeatures2(SortAndPageOptions sortAndPageOpt
108112
return Pageable.unpaged();
109113
}
110114

115+
public List<ImageSourcePackageCve> getCveForImage(String image, String gardenlinuxVersion, SortAndPageOptions sortAndPageOptions) {
116+
var cvesExcludingKernel = imageSourcePackageCveRepository.findByGardenlinuxVersionAndGardenlinuxImageName(
117+
gardenlinuxVersion, image, determinePageAndSortFeatures(sortAndPageOptions))
118+
.stream()
119+
.filter(CvesByStatusRejectedxx())
120+
.toList();
121+
122+
var kernelCves = kernelCveRepository.findByGardenlinuxVersion(gardenlinuxVersion)
123+
.stream()
124+
.map(kernelCve -> new ImageSourcePackageCve(kernelCve.getCveId(), kernelCve.getSourcePackageName(), kernelCve.getSourcePackageVersion(), kernelCve.getGardenlinuxVersion(), "", "", "", kernelCve.isVulnerable(), kernelCve.getCvePublishedDate(), kernelCve.getCveLastModifiedDate(), kernelCve.getCveLastIngestedDate(), kernelCve.getVulnStatus(), kernelCve.getBaseScore(), kernelCve.getVectorString(), kernelCve.getBaseScoreV40(), kernelCve.getBaseScoreV31(), kernelCve.getBaseScoreV30(), kernelCve.getBaseScoreV2(), kernelCve.getVectorStringV40(), kernelCve.getVectorStringV31(), kernelCve.getVectorStringV30(), kernelCve.getVectorStringV2()))
125+
.filter(CvesByStatusRejectedxx())
126+
.toList();
127+
128+
return Stream.concat(cvesExcludingKernel.stream(), kernelCves.stream()).toList();
129+
}
130+
111131
public List<SourcePackageCve> getCveForDistribution(String gardenlinuxVersion, SortAndPageOptions sortAndPageOptions) {
112132
var cvesExcludingKernel = sourcePackageCveRepository.findByGardenlinuxVersion(
113133
gardenlinuxVersion, determinePageAndSortFeatures(sortAndPageOptions))
@@ -128,6 +148,11 @@ private static Predicate<SourcePackageCve> CvesByStatusRejected() {
128148
return cve -> !cve.getVulnStatus().equalsIgnoreCase("Rejected");
129149
}
130150

151+
// fixme
152+
private static Predicate<ImageSourcePackageCve> CvesByStatusRejectedxx() {
153+
return cve -> !cve.getVulnStatus().equalsIgnoreCase("Rejected");
154+
}
155+
131156
public List<KernelCve> kernelCvesForGardenLinuxVersion(String gardenlinuxVersion) {
132157
return kernelCveRepository.findByGardenlinuxVersion(gardenlinuxVersion);
133158
}

src/main/java/io/gardenlinux/glvd/UiController.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.gardenlinux.glvd;
22

3+
import io.gardenlinux.glvd.db.ImageSourcePackageCve;
34
import io.gardenlinux.glvd.db.SourcePackageCve;
45
import io.gardenlinux.glvd.exceptions.CveNotKnownException;
56
import jakarta.annotation.Nonnull;
@@ -39,6 +40,33 @@ gardenlinuxVersion, new SortAndPageOptions(sortBy, sortOrder, pageNumber, pageSi
3940
return "getPackagesForDistro";
4041
}
4142

43+
@GetMapping("/getCveForImage")
44+
public String getCveForImage(
45+
@RequestParam(name = "gardenlinuxVersion", required = true) String gardenlinuxVersion,
46+
@RequestParam(name = "imageName", required = true) String imageName,
47+
@RequestParam(defaultValue = "baseScore") final String sortBy,
48+
@RequestParam(defaultValue = "DESC") final String sortOrder,
49+
@RequestParam(required = false) final String pageNumber,
50+
@RequestParam(required = false) final String pageSize,
51+
@RequestParam(required = false, defaultValue = "true") final boolean onlyVulnerable,
52+
Model model
53+
) {
54+
var sourcePackageCves = glvdService.getCveForImage(
55+
imageName, gardenlinuxVersion, new SortAndPageOptions(sortBy, sortOrder, pageNumber, pageSize)
56+
)
57+
.stream()
58+
.filter(ImageSourcePackageCve::isVulnerable)
59+
.filter(sourcePackageCve -> !sourcePackageCve.getVulnStatus().equalsIgnoreCase("Rejected"))
60+
.toList();
61+
var contexts = glvdService.getCveContextsForDist(glvdService.distVersionToId(gardenlinuxVersion));
62+
model.addAttribute("sourcePackageCves", sourcePackageCves);
63+
model.addAttribute("gardenlinuxVersion", gardenlinuxVersion);
64+
model.addAttribute("imageName", imageName);
65+
model.addAttribute("onlyVulnerable", onlyVulnerable);
66+
model.addAttribute("cveContexts", contexts);
67+
return "getCveForImage";
68+
}
69+
4270
@GetMapping("/getCveForDistribution")
4371
public String getCveForDistribution(
4472
@RequestParam(name = "gardenlinuxVersion", required = true) String gardenlinuxVersion,
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
package io.gardenlinux.glvd.db;
2+
3+
import jakarta.persistence.Column;
4+
import jakarta.persistence.Entity;
5+
import jakarta.persistence.Id;
6+
import jakarta.persistence.Table;
7+
8+
@Entity
9+
@Table(name = "imagesourcepackagecve")
10+
public class ImageSourcePackageCve {
11+
12+
@Id
13+
@Column(name = "cve_id", nullable = false)
14+
private String cveId;
15+
16+
@Column(name = "source_package_name", nullable = false)
17+
private String sourcePackageName;
18+
19+
@Column(name = "source_package_version", nullable = false)
20+
private String sourcePackageVersion;
21+
22+
@Column(name = "gardenlinux_version", nullable = false)
23+
private String gardenlinuxVersion;
24+
25+
@Column(name = "gardenlinux_image_name", nullable = false)
26+
private String gardenlinuxImageName;
27+
28+
@Column(name = "gardenlinux_image_version", nullable = false)
29+
private String gardenlinuxImageVersion;
30+
31+
@Column(name = "gardenlinux_image_commit_id", nullable = false)
32+
private String gardenlinuxImageCommitId;
33+
34+
@Column(name = "is_vulnerable", nullable = false)
35+
private boolean isVulnerable;
36+
37+
@Column(name = "cve_published_date", nullable = false)
38+
private String cvePublishedDate;
39+
40+
@Column(name = "cve_last_modified_date", nullable = false)
41+
private String cveLastModifiedDate;
42+
43+
@Column(name = "cve_last_ingested_date", nullable = false)
44+
private String cveLastIngestedDate;
45+
46+
@Column(name = "vuln_status", nullable = false)
47+
private String vulnStatus;
48+
49+
@Column(name = "base_score", nullable = true)
50+
private Float baseScore;
51+
52+
@Column(name = "vector_string", nullable = true)
53+
private String vectorString;
54+
55+
@Column(name = "base_score_v40", nullable = true)
56+
private Float baseScoreV40;
57+
58+
@Column(name = "base_score_v31", nullable = true)
59+
private Float baseScoreV31;
60+
61+
@Column(name = "base_score_v30", nullable = true)
62+
private Float baseScoreV30;
63+
64+
@Column(name = "base_score_v2", nullable = true)
65+
private Float baseScoreV2;
66+
67+
@Column(name = "vector_string_v40", nullable = true)
68+
private String vectorStringV40;
69+
70+
@Column(name = "vector_string_v31", nullable = true)
71+
private String vectorStringV31;
72+
73+
@Column(name = "vector_string_v30", nullable = true)
74+
private String vectorStringV30;
75+
76+
@Column(name = "vector_string_v2", nullable = true)
77+
private String vectorStringV2;
78+
79+
public ImageSourcePackageCve() {
80+
}
81+
82+
public ImageSourcePackageCve(String cveId, String sourcePackageName, String sourcePackageVersion, String gardenlinuxVersion, String gardenlinuxImageName, String gardenlinuxImageVersion, String gardenlinuxImageCommitId, boolean isVulnerable, String cvePublishedDate, String cveLastModifiedDate, String cveLastIngestedDate, String vulnStatus, Float baseScore, String vectorString, Float baseScoreV40, Float baseScoreV31, Float baseScoreV30, Float baseScoreV2, String vectorStringV40, String vectorStringV31, String vectorStringV30, String vectorStringV2) {
83+
this.cveId = cveId;
84+
this.sourcePackageName = sourcePackageName;
85+
this.sourcePackageVersion = sourcePackageVersion;
86+
this.gardenlinuxVersion = gardenlinuxVersion;
87+
this.gardenlinuxImageName = gardenlinuxImageName;
88+
this.gardenlinuxImageVersion = gardenlinuxImageVersion;
89+
this.gardenlinuxImageCommitId = gardenlinuxImageCommitId;
90+
this.isVulnerable = isVulnerable;
91+
this.cvePublishedDate = cvePublishedDate;
92+
this.cveLastModifiedDate = cveLastModifiedDate;
93+
this.cveLastIngestedDate = cveLastIngestedDate;
94+
this.vulnStatus = vulnStatus;
95+
this.baseScore = baseScore;
96+
this.vectorString = vectorString;
97+
this.baseScoreV40 = baseScoreV40;
98+
this.baseScoreV31 = baseScoreV31;
99+
this.baseScoreV30 = baseScoreV30;
100+
this.baseScoreV2 = baseScoreV2;
101+
this.vectorStringV40 = vectorStringV40;
102+
this.vectorStringV31 = vectorStringV31;
103+
this.vectorStringV30 = vectorStringV30;
104+
this.vectorStringV2 = vectorStringV2;
105+
}
106+
107+
public String getCveId() {
108+
return cveId;
109+
}
110+
111+
public String getSourcePackageName() {
112+
return sourcePackageName;
113+
}
114+
115+
public String getSourcePackageVersion() {
116+
return sourcePackageVersion;
117+
}
118+
119+
public String getGardenlinuxVersion() {
120+
return gardenlinuxVersion;
121+
}
122+
123+
public String getGardenlinuxImageName() {
124+
return gardenlinuxImageName;
125+
}
126+
127+
public String getGardenlinuxImageVersion() {
128+
return gardenlinuxImageVersion;
129+
}
130+
131+
public String getGardenlinuxImageCommitId() {
132+
return gardenlinuxImageCommitId;
133+
}
134+
135+
public boolean isVulnerable() {
136+
return isVulnerable;
137+
}
138+
139+
public String getCvePublishedDate() {
140+
return cvePublishedDate;
141+
}
142+
143+
public String getCveLastModifiedDate() {
144+
return cveLastModifiedDate;
145+
}
146+
147+
public String getCveLastIngestedDate() {
148+
return cveLastIngestedDate;
149+
}
150+
151+
public String getVulnStatus() {
152+
return vulnStatus;
153+
}
154+
155+
public Float getBaseScore() {
156+
return baseScore;
157+
}
158+
159+
public String getVectorString() {
160+
return vectorString;
161+
}
162+
163+
public Float getBaseScoreV40() {
164+
return baseScoreV40;
165+
}
166+
167+
public Float getBaseScoreV31() {
168+
return baseScoreV31;
169+
}
170+
171+
public Float getBaseScoreV30() {
172+
return baseScoreV30;
173+
}
174+
175+
public Float getBaseScoreV2() {
176+
return baseScoreV2;
177+
}
178+
179+
public String getVectorStringV40() {
180+
return vectorStringV40;
181+
}
182+
183+
public String getVectorStringV31() {
184+
return vectorStringV31;
185+
}
186+
187+
public String getVectorStringV30() {
188+
return vectorStringV30;
189+
}
190+
191+
public String getVectorStringV2() {
192+
return vectorStringV2;
193+
}
194+
}

0 commit comments

Comments
 (0)