Skip to content

Commit

Permalink
Implement endpoint to get CVEs per distro (#5)
Browse files Browse the repository at this point in the history
  • Loading branch information
fwilhe authored May 7, 2024
1 parent b3c1125 commit 2f7489a
Show file tree
Hide file tree
Showing 11 changed files with 210 additions and 42 deletions.
14 changes: 13 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,20 @@ ext {
set('snippetsDir', file("build/generated-snippets"))
}

configurations {
asciidoctorExtensions
}

dependencies {
asciidoctorExtensions 'org.springframework.restdocs:spring-restdocs-asciidoctor'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.5.0'
runtimeOnly 'org.postgresql:postgresql'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.boot:spring-boot-testcontainers'
testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc'
testImplementation 'org.springframework.restdocs:spring-restdocs-restassured'
testImplementation 'org.testcontainers:junit-jupiter'
testImplementation 'org.testcontainers:postgresql'
testImplementation 'io.rest-assured:rest-assured:5.4.0'
Expand All @@ -40,6 +45,13 @@ tasks.named('test') {
}

tasks.named('asciidoctor') {
configurations "asciidoctorExtensions"
inputs.dir snippetsDir
dependsOn test
}
bootJar {
dependsOn asciidoctor
from ("${asciidoctor.outputDir}/html5") {
into 'static/docs'
}
}
27 changes: 27 additions & 0 deletions src/docs/asciidoc/index.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
= Garden Linux Vulnerability Database Rest API
Garden Linux Authors;
:doctype: book
:icons: font
:source-highlighter: highlightjs

== Lorem Ipsum

=== Get a CVE by id

Request

include::{snippets}/getCve/curl-request.adoc[]

Response

include::{snippets}/getCve/http-response.adoc[]

=== Get a list of CVEs by distro

Request

include::{snippets}/getCveForDistro/curl-request.adoc[]

Response

include::{snippets}/getCveForDistro/http-response.adoc[]
7 changes: 0 additions & 7 deletions src/main/java/io/gardenlinux/glvd/CveRepository.java

This file was deleted.

14 changes: 11 additions & 3 deletions src/main/java/io/gardenlinux/glvd/GlvdController.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package io.gardenlinux.glvd;

import io.gardenlinux.glvd.dto.Cve;
import io.gardenlinux.glvd.exceptions.NotFoundException;
import jakarta.annotation.Nonnull;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
Expand All @@ -8,6 +10,8 @@
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping(value = "/v1/cves", produces = MediaType.APPLICATION_JSON_VALUE)
public class GlvdController {
Expand All @@ -20,9 +24,13 @@ public GlvdController(@Nonnull GlvdService glvdService) {
}

@GetMapping("/{cveId}")
ResponseEntity<?> getCveId(@PathVariable("cveId") final String cveId) {
var cve = glvdService.getCve(cveId);
return ResponseEntity.ok().body(cve);
ResponseEntity<Cve> getCveId(@PathVariable("cveId") final String cveId) throws NotFoundException {
return ResponseEntity.ok().body(glvdService.getCve(cveId));
}

@GetMapping("/{vendor}/{product}/{codename}")
ResponseEntity<List<String>> getCveDistro(@PathVariable final String vendor, @PathVariable final String product, @PathVariable final String codename) {
return ResponseEntity.ok().body(glvdService.getCveForDistribution(vendor, product, codename));
}

}
17 changes: 14 additions & 3 deletions src/main/java/io/gardenlinux/glvd/GlvdService.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
package io.gardenlinux.glvd;

import io.gardenlinux.glvd.db.CveRepository;
import io.gardenlinux.glvd.dto.Cve;
import io.gardenlinux.glvd.exceptions.NotFoundException;
import jakarta.annotation.Nonnull;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class GlvdService {

Expand All @@ -13,8 +18,14 @@ public GlvdService(@Nonnull CveRepository cveRepository) {
this.cveRepository = cveRepository;
}

public Cve getCve(String cveId) {
var cve = cveRepository.findById(cveId);
return cve.orElseThrow();
public Cve getCve(String cveId) throws NotFoundException {
var cveEntity = cveRepository.findById(cveId).orElseThrow(NotFoundException::new);
// Todo: more specific transformation from db type 'cve' to response type 'cve'
return new Cve(cveEntity.getId(), cveEntity.getLastModified(), cveEntity.getData());

}

public List<String> getCveForDistribution(String vendor, String product, String codename) {
return cveRepository.cvesForDistribution(vendor, product, codename);
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.gardenlinux.glvd;
package io.gardenlinux.glvd.db;

import jakarta.annotation.Nonnull;
import jakarta.persistence.Column;
Expand All @@ -8,7 +8,7 @@
import java.util.Objects;

@Entity(name = "all_cve")
public class Cve {
public class CveEntity {
@Id
@Column(name = "cve_id", nullable = false)
private String id;
Expand All @@ -21,10 +21,10 @@ public class Cve {
@Nonnull
private String data;

public Cve() {
public CveEntity() {
}

public Cve(String id, @Nonnull String lastModified, @Nonnull String data) {
public CveEntity(String id, @Nonnull String lastModified, @Nonnull String data) {
this.id = id;
this.lastModified = lastModified;
this.data = data;
Expand All @@ -49,8 +49,8 @@ public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;

Cve cve = (Cve) o;
return Objects.equals(id, cve.id) && lastModified.equals(cve.lastModified) && data.equals(cve.data);
CveEntity cveEntity = (CveEntity) o;
return Objects.equals(id, cveEntity.id) && lastModified.equals(cveEntity.lastModified) && data.equals(cveEntity.data);
}

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

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

import java.util.List;

public interface CveRepository extends JpaRepository<CveEntity, String> {

@Query(value = """
SELECT
all_cve.data AS cveEntity
FROM
all_cve
INNER JOIN deb_cve USING (cve_id)
INNER JOIN dist_cpe ON (deb_cve.dist_id = dist_cpe.id)
WHERE
dist_cpe.cpe_vendor = ?1 AND
dist_cpe.cpe_product = ?2 and
dist_cpe.deb_codename = ?3
ORDER BY
all_cve.cve_id
""", nativeQuery = true)
List<String> cvesForDistribution(String vendor, String product, String codename);
}
53 changes: 53 additions & 0 deletions src/main/java/io/gardenlinux/glvd/dto/Cve.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package io.gardenlinux.glvd.dto;

import jakarta.annotation.Nonnull;

import java.util.Objects;

public class Cve {
private String id;
@Nonnull
private String lastModified;
@Nonnull
private String data;

public Cve() {
}

public Cve(String id, @Nonnull String lastModified, @Nonnull String data) {
this.id = id;
this.lastModified = lastModified;
this.data = data;
}

public String getId() {
return id;
}

@Nonnull
public String getLastModified() {
return lastModified;
}

@Nonnull
public String getData() {
return data;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;

Cve Cve = (Cve) o;
return Objects.equals(id, Cve.id) && lastModified.equals(Cve.lastModified) && data.equals(Cve.data);
}

@Override
public int hashCode() {
int result = Objects.hashCode(id);
result = 31 * result + lastModified.hashCode();
result = 31 * result + data.hashCode();
return result;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package io.gardenlinux.glvd.exceptions;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;

@ResponseStatus(code = HttpStatus.NOT_FOUND, reason = "Not Found")
public class NotFoundException extends Exception{
}
13 changes: 1 addition & 12 deletions src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,4 @@ spring.application.name=glvd
spring.datasource.url=jdbc:postgresql://localhost:5432/glvd
spring.datasource.username=glvd
spring.datasource.password=glvd
spring.sql.init.mode=always

logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE


spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.use_sql_comments=true
spring.jpa.properties.hibernate.format_sql=true
logging.level.org.hibernate.type=trace


logging.level.org.hibernate.orm.jdbc.bind=trace
spring.sql.init.mode=never
Loading

0 comments on commit 2f7489a

Please sign in to comment.