Skip to content

Commit

Permalink
[Feat] Controller, Service Layer 일부 구현 - #8
Browse files Browse the repository at this point in the history
  • Loading branch information
Juser0 committed Oct 2, 2023
1 parent e8b2ec6 commit a14a6dc
Show file tree
Hide file tree
Showing 14 changed files with 260 additions and 36 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.pipeline.manager;
package com.analyzer.sbom;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
Expand Down
35 changes: 35 additions & 0 deletions manager/src/main/java/com/analyzer/sbom/common/CommonResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.analyzer.sbom.common;

import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Builder;
import lombok.Getter;

@Getter
@JsonInclude(JsonInclude.Include.NON_NULL)
public class CommonResponse<T> {

private String responseCode;
private String responseMessage;
private T data;

@Builder
private CommonResponse(String responseCode, String responseMessage, T data) {
this.responseCode = responseCode;
this.responseMessage = responseMessage;
this.data = data;
}

public static CommonResponse resWithoutData (final String responseCode, final String responseMessage) {
return CommonResponse.builder()
.responseCode(responseCode)
.responseMessage(responseMessage)
.build();
}
public static <T> CommonResponse<T> resWithData (final String responseCode, final String responseMessage, final T data) {
return CommonResponse.<T>builder()
.responseCode(responseCode)
.responseMessage(responseMessage)
.data(data)
.build();
}
}
24 changes: 24 additions & 0 deletions manager/src/main/java/com/analyzer/sbom/config/SwaggerConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.analyzer.sbom.config;

import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SwaggerConfig {
@Bean
public OpenAPI openAPI() {
return new OpenAPI()
.components(new Components())
.info(apiInfo());
}

private Info apiInfo() {
return new Info()
.title("SBOM Vulnerability Analyzer")
.description("SBOM에서 확인 가능한 취약점에 대한 정보를 정리해주는 애플리케이션 명세입니다")
.version("1.0.0");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.analyzer.sbom.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.web.reactive.function.client.WebClient;


@Configuration
public class WebClientConfig {
@Bean
public WebClient.Builder webclientBuilder() {
return WebClient.builder()
.defaultHeader(HttpHeaders.ACCEPT, "*/*")
.defaultHeader(HttpHeaders.CONTENT_TYPE, "application/json");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.analyzer.sbom.controller;

import com.analyzer.sbom.common.CommonResponse;
import com.analyzer.sbom.dto.response.SbomResponseDto;
import com.analyzer.sbom.service.SbomService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

import static org.springframework.http.HttpStatus.*;

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/v1/sbom")
@Tag(name = "SBOM", description = "SBOM controller")
public class SbomController {

private final SbomService sbomService;

@GetMapping
@Operation(summary = "SBOM Scan", description = "Scan Software Bill of Materials")
public ResponseEntity<CommonResponse<JsonNode>> scanSBOM(@RequestParam String token, @RequestParam String projectId, @RequestParam String baseUrl) throws JsonProcessingException {
JsonNode sbomResult = sbomService.scanVulnerability(token, projectId, baseUrl);
return ResponseEntity.status(OK).body(CommonResponse.resWithData("SBOM_SCAN_COMPLETED", "SBOM 스캔이 완료되었습니다", sbomResult));
}

@GetMapping("/report")
@Operation(summary = "Get SBOM Report", description = "Get Software Bill of Materials' security report")
public ResponseEntity<CommonResponse<List<SbomResponseDto>>> getReport(@RequestParam String token, @RequestParam String projectId, @RequestParam String baseUrl) throws JsonProcessingException {
List<SbomResponseDto> sbomReport = sbomService.generateReport(token, projectId, baseUrl);
return ResponseEntity.status(OK).body(CommonResponse.resWithData("SBOM_REPORT_GENERATED", "SBOM 보안 보고서가 생성되었습니다", sbomReport));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.analyzer.sbom.dto.response;

import lombok.Builder;
import lombok.Getter;

import java.util.List;

@Getter
public class SbomResponseDto {
private String name;
private String purl;
private String version;
private String group;
private String vulnId;
private String severity;
private String description;
private String source;
private String referenceUrl;
private String suggestion;
private List<String> recommendUrl;

@Builder
public SbomResponseDto(String name, String purl, String version, String group, String vulnId, String severity, String description, String source, String referenceUrl, String suggestion, List<String> recommendUrl) {
this.name = name;
this.purl = purl;
this.version = version;
this.group = group;
this.vulnId = vulnId;
this.severity = severity;
this.description = description;
this.source = source;
this.referenceUrl = referenceUrl;
this.suggestion = suggestion;
this.recommendUrl = recommendUrl;
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.pipeline.manager.exception;
package com.analyzer.sbom.exception;

import org.springframework.web.bind.annotation.RestControllerAdvice;

Expand Down
103 changes: 103 additions & 0 deletions manager/src/main/java/com/analyzer/sbom/service/SbomService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package com.analyzer.sbom.service;

import com.analyzer.sbom.dto.response.SbomResponseDto;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;

import java.util.ArrayList;
import java.util.List;

@Service
@RequiredArgsConstructor
public class SbomService {

private final WebClient.Builder webClientBuilder;
private final ObjectMapper objectMapper;

@Value("${webclient.nvd}")
private String ref;

public JsonNode scanVulnerability(String token, String projectId, String baseUrl) throws JsonProcessingException {
String jsonData = getAPI(token, projectId, baseUrl);
return objectMapper.readTree(jsonData);
}

public List<SbomResponseDto> generateReport(String token, String projectId, String baseUrl) throws JsonProcessingException {
String sbomResult = getAPI(token, projectId, baseUrl);

List<SbomResponseDto> sbomReport = new ArrayList<SbomResponseDto>();

JsonNode jsonNode = objectMapper.readTree(sbomResult).get("findings");
if (jsonNode.isArray()) {
for (JsonNode finding : jsonNode) {
JsonNode component = finding.get("component");
String name = isExist(component, "name") ? component.get("name").asText() : "";
String version = isExist(component, "version") ? component.get("version").asText() : "";
String purl = isExist(component, "purl") ? component.get("purl").asText() : "";
String group = isExist(component, "group") ? component.get("group").asText() : "";

JsonNode attribution = finding.get("attribution");
String recommendUrl = isExist(attribution, "referenceUrl") ? attribution.get("referenceUrl").asText() : "";

JsonNode vulnerability = finding.get("vulnerability");
String severity = isExist(vulnerability, "severity") ? vulnerability.get("severity").asText() : "";
String vulnId = isExist(vulnerability, "vulnId") ? vulnerability.get("vulnId").asText() : "";
String source = isExist(vulnerability, "source") ? vulnerability.get("source").asText() : "";
String description = isExist(vulnerability, "description") ? vulnerability.get("description").asText() : "";

String referenceUrl = ref + vulnId;

SbomResponseDto sbomResponseDto = SbomResponseDto.builder()
.name(name)
.version(version)
.purl(purl)
.group(group)
.severity(severity)
.vulnId(vulnId)
.source(source)
.description(description)
.referenceUrl(referenceUrl)
.recommendUrl(null)
.suggestion("")
.build();

sbomReport.add(sbomResponseDto);
}
}
return sbomReport;
}

public String getAPI(String token, String projectId, String baseUrl) {
WebClient webClient = webClientBuilder
.baseUrl(baseUrl)
.defaultHeader("X-Api-Key", token)
.build();

String sbomResult = webClient
.get()
.uri("/api/v1/finding/project/{projectId}/export", projectId)
.retrieve()
.bodyToMono(String.class)
.block();

return sbomResult;
}

private boolean isExist(JsonNode source, String fieldName) {
return source.has(fieldName);
}

private String getSuggestionUrl() {
return "";
}

private String getSuggestion() {
return "";
}

}

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.pipeline.manager;
package com.analyzer.sbom;

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
Expand Down

0 comments on commit a14a6dc

Please sign in to comment.