diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 8cc630b3..ec6770e7 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -18,23 +18,23 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - mixeway-scan: - name: Mixeway Scanning - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v1 - - name: Prepare variables - id: vars - shell: bash - run: | - echo "##[set-output name=branch;]$(echo ${GITHUB_REF#refs/heads/})" - echo "::set-output name=sha_short::$(git rev-parse HEAD)" - - name: Prepare Mixeway docker image - run: | - docker pull mixeway/scanner:latest - - name: Run Scan - run: | - docker run -e MODE=STANDALONE -e OSS_USERNAME=${{ secrets.oss_username }} -e OSS_KEY=${{ secrets.oss_key }} -e COMMIT_ID=${{ steps.vars.outputs.sha_short }} -e BRANCH=${{ steps.vars.outputs.branch }} -e MIXEWAY_PROJECT_NAME=${{ github.event.repository.name }} -e MIXEWAY_PROJECT_ID=${{ secrets.mixeway_project_id }} -e MIXEWAY_KEY=${{ secrets.mixeway_key }} -v $PWD:/opt/sources mixeway/scanner:latest +# mixeway-scan: +# name: Mixeway Scanning +# runs-on: ubuntu-latest +# steps: +# - uses: actions/checkout@v1 +# - name: Prepare variables +# id: vars +# shell: bash +# run: | +# echo "##[set-output name=branch;]$(echo ${GITHUB_REF#refs/heads/})" +# echo "::set-output name=sha_short::$(git rev-parse HEAD)" +# - name: Prepare Mixeway docker image +# run: | +# docker pull mixeway/scanner:latest +# - name: Run Scan +# run: | +# docker run -e MODE=STANDALONE -e OSS_USERNAME=${{ secrets.oss_username }} -e OSS_KEY=${{ secrets.oss_key }} -e COMMIT_ID=${{ steps.vars.outputs.sha_short }} -e BRANCH=${{ steps.vars.outputs.branch }} -e MIXEWAY_PROJECT_NAME=${{ github.event.repository.name }} -e MIXEWAY_PROJECT_ID=${{ secrets.mixeway_project_id }} -e MIXEWAY_KEY=${{ secrets.mixeway_key }} -v $PWD:/opt/sources mixeway/scanner:latest integration-testing: name: Integration test diff --git a/.github/workflows/deploybeta.yml b/.github/workflows/deploybeta.yml index 6bdbceb4..ef3d3df6 100644 --- a/.github/workflows/deploybeta.yml +++ b/.github/workflows/deploybeta.yml @@ -25,23 +25,23 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - mixeway-scan: - name: Mixeway Scanning - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v1 - - name: Prepare variables - id: vars - shell: bash - run: | - echo "##[set-output name=branch;]$(echo ${GITHUB_REF#refs/heads/})" - echo "::set-output name=sha_short::$(git rev-parse HEAD)" - - name: Prepare Mixeway docker image - run: | - docker pull mixeway/scanner:latest - - name: Run Scan - run: | - docker run -e MODE=STANDALONE -e OSS_USERNAME=${{ secrets.oss_username }} -e OSS_KEY=${{ secrets.oss_key }} -e COMMIT_ID=${{ steps.vars.outputs.sha_short }} -e BRANCH=${{ steps.vars.outputs.branch }} -e MIXEWAY_PROJECT_NAME=${{ github.event.repository.name }} -e MIXEWAY_PROJECT_ID=${{ secrets.mixeway_project_id }} -e MIXEWAY_KEY=${{ secrets.mixeway_key }} -v $PWD:/opt/sources mixeway/scanner:latest +# mixeway-scan: +# name: Mixeway Scanning +# runs-on: ubuntu-latest +# steps: +# - uses: actions/checkout@v1 +# - name: Prepare variables +# id: vars +# shell: bash +# run: | +# echo "##[set-output name=branch;]$(echo ${GITHUB_REF#refs/heads/})" +# echo "::set-output name=sha_short::$(git rev-parse HEAD)" +# - name: Prepare Mixeway docker image +# run: | +# docker pull mixeway/scanner:latest +# - name: Run Scan +# run: | +# docker run -e MODE=STANDALONE -e OSS_USERNAME=${{ secrets.oss_username }} -e OSS_KEY=${{ secrets.oss_key }} -e COMMIT_ID=${{ steps.vars.outputs.sha_short }} -e BRANCH=${{ steps.vars.outputs.branch }} -e MIXEWAY_PROJECT_NAME=${{ github.event.repository.name }} -e MIXEWAY_PROJECT_ID=${{ secrets.mixeway_project_id }} -e MIXEWAY_KEY=${{ secrets.mixeway_key }} -v $PWD:/opt/sources mixeway/scanner:latest integration-testing: name: Integration test diff --git a/pom.xml b/pom.xml index ffd63d33..772ad9e2 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ io.mixeway mixeway - 1.8.0 + 1.8.2 jar Mixeway @@ -183,7 +183,7 @@ com.google.guava guava - 30.0-jre + 32.0.0-jre @@ -297,7 +297,7 @@ ch.qos.logback logback-core - 1.2.9 + 1.3.12 diff --git a/src/main/java/io/mixeway/api/cicd/controller/CICDController.java b/src/main/java/io/mixeway/api/cicd/controller/CICDController.java new file mode 100644 index 00000000..18e81477 --- /dev/null +++ b/src/main/java/io/mixeway/api/cicd/controller/CICDController.java @@ -0,0 +1,117 @@ +package io.mixeway.api.cicd.controller; + +import io.mixeway.api.cicd.model.LoadSCA; +import io.mixeway.api.cicd.service.CICDService; +import io.mixeway.api.cioperations.model.LoadVulnModel; +import io.mixeway.api.cioperations.model.ZapReportModel; +import io.mixeway.api.protocol.cioperations.GetInfoRequest; +import io.mixeway.api.protocol.cioperations.PrepareCIOperation; +import io.mixeway.api.protocol.securitygateway.SecurityGatewayResponse; +import io.mixeway.utils.Status; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.io.IOException; +import java.net.UnknownHostException; +import java.security.*; +import java.security.cert.CertificateException; + +@RequiredArgsConstructor +@Controller +@RequestMapping("/v3/api/cicd") +@PreAuthorize("hasAuthority('ROLE_API')") +public class CICDController { + private final CICDService cicdService; + + + /** + * + * Request that meant to create CodeProject or return CodeProject by repoUrl contained in getInfoRequest + * + * @param getInfoRequest - info with repoURL and branch + */ + @PostMapping(value = "/codeproject/info") + public ResponseEntity getCPInfo(@Valid @RequestBody GetInfoRequest getInfoRequest, Principal principal) throws CertificateException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException, KeyStoreException, IOException { + return cicdService.getCPInfo(getInfoRequest, principal); + } + + /** + * + * Request that meant to + * 1. Create or get proper branch for CodeProject with given ID + * 2. Call SCA scanner to load vulnerabilities and link those with pair codeproject - codeprojectbranch + * + * @param loadSCA + */ + @PostMapping(value = "/codeproject/load/sca") + public ResponseEntity loadSca(@Valid @RequestBody LoadSCA loadSCA, Principal principal) throws CertificateException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException, KeyStoreException, IOException { + return cicdService.loadSca(loadSCA, principal); + } + + + /** + * + * Request that load vulnerabilities from arbitrary sources such as GitLeaks and KICS: + * 1. Create or get proper branch for CodeProject with given ID + * 2. Load vulnerabilities to DB and link those with pair CodeProject - CodeProjectBranch + * + */ + @PreAuthorize("hasAuthority('ROLE_API')") + @PostMapping(value="/codeproject/loadvulns/{codeProjectId}") + public ResponseEntity loadVulns (@RequestBody LoadVulnModel loadVulnModel, + @PathVariable(value = "codeProjectId") Long id, + Principal principal) throws Exception { + return cicdService.loadVulnerabilitiesFromCICDToProject( + loadVulnModel.getVulns(), + id, + loadVulnModel.getBranch(), + loadVulnModel.getCommitId(), + principal); + } + + /** + * + * Request that start SAST Scan for given scope: + * 1. Create or get proper branch for CodeProject with given ID + * 2. Load vulnerabilities to DB and link those with pair CodeProject - CodeProjectBranch + * + */ + @PreAuthorize("hasAuthority('ROLE_API')") + @PostMapping(value = "/codeproject/run/sast") + public ResponseEntity performSastScanForCodeProject( @RequestBody LoadSCA loadSCA, Principal principal) throws UnrecoverableKeyException, CertificateException, NoSuchAlgorithmException, KeyStoreException, IOException, KeyManagementException { + return cicdService.performSastScanForCodeProject(loadSCA, principal); + } + + + /** + * + * Request that load vulnerabilities from arbitrary sources such as ZAP: + * 1. Create or get proper branch for CodeProject with given ID + * 2. Load vulnerabilities to DB and link those with pair CodeProject - CodeProjectBranch + * TODO Upload report ZAP with info regarding repoUrl to link repo with webapp + * + */ + + @PreAuthorize("hasAuthority('ROLE_API')") + @PostMapping(value="/loadvulns/zap/{ciid}") + public ResponseEntity loadVulnsZap (@RequestBody ZapReportModel loadVulnModel, + @PathVariable(value = "ciid") String ciid, + Principal principal) throws Exception { + return cicdService.loadVulnZap(loadVulnModel,ciid,principal); + } + + /** + * Validate State of security for given CodeProject and Branch + */ + @CrossOrigin(origins="*") + @PreAuthorize("hasAuthority('ROLE_API')") + @PostMapping(value = "/codeproject/validate",produces = "application/json") + public ResponseEntity cicdValidate(@RequestBody LoadSCA loadSCA, + Principal principal) throws UnknownHostException { + return cicdService.validate(loadSCA, principal); + } +} diff --git a/src/main/java/io/mixeway/api/cicd/model/CodeProjectInfo.java b/src/main/java/io/mixeway/api/cicd/model/CodeProjectInfo.java new file mode 100644 index 00000000..b470f341 --- /dev/null +++ b/src/main/java/io/mixeway/api/cicd/model/CodeProjectInfo.java @@ -0,0 +1,7 @@ +package io.mixeway.api.cicd.model; + +public class CodeProjectInfo { + + + +} diff --git a/src/main/java/io/mixeway/api/cicd/model/LoadSCA.java b/src/main/java/io/mixeway/api/cicd/model/LoadSCA.java new file mode 100644 index 00000000..bddc3980 --- /dev/null +++ b/src/main/java/io/mixeway/api/cicd/model/LoadSCA.java @@ -0,0 +1,16 @@ +package io.mixeway.api.cicd.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class LoadSCA { + private Long codeProjectId; + private String branch; + private String commitId; +} diff --git a/src/main/java/io/mixeway/api/cicd/service/CICDService.java b/src/main/java/io/mixeway/api/cicd/service/CICDService.java new file mode 100644 index 00000000..56c13e8a --- /dev/null +++ b/src/main/java/io/mixeway/api/cicd/service/CICDService.java @@ -0,0 +1,207 @@ +package io.mixeway.api.cicd.service; + +import io.mixeway.api.cicd.model.LoadSCA; +import io.mixeway.api.cioperations.model.ZapReportModel; +import io.mixeway.api.protocol.OpenSourceConfig; +import io.mixeway.api.protocol.cioperations.GetInfoRequest; +import io.mixeway.api.protocol.cioperations.InfoScanPerformed; +import io.mixeway.api.protocol.cioperations.PrepareCIOperation; +import io.mixeway.api.protocol.securitygateway.SecurityGatewayResponse; +import io.mixeway.api.protocol.vulnerability.Vuln; +import io.mixeway.config.Constants; +import io.mixeway.db.entity.*; +import io.mixeway.domain.service.cioperations.CreateCiOperationsService; +import io.mixeway.domain.service.cioperations.FindCiOperationsService; +import io.mixeway.domain.service.cioperations.UpdateCiOperationsService; +import io.mixeway.domain.service.scanmanager.code.CreateOrGetCodeProjectService; +import io.mixeway.domain.service.scanmanager.code.FindCodeProjectService; +import io.mixeway.domain.service.scanmanager.code.GetOrCreateCodeProjectBranchService; +import io.mixeway.domain.service.scanmanager.code.UpdateCodeProjectService; +import io.mixeway.domain.service.vulnmanager.VulnTemplate; +import io.mixeway.scanmanager.service.code.CodeScanService; +import io.mixeway.scanmanager.service.opensource.OpenSourceScanService; +import io.mixeway.scanmanager.service.webapp.WebAppScanService; +import io.mixeway.utils.*; +import io.mixeway.utils.ScannerType; +import io.mixeway.utils.Status; +import lombok.RequiredArgsConstructor; +import lombok.extern.log4j.Log4j2; +import org.apache.commons.lang3.StringUtils; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.io.IOException; +import java.net.UnknownHostException; +import java.security.*; +import java.security.cert.CertificateException; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +@Log4j2 +public class CICDService { + private final CreateOrGetCodeProjectService createOrGetCodeProjectService; + private final OpenSourceScanService openSourceScanService; + private final FindCodeProjectService findCodeProjectService; + private final FindCiOperationsService findCiOperationsService; + private final CreateCiOperationsService createCiOperationsService; + private final UpdateCodeProjectService updateCodeProjectService; + private final GetOrCreateCodeProjectBranchService getOrCreateCodeProjectBranchService; + private final PermissionFactory permissionFactory; + private final CodeScanService codeScanService; + private final WebAppScanService webAppScanService; + private final VulnTemplate vulnTemplate; + private final SecurityQualityGateway securityQualityGateway; + private final UpdateCiOperationsService updateCiOperationsService; + + + public ResponseEntity getCPInfo(GetInfoRequest getInfoRequest, Principal principal) throws CertificateException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException, KeyStoreException, IOException { + CodeProject codeProject = createOrGetCodeProjectService.createOrGetCodeProject(getInfoRequest.getRepoUrl(), getInfoRequest.getBranch(), getInfoRequest.getRepoName(), principal); + if (StringUtils.isBlank(codeProject.getdTrackUuid())) { + openSourceScanService.createProjectOnOpenSourceScanner(codeProject); + } + OpenSourceConfig openSourceConfig = openSourceScanService + .getOpenSourceScannerConfiguration( + codeProject.getProject().getId(), + codeProject.getName(), + codeProject.getName(), + principal) + .getBody(); + // FOR NOW owasp dtrack hardcoded + return new ResponseEntity<>(new PrepareCIOperation(openSourceConfig, codeProject, "OWASP Dependency Track"), HttpStatus.OK); + + } + + public ResponseEntity loadSca(LoadSCA loadSCA, Principal principal) throws UnrecoverableKeyException, CertificateException, NoSuchAlgorithmException, KeyStoreException, IOException, KeyManagementException { + Optional codeProject = findCodeProjectService.findById(loadSCA.getCodeProjectId()); + if (codeProject.isPresent() ){ + Optional ciOperations = findCiOperationsService.findByCodeProjectAndCommitId(codeProject.get(), loadSCA.getCommitId()); + if (!ciOperations.isPresent()){ + createCiOperationsService.create(codeProject.get(), loadSCA); + } + CodeProjectBranch codeProjectBranch = getOrCreateCodeProjectBranchService.getOrCreateCodeProjectBranch(codeProject.get(), loadSCA.getBranch()); + updateCodeProjectService.changeCommitId(loadSCA.getCommitId(), codeProject.get()); + openSourceScanService.loadVulnerabilitiesForBranch(codeProject.get(), loadSCA.getBranch()); + return new ResponseEntity<>(HttpStatus.OK); + } else { + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + } + } + + @Transactional + public ResponseEntity loadVulnerabilitiesFromCICDToProject(List vulns, Long projectId, + String branch, + String commitId, Principal principal) { + Optional codeProject = findCodeProjectService.findById(projectId); + if (codeProject.isPresent() && permissionFactory.canUserAccessProject(principal, codeProject.get().getProject())) { + CodeProjectBranch codeProjectBranch = getOrCreateCodeProjectBranchService.getOrCreateCodeProjectBranch(codeProject.get(), branch); + updateCodeProjectService.changeCommitId(commitId, codeProject.get()); + + + // to support legacy application where client call SAST while it should be IAC + List sastVulns = vulns.stream().filter(v -> v.getScannerType().equals(ScannerType.IAC)).collect(Collectors.toList()); + if (sastVulns.size() > 0 ){ + codeScanService.loadVulnsFromCICDToCodeProjectForBranch(codeProject.get(), sastVulns, ScannerType.IAC, codeProjectBranch); + } else { + codeScanService.loadVulnsFromCICDToCodeProjectForBranch(codeProject.get(), new ArrayList<>(), ScannerType.IAC, codeProjectBranch); + } + List gitLeaksVulns = vulns.stream().filter(v -> v.getScannerType().equals(ScannerType.GITLEAKS)).collect(Collectors.toList()); + if (gitLeaksVulns.size() > 0 ){ + codeScanService.loadVulnsFromCICDToCodeProjectForBranch(codeProject.get(), gitLeaksVulns, ScannerType.GITLEAKS, codeProjectBranch); + } else { + codeScanService.loadVulnsFromCICDToCodeProjectForBranch(codeProject.get(), new ArrayList<>(), ScannerType.GITLEAKS, codeProjectBranch); + } + //FOR NOW THIS FUNCTIONALITY IS NOT MIGRATED TO V3 +// List openSourceVulns = vulns.stream().filter(v -> v.getScannerType().equals(ScannerType.OPENSOURCE)).collect(Collectors.toList()); +// if (openSourceVulns.size() > 0) { +// openSourceScanService.loadVulnsFromCICDToCodeProject(codeProject.get(), openSourceVulns); +// } else { +// openSourceScanService.loadVulnsFromCICDToCodeProject(codeProject.get(), new ArrayList<>()); +// } + + return new ResponseEntity<>(new Status("Vulnerabilities uploaded"), HttpStatus.OK); + + } else { + return new ResponseEntity<>(HttpStatus.UNAUTHORIZED); + } + + } + + public ResponseEntity performSastScanForCodeProject(LoadSCA loadSCA, Principal principal) { + Optional codeProject = findCodeProjectService.findById(loadSCA.getCodeProjectId()); + if (codeProject.isPresent() && permissionFactory.canUserAccessProject(principal, codeProject.get().getProject())) { + CodeProjectBranch codeProjectBranch = getOrCreateCodeProjectBranchService.getOrCreateCodeProjectBranch(codeProject.get(), loadSCA.getBranch()); + updateCodeProjectService.updateActiveBranch(codeProject.get(), codeProjectBranch); + codeScanService.putCodeProjectToQueue(codeProject.get().getId(),principal); + + log.info("[CICD] {} put SAST Project in queue - {}", principal.getName(), codeProject.get().getName()); + return new ResponseEntity<>(HttpStatus.OK); + } else { + log.error("[CICD] {} tries to run SAST scan for id {} but project doesnt exist or user has no permission to do so.", principal.getName(), loadSCA.getCodeProjectId()); + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + } + } + + /** + * ZAP reports + */ + + @Transactional + public ResponseEntity loadVulnZap(ZapReportModel loadVulnModel, String ciid, Principal principal) throws ParseException { + log.info("ZAP DAST JSON report received for ciid {}", ciid); + return webAppScanService.prepareAndLoadZapVulns(loadVulnModel,ciid,principal); + } + + public ResponseEntity validate(LoadSCA loadSCA, Principal principal) throws UnknownHostException { + Optional codeProject = findCodeProjectService.findById(loadSCA.getCodeProjectId()); + if (codeProject.isPresent() && permissionFactory.canUserAccessProject(principal, codeProject.get().getProject())) { + CodeProjectBranch codeProjectBranch = getOrCreateCodeProjectBranchService.getOrCreateCodeProjectBranch(codeProject.get(), loadSCA.getBranch()); + + + List vulns = vulnTemplate.projectVulnerabilityRepository.findByCodeProjectAndCodeProjectBranch(codeProject.get(), codeProjectBranch).stream().filter(projectVulnerability -> !projectVulnerability.getStatus().equals(vulnTemplate.STATUS_REMOVED)).collect(Collectors.toList()); + List vulnList = new ArrayList<>(); + vulns.removeIf(projectVulnerability -> projectVulnerability.getGrade() == 0); + for (ProjectVulnerability pv : vulns){ + if (pv.getVulnerabilitySource().getId().equals(vulnTemplate.SOURCE_OPENSOURCE.getId())){ + vulnList.add(new Vuln(pv,null,null,pv.getCodeProject(),Constants.VULN_TYPE_OPENSOURCE)); + } else if (pv.getVulnerabilitySource().getId().equals(vulnTemplate.SOURCE_SOURCECODE.getId())){ + vulnList.add(new Vuln(pv,null,null,pv.getCodeProject(),Constants.VULN_TYPE_SOURCECODE)); + } else if (pv.getVulnerabilitySource().getId().equals(vulnTemplate.SOURCE_GITLEAKS.getId())){ + vulnList.add(new Vuln(pv,null,null,pv.getCodeProject(),Constants.VULN_TYPE_SOURCECODE)); + } else if (pv.getVulnerabilitySource().getId().equals(vulnTemplate.SOURCE_IAC.getId())){ + vulnList.add(new Vuln(pv,null,null,pv.getCodeProject(),Constants.VULN_TYPE_SOURCECODE)); + } + } + vulnList.removeIf(vuln -> vuln.getId() == null); + SecurityGatewayEntry securityGatewayEntry = securityQualityGateway.buildGatewayResponse(vulns); + updateCiOperationWithSecurityGatewayResponse(codeProject.get(), securityGatewayEntry); + return new ResponseEntity( + new SecurityGatewayResponse(securityGatewayEntry.isPassed(), + securityGatewayEntry.isPassed() ? Constants.SECURITY_GATEWAY_PASSED : Constants.SECURITY_GATEWAY_FAILED, + vulnList), + HttpStatus.OK); + + + }else { + log.error("[CICD] {} tries to run Validate project of id {} but project doesnt exist or user has no permission to do so.", principal.getName(), loadSCA.getCodeProjectId()); + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + } + } + + /** + * Updating CIOperations entry (for codeproject, branch and commitid) with scan performed, result and vulnerabilities number + * @param codeProject to edit cioperations + * @param securityGatewayEntry to check vulnerabilities number + */ + private void updateCiOperationWithSecurityGatewayResponse(CodeProject codeProject, SecurityGatewayEntry securityGatewayEntry) { + Optional ciOperations = findCiOperationsService.findByCodeProjectAndCommitId(codeProject, codeProject.getCommitid()); + ciOperations.ifPresent(operations -> updateCiOperationsService.updateCiOperations(operations, securityGatewayEntry, codeProject)); + } +} diff --git a/src/main/java/io/mixeway/api/cioperations/controller/CiOperationsController.java b/src/main/java/io/mixeway/api/cioperations/controller/CiOperationsController.java index 93021207..e2d11351 100644 --- a/src/main/java/io/mixeway/api/cioperations/controller/CiOperationsController.java +++ b/src/main/java/io/mixeway/api/cioperations/controller/CiOperationsController.java @@ -77,16 +77,16 @@ public ResponseEntity codeScan(@PathVariable(value = "projectId") Long i Principal principal) throws IOException, CertificateException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException, KeyStoreException, JSONException, ParseException { return ciOperationsService.codeScan(id,groupName,projectName,commitId, principal); } - @CrossOrigin(origins="*") - @PreAuthorize("hasAuthority('ROLE_API')") - @GetMapping(value = "/project/{projectId}/code/verify/{codeGroup}/{codeProject}/{commitid}",produces = "application/json") - public ResponseEntity codeVerify(@PathVariable(value = "codeGroup") String codeGroup, - @PathVariable(value = "codeProject") String codeProject, - @PathVariable(value = "projectId") Long id, - @PathVariable("commitid") String commitid, - Principal principal) throws CertificateException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException, KeyStoreException, IOException { - return ciOperationsService.codeVerify(codeGroup, codeProject, id, commitid, principal); - } +// @CrossOrigin(origins="*") +// @PreAuthorize("hasAuthority('ROLE_API')") +// @GetMapping(value = "/project/{projectId}/code/verify/{codeGroup}/{codeProject}/{commitid}",produces = "application/json") +// public ResponseEntity codeVerify(@PathVariable(value = "codeGroup") String codeGroup, +// @PathVariable(value = "codeProject") String codeProject, +// @PathVariable(value = "projectId") Long id, +// @PathVariable("commitid") String commitid, +// Principal principal) throws CertificateException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException, KeyStoreException, IOException { +// return ciOperationsService.codeVerify(codeGroup, codeProject, id, commitid, principal); +// } @CrossOrigin(origins="*") diff --git a/src/main/java/io/mixeway/api/dashboard/service/DashboardService.java b/src/main/java/io/mixeway/api/dashboard/service/DashboardService.java index fa3924f2..4c704dd4 100644 --- a/src/main/java/io/mixeway/api/dashboard/service/DashboardService.java +++ b/src/main/java/io/mixeway/api/dashboard/service/DashboardService.java @@ -163,7 +163,7 @@ public ResponseEntity getRootStatistics(Principal princi findProjectService.count(), getScanNumberService.getNumberOfScansRunning(), getScanNumberService.getNumberOfScansInQueue(), - vulnTemplate.projectVulnerabilityRepository.count() + vulnTemplate.projectVulnerabilityRepository.countVulns() ); dashboardTopStatistics.setStatisticCard(statisticCard); dashboardTopStatistics.setProjectVulnerabilityList(projectVulnerabilities.stream().limit(5).collect(Collectors.toList())); diff --git a/src/main/java/io/mixeway/api/project/controller/ProjectRestController.java b/src/main/java/io/mixeway/api/project/controller/ProjectRestController.java index fbfae0fd..5204e7b6 100644 --- a/src/main/java/io/mixeway/api/project/controller/ProjectRestController.java +++ b/src/main/java/io/mixeway/api/project/controller/ProjectRestController.java @@ -17,7 +17,7 @@ @RestController() @RequestMapping("/v2/api/show/project") -public class ProjectRestController { +public class ProjectRestController { private final ProjectRestService projectService; ProjectRestController(ProjectRestService projectRestService){ @@ -110,4 +110,18 @@ public ResponseEntity getProjectByCiid(@PathVariable("ciid") String cii return projectService.getProjectByCiid(ciid, principal); } + @PreAuthorize("hasAuthority('ROLE_USER')") + @GetMapping(value = "/{id}/detailstats") + public ResponseEntity detailStats(@PathVariable("id") Long id, Principal principal) { + return projectService.detailStats(id, principal); + } + + @PreAuthorize("hasAuthority('ROLE_USER')") + @GetMapping(value = "/{id}/detailedhistory") + public ResponseEntity> detailedHistory(@PathVariable("id") Long id, Principal principal) { + return projectService.detailedHistory(id, principal); + } + + + } diff --git a/src/main/java/io/mixeway/api/project/model/DetailStats.java b/src/main/java/io/mixeway/api/project/model/DetailStats.java new file mode 100644 index 00000000..f6973ef2 --- /dev/null +++ b/src/main/java/io/mixeway/api/project/model/DetailStats.java @@ -0,0 +1,16 @@ +package io.mixeway.api.project.model; + +import lombok.*; + +@Builder +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class DetailStats { + private int detectedVulnerabilities; + private int resolvedVulnerabilities; + private int avgTimeToFix; + private int resolvedCriticals; + +} diff --git a/src/main/java/io/mixeway/api/project/service/ProjectAuditService.java b/src/main/java/io/mixeway/api/project/service/ProjectAuditService.java index 0973e64d..9eb64ad4 100644 --- a/src/main/java/io/mixeway/api/project/service/ProjectAuditService.java +++ b/src/main/java/io/mixeway/api/project/service/ProjectAuditService.java @@ -34,7 +34,6 @@ public ResponseEntity> getAuditForCodeVulnerability(Code settings.getLocation(), createOrGetVulnerabilityService.createOrGetVulnerability(settings.getVulnerability() )); - log.info("Test"); return new ResponseEntity<>(vulnerabiltyAudits, HttpStatus.OK); } diff --git a/src/main/java/io/mixeway/api/project/service/ProjectRestService.java b/src/main/java/io/mixeway/api/project/service/ProjectRestService.java index cb720496..35fc9f37 100644 --- a/src/main/java/io/mixeway/api/project/service/ProjectRestService.java +++ b/src/main/java/io/mixeway/api/project/service/ProjectRestService.java @@ -114,7 +114,7 @@ public ResponseEntity> showSeverityChart(Long id, Principal HashMap pieData = new HashMap<>(); if (project.isPresent() && permissionFactory.canUserAccessProject(principal, project.get())){ for (String severity : severityList){ - pieData.put(severity,vulnTemplate.projectVulnerabilityRepository.countByProjectAndSeverity(project.get(), severity)); + pieData.put(severity,vulnTemplate.projectVulnerabilityRepository.countVulnsbyProject(project.get(), severity)); } return new ResponseEntity<>(pieData,HttpStatus.OK); } else { @@ -155,7 +155,7 @@ public ResponseEntity> showVulnerabilitiesForProject( Optional project = findProjectService.findProjectById(id); if (project.isPresent() && permissionFactory.canUserAccessProject(principal, project.get())){ List vulns; - try (Stream vulnsForProject = vulnTemplate.projectVulnerabilityRepository.findByProject(project.get())) { + try (Stream vulnsForProject = vulnTemplate.projectVulnerabilityRepository.findByProject(project.get()).filter(projectVulnerability -> !projectVulnerability.getStatus().getId().equals(vulnTemplate.STATUS_REMOVED.getId()))) { return new ResponseEntity<>(vulnsForProject.collect(Collectors.toList()),HttpStatus.OK); } } else { @@ -199,8 +199,16 @@ public ResponseEntity setGradeForVulnerability(Long id, Long vulnId,int if (project.isPresent() && permissionFactory.canUserAccessProject(principal, project.get())){ Optional projectVulnerability = vulnTemplate.projectVulnerabilityRepository.findById(vulnId); if (projectVulnerability.isPresent() && projectVulnerability.get().getProject().getId().equals(project.get().getId()) && (grade==1 || grade==0)) { - projectVulnerability.get().setGrade(grade); - log.info("{} - changed Grade for Vulnerability {} to {}", principal.getName(), projectVulnerability.get().getId(), grade); + List projectVulnerabilities = vulnTemplate.projectVulnerabilityRepository + .findByVulnerabilityAndLocationAndDescription( + projectVulnerability.get().getVulnerability(), + projectVulnerability.get().getLocation(), + projectVulnerability.get().getDescription() + ); + projectVulnerabilities.forEach(pv -> pv.setGrade(grade)); + + //projectVulnerability.get().setGrade(grade); + log.info("{} - changed Grade for Vulnerability {} to {}, affected vulnerabilities in {} branches", principal.getName(), projectVulnerability.get().getId(), grade, 0); return new ResponseEntity<>( HttpStatus.OK); } } else { @@ -226,9 +234,9 @@ public ResponseEntity showProjectStats(Long id, Principal principa .repos(project.get().getCodes().size()) .webApps(project.get().getWebapps().size()) .assets(project.get().getAssets().size()) - .vulnCrit(projectVulnerabilities.stream().filter(pv -> pv.getSeverity().equals(Constants.VULN_CRITICALITY_CRITICAL) || pv.getSeverity().equals(Constants.VULN_CRITICALITY_HIGH)).count()) - .vulnMedium(projectVulnerabilities.stream().filter(pv -> pv.getSeverity().equals(Constants.VULN_CRITICALITY_MEDIUM)).count()) - .vulnLow(projectVulnerabilities.stream().filter(pv -> pv.getSeverity().equals(Constants.VULN_CRITICALITY_LOW)).count()) + .vulnCrit(projectVulnerabilities.stream().filter(pv -> (pv.getSeverity().equals(Constants.VULN_CRITICALITY_CRITICAL) || pv.getSeverity().equals(Constants.VULN_CRITICALITY_HIGH)) && !Objects.equals(pv.getStatus().getId(), vulnTemplate.STATUS_REMOVED.getId()) && pv.getGrade()!=0).count()) + .vulnMedium(projectVulnerabilities.stream().filter(pv -> pv.getSeverity().equals(Constants.VULN_CRITICALITY_MEDIUM) && !Objects.equals(pv.getStatus().getId(), vulnTemplate.STATUS_REMOVED.getId()) && pv.getGrade()!=0).count()) + .vulnLow(projectVulnerabilities.stream().filter(pv -> pv.getSeverity().equals(Constants.VULN_CRITICALITY_LOW) && !Objects.equals(pv.getStatus().getId(), vulnTemplate.STATUS_REMOVED.getId()) && pv.getGrade()!=0).count()) .build(); return new ResponseEntity<>(projectStats, HttpStatus.OK); @@ -241,4 +249,49 @@ public ResponseEntity getProjectByCiid(String ciid, Principal principal Optional project = findProjectService.findProjectByCiid(ciid); return project.map(value -> new ResponseEntity<>(value, HttpStatus.OK)).orElseGet(() -> new ResponseEntity<>(HttpStatus.NOT_FOUND)); } + + public ResponseEntity detailStats(Long id, Principal principal) { + Optional project = findProjectService.findProjectById(id); + if (project.isPresent() && permissionFactory.canUserAccessProject(principal, project.get())){ + List projectVulnerabilities = vulnTemplate.projectVulnerabilityRepository.findByProject(project.get()).collect(Collectors.toList()); + int detectedVulnerabilities = projectVulnerabilities.size(); + long detectedCriticalVulnerabilities = projectVulnerabilities.stream().filter(pv -> pv.getSeverity().equals(Constants.API_SEVERITY_CRITICAL)).count(); + long resolvedCriticalVulnerabilities = projectVulnerabilities.stream().filter(pv -> pv.getSeverity().equals(Constants.API_SEVERITY_CRITICAL) && Objects.equals(pv.getStatus().getId(), vulnTemplate.STATUS_REMOVED.getId()) && pv.getGrade()!=0).count(); + List solvedVulnerabilities = projectVulnerabilities.stream().filter(pv -> pv.getStatus().getId().equals(vulnTemplate.STATUS_REMOVED.getId())).collect(Collectors.toList()); + int percentResolvedCritical = (int) Math.ceil(((double) resolvedCriticalVulnerabilities / detectedCriticalVulnerabilities) * 100); + int avgTimeToFix= (int) Math.ceil(calculateAverageDifferenceInDays(solvedVulnerabilities)); + DetailStats detailStats = DetailStats.builder() + .resolvedCriticals(percentResolvedCritical) + .detectedVulnerabilities(detectedVulnerabilities) + .resolvedVulnerabilities(solvedVulnerabilities.size()) + .avgTimeToFix(avgTimeToFix) + .build(); + return new ResponseEntity<>(detailStats, HttpStatus.OK); + } + return new ResponseEntity<>(HttpStatus.EXPECTATION_FAILED); + } + + private static double calculateAverageDifferenceInDays(List list) { + if (list == null || list.isEmpty()) { + // Handle this case as per your requirements, could throw an exception or return 0 + return 0; + } + + long sumOfDifferences = 0; + for (ProjectVulnerability pv : list) { + sumOfDifferences += pv.calculateDifferenceInDays(); + } + + // Calculate the average + return sumOfDifferences / (double) list.size(); + } + + public ResponseEntity> detailedHistory(Long id, Principal principal) { + Optional project = findProjectService.findProjectById(id); + if (project.isPresent() && permissionFactory.canUserAccessProject(principal, project.get())){ + List vulnHistories = operateOnVulnHistoryService.getLatestVulnHistoryForProject(project.get()); + return new ResponseEntity<>(vulnHistories, HttpStatus.OK); + } + return new ResponseEntity<>(HttpStatus.EXPECTATION_FAILED); + } } diff --git a/src/main/java/io/mixeway/api/protocol/vulnerability/Vuln.java b/src/main/java/io/mixeway/api/protocol/vulnerability/Vuln.java index ffc45a11..a3da96df 100644 --- a/src/main/java/io/mixeway/api/protocol/vulnerability/Vuln.java +++ b/src/main/java/io/mixeway/api/protocol/vulnerability/Vuln.java @@ -58,7 +58,7 @@ public Vuln(ProjectVulnerability projectVulnerability, St } else if ((target instanceof CodeProject) && projectVulnerability.getVulnerabilitySource().getName().equals(Constants.VULN_TYPE_OPENSOURCE)){ CodeProject cp = (CodeProject)target; this.setId(projectVulnerability.getId()); - this.setLocation(cp.getName()); + this.setLocation(cp.getName() + " / " + projectVulnerability.getSoftwarePacket().getName()); this.setType(Constants.API_SCANNER_PACKAGE); this.setVulnerabilityName(projectVulnerability.getVulnerability().getName()); this.setSeverity(projectVulnerability.getVulnerability().getSeverity() == null ? projectVulnerability.getSeverity() : projectVulnerability.getVulnerability().getSeverity()); @@ -69,7 +69,11 @@ public Vuln(ProjectVulnerability projectVulnerability, St this.setDateCreated(projectVulnerability.getInserted()); this.setPacketName(projectVulnerability.getSoftwarePacket().getName()); this.setGrade(projectVulnerability.getGrade()); - } else if ((target instanceof CodeProject) && projectVulnerability.getVulnerabilitySource().getName().equals(Constants.VULN_TYPE_SOURCECODE)){ + } else if ((target instanceof CodeProject) && + (projectVulnerability.getVulnerabilitySource().getName().equals(Constants.VULNEARBILITY_SOURCE_GITLEAKS) || + projectVulnerability.getVulnerabilitySource().getName().equals(Constants.VULN_TYPE_SOURCECODE) || + projectVulnerability.getVulnerabilitySource().getName().equals(Constants.VULNEARBILITY_SOURCE_IAC)) + ){ this.setGrade(projectVulnerability.getGrade()); this.setId(projectVulnerability.getId()); this.setVulnerabilityName(projectVulnerability.getVulnerability().getName()); diff --git a/src/main/java/io/mixeway/api/statistic/service/VulnsService.java b/src/main/java/io/mixeway/api/statistic/service/VulnsService.java index 1ea257f3..c29cbd13 100644 --- a/src/main/java/io/mixeway/api/statistic/service/VulnsService.java +++ b/src/main/java/io/mixeway/api/statistic/service/VulnsService.java @@ -159,9 +159,9 @@ public ResponseEntity> getGlobalStatistics(Principal princ for (Project project: projects){ GlobalStatistic globalStatistic = new GlobalStatistic(); List codeVulns = getProjectVulnerabilitiesService - .getProjectVulnerabilitiesForProjectAndSourceAndSeverity(project, vulnTemplate.SOURCE_SOURCECODE, Arrays.asList("Critical", "High")) ; + .getProjectVulnerabilitiesForProjectAndSourceAndSeverity(project, vulnTemplate.SOURCE_SOURCECODE, Arrays.asList("Critical", "High")); List scaVulns = getProjectVulnerabilitiesService - .getProjectVulnerabilitiesForProjectAndSourceAndSeverity(project, vulnTemplate.SOURCE_OPENSOURCE, Arrays.asList("Critical", "High")) ; + .getProjectVulnerabilitiesForProjectAndSourceAndSeverity(project, vulnTemplate.SOURCE_OPENSOURCE, Arrays.asList("Critical", "High")); globalStatistic.setProject(project.getName()); globalStatistic.setCodeVulns(codeVulns.size()); globalStatistic.setScaVulns(scaVulns.size()); diff --git a/src/main/java/io/mixeway/api/vulnmanage/model/Vuln.java b/src/main/java/io/mixeway/api/vulnmanage/model/Vuln.java index 08b8f577..fa6b7ec0 100644 --- a/src/main/java/io/mixeway/api/vulnmanage/model/Vuln.java +++ b/src/main/java/io/mixeway/api/vulnmanage/model/Vuln.java @@ -71,7 +71,7 @@ public Vuln(ProjectVulnerability projectVulnerability, St this.setDateCreated(projectVulnerability.getInserted()); this.setPacketName(projectVulnerability.getSoftwarePacket().getName()); this.setGrade(projectVulnerability.getGrade()); - } else if ((target instanceof CodeProject) && projectVulnerability.getVulnerabilitySource().getName().equals(Constants.VULN_TYPE_SOURCECODE)){ + } else if ((target instanceof CodeProject) && (projectVulnerability.getVulnerabilitySource().getName().equals(Constants.VULN_TYPE_SOURCECODE) || projectVulnerability.getVulnerabilitySource().getName().equals(Constants.VULNEARBILITY_SOURCE_IAC) || projectVulnerability.getVulnerabilitySource().getName().equals(Constants.VULNEARBILITY_SOURCE_GITLEAKS) )){ this.setGrade(projectVulnerability.getGrade()); this.setId(projectVulnerability.getId()); this.setVulnerabilityName(projectVulnerability.getVulnerability().getName()); @@ -87,7 +87,8 @@ public Vuln(ProjectVulnerability projectVulnerability, St this.setDateCreated(projectVulnerability.getInserted()); this.setType(Constants.API_SCANNER_CODE); }catch (Exception e){ - log.info("asd"); + e.printStackTrace(); + log.info("problem with vuln for {}", projectVulnerability.getCodeProject().getName()); } } else if ((target instanceof WebApp) && projectVulnerability.getVulnerabilitySource().getName().equals(Constants.VULN_TYPE_WEBAPP)){ this.setGrade(projectVulnerability.getGrade()); diff --git a/src/main/java/io/mixeway/api/vulnmanage/service/GetVulnerabilitiesService.java b/src/main/java/io/mixeway/api/vulnmanage/service/GetVulnerabilitiesService.java index 993c53ee..35ef317a 100644 --- a/src/main/java/io/mixeway/api/vulnmanage/service/GetVulnerabilitiesService.java +++ b/src/main/java/io/mixeway/api/vulnmanage/service/GetVulnerabilitiesService.java @@ -7,6 +7,7 @@ import io.mixeway.config.Constants; import io.mixeway.db.entity.*; import io.mixeway.db.repository.*; +import io.mixeway.domain.service.scanmanager.code.FindCodeProjectService; import io.mixeway.domain.service.vulnmanager.VulnTemplate; import io.mixeway.scanmanager.service.opensource.OpenSourceScanService; import lombok.extern.log4j.Log4j2; @@ -78,6 +79,9 @@ public class GetVulnerabilitiesService { @Autowired SecurityGatewayRepository securityGatewayRepository; + @Autowired + FindCodeProjectService findCodeProjectService; + ArrayList severitiesNot = new ArrayList() {{ add("Log"); add("Info"); @@ -110,17 +114,45 @@ private Vulnerabilities setPackageVulns(Vulnerabilities vulns, Project project) List tmpVulns = vulns.getVulnerabilities(); List softVuln = null; if (project != null) { - try (Stream vulnsForProject = vulnTemplate.projectVulnerabilityRepository.findByProjectAndVulnerabilitySource(project, vulnTemplate.SOURCE_OPENSOURCE)) { + try (Stream vulnsForProject = vulnTemplate.projectVulnerabilityRepository.findByProjectAndVulnerabilitySource(project, vulnTemplate.SOURCE_OPENSOURCE).filter(projectVulnerability -> !projectVulnerability.getStatus().equals(vulnTemplate.STATUS_REMOVED))) { softVuln = vulnsForProject.collect(Collectors.toList()); } } else { try (Stream vulnsForProject = vulnTemplate.projectVulnerabilityRepository - .findByProjectInAndVulnerabilitySource(projectRepository.findByEnableVulnManage(true),vulnTemplate.SOURCE_OPENSOURCE)) { + .findByProjectInAndVulnerabilitySource(projectRepository.findByEnableVulnManage(true),vulnTemplate.SOURCE_OPENSOURCE) + .filter(projectVulnerability -> !projectVulnerability.getStatus().equals(vulnTemplate.STATUS_REMOVED))) { softVuln = vulnsForProject.collect(Collectors.toList()); } } + softVuln.removeIf(projectVulnerability -> projectVulnerability.getGrade() == 0); + + + // Usuniecie duplikatach w branchach + Map uniqueVulnsMap = new HashMap<>(); + for (ProjectVulnerability projectVulnerability : softVuln) { + CodeProjectBranch codeProjectBranch = projectVulnerability.getCodeProjectBranch(); + CodeProject codeProject = projectVulnerability.getCodeProject(); + + if (codeProjectBranch != null && codeProject != null) { + String branchName = codeProjectBranch.getName(); + String projectBranch = codeProject.getBranch(); + + if (branchName != null && branchName.equals(projectBranch)) { + String uniqueKey = branchName + "_" + projectBranch + "_" + projectVulnerability.getId(); // Tworzenie unikalnego klucza + uniqueVulnsMap.put(uniqueKey, projectVulnerability); + } + } else if ( codeProjectBranch == null && codeProject != null ){ + String uniqueKey = UUID.randomUUID().toString(); + uniqueVulnsMap.put(uniqueKey, projectVulnerability); + } + } + + List uniqueVulns = new ArrayList<>(uniqueVulnsMap.values()); + + + for (ProjectVulnerability projectVulnerability : uniqueVulns) { // for (Asset a : projectVulnerability.getSoftwarePacket().getAssets()) { // String hostname; // AtomicReference ipAddress = null; @@ -130,8 +162,13 @@ private Vulnerabilities setPackageVulns(Vulnerabilities vulns, Project project) // Vuln v = new Vuln(projectVulnerability, hostname, ipAddress.get(), a, Constants.API_SCANNER_PACKAGE); // tmpVulns.add(v); // } - Vuln v = new Vuln(projectVulnerability, null, null,projectVulnerability.getCodeProject(), Constants.API_SCANNER_PACKAGE); - tmpVulns.add(v); + try { + Vuln v = new Vuln(projectVulnerability, null, null, projectVulnerability.getCodeProject(), Constants.API_SCANNER_PACKAGE); + tmpVulns.add(v); + } catch (NullPointerException e ){ + e.printStackTrace(); + log.error("[Export for SCA Vulns] Error during exporting vuln for {}", projectVulnerability.getProject().getName()); + } } vulns.setVulnerabilities(tmpVulns); return vulns; @@ -165,20 +202,56 @@ private Vulnerabilities setAuditResults(Vulnerabilities vulns,Project project) { private Vulnerabilities setCodeVulns(Vulnerabilities vulns, Project project) throws UnknownHostException { List tmpVulns = vulns.getVulnerabilities(); - List codeVulns = null; + List codeVulns = new ArrayList<>(); if (project != null) { - try (Stream vulnsForProject = vulnTemplate.projectVulnerabilityRepository - .findByProjectAndVulnerabilitySourceAndAnalysisNot(project, vulnTemplate.SOURCE_SOURCECODE, Constants.FORTIFY_NOT_AN_ISSUE)) { - codeVulns = vulnsForProject.collect(Collectors.toList()); - } + List sastSources = Arrays.asList(vulnTemplate.SOURCE_SOURCECODE, vulnTemplate.SOURCE_GITLEAKS, vulnTemplate.SOURCE_IAC); + List projects = Collections.singletonList(project); + List codeProjectsWithVulnManageEnabled = findCodeProjectService.getCodeProjectsInListOfProjects(projects); + List projectVulnerabilities = + vulnTemplate.projectVulnerabilityRepository.findVulnerabilitiesForCode(codeProjectsWithVulnManageEnabled, sastSources) + .stream() + .filter(projectVulnerability -> !projectVulnerability.getStatus().equals(vulnTemplate.STATUS_REMOVED)) + .collect(Collectors.toList()); + codeVulns.addAll(projectVulnerabilities); } else { - try (Stream vulnsForProject = vulnTemplate.projectVulnerabilityRepository - .findByProjectInAndVulnerabilitySourceAndAnalysisNot(projectRepository.findByEnableVulnManage(true),vulnTemplate.SOURCE_SOURCECODE, Constants.FORTIFY_NOT_AN_ISSUE)){ - codeVulns = vulnsForProject.collect(Collectors.toList()); + List enabledVulnManageProjects = projectRepository.findByEnableVulnManage(true); + List codeProjectsWithVulnManageEnabled = findCodeProjectService.getCodeProjectsInListOfProjects(enabledVulnManageProjects); + List sastSources = Arrays.asList(vulnTemplate.SOURCE_SOURCECODE, vulnTemplate.SOURCE_GITLEAKS, vulnTemplate.SOURCE_IAC); + List projectVulnerabilities = vulnTemplate.projectVulnerabilityRepository.findVulnerabilitiesForCode(codeProjectsWithVulnManageEnabled, sastSources) + .stream() + .filter(projectVulnerability -> !projectVulnerability.getStatus().equals(vulnTemplate.STATUS_REMOVED)) + .collect(Collectors.toList());; + codeVulns.addAll(projectVulnerabilities); + } + + codeVulns.removeIf(projectVulnerability -> projectVulnerability.getGrade() == 0); + + // Return only vulnerabilities in default branch + Map uniqueVulnsMap = new HashMap<>(); + + for (ProjectVulnerability projectVulnerability : codeVulns) { + CodeProjectBranch codeProjectBranch = projectVulnerability.getCodeProjectBranch(); + CodeProject codeProject = projectVulnerability.getCodeProject(); + + if (codeProjectBranch != null && codeProject != null) { + String branchName = codeProjectBranch.getName(); + String projectBranch = codeProject.getBranch(); + + if (branchName != null && branchName.equals(projectBranch)) { + String uniqueKey = branchName + "_" + projectBranch + "_" + projectVulnerability.getId(); // Tworzenie unikalnego klucza + uniqueVulnsMap.put(uniqueKey, projectVulnerability); + } + } else if ( codeProjectBranch == null && codeProject != null ){ + String uniqueKey = UUID.randomUUID().toString(); + uniqueVulnsMap.put(uniqueKey, projectVulnerability); } } - for (ProjectVulnerability cv : codeVulns) { + + List uniqueVulns = new ArrayList<>(uniqueVulnsMap.values()); + + + for (ProjectVulnerability cv : uniqueVulns) { Vuln v = new Vuln(cv, null, null,new CodeProject(), Constants.API_SCANNER_PACKAGE); tmpVulns.add(v); } @@ -191,13 +264,13 @@ private Vulnerabilities setWebApplicationVulns(Vulnerabilities vulns,Project pro if (project != null) { //webAppVulns = new ArrayList<>(webAppVulnRepository.findByWebAppIn(project.getWebapps())); try (Stream vulnsForProject = vulnTemplate.projectVulnerabilityRepository - .findByProjectAndVulnerabilitySource(project, vulnTemplate.SOURCE_WEBAPP)) { + .findByProjectAndVulnerabilitySource(project, vulnTemplate.SOURCE_WEBAPP).filter(projectVulnerability -> !projectVulnerability.getStatus().equals(vulnTemplate.STATUS_REMOVED))) { webAppVulns = vulnsForProject.collect(Collectors.toList()); } } else { try (Stream vulnsForProject = vulnTemplate.projectVulnerabilityRepository - .findByProjectInAndVulnerabilitySource(projectRepository.findByEnableVulnManage(true),vulnTemplate.SOURCE_WEBAPP)) { + .findByProjectInAndVulnerabilitySource(projectRepository.findByEnableVulnManage(true),vulnTemplate.SOURCE_WEBAPP).filter(projectVulnerability -> !projectVulnerability.getStatus().equals(vulnTemplate.STATUS_REMOVED))) { webAppVulns = vulnsForProject.collect(Collectors.toList()); } } @@ -213,12 +286,12 @@ private Vulnerabilities setInfrastructureVulns(Vulnerabilities vulns,Project pro List infraVulns = null; if (project != null) { try (Stream vulnsForProject = vulnTemplate.projectVulnerabilityRepository - .findByProjectAndVulnerabilitySource(project,vulnTemplate.SOURCE_NETWORK)) { + .findByProjectAndVulnerabilitySource(project,vulnTemplate.SOURCE_NETWORK).filter(projectVulnerability -> !projectVulnerability.getStatus().equals(vulnTemplate.STATUS_REMOVED))) { infraVulns = vulnsForProject.collect(Collectors.toList()); } } else { try (Stream vulnsForProject = vulnTemplate.projectVulnerabilityRepository - .findByProjectInAndVulnerabilitySource(projectRepository.findByEnableVulnManage(true),vulnTemplate.SOURCE_NETWORK)) { + .findByProjectInAndVulnerabilitySource(projectRepository.findByEnableVulnManage(true),vulnTemplate.SOURCE_NETWORK).filter(projectVulnerability -> !projectVulnerability.getStatus().equals(vulnTemplate.STATUS_REMOVED))) { infraVulns = vulnsForProject.collect(Collectors.toList()); } } diff --git a/src/main/java/io/mixeway/db/entity/CiOperations.java b/src/main/java/io/mixeway/db/entity/CiOperations.java index 65d6e5fd..ffa4999f 100644 --- a/src/main/java/io/mixeway/db/entity/CiOperations.java +++ b/src/main/java/io/mixeway/db/entity/CiOperations.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonIgnore; +import io.mixeway.api.cicd.model.LoadSCA; import io.mixeway.api.protocol.cioperations.InfoScanPerformed; import org.hibernate.annotations.CreationTimestamp; import org.hibernate.annotations.OnDelete; @@ -43,6 +44,12 @@ public CiOperations(CodeProject codeProject, InfoScanPerformed infoScanPerformed this.commitId = infoScanPerformed.getCommitId(); this.openSourceScan = true; } + public CiOperations(CodeProject codeProject, LoadSCA loadSCA) { + this.codeProject = codeProject; + this.project = codeProject.getProject(); + this.commitId = loadSCA.getCommitId(); + this.openSourceScan = true; + } public Date getEnded() { diff --git a/src/main/java/io/mixeway/db/entity/CodeProject.java b/src/main/java/io/mixeway/db/entity/CodeProject.java index 093aaace..3a8b54aa 100755 --- a/src/main/java/io/mixeway/db/entity/CodeProject.java +++ b/src/main/java/io/mixeway/db/entity/CodeProject.java @@ -34,6 +34,7 @@ public class CodeProject implements VulnSource { @JsonIgnore private Boolean skipAllScan; @JsonIgnore private String additionalPath; @JsonIgnore private boolean inQueue; + @JsonIgnore private Set branches; @JsonIgnore private Set softwarePackets; private String branch; @JsonIgnore @@ -51,10 +52,20 @@ public class CodeProject implements VulnSource { @JsonIgnore private String scope; @JsonIgnore private int remoteid; private String appClient; + private String activeBranch; @JsonIgnore private Project project; + @Column(name="activebranch") + public String getActiveBranch() { + return activeBranch; + } + + public void setActiveBranch(String activeBranch) { + this.activeBranch = activeBranch; + } + public String getRemotename() { return remotename; } @@ -148,6 +159,18 @@ public CodeProject(String projectName, String branch, String commitid) { this.skipAllScan = true; this.inQueue = false; + } + public CodeProject(Project project, String projectName, String branch, String commitid, String repoUrl, String repoUsername, String repoPassword) { + this.project = project; + this.name = projectName; + this.branch = branch; + this.commitid = commitid; + this.skipAllScan = true; + this.inQueue = false; + this.repoUrl = repoUrl; + this.repoUsername = repoUsername; + this.repoPassword = repoPassword; + } public CodeProject() { @@ -184,7 +207,7 @@ public String getBranch() { return branch; } - public void setBranch(String branch) { + protected void setBranch(String branch) { this.branch = branch; } @@ -304,6 +327,16 @@ public void setName(String name) { public Set getVulns() { return vulns; } + + @OneToMany(mappedBy = "codeProject", cascade = CascadeType.ALL, fetch = FetchType.LAZY) + public Set getBranches() { + return branches; + } + + public void setBranches(Set branches) { + this.branches = branches; + } + public void setVulns(Set vulns) { this.vulns = vulns; } diff --git a/src/main/java/io/mixeway/db/entity/CodeProjectBranch.java b/src/main/java/io/mixeway/db/entity/CodeProjectBranch.java new file mode 100644 index 00000000..89406de2 --- /dev/null +++ b/src/main/java/io/mixeway/db/entity/CodeProjectBranch.java @@ -0,0 +1,55 @@ +package io.mixeway.db.entity; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import org.springframework.boot.autoconfigure.domain.EntityScan; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import javax.persistence.*; + +import java.text.SimpleDateFormat; +import java.util.Date; + +import static org.apache.commons.lang3.Validate.notNull; + +@Entity +@EntityScan +@Table(name = "codeprojectbranch") +@EntityListeners(AuditingEntityListener.class) +public class CodeProjectBranch { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @ManyToOne(fetch = FetchType.EAGER, optional = false) + @JoinColumn(name = "codeproject_id", nullable = false) + @JsonIgnore + private CodeProject codeProject; + private String inserted; + private String name; + + protected CodeProjectBranch(){} + + public CodeProjectBranch(CodeProject project, String name){ + notNull(name); + notNull(project); + this.inserted = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()); + this.name = name; + this.codeProject = project; + } + + public Long getId() { + return id; + } + + public CodeProject getCodeProject() { + return codeProject; + } + + public String getInserted() { + return inserted; + } + + public String getName() { + return name; + } +} diff --git a/src/main/java/io/mixeway/db/entity/ProjectVulnerability.java b/src/main/java/io/mixeway/db/entity/ProjectVulnerability.java index 2204f73c..df2bc798 100644 --- a/src/main/java/io/mixeway/db/entity/ProjectVulnerability.java +++ b/src/main/java/io/mixeway/db/entity/ProjectVulnerability.java @@ -18,6 +18,9 @@ import javax.persistence.*; import java.net.URISyntaxException; import java.text.SimpleDateFormat; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; import java.util.Date; import java.util.List; import java.util.Optional; @@ -34,7 +37,6 @@ indexes = { @Index(columnList = "id",name="projectvulnerability_index") }) -@EntityListeners(AuditingEntityListener.class) public class ProjectVulnerability { private static final Logger log = LoggerFactory.getLogger(ProjectVulnerability.class); @@ -90,6 +92,13 @@ public class ProjectVulnerability { @OnDelete(action = OnDeleteAction.CASCADE) @Audited(targetAuditMode = NOT_AUDITED) private Status status; + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "codeprojectbranch_id") + @OnDelete(action = OnDeleteAction.CASCADE) + @Audited(targetAuditMode = NOT_AUDITED) + private CodeProjectBranch codeProjectBranch; + + private String created; @Audited private String analysis; @@ -117,7 +126,7 @@ public class ProjectVulnerability { */ public ProjectVulnerability(V source,CodeProject codeProject, Vulnerability vulnerability, String description, String recommendation, String severity, String port, String location, String analysis, - VulnerabilitySource vulnerabilitySource, CisRequirement cisRequirement) { + VulnerabilitySource vulnerabilitySource, CisRequirement cisRequirement, CodeProjectBranch codeProjectBranch) { this.location = location; if (source instanceof Interface){ this.anInterface = (Interface)source; @@ -143,7 +152,13 @@ public ProjectVulnerability(V source,CodeProject codeProj this.severity = (severity.toLowerCase()); this.port = port; this.analysis = analysis; + if (analysis != null && analysis.equals(Constants.FORTIFY_NOT_AN_ISSUE)){ + this.grade = 0; + } else if (analysis != null && analysis.equals(Constants.FORTIFY_ANALYSIS_EXPLOITABLE)){ + this.grade = 1; + } this.vulnerabilitySource = vulnerabilitySource; + this.codeProjectBranch = codeProjectBranch; } /** @@ -154,7 +169,7 @@ public ProjectVulnerability(V source,CodeProject codeProj * @param softwarePacketVuln */ public ProjectVulnerability(CodeProject codeProject, Vulnerability vuln, VulnerabilityModel vulnerabilityModel, - SoftwarePacket softwarePacketVuln, VulnerabilitySource vulnerabilitySource) { + SoftwarePacket softwarePacketVuln, VulnerabilitySource vulnerabilitySource, CodeProjectBranch codeProjectBranch) { this.location = softwarePacketVuln.getName(); this.codeProject = codeProject; this.project = codeProject.getProject(); @@ -164,6 +179,15 @@ public ProjectVulnerability(CodeProject codeProject, Vulnerability vuln, Vulnera this.severity = vulnerabilityModel.getSeverity().toLowerCase(); this.recommendation = vulnerabilityModel.getRecomendations(); this.description = vulnerabilityModel.getDescription(); + this.codeProjectBranch = codeProjectBranch; + } + + public CodeProjectBranch getCodeProjectBranch() { + return codeProjectBranch; + } + + public void setCodeProjectBranch(CodeProjectBranch codeProjectBranch) { + this.codeProjectBranch = codeProjectBranch; } public CisRequirement getCisRequirement() { @@ -330,6 +354,13 @@ public ProjectVulnerability(){ } + public String getCreated() { + return created; + } + + public void setCreated(String created) { + this.created = created; + } /** * Updates information for vulnerability of type OpenSource @@ -401,14 +432,17 @@ public boolean equals(Object o) { if (other.externalId > 0) { return other.externalId == this.externalId; - } else if (StringUtils.isNotEmpty(other.location)) { - return (other.location.equals(this.location) && other.vulnerability.getId().equals(this.vulnerability.getId())); - } else if (other.softwarePacket != null) { + } else if (StringUtils.isNotEmpty(other.location) && other.codeProjectBranch ==null) { + return (other.location.equals(this.location) && other.vulnerability.getId().equals(this.vulnerability.getId()) ); + } else if (StringUtils.isNotEmpty(other.location) && (other.codeProjectBranch !=null && this.codeProjectBranch!=null)) { + return (other.location.equals(this.location) && other.vulnerability.getId().equals(this.vulnerability.getId()) && other.codeProjectBranch.getId().equals(this.getCodeProjectBranch().getId())); + } else if (other.softwarePacket != null && (other.codeProjectBranch !=null && this.codeProjectBranch!=null)) { return (other.softwarePacket.getId().equals(this.softwarePacket.getId()) && other.getVulnerability().getId().equals(this.getVulnerability().getId()) && - this.vulnerabilitySource.getId().equals(other.vulnerabilitySource.getId())); - } else if (other.codeProject != null) { + this.vulnerabilitySource.getId().equals(other.vulnerabilitySource.getId()) && other.codeProjectBranch.getId().equals(this.getCodeProjectBranch().getId())); + } else if (other.codeProject != null && (other.codeProjectBranch !=null && this.codeProjectBranch!=null)) { return (other.codeProject.getId().equals(this.codeProject.getId()) && other.getVulnerability().getId().equals(this.getVulnerability().getId()) && - this.vulnerabilitySource.getId().equals(other.vulnerabilitySource.getId()) && other.location.equals(this.getLocation())); + this.vulnerabilitySource.getId().equals(other.vulnerabilitySource.getId()) && other.location.equals(this.getLocation()) + && other.codeProjectBranch.getId().equals(this.getCodeProjectBranch().getId())); } else if (this.vulnerability != null) { return (other.location.equals(this.location) && (other.vulnerability.getId().equals(this.vulnerability.getId())) && this.vulnerabilitySource.getId().equals(other.vulnerabilitySource.getId())); @@ -418,6 +452,7 @@ public boolean equals(Object o) { } } catch (NullPointerException e){ if (this.vulnerability != null) { + e.printStackTrace(); log.error("[Project Entity] Error during equal method in project enity: this.vulnerability.id={},this.vulnerabilitySource.id={},this.location={} and " + "o.vulnerability.id={},o.vulnerabilitySource.id={},o.location={}", this.vulnerability.getId(), this.vulnerabilitySource.getId(), this.location, other.getVulnerability().getId(), other.getVulnerabilitySource().getId(), other.getLocation()); @@ -439,9 +474,11 @@ public final int hashCode() { @PrePersist public void prePersist() { this.inserted = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()); + this.created= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()); this.severity = org.apache.commons.lang3.StringUtils.capitalize(this.severity); } + @PreUpdate public void preUpdate() { this.inserted = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()); @@ -460,4 +497,13 @@ public String getCustomSeverity(){ public void removeTicket() throws URISyntaxException { BugTrackingService.deleteTicket(this); } + + public long calculateDifferenceInDays() { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"); + + LocalDateTime createdDateTime = LocalDateTime.parse(this.created, formatter); + LocalDateTime insertedDateTime = LocalDateTime.parse(this.inserted, formatter); + + return ChronoUnit.DAYS.between(createdDateTime, insertedDateTime); + } } diff --git a/src/main/java/io/mixeway/db/entity/VulnHistory.java b/src/main/java/io/mixeway/db/entity/VulnHistory.java index dcd809f6..608ebd0a 100755 --- a/src/main/java/io/mixeway/db/entity/VulnHistory.java +++ b/src/main/java/io/mixeway/db/entity/VulnHistory.java @@ -36,6 +36,26 @@ public class VulnHistory { private String name; private String inserted; private Project project; + private Long resolvedVulnerabilities; + private Long avgTimeToFix; + private Long percentResolvedCriticals; + private Long codeCritVuln; + private Long codeHighVuln; + private Long codeMediumVuln; + private Long codeLowVuln; + private Long scaCritVuln; + private Long scaHighVuln; + private Long scaMediumVuln; + private Long scaLowVuln; + private Long webAppCritVuln; + private Long webAppHighVuln; + private Long webAppMediumVuln; + private Long webAppLowVuln; + private Long assetCritVuln; + private Long assetHighVuln; + private Long assetMediumVuln; + private Long assetLowVuln; + @Column(name = "softwarepacketvulnnumber") public Long getSoftwarePacketVulnNumber() { @@ -110,4 +130,174 @@ public void setProject(Project project) { this.project = project; } + @Column(name="resolvedvulnerabilities") + public Long getResolvedVulnerabilities() { + return resolvedVulnerabilities; + } + + public void setResolvedVulnerabilities(Long resolvedVulnerabilities) { + this.resolvedVulnerabilities = resolvedVulnerabilities; + } + + @Column(name="avgtimetofix") + public Long getAvgTimeToFix() { + return avgTimeToFix; + } + + public void setAvgTimeToFix(Long avgTimeToFix) { + this.avgTimeToFix = avgTimeToFix; + } + + @Column(name="percentresolvedcriticals") + public Long getPercentResolvedCriticals() { + return percentResolvedCriticals; + } + + public void setPercentResolvedCriticals(Long percentResolvedCriticals) { + this.percentResolvedCriticals = percentResolvedCriticals; + } + + @Column(name="codecritvuln") + public Long getCodeCritVuln() { + return codeCritVuln; + } + + public void setCodeCritVuln(Long codeCritVuln) { + this.codeCritVuln = codeCritVuln; + } + + @Column(name="codehighvuln") + public Long getCodeHighVuln() { + return codeHighVuln; + } + + public void setCodeHighVuln(Long codeHighVuln) { + this.codeHighVuln = codeHighVuln; + } + + @Column(name="codemediumvuln") + public Long getCodeMediumVuln() { + return codeMediumVuln; + } + + public void setCodeMediumVuln(Long codeMediumVuln) { + this.codeMediumVuln = codeMediumVuln; + } + + @Column(name="codelowvuln") + public Long getCodeLowVuln() { + return codeLowVuln; + } + + public void setCodeLowVuln(Long codeLowVuln) { + this.codeLowVuln = codeLowVuln; + } + + @Column(name="scacritvuln") + public Long getScaCritVuln() { + return scaCritVuln; + } + + public void setScaCritVuln(Long scaCritVuln) { + this.scaCritVuln = scaCritVuln; + } + + @Column(name="scahighvuln") + public Long getScaHighVuln() { + return scaHighVuln; + } + + public void setScaHighVuln(Long scaHighVuln) { + this.scaHighVuln = scaHighVuln; + } + + @Column(name="scamediumvuln") + public Long getScaMediumVuln() { + return scaMediumVuln; + } + + public void setScaMediumVuln(Long scaMediumVuln) { + this.scaMediumVuln = scaMediumVuln; + } + + @Column(name="scalowvuln") + public Long getScaLowVuln() { + return scaLowVuln; + } + + public void setScaLowVuln(Long scaLowVuln) { + this.scaLowVuln = scaLowVuln; + } + + @Column(name="webappcritvuln") + public Long getWebAppCritVuln() { + return webAppCritVuln; + } + + public void setWebAppCritVuln(Long webAppCritVuln) { + this.webAppCritVuln = webAppCritVuln; + } + + @Column(name="webapphighvuln") + public Long getWebAppHighVuln() { + return webAppHighVuln; + } + + public void setWebAppHighVuln(Long webAppHighVuln) { + this.webAppHighVuln = webAppHighVuln; + } + + @Column(name="webappmediumvuln") + public Long getWebAppMediumVuln() { + return webAppMediumVuln; + } + + public void setWebAppMediumVuln(Long webAppMediumVuln) { + this.webAppMediumVuln = webAppMediumVuln; + } + + @Column(name="webapplowvuln") + public Long getWebAppLowVuln() { + return webAppLowVuln; + } + + public void setWebAppLowVuln(Long webAppLowVuln) { + this.webAppLowVuln = webAppLowVuln; + } + + @Column(name="assetcritvuln") + public Long getAssetCritVuln() { + return assetCritVuln; + } + + public void setAssetCritVuln(Long assetCritVuln) { + this.assetCritVuln = assetCritVuln; + } + + @Column(name="assethighvuln") + public Long getAssetHighVuln() { + return assetHighVuln; + } + + public void setAssetHighVuln(Long assetHighVuln) { + this.assetHighVuln = assetHighVuln; + } + + @Column(name="assetmediumvuln") + public Long getAssetMediumVuln() { + return assetMediumVuln; + } + + public void setAssetMediumVuln(Long assetMediumVuln) { + this.assetMediumVuln = assetMediumVuln; + } + + @Column(name="assetlowvuln") + public Long getAssetLowVuln() { + return assetLowVuln; + } + + public void setAssetLowVuln(Long assetLowVuln) { + this.assetLowVuln = assetLowVuln; + } } diff --git a/src/main/java/io/mixeway/db/repository/CodeProjectBranchRepository.java b/src/main/java/io/mixeway/db/repository/CodeProjectBranchRepository.java new file mode 100644 index 00000000..c2a86020 --- /dev/null +++ b/src/main/java/io/mixeway/db/repository/CodeProjectBranchRepository.java @@ -0,0 +1,13 @@ +package io.mixeway.db.repository; + +import io.mixeway.db.entity.CodeProject; +import io.mixeway.db.entity.CodeProjectBranch; +import io.mixeway.db.entity.CodeScan; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; + +public interface CodeProjectBranchRepository extends JpaRepository { + List findCodeProjectBranchByCodeProject(CodeProject codeProject); + CodeProjectBranch findCodeProjectBranchByCodeProjectAndName(CodeProject project, String name); +} diff --git a/src/main/java/io/mixeway/db/repository/CodeProjectRepository.java b/src/main/java/io/mixeway/db/repository/CodeProjectRepository.java index d6c0b628..82922c6e 100755 --- a/src/main/java/io/mixeway/db/repository/CodeProjectRepository.java +++ b/src/main/java/io/mixeway/db/repository/CodeProjectRepository.java @@ -55,4 +55,10 @@ public interface CodeProjectRepository extends JpaRepository List findBydTrackUuidNotNullAndRepoUrlNotNull(); @Query("select cp from CodeProject cp where cp.remotename is null and cp.repoUrl is not null and cp.dTrackUuid is null") List getCodeProjectsForSynchro(); + + @Modifying + @Query("UPDATE CodeProject e SET e.branch = :branch WHERE e.id = :id") + void updateCodeProjectBranch(@Param("id") Long id, @Param("branch") String branch); + + List findByProjectIn(List enabledVulnManageProjects); } diff --git a/src/main/java/io/mixeway/db/repository/ProjectVulnerabilityRepository.java b/src/main/java/io/mixeway/db/repository/ProjectVulnerabilityRepository.java index e6b9f97a..9971a381 100644 --- a/src/main/java/io/mixeway/db/repository/ProjectVulnerabilityRepository.java +++ b/src/main/java/io/mixeway/db/repository/ProjectVulnerabilityRepository.java @@ -30,23 +30,26 @@ public interface ProjectVulnerabilityRepository extends JpaRepository findByProjectAndVulnerabilitySourceAndAnalysisNot(Project project, VulnerabilitySource source, String analyis); Stream findByProjectAndVulnerabilitySourceInAndAnalysisNot(Project project, List source, String analyis); @Query(value="select count(pv.*) as value, v.name as namee from projectvulnerability pv, vulnerability v, vulnerabilitysource source where v.id=pv.vulnerability_id " + - "and pv.severity in ('Critical','High') and analysis != 'Not an Issue' and source.id=pv.vulnerabilitysource_id and source.name='SourceCode' and pv.project_id in :projects and v.severity!='skip' group by v.id order by value desc limit 10", nativeQuery = true) + "and pv.severity in ('Critical','High') and pv.status_id!=3 and analysis != 'Not an Issue' and source.id=pv.vulnerabilitysource_id and source.name='SourceCode' and pv.project_id in :projects and v.severity!='skip' group by v.id order by value desc limit 10", nativeQuery = true) List top10CodeVulns(@Param("projects") List projects); @Query(value="select count(pv.*) as value, cp.name || '( '|| p.name||')' as namee from projectvulnerability pv, " + - "codeproject cp, project p, vulnerability v where v.id=pv.vulnerability_id and v.severity!='skip' and p.id=pv.project_id and cp.id=pv.codeproject_id and pv.project_id in :projects group by cp.id, p.name order by value desc limit 10", nativeQuery = true) + "codeproject cp, project p, vulnerability v where pv.status_id!=3 and v.id=pv.vulnerability_id and v.severity!='skip' and p.id=pv.project_id and cp.id=pv.codeproject_id and pv.project_id in :projects group by cp.id, p.name order by value desc limit 10", nativeQuery = true) List top10CodeProjects(@Param("projects") List projects); Long countByCodeProjectInAndSeverityAndAnalysis(List codeProject, String severity, String analysis); Long countByCodeProjectInAndSeverityAndAnalysisNot(List codeProject, String severity, String analysis); Stream findByVulnerabilitySourceAndAnalysisNot(VulnerabilitySource vulnerabilitySource, String analysisNot); Stream findByProjectInAndVulnerabilitySourceAndAnalysisNot(List project,VulnerabilitySource vulnerabilitySource, String analysisNot); + Stream findByProjectInAndVulnerabilitySourceAndAnalysisNotOrAnalysisIsNull(List project,VulnerabilitySource vulnerabilitySource, String analysisNot); Stream findByCodeProjectAndVulnerabilitySource(CodeProject cp, VulnerabilitySource vulnerabilitySource); + Stream findByCodeProjectAndVulnerabilitySourceAndCodeProjectBranch(CodeProject cp, VulnerabilitySource vulnerabilitySource, CodeProjectBranch codeProjectBranch); List findByVulnerabilitySourceAndCodeProject(VulnerabilitySource vulnerabilitySource, CodeProject cp); + List findByVulnerabilitySourceAndCodeProjectAndCodeProjectBranch(VulnerabilitySource vulnerabilitySource, CodeProject cp, CodeProjectBranch codeProjectBranch); Stream findByProjectAndVulnerabilitySourceAndAnalysis(Project project, VulnerabilitySource vs, String analysis); @Query(value = "select ((count(*) filter (where pv.severity='Critical') * :critWage) + (count(*) filter (where pv.severity='High') * :highWage)) from " + - "projectvulnerability pv, vulnerability v where v.id=pv.vulnerability_id and v.severity!='skip' and pv.project_id=:project_id and pv.vulnerabilitysource_id = (select id from vulnerabilitysource where name='SourceCode')", nativeQuery = true) + "projectvulnerability pv, vulnerability v where pv.status_id!=3 and v.id=pv.vulnerability_id and v.severity!='skip' and pv.project_id=:project_id and pv.vulnerabilitysource_id in (select id from vulnerabilitysource where name='SourceCode' or name='IaC' or name='GitLeaks')", nativeQuery = true) int countCodeRiskForProject(@Param("project_id")Long project_id,@Param("critWage") int critWage, @Param("highWage") int highWage); @Query(value = "select ((count(*) filter (where pv.severity='Critical') * :critWage) + (count(*) filter (where pv.severity='High') * :highWage)) from " + - "projectvulnerability pv, vulnerability v where v.id=pv.vulnerability_id and v.severity!='skip'and pv.codeproject_id =:codeProject_id and pv.analysis !=:analysis and pv.vulnerabilitysource_id = (select id from vulnerabilitysource where name='SourceCode')", nativeQuery = true) + "projectvulnerability pv, vulnerability v where pv.status_id!=3 and v.id=pv.vulnerability_id and v.severity!='skip'and pv.codeproject_id =:codeProject_id and pv.analysis !=:analysis and pv.vulnerabilitysource_id = (select id from vulnerabilitysource where name='SourceCode')", nativeQuery = true) int countRiskForCodeProject(@Param("codeProject_id")Long codeProject_id,@Param("critWage") int critWage, @Param("highWage") int highWage, @Param("analysis") String analysis); @Query(value="select count(*) from projectvulnerability where codeproject_id=?1 and severity=?2 and analysis=?3 and vulnerabilitysource_id = (select id from vulnerabilitysource where name='SourceCode'", nativeQuery = true) @@ -57,7 +60,7 @@ int countRiskForCodeProject(@Param("codeProject_id")Long codeProject_id,@Param(" List findByProjectAndVulnerabilitySourceAndSeverityNotIn(Project project, VulnerabilitySource vulnerabilitySource, List severities); - List findByProjectAndVulnerabilitySourceAndSeverityIn(Project project, VulnerabilitySource vulnerabilitySource, List severities); + List findByProjectAndVulnerabilitySourceAndSeverityInAndStatusNot(Project project, VulnerabilitySource vulnerabilitySource, List severities, Status status); List findByAnInterface(Interface anInterface); @@ -65,11 +68,11 @@ int countRiskForCodeProject(@Param("codeProject_id")Long codeProject_id,@Param(" @Query(value="select distinct v.port from ProjectVulnerability v where v.anInterface = :interface and v.vulnerabilitySource.name='Service Detection'") List getPortsFromInfraVulnForInterface(@Param("interface") Interface anInterface); @Query(value="select count(pv.*) as value, v.name as namee from projectvulnerability pv, vulnerability v, vulnerabilitysource vs where " + - "vs.id=pv.vulnerabilitysource_id and pv.vulnerability_id=v.id and vs.name='Network' and pv.severity in ('Critic','Critical','High') and pv.project_id in :projects group " + + "vs.id=pv.vulnerabilitysource_id and pv.status_id!=3 and pv.vulnerability_id=v.id and vs.name='Network' and pv.severity in ('Critic','Critical','High') and pv.project_id in :projects group " + "by v.name order by value desc limit 10", nativeQuery = true) List top10InfraVulns(@Param("projects") List projects); @Query(value="select count(*) as value, i.privateip||' ('||p.name||')' as namee from project p, projectvulnerability iv, interface i, asset a,vulnerabilitysource so where p.id=iv.project_Id and so.id=iv.vulnerabilitysource_id " + - "and so.name='Network' and iv.project_id in :projects and iv.interface_id=i.id and i.asset_id=a.id and iv.severity in ('Critical','High') group by namee order by value desc limit 10",nativeQuery = true) + "and so.name='Network' and iv.status_id!=3 and iv.project_id in :projects and iv.interface_id=i.id and i.asset_id=a.id and iv.severity in ('Critical','High') group by namee order by value desc limit 10",nativeQuery = true) List top10Interfaces(@Param("projects") List projects); Long countByAnInterfaceInAndSeverity(List interfaces, String severity); Stream findByanInterfaceInAndSeverityNotIn(List interfaces, List severities); @@ -77,11 +80,11 @@ int countRiskForCodeProject(@Param("codeProject_id")Long codeProject_id,@Param(" @Query(value = "SELECT i from ProjectVulnerability i where i.anInterface in :interfaces and i.port like '%www%'") List getVulnsByInterfacesAndWithWWW(@Param("interfaces") List interfaces); @Query(value = "select ((count(*) filter (where severity='Critical') * :critWage) + (count(*) filter (where severity='High') * :highWage) + (count(*) filter (where severity='Medium') * :mediumWage)) from " + - "projectvulnerability where interface_id in (select id from interface where asset_id in (select id from asset where project_id =:project_id)) and " + + "projectvulnerability where status_id != 3 and interface_id in (select id from interface where asset_id in (select id from asset where project_id =:project_id)) and " + "vulnerabilitysource_id = (select id from vulnerabilitysource where name='Network')", nativeQuery = true) int countNetworkRiskForProject(@Param("project_id")Long project_id,@Param("critWage") int critWage, @Param("highWage") int highWage,@Param("mediumWage") int mediumWage); @Query(value = "select ((count(*) filter (where severity='Critical') * :critWage) + (count(*) filter (where severity='High') * :highWage) + (count(*) filter (where severity='Medium') * :mediumWage)) from " + - "projectvulnerability where interface_id =:interface_id and vulnerabilitysource_id = (select id from vulnerabilitysource where name='Network')", nativeQuery = true) + "projectvulnerability where status_id!=3 and interface_id =:interface_id and vulnerabilitysource_id = (select id from vulnerabilitysource where name='Network')", nativeQuery = true) int countRiskForInterface(@Param("interface_id")Long interface_id,@Param("critWage") int critWage, @Param("highWage") int highWage,@Param("mediumWage") int mediumWage); // @@ -93,12 +96,12 @@ int countRiskForCodeProject(@Param("codeProject_id")Long codeProject_id,@Param(" Optional findBySoftwarePacketAndVulnerabilityAndCodeProject(SoftwarePacket softwarePacket, Vulnerability vulnerability, CodeProject codeProject); @Query(value = "select count(spv) as value, sp.name as namee from softwarepacket sp inner join projectvulnerability spv on " + "spv.softwarepacket_id=sp.id inner join vulnerabilitysource vs on vs.id=spv.vulnerabilitysource_id where vs.name='OpenSource' and " + - "spv.severity in ('Critic', 'Critical', 'High') and spv.project_id in :projects group by sp.name order by value desc limit 10", nativeQuery = true) + "spv.severity in ('Critic', 'Critical', 'High') and spv.status_id!=3 and spv.project_id in :projects group by sp.name order by value desc limit 10", nativeQuery = true) List top10OpenSource(@Param("projects") List projects); @Query(value="select count(spv) as value, cp.name||' ('||p.name||')' as namee from codeproject cp " + "inner join projectvulnerability spv on cp.id = spv.codeproject_id inner join project p on " + "p.id=spv.project_id inner join vulnerabilitysource vs on vs.id=spv.vulnerabilitysource_id where vs.name='OpenSource' and spv.severity in " + - "('Critic', 'Critical', 'High') and spv.project_id in :projects group by cp.name, p.name order by value desc limit 10", nativeQuery = true) + "('Critic', 'Critical', 'High') and spv.status_id!=3 and spv.project_id in :projects group by cp.name, p.name order by value desc limit 10", nativeQuery = true) List top10OpenSourceCodeProjects(@Param("projects") List projects); Optional findByVulnerabilityAndVulnerabilitySource(Vulnerability vulnerability, VulnerabilitySource vulnerabilitySource); @Query(value="select spv.* from projectvulnerability spv, codeproject_softwarepacket csp where spv.softwarepacket_id = csp.softwarepacket_id " + @@ -109,11 +112,11 @@ int countRiskForCodeProject(@Param("codeProject_id")Long codeProject_id,@Param(" // @Query(value = "select count(*) as value, w.url ||' ('||p.name||')' as namee from project p, projectvulnerability wv, webapp w, " + - "vulnerabilitysource vs where vs.id=wv.vulnerabilitysource_id and vs.name='WebApplication' and p.id=wv.project_id and w.id=wv.webapp_id " + + "vulnerabilitysource vs where wv.status_id != 3 and vs.id=wv.vulnerabilitysource_id and vs.name='WebApplication' and p.id=wv.project_id and w.id=wv.webapp_id " + "and wv.severity in ('High','Critical') and wv.project_id in :projects group by w.url,p.name order by value desc limit 10", nativeQuery = true) List top10WebApps(@Param("projects") List projects); @Query(value = "select count(pv.*) as value, v.name as namee from projectvulnerability pv, vulnerability v, vulnerabilitysource vs where " + - "vs.id=pv.vulnerabilitysource_id and pv.vulnerability_id=v.id and vs.name='WebApplication' and pv.severity in ('Critic','Critical','High') and pv.project_id in :projects" + + "vs.id=pv.vulnerabilitysource_id and pv.status_id!=3 and pv.vulnerability_id=v.id and vs.name='WebApplication' and pv.severity in ('Critic','Critical','High') and pv.project_id in :projects" + " group by v.name order by value desc limit 10", nativeQuery = true) List top10WebAppVulns(@Param("projects") List projects); Long countByWebAppInAndSeverity(List webApps, String severity); @@ -123,10 +126,10 @@ int countRiskForCodeProject(@Param("codeProject_id")Long codeProject_id,@Param(" void deleteByWebApp(WebApp webApp); Stream findByWebAppInAndVulnerabilitySourceAndSeverityIn(List webApps, VulnerabilitySource vulnerabilitySource, List severities); @Query(value = "select ((count(*) filter (where severity='Critical') * :critWage) + (count(*) filter (where severity='High') * :highWage) + (count(*) filter (where severity='Medium') * :mediumWage)) from " + - "projectvulnerability where webapp_id in (select id from webapp where project_id=:project_id) and vulnerabilitysource_id = (select id from vulnerabilitysource where name='WebApplication')", nativeQuery = true) + "projectvulnerability where status_id!=3 and webapp_id in (select id from webapp where project_id=:project_id) and vulnerabilitysource_id = (select id from vulnerabilitysource where name='WebApplication')", nativeQuery = true) int countWebAppRiskForProject(@Param("project_id")Long project_id,@Param("critWage") int critWage, @Param("highWage") int highWage,@Param("mediumWage") int mediumWage); @Query(value = "select ((count(*) filter (where severity='Critical') * :critWage) + (count(*) filter (where severity='High') * :highWage) + (count(*) filter (where severity='Medium') * :mediumWage)) from " + - "projectvulnerability where webapp_id =:webapp_id and vulnerabilitysource_id = (select id from vulnerabilitysource where name='WebApplication')", nativeQuery = true) + "projectvulnerability where status_id!=3 and webapp_id =:webapp_id and vulnerabilitysource_id = (select id from vulnerabilitysource where name='WebApplication')", nativeQuery = true) int countRiskForWebApp(@Param("webapp_id")Long webapp_id,@Param("critWage") int critWage, @Param("highWage") int highWage,@Param("mediumWage") int mediumWage); // @@ -151,6 +154,11 @@ int countRiskForCodeProject(@Param("codeProject_id")Long codeProject_id,@Param(" @Query(value = "update projectvulnerability set status_id = :status where id in :vulns", nativeQuery = true) void updateVulnState(@Param("vulns") List tmpVulns,@Param("status") Long status); + @Modifying + @QueryHints({@QueryHint(name = "javax.persistence.lock.timeout", value ="5000")}) + @Query(value = "update projectvulnerability set status_id = :status where id in :vulns and codeprojectbranch_id = :branch", nativeQuery = true) + void updateVulnStateForBranch(@Param("vulns") List tmpVulns,@Param("status") Long status, @Param("branch") Long branch); + @QueryHints({@QueryHint(name = "javax.persistence.lock.timeout", value ="5000")}) void deleteByStatus(Status status); @QueryHints({@QueryHint(name = "javax.persistence.lock.timeout", value ="5000")}) @@ -160,6 +168,9 @@ int countRiskForCodeProject(@Param("codeProject_id")Long codeProject_id,@Param(" @QueryHints({@QueryHint(name = "javax.persistence.lock.timeout", value ="5000")}) int deleteByStatusAndCodeProjectAndVulnerabilitySource(Status status, CodeProject codeProject, VulnerabilitySource vulnerabilitySource); + @QueryHints({@QueryHint(name = "javax.persistence.lock.timeout", value ="5000")}) + int deleteByStatusAndCodeProjectAndVulnerabilitySourceAndCodeProjectBranch(Status status, CodeProject codeProject, VulnerabilitySource vulnerabilitySource, CodeProjectBranch codeProjectBranch); + @Modifying @Query(value = "delete from ProjectVulnerability pv where pv.id in :ids") int deleteProjectVulnerabilityIn(@Param("ids") List ids); @@ -180,13 +191,27 @@ int countRiskForCodeProject(@Param("codeProject_id")Long codeProject_id,@Param(" void transferCodeProjectVulnerabilities(long newProjectId, long oldProjectId, long codeProjectId); Long countBySeverityIn(List severities); - @Query(value="select p.id, count(pv.id) from project p, projectvulnerability pv, vulnerability v where v.id=pv.vulnerability_id and (v. severity is null or v.severity!='skip') and pv.project_id = p.id and pv.severity in ('Critical', 'High', 'Medium') group by p.id order by count desc limit 10", nativeQuery = true) + @Query(value="select p.id, count(pv.id) from project p, projectvulnerability pv, vulnerability v where v.id=pv.vulnerability_id and (v. severity is null or v.severity!='skip') and pv.project_id = p.id and pv.severity in ('Critical', 'High', 'Medium') and pv.status_id!=3 group by p.id order by count desc limit 10", nativeQuery = true) List top10VulnerableProjects(); - @Query(value="select v.id, count(pv.id) from vulnerability v, projectvulnerability pv where (v. severity is null or v.severity!='skip') and pv.vulnerability_id = v.id and pv.severity in ('Critical', 'High', 'Medium') group by v.id order by count desc limit 10", nativeQuery = true) + @Query(value="select v.id, count(pv.id) from vulnerability v, projectvulnerability pv where (v. severity is null or v.severity!='skip') and pv.vulnerability_id = v.id and pv.severity in ('Critical', 'High', 'Medium') and pv.status_id!=3 group by v.id order by count desc limit 10", nativeQuery = true) List top10Vulnerabilities(); List findByCodeProjectAndStatus(CodeProject codeProject, Status status); List findByWebAppAndStatus(WebApp webApp, Status status); List findByProjectAndVulnerability(Project project, Vulnerability vulnerability); long countByProjectAndSeverity(Project project, String severity); + @Query("SELECT count(*) FROM ProjectVulnerability pv WHERE pv.project = :project AND pv.severity = :severity AND pv.grade!=0 AND pv.status.id != 3") + long countVulnsbyProject(@Param("project") Project project, @Param("severity") String severity); + + + Optional findBySoftwarePacketAndVulnerabilityAndCodeProjectAndCodeProjectBranch(SoftwarePacket sPacket, Vulnerability vuln, CodeProject codeProject, CodeProjectBranch codeProjectBranch); + + @Query("SELECT pv FROM ProjectVulnerability pv WHERE pv.codeProject IN :codeProjects AND pv.vulnerabilitySource IN :sources AND pv.grade!=0") + List findVulnerabilitiesForCode(@Param("codeProjects") List codeProjects, @Param("sources") List sources); + + List findByVulnerabilityAndLocationAndDescription(Vulnerability vulnerability, String location, String description); + + List findByCodeProjectAndCodeProjectBranch(CodeProject codeProject, CodeProjectBranch codeProjectBranch); + @Query("SELECT count(*) FROM ProjectVulnerability pv where pv.status.id!=3") + long countVulns(); } diff --git a/src/main/java/io/mixeway/domain/service/cioperations/CreateCiOperationsService.java b/src/main/java/io/mixeway/domain/service/cioperations/CreateCiOperationsService.java index 7b6f6980..a90b88aa 100644 --- a/src/main/java/io/mixeway/domain/service/cioperations/CreateCiOperationsService.java +++ b/src/main/java/io/mixeway/domain/service/cioperations/CreateCiOperationsService.java @@ -1,5 +1,6 @@ package io.mixeway.domain.service.cioperations; +import io.mixeway.api.cicd.model.LoadSCA; import io.mixeway.api.protocol.cioperations.InfoScanPerformed; import io.mixeway.db.entity.CiOperations; import io.mixeway.db.entity.CodeProject; @@ -33,6 +34,9 @@ public void create(SASTRequestVerify verifyRequest, Project project, String comm public CiOperations create(CodeProject codeProject, InfoScanPerformed infoScanPerformed) { return ciOperationsRepository.save(new CiOperations(codeProject, infoScanPerformed)); } + public CiOperations create(CodeProject codeProject, LoadSCA loadSca) { + return ciOperationsRepository.save(new CiOperations(codeProject, loadSca)); + } public CiOperations create(SecurityGatewayEntry securityGatewayEntry, CodeProject codeProject, Optional optionalCiOperations){ CiOperations ciOperations = optionalCiOperations.orElseGet(CiOperations::new); ciOperations.setResult(securityGatewayEntry.isPassed() ? "Ok" : "Not Ok"); diff --git a/src/main/java/io/mixeway/domain/service/projectvulnerability/DeleteProjectVulnerabilityService.java b/src/main/java/io/mixeway/domain/service/projectvulnerability/DeleteProjectVulnerabilityService.java index b19d499c..4f0347f1 100644 --- a/src/main/java/io/mixeway/domain/service/projectvulnerability/DeleteProjectVulnerabilityService.java +++ b/src/main/java/io/mixeway/domain/service/projectvulnerability/DeleteProjectVulnerabilityService.java @@ -22,8 +22,8 @@ public class DeleteProjectVulnerabilityService { private final ProjectVulnerabilityRepository projectVulnerabilityRepository; private final VulnTemplate vulnTemplate; - public void deleteProjectVulnerabilityWithStatus(Project project, Status status) { - List toRemove = vulnTemplate.projectVulnerabilityRepository.findByProjectAndVulnerabilitySource(project, vulnTemplate.SOURCE_SOURCECODE).filter(v -> v.getStatus().getId().equals(status.getId())).collect(Collectors.toList()); + public void deleteProjectVulnerabilityWithStatus(Project project, Status status, VulnerabilitySource vulnerabilitySource) { + List toRemove = vulnTemplate.projectVulnerabilityRepository.findByProjectAndVulnerabilitySource(project, vulnerabilitySource).filter(v -> v.getStatus().getId().equals(status.getId())).collect(Collectors.toList()); if (toRemove.size() > 0) { vulnTemplate.projectVulnerabilityRepository.deleteAll(toRemove); log.info("[ProjectVulnerability] Removed {} Project Vulnerabilities with status {} for project {}", toRemove.size(),status.getName(),project.getName()); diff --git a/src/main/java/io/mixeway/domain/service/projectvulnerability/GetProjectVulnerabilitiesService.java b/src/main/java/io/mixeway/domain/service/projectvulnerability/GetProjectVulnerabilitiesService.java index 5a55f432..b81bf191 100644 --- a/src/main/java/io/mixeway/domain/service/projectvulnerability/GetProjectVulnerabilitiesService.java +++ b/src/main/java/io/mixeway/domain/service/projectvulnerability/GetProjectVulnerabilitiesService.java @@ -31,7 +31,7 @@ public List getProjectVulnerabilitiesForSource(VulnSource } public List getProjectVulnerabilitiesForProjectAndSourceAndSeverity(Project project, VulnerabilitySource vulnerabilitySource,List severities){ - return vulnTemplate.projectVulnerabilityRepository.findByProjectAndVulnerabilitySourceAndSeverityIn(project,vulnerabilitySource, severities); + return vulnTemplate.projectVulnerabilityRepository.findByProjectAndVulnerabilitySourceAndSeverityInAndStatusNot(project,vulnerabilitySource, severities, vulnTemplate.STATUS_REMOVED); } public List getProjectVulnerablitiesForCodeProject(CodeProject codeProject, String filter) { @@ -93,5 +93,25 @@ public List getOldVulnsForCodeProjectAndSource(CodeProject return codeVulns; } + /** + * Getting old vulnerabilities for CodeProject, and set status to removed v3API + * + * @param codeProject CodeProject to delate vulns for + * @return List of deleted vulns to set proper status + */ +// @Transactional(propagation = Propagation.REQUIRES_NEW) + @Transactional + public List getOldVulnsForCodeProjectAndSourceForBranch(CodeProject codeProject, VulnerabilitySource vulnerabilitySource, CodeProjectBranch codeProjectBranch){ + List codeVulns = vulnTemplate.projectVulnerabilityRepository.findByCodeProjectAndVulnerabilitySourceAndCodeProjectBranch(codeProject, vulnerabilitySource, codeProjectBranch).collect(Collectors.toList()); + if (codeVulns.size() > 0) { + vulnTemplate.projectVulnerabilityRepository.updateVulnState(codeVulns.stream().map(ProjectVulnerability::getId).collect(Collectors.toList()), + vulnTemplate.STATUS_REMOVED.getId()); + codeVulns.forEach(pv -> pv.setStatus(vulnTemplate.STATUS_REMOVED)); + } + + return codeVulns; + } + + } diff --git a/src/main/java/io/mixeway/domain/service/scanmanager/code/CreateCodeProjectBranchService.java b/src/main/java/io/mixeway/domain/service/scanmanager/code/CreateCodeProjectBranchService.java new file mode 100644 index 00000000..ede3bd38 --- /dev/null +++ b/src/main/java/io/mixeway/domain/service/scanmanager/code/CreateCodeProjectBranchService.java @@ -0,0 +1,19 @@ +package io.mixeway.domain.service.scanmanager.code; + +import io.mixeway.db.entity.CodeProject; +import io.mixeway.db.entity.CodeProjectBranch; +import io.mixeway.db.repository.CodeProjectBranchRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.log4j.Log4j2; +import org.springframework.stereotype.Service; + +@Service +@Log4j2 +@RequiredArgsConstructor +public class CreateCodeProjectBranchService { + private final CodeProjectBranchRepository codeProjectBranchRepository; + + public CodeProjectBranch createCodeProjectBranch(CodeProject codeProject, String branch){ + return codeProjectBranchRepository.save(new CodeProjectBranch(codeProject,branch)); + } +} diff --git a/src/main/java/io/mixeway/domain/service/scanmanager/code/CreateOrGetCodeProjectService.java b/src/main/java/io/mixeway/domain/service/scanmanager/code/CreateOrGetCodeProjectService.java index 754b98b7..4e77c1d5 100644 --- a/src/main/java/io/mixeway/domain/service/scanmanager/code/CreateOrGetCodeProjectService.java +++ b/src/main/java/io/mixeway/domain/service/scanmanager/code/CreateOrGetCodeProjectService.java @@ -3,7 +3,9 @@ import io.mixeway.api.project.model.CodeProjectPutModel; import io.mixeway.config.Constants; import io.mixeway.db.entity.CodeProject; +import io.mixeway.db.entity.CodeProjectBranch; import io.mixeway.db.entity.Project; +import io.mixeway.db.repository.CodeProjectBranchRepository; import io.mixeway.db.repository.CodeProjectRepository; import io.mixeway.domain.service.project.GetOrCreateProjectService; import io.mixeway.scanmanager.model.CodeScanRequestModel; @@ -34,40 +36,39 @@ public class CreateOrGetCodeProjectService { private final CodeProjectRepository codeProjectRepository; private final VaultHelper vaultHelper; private final GetOrCreateProjectService getOrCreateProjectService; + private final GetOrCreateCodeProjectBranchService getOrCreateCodeProjectBranchService; public CodeProject getOrCreateCodeProject(Project project, String projectName, String codeDefaultBranch) { Optional codeProject = codeProjectRepository.findByProjectAndName(project, projectName); + codeProject.ifPresent(value -> getOrCreateCodeProjectBranchService.getOrCreateCodeProjectBranch(value, codeDefaultBranch)); return codeProject.orElseGet(() -> createCodeProject(project, projectName, codeDefaultBranch)); } public CodeProject createCodeProject(Project project, String projectName, String codeDefaultBranch) { - CodeProject codeProject = new CodeProject(); - codeProject.setProject(project); - codeProject.setName(projectName); - codeProject.setBranch(codeDefaultBranch); - return codeProjectRepository.saveAndFlush(codeProject); + CodeProject codeProject = new CodeProject(project, projectName, (codeDefaultBranch == null || codeDefaultBranch.isEmpty()) ? "master" : codeDefaultBranch, null,null,null,null); + codeProject = codeProjectRepository.saveAndFlush(codeProject); + getOrCreateCodeProjectBranchService.getOrCreateCodeProjectBranch(codeProject, codeProject.getBranch()); + return codeProject; } public CodeProject createCodeProject(CodeScanRequestModel codeScanRequest, Project project) { - CodeProject codeProject = new CodeProject(); - codeProject.setBranch(codeScanRequest.getBranch()); - codeProject.setRepoUrl(codeScanRequest.getRepoUrl()); - codeProject.setName(codeScanRequest.getCodeProjectName()); - codeProject.setProject(project); - codeProject.setRepoUsername(codeScanRequest.getRepoUsername()); - codeProject.setRepoPassword(codeScanRequest.getRepoPassword()); + String branch = codeScanRequest.getBranch(); + CodeProject codeProject = new CodeProject(project, codeScanRequest.getCodeProjectName(), (branch == null || branch.isEmpty()) ? "master" : branch, null,codeScanRequest.getRepoUrl(), codeScanRequest.getRepoUsername(), codeScanRequest.getRepoPassword()); + codeProject.setTechnique(codeScanRequest.getTech()); - return codeProjectRepository.saveAndFlush(codeProject); + + codeProject = codeProjectRepository.saveAndFlush(codeProject); + getOrCreateCodeProjectBranchService.getOrCreateCodeProjectBranch(codeProject, codeProject.getBranch()); + return codeProject; } public CodeProject createCodeProject(String repoUrl, String repoName, String branch, Principal principal, Project project) { - CodeProject codeProject = new CodeProject(); - codeProject.setRepoUrl(repoUrl); - codeProject.setName(repoName); - codeProject.setBranch(branch); - codeProject.setProject(project); - return codeProjectRepository.saveAndFlush(codeProject); + CodeProject codeProject = new CodeProject(project, repoName, (branch == null || branch.isEmpty()) ? "master" : branch, null,repoUrl,null,null); + + codeProject = codeProjectRepository.saveAndFlush(codeProject); + getOrCreateCodeProjectBranchService.getOrCreateCodeProjectBranch(codeProject, codeProject.getBranch()); + return codeProject; } public CodeProject createOrGetCodeProject(String repoUrl, String branch, String codeProjectName, Principal principal) throws MalformedURLException { @@ -79,28 +80,44 @@ public CodeProject createOrGetCodeProject(String repoUrl, String branch, String Optional codeProject = codeProjectRepository.findByRepoUrlOrRepoUrlAndName(repoUrl, repoUrl+".git", codeProjectName); if (codeProject.isPresent()){ + getOrCreateCodeProjectBranchService.getOrCreateCodeProjectBranch(codeProject.get(), branch); return codeProject.get(); } else { Project project = getOrCreateProjectService.getProjectByName(name, principal); - CodeProject codeProject1 = createCodeProject(project, name, "master"); - codeProject1.setBranch(branch); - codeProject1.setRepoUrl(repoUrl); - return codeProjectRepository.saveAndFlush(codeProject1); + CodeProject codeProject1 = new CodeProject(project, + name, + (branch == null || branch.isEmpty()) ? "master" : branch, + null, + repoUrl, + null, + null); + + codeProject1 = codeProjectRepository.saveAndFlush(codeProject1); + getOrCreateCodeProjectBranchService.getOrCreateCodeProjectBranch(codeProject1, codeProject1.getBranch()); + + return codeProject1; } } public CodeProject createOrGetCodeProject(String repoUrl, String branch, Principal principal, Project project) throws MalformedURLException { Optional codeProject = codeProjectRepository.findByProjectAndRepoUrl(project, repoUrl); if (codeProject.isPresent()){ + getOrCreateCodeProjectBranchService.getOrCreateCodeProjectBranch(codeProject.get(), branch); return codeProject.get(); } else { URL repo = new URL(repoUrl.split("\\.git")[0]); String projectName, codeProjectName = null; String[] repoUrlParts = repo.getPath().split("/"); String name = repoUrlParts[repoUrlParts.length-1]; - CodeProject codeProject1 = createCodeProject(project, name, "master"); - codeProject1.setBranch(branch); - codeProject1.setRepoUrl(repoUrl); - return codeProjectRepository.saveAndFlush(codeProject1); + CodeProject codeProject1 = new CodeProject(project, + name, + (branch == null || branch.isEmpty()) ? "master" : branch, + null, + repoUrl, + null, + null); + codeProject1 = codeProjectRepository.saveAndFlush(codeProject1); + getOrCreateCodeProjectBranchService.getOrCreateCodeProjectBranch(codeProject1, codeProject1.getBranch()); + return codeProject1; } } @@ -116,13 +133,18 @@ public void createCodeProject(Project project, CodeGroupPutModel codeGroupPutMod codeProject.setVersionIdsingle(codeGroupPutModel.getVersionIdSingle()); codeProject.setProject(project); codeProject.setAppClient(codeGroupPutModel.getAppClient()); + String branch = codeGroupPutModel.getBranch(); + //codeProject.setBranch((branch == null || branch.isEmpty()) ? "master" : branch); + String uuidToken = UUID.randomUUID().toString(); if (StringUtils.isNotBlank(codeGroupPutModel.getGitpassword()) && vaultHelper.savePassword(codeGroupPutModel.getGitpassword(), uuidToken)) { codeProject.setRepoPassword(uuidToken); } else { codeProject.setRepoPassword(codeGroupPutModel.getGitpassword()); } - codeProjectRepository.saveAndFlush(codeProject); + codeProject= codeProjectRepository.saveAndFlush(codeProject); + getOrCreateCodeProjectBranchService.getOrCreateCodeProjectBranch(codeProject, codeProject.getBranch()); + } } @@ -148,16 +170,21 @@ private String setRepoUrl(CodeGroupPutModel codeGroupPutModel) { public void createCodeProject(Project project, CodeProjectPutModel codeProjectPutModel) { Optional codeProjectOptional = codeProjectRepository.findByProjectAndName(project, codeProjectPutModel.getCodeProjectName()); if (!codeProjectOptional.isPresent()){ - CodeProject codeProject = new CodeProject(); + CodeProject codeProject = new CodeProject( + codeProjectPutModel.getCodeProjectName(), + codeProjectPutModel.getBranch()!=null && !codeProjectPutModel.getBranch().equals("") ? codeProjectPutModel.getBranch() : Constants.CODE_DEFAULT_BRANCH, + null); codeProject.setProject(project); - codeProject.setName(codeProjectPutModel.getCodeProjectName()); codeProject.setSkipAllScan(false); codeProject.setdTrackUuid(codeProjectPutModel.getDTrackUuid()); - codeProject.setBranch(codeProjectPutModel.getBranch()!=null && !codeProjectPutModel.getBranch().equals("") ? codeProjectPutModel.getBranch() : Constants.CODE_DEFAULT_BRANCH); codeProject.setAdditionalPath(codeProjectPutModel.getAdditionalPath()); codeProject.setRepoUrl(codeProjectPutModel.getProjectGiturl()); codeProject.setTechnique(codeProjectPutModel.getProjectTech()); - codeProjectRepository.save(codeProject); + codeProject = codeProjectRepository.saveAndFlush(codeProject); + getOrCreateCodeProjectBranchService.getOrCreateCodeProjectBranch(codeProject, codeProject.getBranch()); + + } else { + getOrCreateCodeProjectBranchService.getOrCreateCodeProjectBranch(codeProjectOptional.get(), codeProjectOptional.get().getBranch()); } diff --git a/src/main/java/io/mixeway/domain/service/scanmanager/code/FindCodeProjectService.java b/src/main/java/io/mixeway/domain/service/scanmanager/code/FindCodeProjectService.java index a4ccfbc8..c46641b8 100644 --- a/src/main/java/io/mixeway/domain/service/scanmanager/code/FindCodeProjectService.java +++ b/src/main/java/io/mixeway/domain/service/scanmanager/code/FindCodeProjectService.java @@ -59,4 +59,8 @@ public List getCodeProjectsWithOSIntegrationEnabled() { public List findProjectWithoutOSIntegration(){ return codeProjectRepository.getCodeProjectsForSynchro(); } + + public List getCodeProjectsInListOfProjects(List enabledVulnManageProjects) { + return codeProjectRepository.findByProjectIn(enabledVulnManageProjects); + } } diff --git a/src/main/java/io/mixeway/domain/service/scanmanager/code/GetOrCreateCodeProjectBranchService.java b/src/main/java/io/mixeway/domain/service/scanmanager/code/GetOrCreateCodeProjectBranchService.java new file mode 100644 index 00000000..6822f60b --- /dev/null +++ b/src/main/java/io/mixeway/domain/service/scanmanager/code/GetOrCreateCodeProjectBranchService.java @@ -0,0 +1,26 @@ +package io.mixeway.domain.service.scanmanager.code; + +import io.mixeway.db.entity.CodeProject; +import io.mixeway.db.entity.CodeProjectBranch; +import io.mixeway.db.repository.CodeProjectBranchRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.log4j.Log4j2; +import org.springframework.stereotype.Service; + +@Service +@Log4j2 +@RequiredArgsConstructor +public class GetOrCreateCodeProjectBranchService { + private final CodeProjectBranchRepository codeProjectBranchRepository; + private final CreateCodeProjectBranchService createCodeProjectBranchService; + + public CodeProjectBranch getOrCreateCodeProjectBranch(CodeProject codeProject, String branch){ + CodeProjectBranch codeProjectBranch = codeProjectBranchRepository.findCodeProjectBranchByCodeProjectAndName(codeProject,branch); + if (codeProjectBranch == null){ + codeProjectBranch = createCodeProjectBranchService.createCodeProjectBranch(codeProject,branch); + } else { + return codeProjectBranch; + } + return codeProjectBranch; + } +} diff --git a/src/main/java/io/mixeway/domain/service/scanmanager/code/OperateOnCodeProject.java b/src/main/java/io/mixeway/domain/service/scanmanager/code/OperateOnCodeProject.java index f4f66c56..54770cf4 100644 --- a/src/main/java/io/mixeway/domain/service/scanmanager/code/OperateOnCodeProject.java +++ b/src/main/java/io/mixeway/domain/service/scanmanager/code/OperateOnCodeProject.java @@ -9,7 +9,9 @@ import io.mixeway.utils.VaultHelper; import lombok.RequiredArgsConstructor; import org.apache.commons.lang3.StringUtils; +import org.springframework.data.jpa.repository.Modifying; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.util.List; import java.util.UUID; @@ -56,9 +58,10 @@ public void setVersionId(CodeProject codeProject, EditCodeProjectModel editCodeP codeProjectRepository.save(codeProject); } + @Modifying + @Transactional public void setBranch(CodeProject codeProject, String branch) { - codeProject.setBranch(branch); - codeProjectRepository.save(codeProject); + codeProjectRepository.updateCodeProjectBranch(codeProject.getId(), branch); } public void setRepoUsername(CodeProject codeProject, EditCodeProjectModel editCodeProjectModel) { diff --git a/src/main/java/io/mixeway/domain/service/scanmanager/code/UpdateCodeProjectService.java b/src/main/java/io/mixeway/domain/service/scanmanager/code/UpdateCodeProjectService.java index 3ea22ae2..8c8e47b9 100644 --- a/src/main/java/io/mixeway/domain/service/scanmanager/code/UpdateCodeProjectService.java +++ b/src/main/java/io/mixeway/domain/service/scanmanager/code/UpdateCodeProjectService.java @@ -1,6 +1,7 @@ package io.mixeway.domain.service.scanmanager.code; import io.mixeway.db.entity.CodeProject; +import io.mixeway.db.entity.CodeProjectBranch; import io.mixeway.db.entity.Project; import io.mixeway.db.repository.CodeProjectRepository; import io.mixeway.scanmanager.model.CodeScanRequestModel; @@ -36,8 +37,8 @@ public class UpdateCodeProjectService { */ @Transactional public CodeProject updateCodeProject(CodeScanRequestModel codeScanRequest, CodeProject codeProject) { + codeProjectRepository.updateCodeProjectBranch(codeProject.getId(), codeScanRequest.getBranch()); codeProject.setTechnique(codeScanRequest.getTech()); - codeProject.setBranch(codeScanRequest.getBranch()); codeProject.setRepoUrl(codeScanRequest.getRepoUrl()); log.info("{} - Updated CodeProject [{}] {}", "ScanManager", codeProject.getProject().getName(), codeProject.getName()); return codeProjectRepository.saveAndFlush(codeProject); @@ -49,7 +50,6 @@ public CodeProject updateCodeProject(CodeScanRequestModel codeScanRequest, CodeP @Transactional public CodeProject updateCodeProjectAndPutToQueue(CodeScanRequestModel codeScanRequest, CodeProject codeProject) { codeProject.setTechnique(codeScanRequest.getTech()); - codeProject.setBranch(codeScanRequest.getBranch()); codeProject.setRepoUrl(codeScanRequest.getRepoUrl()); codeProject.setInQueue(true); codeProject.setRequestId(UUID.randomUUID().toString()); @@ -118,4 +118,11 @@ public void updateOpenSourceSettings(CodeProject codeProject, String remoteId, S codeProject.setRemotename(remoteName); codeProjectRepository.save(codeProject); } + + @Transactional + public void updateActiveBranch(CodeProject codeProject, CodeProjectBranch codeProjectBranch) { + codeProject.setActiveBranch(codeProjectBranch.getName()); + codeProjectRepository.save(codeProject); + log.info("[UpdateCodeProject] Updated project {} set branch to {}", codeProject.getName(), codeProjectBranch.getName()); + } } diff --git a/src/main/java/io/mixeway/domain/service/vulnhistory/CreateVulnHistoryService.java b/src/main/java/io/mixeway/domain/service/vulnhistory/CreateVulnHistoryService.java index d3c679fd..0f7d84b1 100644 --- a/src/main/java/io/mixeway/domain/service/vulnhistory/CreateVulnHistoryService.java +++ b/src/main/java/io/mixeway/domain/service/vulnhistory/CreateVulnHistoryService.java @@ -1,11 +1,10 @@ package io.mixeway.domain.service.vulnhistory; import io.mixeway.config.Constants; -import io.mixeway.db.entity.Project; -import io.mixeway.db.entity.VulnHistory; -import io.mixeway.db.entity.VulnerabilitySource; +import io.mixeway.db.entity.*; import io.mixeway.db.repository.NodeAuditRepository; import io.mixeway.db.repository.VulnHistoryRepository; +import io.mixeway.domain.service.scanmanager.code.FindCodeProjectService; import io.mixeway.domain.service.vulnmanager.VulnTemplate; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -13,10 +12,7 @@ import java.text.DateFormat; import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.Objects; +import java.util.*; import java.util.stream.Collectors; @@ -29,36 +25,83 @@ public class CreateVulnHistoryService { private final VulnHistoryRepository vulnHistoryRepository; private final VulnTemplate vulnTemplate; private final NodeAuditRepository nodeAuditRepository; + private final FindCodeProjectService findCodeProjectService; - private List severities = new ArrayList(){{ + private final List severities = new ArrayList(){{ add("Medium" ); add("High"); add("Critical"); }}; - private List scores = new ArrayList(){{ + private final List scores = new ArrayList(){{ add("WARN" ); add("FAIL"); }}; - private List critSeverities = new ArrayList(){{ + private final List critSeverities = new ArrayList(){{ add("High"); add("Critical"); }}; + private DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); public void createScheduled(Project project){ + final List codeSources = new ArrayList(){{ + add(vulnTemplate.SOURCE_SOURCECODE); + add(vulnTemplate.SOURCE_IAC); + add(vulnTemplate.SOURCE_GITLEAKS); + }}; + final List scaSources = new ArrayList(){{ + add(vulnTemplate.SOURCE_OPENSOURCE); + }}; + VulnHistory vulnHistory = new VulnHistory(); vulnHistory.setName(Constants.VULN_HISTORY_ALL); - vulnHistory.setInfrastructureVulnHistory(createInfraVulnHistory(project)); - vulnHistory.setWebAppVulnHistory(createWebAppVulnHistory(project)); - vulnHistory.setCodeVulnHistory(createCodeVulnHistory(project)); + createInfraVulnHistory(project, vulnHistory); + createWebAppVulnHistory(project, vulnHistory); + createCodeVulnHistory(project, codeSources, vulnHistory); + createSCAVulnHistory(project, scaSources, vulnHistory); + createAdditionalInfo(project, vulnHistory); + + + vulnHistory.setAuditVulnHistory(createAuditHistory(project)); - vulnHistory.setSoftwarePacketVulnNumber((long) createSoftwarePacketHistory(project)); + vulnHistory.setProject(project); vulnHistory.setInserted(format.format(new Date())); vulnHistoryRepository.save(vulnHistory); } + + private void createAdditionalInfo(Project project, VulnHistory vulnHistory) { + List projectVulnerabilities = vulnTemplate.projectVulnerabilityRepository.findByProject(project).collect(Collectors.toList()); + int detectedVulnerabilities = projectVulnerabilities.size(); + long detectedCriticalVulnerabilities = projectVulnerabilities.stream().filter(pv -> pv.getSeverity().equals(Constants.API_SEVERITY_CRITICAL)).count(); + long resolvedCriticalVulnerabilities = projectVulnerabilities.stream().filter(pv -> pv.getSeverity().equals(Constants.API_SEVERITY_CRITICAL) && Objects.equals(pv.getStatus().getId(), vulnTemplate.STATUS_REMOVED.getId()) && pv.getGrade()!=0).count(); + long acknowlegedVulnerabilities = projectVulnerabilities.stream().filter(pv -> pv.getSeverity().equals(Constants.API_SEVERITY_CRITICAL) && pv.getGrade() == 0).count(); + resolvedCriticalVulnerabilities += acknowlegedVulnerabilities; + List solvedVulnerabilities = projectVulnerabilities.stream().filter(pv -> pv.getStatus().getId().equals(vulnTemplate.STATUS_REMOVED.getId())).collect(Collectors.toList()); + int percentResolvedCritical = (int) Math.ceil(((double) resolvedCriticalVulnerabilities / detectedCriticalVulnerabilities) * 100); + int avgTimeToFix= (int) Math.ceil(calculateAverageDifferenceInDays(solvedVulnerabilities)); + vulnHistory.setAvgTimeToFix((long)avgTimeToFix); + vulnHistory.setPercentResolvedCriticals((long)percentResolvedCritical); + vulnHistory.setResolvedVulnerabilities(projectVulnerabilities.stream().filter(pv -> pv.getStatus().getId().equals(vulnTemplate.STATUS_REMOVED.getId())).count()); + + } + private static double calculateAverageDifferenceInDays(List list) { + if (list == null || list.isEmpty()) { + // Handle this case as per your requirements, could throw an exception or return 0 + return 0; + } + + long sumOfDifferences = 0; + for (ProjectVulnerability pv : list) { + sumOfDifferences += pv.calculateDifferenceInDays(); + } + + // Calculate the average + return sumOfDifferences / (double) list.size(); + } + public void create(Project project, String date, Long infra, Long webApp, Long code, Long audit, Long software){ VulnHistory vulnHistory = new VulnHistory(); vulnHistory.setName(Constants.VULN_HISTORY_ALL); @@ -71,10 +114,14 @@ public void create(Project project, String date, Long infra, Long webApp, Long c vulnHistory.setInserted(date); vulnHistoryRepository.save(vulnHistory); } - private Long createWebAppVulnHistory(Project p){ - return vulnTemplate.projectVulnerabilityRepository - .findByWebAppInAndVulnerabilitySourceAndSeverityIn(new ArrayList<>(p.getWebapps()),vulnTemplate.SOURCE_WEBAPP, severities).count(); - + private void createWebAppVulnHistory(Project p, VulnHistory vulnHistory){ + List webAppVulns = vulnTemplate.projectVulnerabilityRepository + .findByWebAppInAndVulnerabilitySource(new ArrayList<>(p.getWebapps()),vulnTemplate.SOURCE_WEBAPP).stream().filter(pv -> pv.getGrade()!=0 && !pv.getStatus().getId().equals(vulnTemplate.STATUS_REMOVED.getId())).collect(Collectors.toList()); + vulnHistory.setWebAppVulnHistory(webAppVulns.stream().filter(pv -> severities.contains(pv.getSeverity())).count()); + vulnHistory.setWebAppCritVuln(webAppVulns.stream().filter(pv -> pv.getSeverity().equals(Constants.VULN_CRITICALITY_CRITICAL)).count()); + vulnHistory.setWebAppHighVuln(webAppVulns.stream().filter(pv -> pv.getSeverity().equals(Constants.VULN_CRITICALITY_HIGH)).count()); + vulnHistory.setWebAppMediumVuln(webAppVulns.stream().filter(pv -> pv.getSeverity().equals(Constants.VULN_CRITICALITY_MEDIUM)).count()); + vulnHistory.setWebAppLowVuln(webAppVulns.stream().filter(pv -> pv.getSeverity().equals(Constants.VULN_CRITICALITY_LOW)).count()); } /** @@ -83,30 +130,93 @@ private Long createWebAppVulnHistory(Project p){ * IaC * GitLeaks * - * @param p - * @return */ - private Long createCodeVulnHistory(Project p){ - List codeSources = new ArrayList(){{ - add(vulnTemplate.SOURCE_SOURCECODE); - add(vulnTemplate.SOURCE_IAC); - add(vulnTemplate.SOURCE_GITLEAKS); - }}; - return vulnTemplate.projectVulnerabilityRepository.findByProjectAndVulnerabilitySourceInAndAnalysisNot(p,codeSources, Constants.FORTIFY_NOT_AN_ISSUE).count(); + private void createCodeVulnHistory(Project p, List list, VulnHistory vulnHistory){ + + List projects = Collections.singletonList(p); + List codeProjects = findCodeProjectService.getCodeProjectsInListOfProjects(projects); + List projectVulnerabilities = vulnTemplate.projectVulnerabilityRepository.findVulnerabilitiesForCode(codeProjects, list); + projectVulnerabilities.removeIf(projectVulnerability -> projectVulnerability.getGrade() == 0); + projectVulnerabilities.removeIf(projectVulnerability -> Objects.equals(projectVulnerability.getSeverity(), Constants.API_SEVERITY_LOW)); + projectVulnerabilities.removeIf(projectVulnerability -> Objects.equals(projectVulnerability.getSeverity(), Constants.API_SEVERITY_MEDIUM)); + projectVulnerabilities.removeIf(projectVulnerability -> Objects.equals(projectVulnerability.getSeverity(), Constants.API_SEVERITY_INFO)); + + // Return only vulnerabilities in default branch + Map uniqueVulnsMap = new HashMap<>(); + + for (ProjectVulnerability projectVulnerability : projectVulnerabilities) { + CodeProjectBranch codeProjectBranch = projectVulnerability.getCodeProjectBranch(); + CodeProject codeProject = projectVulnerability.getCodeProject(); + + if (codeProjectBranch != null && codeProject != null) { + String branchName = codeProjectBranch.getName(); + String projectBranch = codeProject.getBranch(); + + if (branchName != null && branchName.equals(projectBranch)) { + String uniqueKey = branchName + "_" + projectBranch + "_" + projectVulnerability.getId(); // Tworzenie unikalnego klucza + uniqueVulnsMap.put(uniqueKey, projectVulnerability); + } + } + } + + List uniqueVulns = new ArrayList<>(uniqueVulnsMap.values()); + + vulnHistory.setCodeVulnHistory((long)uniqueVulns.size()); + vulnHistory.setCodeCritVuln(uniqueVulns.stream().filter(pv -> pv.getSeverity().equals(Constants.VULN_CRITICALITY_CRITICAL)).count()); + vulnHistory.setCodeHighVuln(uniqueVulns.stream().filter(pv -> pv.getSeverity().equals(Constants.VULN_CRITICALITY_HIGH)).count()); + vulnHistory.setCodeMediumVuln(uniqueVulns.stream().filter(pv -> pv.getSeverity().equals(Constants.VULN_CRITICALITY_MEDIUM)).count()); + vulnHistory.setCodeLowVuln(uniqueVulns.stream().filter(pv -> pv.getSeverity().equals(Constants.VULN_CRITICALITY_LOW)).count()); } - private Long createInfraVulnHistory(Project p){ - return getInfraVulnsForProject(p); + + private void createSCAVulnHistory(Project p, List list, VulnHistory vulnHistory){ + + List projects = Collections.singletonList(p); + List codeProjects = findCodeProjectService.getCodeProjectsInListOfProjects(projects); + List projectVulnerabilities = vulnTemplate.projectVulnerabilityRepository.findVulnerabilitiesForCode(codeProjects, list); + projectVulnerabilities.removeIf(projectVulnerability -> projectVulnerability.getGrade() == 0); + projectVulnerabilities.removeIf(projectVulnerability -> Objects.equals(projectVulnerability.getSeverity(), Constants.API_SEVERITY_LOW)); + projectVulnerabilities.removeIf(projectVulnerability -> Objects.equals(projectVulnerability.getSeverity(), Constants.API_SEVERITY_MEDIUM)); + projectVulnerabilities.removeIf(projectVulnerability -> Objects.equals(projectVulnerability.getSeverity(), Constants.API_SEVERITY_INFO)); + + // Return only vulnerabilities in default branch + Map uniqueVulnsMap = new HashMap<>(); + + for (ProjectVulnerability projectVulnerability : projectVulnerabilities) { + CodeProjectBranch codeProjectBranch = projectVulnerability.getCodeProjectBranch(); + CodeProject codeProject = projectVulnerability.getCodeProject(); + + if (codeProjectBranch != null && codeProject != null) { + String branchName = codeProjectBranch.getName(); + String projectBranch = codeProject.getBranch(); + + if (branchName != null && branchName.equals(projectBranch)) { + String uniqueKey = branchName + "_" + projectBranch + "_" + projectVulnerability.getId(); // Tworzenie unikalnego klucza + uniqueVulnsMap.put(uniqueKey, projectVulnerability); + } + } + } + + List uniqueVulns = new ArrayList<>(uniqueVulnsMap.values()); + + vulnHistory.setSoftwarePacketVulnNumber((long)uniqueVulns.size()); + vulnHistory.setScaCritVuln(uniqueVulns.stream().filter(pv -> pv.getSeverity().equals(Constants.VULN_CRITICALITY_CRITICAL)).count()); + vulnHistory.setScaHighVuln(uniqueVulns.stream().filter(pv -> pv.getSeverity().equals(Constants.VULN_CRITICALITY_HIGH)).count()); + vulnHistory.setScaMediumVuln(uniqueVulns.stream().filter(pv -> pv.getSeverity().equals(Constants.VULN_CRITICALITY_MEDIUM)).count()); + vulnHistory.setScaLowVuln(uniqueVulns.stream().filter(pv -> pv.getSeverity().equals(Constants.VULN_CRITICALITY_LOW)).count()); + } + private VulnHistory createInfraVulnHistory(Project p, VulnHistory vulnHistory){ + List infraVulns =vulnTemplate.projectVulnerabilityRepository.findByProjectAndVulnerabilitySourceAndSeverityInAndStatusNot(p, vulnTemplate.SOURCE_NETWORK, severities, vulnTemplate.STATUS_REMOVED).stream().filter(pv -> pv.getGrade()!=0).collect(Collectors.toList()); + vulnHistory.setInfrastructureVulnHistory((long)infraVulns.size()); + vulnHistory.setAssetCritVuln(infraVulns.stream().filter(pv-> pv.getSeverity().equals(Constants.VULN_CRITICALITY_CRITICAL)).count()); + vulnHistory.setAssetHighVuln(infraVulns.stream().filter(pv-> pv.getSeverity().equals(Constants.VULN_CRITICALITY_HIGH)).count()); + vulnHistory.setAssetMediumVuln(infraVulns.stream().filter(pv-> pv.getSeverity().equals(Constants.VULN_CRITICALITY_MEDIUM)).count()); + vulnHistory.setAssetLowVuln(infraVulns.stream().filter(pv-> pv.getSeverity().equals(Constants.VULN_CRITICALITY_LOW)).count()); + return vulnHistory; } private Long createAuditHistory(Project p){ return (long)(nodeAuditRepository.findByNodeInAndScoreIn(p.getNodes(),scores).size()); } - private int createSoftwarePacketHistory(Project project) { - return (int) vulnTemplate.projectVulnerabilityRepository.findByProjectAndVulnerabilitySourceAndSeverityIn(project, vulnTemplate.SOURCE_OPENSOURCE, critSeverities) - .stream().filter(pv -> !Objects.equals(pv.getVulnerability().getSeverity(), Constants.SKIP_VULENRABILITY)).count(); - } - private long getInfraVulnsForProject(Project project){ - return vulnTemplate.projectVulnerabilityRepository.findByProjectAndVulnerabilitySourceAndSeverityIn(project, vulnTemplate.SOURCE_NETWORK, severities).size(); - } + } diff --git a/src/main/java/io/mixeway/domain/service/vulnhistory/OperateOnVulnHistoryService.java b/src/main/java/io/mixeway/domain/service/vulnhistory/OperateOnVulnHistoryService.java index 674bdabc..43c45c7b 100644 --- a/src/main/java/io/mixeway/domain/service/vulnhistory/OperateOnVulnHistoryService.java +++ b/src/main/java/io/mixeway/domain/service/vulnhistory/OperateOnVulnHistoryService.java @@ -73,4 +73,9 @@ public ProjectVulnTrendChart getVulnTrendChart(Project project, int limit){ projectVulnTrendChart.setSeries(series); return projectVulnTrendChart; } + + public List getLatestVulnHistoryForProject(Project project){ + return vulnHistoryRepository.getVulnHistoryLimit(project.getId(), 30); + } + } diff --git a/src/main/java/io/mixeway/domain/service/vulnmanager/VulnTemplate.java b/src/main/java/io/mixeway/domain/service/vulnmanager/VulnTemplate.java index 020db5aa..2bc7540b 100644 --- a/src/main/java/io/mixeway/domain/service/vulnmanager/VulnTemplate.java +++ b/src/main/java/io/mixeway/domain/service/vulnmanager/VulnTemplate.java @@ -110,7 +110,7 @@ public void vulnerabilityPersistListSoftware(List oldTmpVu List newVulns = new ArrayList<>(); for (ProjectVulnerability projectVulnerability : projectVulnerabilities .stream() - .filter(distinctByKeys(ProjectVulnerability::getCodeProject, ProjectVulnerability::getSoftwarePacket, ProjectVulnerability::getVulnerability, ProjectVulnerability::getSeverity)) + .filter(distinctByKeys(ProjectVulnerability::getCodeProject, ProjectVulnerability::getSoftwarePacket, ProjectVulnerability::getVulnerability, ProjectVulnerability::getSeverity, ProjectVulnerability::getCodeProjectBranch)) .collect(Collectors.toList())){ List oldVulnsToKeep = oldTmpVulns.stream() .filter(o -> o.equals(projectVulnerability)) diff --git a/src/main/java/io/mixeway/scanmanager/integrations/acunetix/apiclient/AcunetixApiClient.java b/src/main/java/io/mixeway/scanmanager/integrations/acunetix/apiclient/AcunetixApiClient.java index a772fedb..9e451327 100644 --- a/src/main/java/io/mixeway/scanmanager/integrations/acunetix/apiclient/AcunetixApiClient.java +++ b/src/main/java/io/mixeway/scanmanager/integrations/acunetix/apiclient/AcunetixApiClient.java @@ -265,7 +265,7 @@ public Boolean loadVulnerabilities(Scanner scanner, WebApp webApp, String pagina Vulnerability vulnerability = vulnTemplate.createOrGetVulnerabilityService.createOrGetVulnerabilityWithRecommendationAndReferences(vulnFromAcu.getVt_name(),vulnFromAcu.getRecommendation(),prepareRefs(vulnFromAcu.getReferences())); ProjectVulnerability vuln = new ProjectVulnerability(webApp,null,vulnerability,null, null, AcunetixSeverity.resolveSeverity(vulnFromAcu.getSeverity()),null,vulnFromAcu.getAffects_url(), - null,vulnTemplate.SOURCE_WEBAPP,null); + null,vulnTemplate.SOURCE_WEBAPP,null, null); if (webApp.getCodeProject() != null) { vuln.setCodeProject(webApp.getCodeProject()); } diff --git a/src/main/java/io/mixeway/scanmanager/integrations/checkmarx/apiclient/CheckmarxApiClient.java b/src/main/java/io/mixeway/scanmanager/integrations/checkmarx/apiclient/CheckmarxApiClient.java index bb6ed757..c0a5343b 100644 --- a/src/main/java/io/mixeway/scanmanager/integrations/checkmarx/apiclient/CheckmarxApiClient.java +++ b/src/main/java/io/mixeway/scanmanager/integrations/checkmarx/apiclient/CheckmarxApiClient.java @@ -17,6 +17,7 @@ import io.mixeway.utils.SecureRestTemplate; import io.mixeway.utils.VaultHelper; import org.apache.commons.lang3.StringUtils; +import org.apache.http.NoHttpResponseException; import org.codehaus.jettison.json.JSONException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -28,6 +29,7 @@ import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.ResourceAccessException; import org.springframework.web.client.RestTemplate; import java.io.ByteArrayInputStream; @@ -73,9 +75,9 @@ public class CheckmarxApiClient implements CodeScanClient, SecurityScanner { this.secureRestTemplate = secureRestTemplate; } @Override - public void loadVulnerabilities(Scanner scanner, String urlToGetNext, Boolean single, CodeProject codeProject, List codeVulns) throws ParseException, JSONException, CertificateException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException, KeyStoreException, IOException { + public void loadVulnerabilities(Scanner scanner, String urlToGetNext, Boolean single, CodeProject codeProject, List codeVulns, CodeProjectBranch codeProjectBranch) throws ParseException, JSONException, CertificateException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException, KeyStoreException, IOException { List cxResults = downloadResultsForScan(scanner,codeProject); - processVulnReportForCodeProject(cxResults,codeProject,codeVulns); + processVulnReportForCodeProject(cxResults,codeProject,codeVulns, codeProjectBranch); } @Override @@ -437,6 +439,8 @@ private boolean createScan(Scanner scanner, CodeProject codeProject) throws Cert } } catch (HttpClientErrorException e){ log.error("[Checkmarx] Error creating scan - {}", e.getStatusCode()); + } catch (ResourceAccessException e) { + log.error("[Checkmarx] Error creating the scan - checkmarx not avaliable"); } return false; } @@ -573,13 +577,13 @@ private List processCsvReport(String body, CodeProject code * @param results * @param codeProject */ - private void processVulnReportForCodeProject(List results, CodeProject codeProject, List oldVulns) { + private void processVulnReportForCodeProject(List results, CodeProject codeProject, List oldVulns, CodeProjectBranch codeProjectBranch) { List vulnsToPersist = new ArrayList<>(); for (CxResultCsvTemplate cxVuln: results) { Vulnerability vulnerability = vulnTemplate.createOrGetVulnerabilityService.createOrGetVulnerability(cxVuln.getQuery()); ProjectVulnerability projectVulnerability = new ProjectVulnerability(codeProject,codeProject,vulnerability,cxVuln.getDescription(),null, - cxVuln.getSeverity(),null,cxVuln.getDstLocation()+":"+cxVuln.getDstLine(),getTag(cxVuln.getAnalysis()), vulnTemplate.SOURCE_SOURCECODE, null ); + cxVuln.getSeverity(),null,cxVuln.getDstLocation()+":"+cxVuln.getDstLine(),getTag(cxVuln.getAnalysis()), vulnTemplate.SOURCE_SOURCECODE, null, codeProjectBranch ); vulnsToPersist.add(projectVulnerability); } diff --git a/src/main/java/io/mixeway/scanmanager/integrations/checkmarx/model/CxSetGitRepo.java b/src/main/java/io/mixeway/scanmanager/integrations/checkmarx/model/CxSetGitRepo.java index 43e6b5f8..efd79e6d 100644 --- a/src/main/java/io/mixeway/scanmanager/integrations/checkmarx/model/CxSetGitRepo.java +++ b/src/main/java/io/mixeway/scanmanager/integrations/checkmarx/model/CxSetGitRepo.java @@ -11,6 +11,8 @@ import lombok.NoArgsConstructor; import lombok.Setter; +import java.util.Objects; + @Setter @Getter @NoArgsConstructor @@ -25,7 +27,11 @@ public CxSetGitRepo(CodeProject codeProject, String pass){ } else { this.url = codeProject.getRepoUrl(); } - this.branch = "refs/heads/" + codeProject.getBranch(); + if (codeProject.getActiveBranch() != null && !Objects.equals(codeProject.getActiveBranch(), "")) { + this.branch = "refs/heads/" + codeProject.getActiveBranch(); + } else { + this.branch = "refs/heads/" + codeProject.getBranch(); + } } } diff --git a/src/main/java/io/mixeway/scanmanager/integrations/dependencytrack/apiclient/DependencyTrackApiClient.java b/src/main/java/io/mixeway/scanmanager/integrations/dependencytrack/apiclient/DependencyTrackApiClient.java index b7eccff7..e69388d9 100644 --- a/src/main/java/io/mixeway/scanmanager/integrations/dependencytrack/apiclient/DependencyTrackApiClient.java +++ b/src/main/java/io/mixeway/scanmanager/integrations/dependencytrack/apiclient/DependencyTrackApiClient.java @@ -4,6 +4,7 @@ import io.mixeway.db.entity.Scanner; import io.mixeway.db.entity.*; import io.mixeway.db.repository.*; +import io.mixeway.domain.service.scanmanager.code.GetOrCreateCodeProjectBranchService; import io.mixeway.domain.service.vulnmanager.VulnTemplate; import io.mixeway.scanmanager.integrations.dependencytrack.model.Component; import io.mixeway.scanmanager.integrations.dependencytrack.model.DTrackCreateProject; @@ -55,6 +56,7 @@ public class DependencyTrackApiClient implements SecurityScanner, OpenSourceScan private final CodeProjectRepository codeProjectRepository; private final CiOperationsRepository ciOperationsRepository; private final VulnTemplate vulnTemplate; + private final GetOrCreateCodeProjectBranchService getOrCreateCodeProjectBranchService; @Override @@ -69,8 +71,11 @@ public boolean canProcessRequest() { } @Override - public void loadVulnerabilities(CodeProject codeProject) throws CertificateException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException, KeyStoreException, IOException { + public void loadVulnerabilities(CodeProject codeProject, CodeProjectBranch codeProjectBranch) throws CertificateException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException, KeyStoreException, IOException { List dTrack = scannerRepository.findByScannerType(scannerTypeRepository.findByNameIgnoreCase(Constants.SCANNER_TYPE_DEPENDENCYTRACK)); + if (codeProjectBranch == null){ + codeProjectBranch = getOrCreateCodeProjectBranchService.getOrCreateCodeProjectBranch(codeProject, codeProject.getBranch()); + } //Multiple dTrack instances not yet supported if (dTrack.size() == 1 && codeProject.getdTrackUuid() != null){ RestTemplate restTemplate = secureRestTemplate.prepareClientWithCertificate(dTrack.get(0)); @@ -81,7 +86,7 @@ public void loadVulnerabilities(CodeProject codeProject) throws CertificateExcep "/api/v1/vulnerability/project/" + codeProject.getdTrackUuid(), HttpMethod.GET, entity, new ParameterizedTypeReference>() { }); if (response.getStatusCode() == HttpStatus.OK) { - createVulns(codeProject, Objects.requireNonNull(response.getBody())); + createVulns(codeProject, Objects.requireNonNull(response.getBody()), codeProjectBranch); updateCiOperations(codeProject); } else { log.error("Unable to get Findings from Dependency Track for project {}", codeProject.getdTrackUuid()); @@ -182,9 +187,9 @@ public void autoDiscovery() { } @Transactional(propagation = Propagation.REQUIRES_NEW) - public void createVulns(CodeProject codeProject, List body) throws URISyntaxException { + public void createVulns(CodeProject codeProject, List body, CodeProjectBranch codeProjectBranch) throws URISyntaxException { List oldVulns = vulnTemplate.projectVulnerabilityRepository - .findByVulnerabilitySourceAndCodeProject(vulnTemplate.SOURCE_OPENSOURCE, codeProject); + .findByVulnerabilitySourceAndCodeProjectAndCodeProjectBranch(vulnTemplate.SOURCE_OPENSOURCE, codeProject, codeProjectBranch); List vulnsToPersist = new ArrayList<>(); for(DTrackVuln dTrackVuln : body){ List softwarePackets = new ArrayList<>(); @@ -204,16 +209,17 @@ public void createVulns(CodeProject codeProject, List body) throws U Vulnerability vuln = vulnTemplate.createOrGetVulnerabilityService.createOrGetVulnerabilityWithDescAndReferences(dTrackVuln.getVulnId(), dTrackVuln.getDescription(), dTrackVuln.getReferences(), dTrackVuln.getRecommendation()); Optional softwarePacketVulnerability = vulnTemplate.projectVulnerabilityRepository - .findBySoftwarePacketAndVulnerabilityAndCodeProject(sPacket,vuln, codeProject); + .findBySoftwarePacketAndVulnerabilityAndCodeProjectAndCodeProjectBranch(sPacket,vuln, codeProject,codeProjectBranch); if (!softwarePacketVulnerability.isPresent()){ ProjectVulnerability projectVulnerability = new ProjectVulnerability(sPacket,codeProject,vuln,dTrackVuln.getDescription(),dTrackVuln.getRecommendation(), - dTrackVuln.getSeverity(), null, null, null,vulnTemplate.SOURCE_OPENSOURCE,null); + dTrackVuln.getSeverity(), null, null, null,vulnTemplate.SOURCE_OPENSOURCE,null, codeProjectBranch); projectVulnerability.setStatus(vulnTemplate.STATUS_NEW); vulnsToPersist.add(projectVulnerability); } else { softwarePacketVulnerability.get().setCodeProject(codeProject); softwarePacketVulnerability.get().setInserted(dateFormat.format(new Date())); softwarePacketVulnerability.get().setStatus(vulnTemplate.STATUS_EXISTING); + softwarePacketVulnerability.get().setCodeProjectBranch(codeProjectBranch); vulnsToPersist.add(softwarePacketVulnerability.get()) ; } @@ -221,6 +227,7 @@ public void createVulns(CodeProject codeProject, List body) throws U } //codeProjectRepository.saveAndFlush(codeProject); } + log.info("[Dependency-Track] Send {} vulns to persist for {}", vulnsToPersist.size(), codeProject.getName()); vulnTemplate.vulnerabilityPersistListSoftware(oldVulns,vulnsToPersist); if (codeProject.getEnableJira()) { vulnTemplate.processBugTracking(codeProject, vulnTemplate.SOURCE_OPENSOURCE); diff --git a/src/main/java/io/mixeway/scanmanager/integrations/nessus/apiclient/NessusApiClient.java b/src/main/java/io/mixeway/scanmanager/integrations/nessus/apiclient/NessusApiClient.java index 028f1435..8dacde76 100644 --- a/src/main/java/io/mixeway/scanmanager/integrations/nessus/apiclient/NessusApiClient.java +++ b/src/main/java/io/mixeway/scanmanager/integrations/nessus/apiclient/NessusApiClient.java @@ -535,7 +535,7 @@ else if (vuln.getInt(Constants.NESSUS_SEVERITY) == 3) Vulnerability vulnerability = vulnTemplate.createOrGetVulnerabilityService.createOrGetVulnerability(vuln.getString(Constants.NESSUS_PLUGIN_NAME)); ProjectVulnerability projectVulnerability = new ProjectVulnerability(i, null, vulnerability,bodyJ.getJSONObject(Constants.NESSUS_SCAN_INFO).getJSONObject(Constants.NESSUS_PLUGINDESCRIPTION) .getJSONObject(Constants.NESSUS_PLUGINATTRIBUTES).getString(Constants.NESSUS_VULN_DESCRIPTION), - null,threat, key,null,null, vulnTemplate.SOURCE_NETWORK,null); + null,threat, key,null,null, vulnTemplate.SOURCE_NETWORK,null,null); projectVulnerability.updateStatusAndGrade(oldVulns, vulnTemplate); projectVulnerabilities.add(projectVulnerability); diff --git a/src/main/java/io/mixeway/scanmanager/integrations/nexpose/apiclient/NexposeApiClient.java b/src/main/java/io/mixeway/scanmanager/integrations/nexpose/apiclient/NexposeApiClient.java index 9de56a94..9bdcaafd 100644 --- a/src/main/java/io/mixeway/scanmanager/integrations/nexpose/apiclient/NexposeApiClient.java +++ b/src/main/java/io/mixeway/scanmanager/integrations/nexpose/apiclient/NexposeApiClient.java @@ -144,7 +144,7 @@ private void loadVulnerabilitiesForAsset(InfraScan scan, Interface intf, int id, "Categories: "+ StringUtils.join(vulnDetails.getCategories(),", ")+"
" + "

Proof:
"+result.getProof()+ "
Description:
"+vulnDetails.getDescription().getHtml(),null, - setNexposeThreat(vulnDetails.getSeverity()),String.valueOf(result.getPort()),null,null, vulnTemplate.SOURCE_NETWORK,null); + setNexposeThreat(vulnDetails.getSeverity()),String.valueOf(result.getPort()),null,null, vulnTemplate.SOURCE_NETWORK,null,null); projectVulnerability.updateStatusAndGrade(oldVulns, vulnTemplate); vulnTemplate.projectVulnerabilityRepository.save(projectVulnerability); diff --git a/src/main/java/io/mixeway/scanmanager/integrations/nexusiq/apiclient/NexusIqApiClient.java b/src/main/java/io/mixeway/scanmanager/integrations/nexusiq/apiclient/NexusIqApiClient.java index be6066d3..a66f987b 100644 --- a/src/main/java/io/mixeway/scanmanager/integrations/nexusiq/apiclient/NexusIqApiClient.java +++ b/src/main/java/io/mixeway/scanmanager/integrations/nexusiq/apiclient/NexusIqApiClient.java @@ -150,14 +150,14 @@ public boolean canProcessRequest() { } @Override - public void loadVulnerabilities(CodeProject codeProject) throws CertificateException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException, KeyStoreException, IOException { + public void loadVulnerabilities(CodeProject codeProject, CodeProjectBranch codeProjectBranch) throws CertificateException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException, KeyStoreException, IOException { Scanner scanner = getScannerService.getScannerByType(findScannerTypeService.findByName(Constants.SCANNER_TYPE_NEXUS_IQ)); if (scanner!=null) { String getRawDataReportUrl = getRawDataUrl(scanner, codeProject); RawReport rawReport = getRawReport(scanner, getRawDataReportUrl); try { if (rawReport != null ) - saveVulnerabilities(codeProject, rawReport); + saveVulnerabilities(codeProject, rawReport, codeProjectBranch); } catch (URISyntaxException e) { throw new RuntimeException(e); } @@ -183,7 +183,7 @@ private void updateCiOperations(CodeProject codeProject) { } - private void saveVulnerabilities(CodeProject codeProject, RawReport rawReport) throws URISyntaxException { + private void saveVulnerabilities(CodeProject codeProject, RawReport rawReport, CodeProjectBranch codeProjectBranch) throws URISyntaxException { List oldVulns = vulnTemplate.projectVulnerabilityRepository .findByVulnerabilitySourceAndCodeProject(vulnTemplate.SOURCE_OPENSOURCE, codeProject); List projectVulnerabilitiesFromReport = new ArrayList<>(); @@ -219,7 +219,8 @@ private void saveVulnerabilities(CodeProject codeProject, RawReport rawReport) t null, null, vulnTemplate.SOURCE_OPENSOURCE, - null); + null, + codeProjectBranch); projectVulnerability.setStatus(vulnTemplate.STATUS_NEW); projectVulnerabilitiesFromReport.add(projectVulnerability); } @@ -296,7 +297,8 @@ private String getRawDataUrl(Scanner scanner, CodeProject codeProject) throws Un @Override public boolean createProject(CodeProject codeProject) throws CertificateException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException, KeyStoreException, IOException { - return false; + this.autoDiscoveryProject(codeProject); + return true; } @Override @@ -342,6 +344,21 @@ public void autoDiscovery() throws UnrecoverableKeyException, CertificateExcepti } log.info("[Nexus-IQ] Synchronization completed."); } + public void autoDiscoveryProject(CodeProject codeProject) throws UnrecoverableKeyException, CertificateException, NoSuchAlgorithmException, KeyStoreException, IOException, KeyManagementException { + Scanner scanner = getScannerService.getScannerByType(findScannerTypeService.findByName(Constants.SCANNER_TYPE_NEXUS_IQ)); + if (scanner != null) { + + List synchroList = loadNexusData(scanner); + log.info("[Nexus-IQ] Starting synchronization, found {} resources on remote nexus", synchroList.size()); + Synchro sync = synchroList.stream().filter(s -> s.getRepoUrl().replace(".git","").equals(codeProject.getRepoUrl().replace(".git",""))) + .findAny().orElse(null); + if (sync != null){ + updateCodeProjectService.updateOpenSourceSettings(codeProject,sync.getId(), sync.getName()); + log.info("[Nexus-IQ] Synchronized infos for {} with {} and {}", codeProject.getName(), sync.getId(), sync.getName()); + } + } + log.info("[Nexus-IQ] Synchronization completed."); + } private List loadNexusData(Scanner scanner) throws UnrecoverableKeyException, CertificateException, NoSuchAlgorithmException, KeyStoreException, IOException, KeyManagementException { List synchroList = new ArrayList<>(); diff --git a/src/main/java/io/mixeway/scanmanager/integrations/openvas/apiclient/OpenVasApiClient.java b/src/main/java/io/mixeway/scanmanager/integrations/openvas/apiclient/OpenVasApiClient.java index 673ae4b3..520a4c9d 100644 --- a/src/main/java/io/mixeway/scanmanager/integrations/openvas/apiclient/OpenVasApiClient.java +++ b/src/main/java/io/mixeway/scanmanager/integrations/openvas/apiclient/OpenVasApiClient.java @@ -183,7 +183,7 @@ public void loadVulnerabilities(InfraScan infraScan) throws JSONException, Certi if (response.getStatusCode() == HttpStatus.OK) { setVulnerabilities(infraScan, response.getBody()); //vulnTemplate.projectVulnerabilityRepository.deleteByStatusAndProject(vulnTemplate.STATUS_REMOVED, infraScan.getProject()); - deleteProjectVulnerabilityService.deleteProjectVulnerabilityWithStatus(infraScan.getProject(), vulnTemplate.STATUS_REMOVED); + deleteProjectVulnerabilityService.deleteProjectVulnerabilityWithStatus(infraScan.getProject(), vulnTemplate.STATUS_REMOVED, vulnTemplate.SOURCE_NETWORK); infraScan.setRunning(false); infraScan.setTaskId(null); infraScanRepository.save(infraScan); @@ -286,7 +286,7 @@ void setVulnerabilities(InfraScan ns, String body) throws JSONException { if (intfActive != null) { Vulnerability vulnerability = vulnTemplate.createOrGetVulnerabilityService.createOrGetVulnerability(v.getString(Constants.IF_VULN_NAME)); ProjectVulnerability projectVulnerability = new ProjectVulnerability(intfActive,null,vulnerability,v.getString(Constants.IF_VULN_DESC),null - ,v.getString(Constants.IF_VULN_THREAT),v.getString(Constants.IF_VULN_PORT),null,null,vulnTemplate.SOURCE_NETWORK, null); + ,v.getString(Constants.IF_VULN_THREAT),v.getString(Constants.IF_VULN_PORT),null,null,vulnTemplate.SOURCE_NETWORK, null,null); //projectVulnerability.updateStatusAndGrade(oldVulns, vulnTemplate); vulnsToPersist.add(projectVulnerability); scannerInterfaces.add(intfActive); diff --git a/src/main/java/io/mixeway/scanmanager/service/audit/OpenScapService.java b/src/main/java/io/mixeway/scanmanager/service/audit/OpenScapService.java index 8189ef2b..eea2c7dd 100644 --- a/src/main/java/io/mixeway/scanmanager/service/audit/OpenScapService.java +++ b/src/main/java/io/mixeway/scanmanager/service/audit/OpenScapService.java @@ -70,7 +70,7 @@ private List processVulnerabilitiesFromBenchmark(Benchmark .filter(entry -> entry.getKey().getId().equals(ruleRef)) .map(Map.Entry::getValue).findFirst().get(); ProjectVulnerability projectVulnerability = new ProjectVulnerability(anInterface,null,null,rule.getDescription(),null, - "High",null,null,null, vulnTemplate.SOURCE_CISBENCHMARK, cisRequirement ); + "High",null,null,null, vulnTemplate.SOURCE_CISBENCHMARK, cisRequirement,null ); projectVulnerabilities.add(projectVulnerability); diff --git a/src/main/java/io/mixeway/scanmanager/service/code/CodeScanClient.java b/src/main/java/io/mixeway/scanmanager/service/code/CodeScanClient.java index 328ca6a7..730f1faa 100644 --- a/src/main/java/io/mixeway/scanmanager/service/code/CodeScanClient.java +++ b/src/main/java/io/mixeway/scanmanager/service/code/CodeScanClient.java @@ -1,6 +1,7 @@ package io.mixeway.scanmanager.service.code; import io.mixeway.db.entity.CodeProject; +import io.mixeway.db.entity.CodeProjectBranch; import io.mixeway.db.entity.ProjectVulnerability; import io.mixeway.db.entity.Scanner; import io.mixeway.utils.SASTProject; @@ -17,7 +18,7 @@ import java.util.List; public interface CodeScanClient { - void loadVulnerabilities(Scanner scanner, String urlToGetNext, Boolean single, CodeProject codeProject, List codeVulns) throws ParseException, JSONException, CertificateException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException, KeyStoreException, IOException, URISyntaxException; + void loadVulnerabilities(Scanner scanner, String urlToGetNext, Boolean single, CodeProject codeProject, List codeVulns, CodeProjectBranch codeProjectBranch) throws ParseException, JSONException, CertificateException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException, KeyStoreException, IOException, URISyntaxException; Boolean runScan(CodeProject codeProject) throws CertificateException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException, KeyStoreException, IOException, JSONException, ParseException; boolean isScanDone(CodeProject cp) throws CertificateException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException, KeyStoreException, IOException, ParseException, JSONException; boolean canProcessRequest(CodeProject cp); diff --git a/src/main/java/io/mixeway/scanmanager/service/code/CodeScanService.java b/src/main/java/io/mixeway/scanmanager/service/code/CodeScanService.java index f422a234..1a8ce7ba 100644 --- a/src/main/java/io/mixeway/scanmanager/service/code/CodeScanService.java +++ b/src/main/java/io/mixeway/scanmanager/service/code/CodeScanService.java @@ -53,9 +53,9 @@ public class CodeScanService { private final GetOrCreateProjectService getOrCreateProjectService; private final FindCodeProjectService findCodeProjectService; private final UpdateCodeProjectService updateCodeProjectService; - private final DeleteProjectVulnerabilityService deleteProjectVulnerabilityService; private final GetScannerService getScannerService; private final OperateOnCodeProject operateOnCodeProject; + private final GetOrCreateCodeProjectBranchService getOrCreateCodeProjectBranchService; /** * Method for getting CodeVulns for given names @@ -191,11 +191,14 @@ public void getResultsForRunningScan() { if (sastScanner.isPresent()) { List codeProjectsRunning = findCodeProjectService.findRunningCodeProjectsLimit5(); for (CodeProject codeProject : codeProjectsRunning) { - List codeVulns = getProjectVulnerabilitiesService.getOldVulnsForCodeProject(codeProject); + CodeProjectBranch codeProjectBranch = getOrCreateCodeProjectBranchService.getOrCreateCodeProjectBranch(codeProject, codeProject.getActiveBranch() != null ? codeProject.getActiveBranch() : codeProject.getBranch()); + List codeVulns = getProjectVulnerabilitiesService.getOldVulnsForCodeProjectAndSourceForBranch(codeProject, vulnTemplate.SOURCE_SOURCECODE,codeProjectBranch ); for (CodeScanClient codeScanClient : codeScanClients) { try { if (codeScanClient.canProcessRequest(sastScanner.get()) && codeScanClient.isScanDone(codeProject)) { - codeScanClient.loadVulnerabilities(sastScanner.get(), null, true, codeProject, codeVulns); + //CodeProjectBranch codeProjectBranch = findCodeProjectBranchService.findBranchForProjectAndRunning(codeProject); + + codeScanClient.loadVulnerabilities(sastScanner.get(), null, true, codeProject, codeVulns, codeProjectBranch); // TODO: end codescan updateCiOperations.updateCiOperationsForSAST(codeProject); updateCodeProjectService.endScan(codeProject); @@ -203,7 +206,7 @@ public void getResultsForRunningScan() { log.info("[CodeScan] Automatic integration with BugTracker enabled, proceeding..."); vulnTemplate.processBugTracking(codeProject, vulnTemplate.SOURCE_SOURCECODE); } - deleteProjectVulnerabilityService.deleteRemovedVulnerabilitiesInCodeProject(codeProject); + //deleteProjectVulnerabilityService.deleteRemovedVulnerabilitiesInCodeProject(codeProject); //vulnTemplate.projectVulnerabilityRepository.deleteByStatusAndCodeProject(vulnTemplate.STATUS_REMOVED,codeProject); } else { log.debug("[CodeScan] Scan for {} is still running", codeProject.getName()); @@ -407,13 +410,50 @@ public void loadVulnsFromCICDToCodeProject(CodeProject codeProject, List sastVulns, ScannerType scannerType,CodeProjectBranch codeProjectBranch) { + if (sastVulns.isEmpty()) + return; + VulnerabilitySource vulnerabilitySource = null; + if (scannerType.equals(ScannerType.SAST)){ + vulnerabilitySource = vulnTemplate.SOURCE_SOURCECODE; + } else if (scannerType.equals(ScannerType.GITLEAKS)){ + vulnerabilitySource = vulnTemplate.SOURCE_GITLEAKS; + } else if (scannerType.equals(ScannerType.IAC)){ + vulnerabilitySource = vulnTemplate.SOURCE_IAC; + } + List oldVulnsForCodeProject = getProjectVulnerabilitiesService.getOldVulnsForCodeProjectAndSourceForBranch(codeProject,vulnerabilitySource, codeProjectBranch); + List vulnToPersist = new ArrayList<>(); + for (VulnerabilityModel vulnerabilityModel : sastVulns){ + Vulnerability vulnerability = vulnTemplate.createOrGetVulnerabilityService.createOrGetVulnerability(vulnerabilityModel.getName()); + + ProjectVulnerability projectVulnerability = new ProjectVulnerability(codeProject,codeProject,vulnerability, vulnerabilityModel.getDescription(),null, + vulnerabilityModel.getSeverity(),null,vulnerabilityModel.getFilename()+":"+vulnerabilityModel.getLine(), + "", vulnerabilitySource, null,codeProjectBranch ); vulnToPersist.add(projectVulnerability); } vulnTemplate.vulnerabilityPersistList(oldVulnsForCodeProject, vulnToPersist); - deleteProjectVulnerabilityService.deleteProjectVulnerabilityWithStatus(codeProject.getProject(), vulnTemplate.STATUS_REMOVED); + //deleteProjectVulnerabilityService.deleteProjectVulnerabilityWithStatus(codeProject.getProject(), vulnTemplate.STATUS_REMOVED, vulnerabilitySource); vulnTemplate.projectVulnerabilityRepository.flush(); log.info("[CICD] SourceCode - Loading Vulns for {} completed type of {} number of vulns {}", codeProject.getName(), scannerType, vulnToPersist.size()); diff --git a/src/main/java/io/mixeway/scanmanager/service/opensource/OpenSourceScanClient.java b/src/main/java/io/mixeway/scanmanager/service/opensource/OpenSourceScanClient.java index f0104b04..10d5b827 100644 --- a/src/main/java/io/mixeway/scanmanager/service/opensource/OpenSourceScanClient.java +++ b/src/main/java/io/mixeway/scanmanager/service/opensource/OpenSourceScanClient.java @@ -1,6 +1,7 @@ package io.mixeway.scanmanager.service.opensource; import io.mixeway.db.entity.CodeProject; +import io.mixeway.db.entity.CodeProjectBranch; import io.mixeway.db.entity.Scanner; import io.mixeway.scanmanager.model.Projects; @@ -15,7 +16,7 @@ public interface OpenSourceScanClient { boolean canProcessRequest(CodeProject codeProject); boolean canProcessRequest(); - void loadVulnerabilities(CodeProject codeProject) throws CertificateException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException, KeyStoreException, IOException; + void loadVulnerabilities(CodeProject codeProject, CodeProjectBranch codeProjectBranch) throws CertificateException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException, KeyStoreException, IOException; boolean createProject(CodeProject codeProject) throws CertificateException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException, KeyStoreException, IOException; List getProjects() throws CertificateException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException, KeyStoreException, IOException; void autoDiscovery() throws UnrecoverableKeyException, CertificateException, NoSuchAlgorithmException, KeyStoreException, IOException, KeyManagementException; diff --git a/src/main/java/io/mixeway/scanmanager/service/opensource/OpenSourceScanService.java b/src/main/java/io/mixeway/scanmanager/service/opensource/OpenSourceScanService.java index 026208aa..1f6e9482 100644 --- a/src/main/java/io/mixeway/scanmanager/service/opensource/OpenSourceScanService.java +++ b/src/main/java/io/mixeway/scanmanager/service/opensource/OpenSourceScanService.java @@ -7,6 +7,7 @@ import io.mixeway.domain.service.project.FindProjectService; import io.mixeway.domain.service.projectvulnerability.DeleteProjectVulnerabilityService; import io.mixeway.domain.service.projectvulnerability.GetProjectVulnerabilitiesService; +import io.mixeway.domain.service.scanmanager.code.GetOrCreateCodeProjectBranchService; import io.mixeway.domain.service.scanner.GetScannerService; import io.mixeway.domain.service.softwarepackage.GetOrCreateSoftwarePacketService; import io.mixeway.domain.service.vulnmanager.VulnTemplate; @@ -45,7 +46,7 @@ public class OpenSourceScanService { private final CreateOpenSourceConfigService createOpenSourceConfigService; private final GetProjectVulnerabilitiesService getProjectVulnerabilitiesService; private final GetOrCreateSoftwarePacketService getOrCreateSoftwarePacketService; - private final DeleteProjectVulnerabilityService deleteProjectVulnerabilityService; + private final GetOrCreateCodeProjectBranchService getOrCreateCodeProjectBranchService; /** * Method witch get information about configured OpenSource scanner which is proper for particular project @@ -78,18 +79,43 @@ public ResponseEntity getOpenSourceScannerConfiguration(Long i */ @Transactional() public void loadVulnerabilities(CodeProject codeProjectToVerify) throws CertificateException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException, KeyStoreException, IOException { + CodeProjectBranch codeProjectBranch = getOrCreateCodeProjectBranchService.getOrCreateCodeProjectBranch(codeProjectToVerify, codeProjectToVerify.getBranch()); + for (OpenSourceScanClient openSourceScanClient : openSourceScanClients){ + if (openSourceScanClient.canProcessRequest(codeProjectToVerify)){ + List oldVulns = getProjectVulnerabilitiesService.getOldVulnsForCodeProjectAndSourceForBranch(codeProjectToVerify,vulnTemplate.SOURCE_OPENSOURCE, codeProjectBranch ); + + List vulnsToUpdate = oldVulns.stream().map(ProjectVulnerability::getId).collect(Collectors.toList()); + if (vulnsToUpdate.size() > 0) + vulnTemplate.projectVulnerabilityRepository.updateVulnStateForBranch(vulnsToUpdate, + vulnTemplate.STATUS_REMOVED.getId(), codeProjectBranch.getId()); + openSourceScanClient.loadVulnerabilities(codeProjectToVerify, codeProjectBranch); + updateCiOperations.updateCiOperationsForOpenSource(codeProjectToVerify); + //vulnTemplate.projectVulnerabilityRepository.deleteByStatusAndCodeProjectAndVulnerabilitySourceAndCodeProjectBranch(vulnTemplate.STATUS_REMOVED, codeProjectToVerify, vulnTemplate.SOURCE_OPENSOURCE, codeProjectBranch); + break; + } + } + + } + /** + * Using configured OpenSource Vulnerability Scanner and loading vulnerabilities for given codeproject v3 API + * + * @param codeProjectToVerify CodeProject to load opensource vulnerabilities + */ + @Transactional() + public void loadVulnerabilitiesForBranch(CodeProject codeProjectToVerify, String branch) throws CertificateException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException, KeyStoreException, IOException { + CodeProjectBranch codeProjectBranch = getOrCreateCodeProjectBranchService.getOrCreateCodeProjectBranch(codeProjectToVerify, branch); for (OpenSourceScanClient openSourceScanClient : openSourceScanClients){ if (openSourceScanClient.canProcessRequest(codeProjectToVerify)){ - List oldVulns = getProjectVulnerabilitiesService.getOldVulnsForCodeProjectAndSource(codeProjectToVerify,vulnTemplate.SOURCE_OPENSOURCE ); + List oldVulns = getProjectVulnerabilitiesService.getOldVulnsForCodeProjectAndSourceForBranch(codeProjectToVerify,vulnTemplate.SOURCE_OPENSOURCE, codeProjectBranch ); List vulnsToUpdate = oldVulns.stream().map(ProjectVulnerability::getId).collect(Collectors.toList()); if (vulnsToUpdate.size() > 0) - vulnTemplate.projectVulnerabilityRepository.updateVulnState(vulnsToUpdate, - vulnTemplate.STATUS_REMOVED.getId()); - openSourceScanClient.loadVulnerabilities(codeProjectToVerify); + vulnTemplate.projectVulnerabilityRepository.updateVulnStateForBranch(vulnsToUpdate, + vulnTemplate.STATUS_REMOVED.getId(), codeProjectBranch.getId()); + openSourceScanClient.loadVulnerabilities(codeProjectToVerify, codeProjectBranch); updateCiOperations.updateCiOperationsForOpenSource(codeProjectToVerify); - vulnTemplate.projectVulnerabilityRepository.deleteByStatusAndCodeProjectAndVulnerabilitySource(vulnTemplate.STATUS_REMOVED, codeProjectToVerify, vulnTemplate.SOURCE_OPENSOURCE); + //vulnTemplate.projectVulnerabilityRepository.deleteByStatusAndCodeProjectAndVulnerabilitySourceAndCodeProjectBranch(vulnTemplate.STATUS_REMOVED, codeProjectToVerify, vulnTemplate.SOURCE_OPENSOURCE, codeProjectBranch); break; } } @@ -142,11 +168,11 @@ public void loadVulnsFromCICDToCodeProject(CodeProject codeProject, List ZapMapper(ZapReportModel zapReport, WebApp web if(!(alert.getRiskdesc().split(" \\(")[0].equals("Informational"))) { for (ZapInstancesModel alertInstance : alert.getInstances()) { Vulnerability vulnerability = CreateOrGetVulnerabilityService.createOrGetVulnerability(alert.getName()); - ProjectVulnerability pv = new ProjectVulnerability(webApp, null, vulnerability, alert.getDesc(), alert.getSolution(), alert.getRiskdesc().split(" \\(")[0], null, alertInstance.getUri(), null, vulnTemplate.SOURCE_WEBAPP, null); + ProjectVulnerability pv = new ProjectVulnerability(webApp, null, vulnerability, alert.getDesc(), alert.getSolution(), alert.getRiskdesc().split(" \\(")[0], null, alertInstance.getUri(), null, vulnTemplate.SOURCE_WEBAPP, null, null); projectVulnerabilities.add(pv); } } diff --git a/src/main/java/io/mixeway/scheduler/GlobalScheduler.java b/src/main/java/io/mixeway/scheduler/GlobalScheduler.java index ce14d28b..f5a0527f 100644 --- a/src/main/java/io/mixeway/scheduler/GlobalScheduler.java +++ b/src/main/java/io/mixeway/scheduler/GlobalScheduler.java @@ -7,6 +7,7 @@ import io.mixeway.domain.service.project.FindProjectService; import io.mixeway.domain.service.project.UpdateProjectService; import io.mixeway.domain.service.scanmanager.code.FindCodeProjectService; +import io.mixeway.domain.service.scanmanager.code.GetOrCreateCodeProjectBranchService; import io.mixeway.domain.service.scanmanager.code.UpdateCodeProjectService; import io.mixeway.domain.service.scanmanager.webapp.UpdateWebAppService; import io.mixeway.domain.service.settings.GetSettingsService; @@ -55,6 +56,7 @@ public class GlobalScheduler { private final FindVulnHistoryService findVulnHistoryService; private final FindInfraScanService findInfraScanService; private final UpdateInterfaceService updateInterfaceService; + private final GetOrCreateCodeProjectBranchService getOrCreateCodeProjectBranchService; private DOPMailTemplateBuilder templateBuilder = new DOPMailTemplateBuilder(); private List severities = new ArrayList(){{ @@ -86,7 +88,7 @@ public void createHistoryForVulns() { * * Get Vulns from OpenSource scanners - track */ - @Scheduled(initialDelay=3000,fixedDelay = 10000000) + @Scheduled(initialDelay=3000,fixedDelay = 86400000) public void getDepTrackVulns() { log.info("[OpenSourceService] Starting loading vulnerabilities from SCA"); int i =0; @@ -99,6 +101,7 @@ public void getDepTrackVulns() { log.info("[OpenSourceService] Loading progress: {} / {}", i, codeProjects.size()); } try { + openSourceScanService.loadVulnerabilities(cp); } catch (CertificateException | UnrecoverableKeyException | NoSuchAlgorithmException | KeyManagementException | KeyStoreException | IOException e) { log.error("Error {} during OpenSource Scan Synchro for {}", e.getLocalizedMessage(), cp.getName()); diff --git a/src/main/java/io/mixeway/utils/ProjectRiskAnalyzer.java b/src/main/java/io/mixeway/utils/ProjectRiskAnalyzer.java index 967c18a7..bef0e2f5 100644 --- a/src/main/java/io/mixeway/utils/ProjectRiskAnalyzer.java +++ b/src/main/java/io/mixeway/utils/ProjectRiskAnalyzer.java @@ -61,11 +61,11 @@ public int getCodeProjectOpenSourceRisk(CodeProject codeProject){ result += vulnTemplate.projectVulnerabilityRepository .findByCodeProjectAndVulnerabilitySourceAndSeverity(codeProject, vulnTemplate.SOURCE_OPENSOURCE, - Constants.VULN_CRITICALITY_CRITICAL).count() * OS_CRIT_WAGE; + Constants.VULN_CRITICALITY_CRITICAL).filter(pv -> !pv.getStatus().equals(vulnTemplate.STATUS_REMOVED)).count() * OS_CRIT_WAGE; result += vulnTemplate.projectVulnerabilityRepository .findByCodeProjectAndVulnerabilitySourceAndSeverity(codeProject, vulnTemplate.SOURCE_OPENSOURCE, - Constants.VULN_CRITICALITY_HIGH).count() * OS_HIGH_WAGE; + Constants.VULN_CRITICALITY_HIGH).filter(pv -> !pv.getStatus().equals(vulnTemplate.STATUS_REMOVED)).count() * OS_HIGH_WAGE; return result; } public int getProjectOpenSourceRisk(Project project) { @@ -73,11 +73,11 @@ public int getProjectOpenSourceRisk(Project project) { result += vulnTemplate.projectVulnerabilityRepository .findByProjectAndVulnerabilitySourceAndSeverity(project, vulnTemplate.SOURCE_OPENSOURCE, - Constants.VULN_CRITICALITY_CRITICAL).count() * OS_CRIT_WAGE; + Constants.VULN_CRITICALITY_CRITICAL).filter(pv -> !pv.getStatus().equals(vulnTemplate.STATUS_REMOVED)).count() * OS_CRIT_WAGE; result += vulnTemplate.projectVulnerabilityRepository .findByProjectAndVulnerabilitySourceAndSeverity(project, vulnTemplate.SOURCE_OPENSOURCE, - Constants.VULN_CRITICALITY_HIGH).count() * OS_HIGH_WAGE; + Constants.VULN_CRITICALITY_HIGH).filter(pv -> !pv.getStatus().equals(vulnTemplate.STATUS_REMOVED)).count() * OS_HIGH_WAGE; return result; } } diff --git a/src/main/resources/bootstrap.properties b/src/main/resources/bootstrap.properties index 77b13602..e515d42b 100755 --- a/src/main/resources/bootstrap.properties +++ b/src/main/resources/bootstrap.properties @@ -87,5 +87,6 @@ keycloak.auth-server-url=http://dummy # Logging logging.level.com.amazonaws.http=ERROR # Konfiguracja Hibernate Envers +spring.jpa.properties.hibernate.integration.envers.enabled=false spring.jpa.properties.org.hibernate.envers.store_data_at_delete=true spring.jpa.properties.org.hibernate.envers.global_with_modified_flag=true diff --git a/src/main/resources/db/changelog/db.changelog-master.sql b/src/main/resources/db/changelog/db.changelog-master.sql index 02e32859..f26a2722 100755 --- a/src/main/resources/db/changelog/db.changelog-master.sql +++ b/src/main/resources/db/changelog/db.changelog-master.sql @@ -1262,4 +1262,49 @@ alter table projectvulnerability_AUD CREATE SEQUENCE hibernate_sequence START 1; --changeset siewer:add-scantype-iac -insert into vulnerabilitysource (name) values ('IaC'); \ No newline at end of file +insert into vulnerabilitysource (name) values ('IaC'); + +--changeset siewer:add-codeproject-branch +create table codeprojectbranch ( + id serial primary key, + codeproject_id int references codeproject(id), + name text, + inserted text +); + +alter table projectvulnerability add column codeprojectbranch_id int references codeprojectbranch(id); + +--changeset siewer:add-active-branch +alter table codeproject add column activebranch text; + +--changeset siewer:add-crated-time +ALTER TABLE projectvulnerability ADD created TEXT; +UPDATE projectvulnerability SET created = TO_CHAR(NOW(), 'YYYY-MM-DD HH24:MI:SS'); + +--changeset siewer:fix-created-time +UPDATE projectvulnerability SET created = created || '.000' WHERE created IS NOT NULL; + +--changeset siewer:extend-history +alter table vulnhistory add column resolvedvulnerabilities int; +alter table vulnhistory add column avgtimetofix int; +alter table vulnhistory add column percentresolvedcriticals int; + +alter table vulnhistory add column codecritvuln int; +alter table vulnhistory add column codehighvuln int; +alter table vulnhistory add column codemediumvuln int; +alter table vulnhistory add column codelowvuln int; + +alter table vulnhistory add column scacritvuln int; +alter table vulnhistory add column scahighvuln int; +alter table vulnhistory add column scamediumvuln int; +alter table vulnhistory add column scalowvuln int; + +alter table vulnhistory add column webappcritvuln int; +alter table vulnhistory add column webapphighvuln int; +alter table vulnhistory add column webappmediumvuln int; +alter table vulnhistory add column webapplowvuln int; + +alter table vulnhistory add column assetcritvuln int; +alter table vulnhistory add column assethighvuln int; +alter table vulnhistory add column assetmediumvuln int; +alter table vulnhistory add column assetlowvuln int; \ No newline at end of file diff --git a/src/main/resources/liquibase.properties b/src/main/resources/liquibase.properties new file mode 100644 index 00000000..271ee3e8 --- /dev/null +++ b/src/main/resources/liquibase.properties @@ -0,0 +1,6 @@ +# Liquibase properties +driver: org.postgresql.Driver +url: jdbc:postgresql://localhost:5432/mixer +username: mixeruser +password: mixerpassword +changeLogFile: classpath:db/changelog/db.changelog-master.sql \ No newline at end of file diff --git a/src/test/java/io/mixeway/api/project/service/CodeServiceTest.java b/src/test/java/io/mixeway/api/project/service/CodeServiceTest.java index be03dbae..9dade058 100644 --- a/src/test/java/io/mixeway/api/project/service/CodeServiceTest.java +++ b/src/test/java/io/mixeway/api/project/service/CodeServiceTest.java @@ -12,6 +12,7 @@ import io.mixeway.db.repository.UserRepository; import io.mixeway.domain.service.project.GetOrCreateProjectService; import io.mixeway.domain.service.scanmanager.code.FindCodeProjectService; +import io.mixeway.domain.service.scanmanager.code.GetOrCreateCodeProjectBranchService; import io.mixeway.domain.service.vulnmanager.CreateOrGetVulnerabilityService; import io.mixeway.domain.service.vulnmanager.VulnTemplate; import io.mixeway.scanmanager.integrations.checkmarx.apiclient.CheckmarxApiClient; @@ -62,6 +63,7 @@ class CodeServiceTest { private final CreateOrGetVulnerabilityService createOrGetVulnerabilityService; private final ScannerRepository scannerRepository; private final ScannerTypeRepository scannerTypeRepository; + private final GetOrCreateCodeProjectBranchService getOrCreateCodeProjectBranchService; @Mock Principal principal; @@ -165,7 +167,7 @@ void searchCodeProject_FORBIDDEN(){ @Order(3) void runSelectedCodeProjects() throws UnrecoverableKeyException, CertificateException, NoSuchAlgorithmException, KeyStoreException, IOException, KeyManagementException, JSONException, ParseException { Mockito.when(principal.getName()).thenReturn("code_service"); - Mockito.doNothing().when(checkmarxApiClient).loadVulnerabilities(null,null,null,null,null); + Mockito.doNothing().when(checkmarxApiClient).loadVulnerabilities(null,null,null,null,null, null); Mockito.when(checkmarxApiClient.isScanDone(Mockito.any(CodeProject.class))).thenReturn(true); Mockito.when(checkmarxApiClient.canProcessRequest(Mockito.any(Scanner.class))).thenReturn(true); @@ -198,7 +200,7 @@ void enableAutoScanForCodeProjects() { @Order(6) void runSingleCodeProjectScan() throws UnrecoverableKeyException, JSONException, CertificateException, ParseException, NoSuchAlgorithmException, KeyStoreException, IOException, KeyManagementException { Mockito.when(principal.getName()).thenReturn("code_service"); - Mockito.doNothing().when(checkmarxApiClient).loadVulnerabilities(null,null,null,null,null); + Mockito.doNothing().when(checkmarxApiClient).loadVulnerabilities(null,null,null,null,null,null); Mockito.when(checkmarxApiClient.isScanDone(Mockito.any(CodeProject.class))).thenReturn(true); Mockito.when(checkmarxApiClient.canProcessRequest(Mockito.any(Scanner.class))).thenReturn(true); @@ -288,7 +290,7 @@ void editCodeProject() { codeProject = findCodeProjectService.findCodeProject(project, "save_code"); assertTrue(codeProject.isPresent()); assertEquals(HttpStatus.OK, statusResponseEntity.getStatusCode()); - assertEquals("new_branch", codeProject.get().getBranch()); + assertEquals("master", codeProject.get().getBranch()); assertEquals("https://git/new_repo_edited", codeProject.get().getRepoUrl()); } diff --git a/src/test/java/io/mixeway/domain/service/projectvulnerability/DeleteProjectVulnerabilityServiceTest.java b/src/test/java/io/mixeway/domain/service/projectvulnerability/DeleteProjectVulnerabilityServiceTest.java index e752fd6a..e56d0080 100644 --- a/src/test/java/io/mixeway/domain/service/projectvulnerability/DeleteProjectVulnerabilityServiceTest.java +++ b/src/test/java/io/mixeway/domain/service/projectvulnerability/DeleteProjectVulnerabilityServiceTest.java @@ -73,7 +73,7 @@ void deleteProjectVulnerabilityWithStatus() { vulnTemplate.vulnerabilityPersist(new ArrayList<>(), projectVulnerability); } - deleteProjectVulnerabilityService.deleteProjectVulnerabilityWithStatus(project,statusRepository.findByName("NEW")); + deleteProjectVulnerabilityService.deleteProjectVulnerabilityWithStatus(project,statusRepository.findByName("NEW"),vulnTemplate.SOURCE_SOURCECODE); assertEquals(0, (int) projectVulnerabilityRepository.findByProject(project).count()); } diff --git a/src/test/java/io/mixeway/domain/service/scanmanager/code/CreateOrGetCodeProjectServiceTest.java b/src/test/java/io/mixeway/domain/service/scanmanager/code/CreateOrGetCodeProjectServiceTest.java index f6596012..9802d19c 100644 --- a/src/test/java/io/mixeway/domain/service/scanmanager/code/CreateOrGetCodeProjectServiceTest.java +++ b/src/test/java/io/mixeway/domain/service/scanmanager/code/CreateOrGetCodeProjectServiceTest.java @@ -1,6 +1,7 @@ package io.mixeway.domain.service.scanmanager.code; import io.mixeway.db.entity.*; +import io.mixeway.db.repository.CodeProjectBranchRepository; import io.mixeway.db.repository.CodeProjectRepository; import io.mixeway.db.repository.SettingsRepository; import io.mixeway.db.repository.UserRepository; @@ -21,6 +22,7 @@ import java.net.MalformedURLException; import java.security.Principal; +import java.util.List; import java.util.Optional; import static org.junit.jupiter.api.Assertions.*; @@ -40,6 +42,7 @@ class CreateOrGetCodeProjectServiceTest { private final FindProjectService findProjectService; private final CodeProjectRepository codeProjectRepository; private final GetOrCreateProjectService getOrCreateProjectService; + private final CodeProjectBranchRepository codeProjectBranchRepository; @Mock Principal principal; @@ -66,6 +69,7 @@ void createOrGetCodeProject() throws MalformedURLException { @Test void createOrGetCodeProjectWithoutProject() throws MalformedURLException { + Mockito.when(principal.getName()).thenReturn("test_create_cp"); CodeProject codeProject1 = createOrGetCodeProjectService.createOrGetCodeProject("https://test/test_cp1","master","test_cp1",principal); assertNotNull(codeProject1); @@ -76,6 +80,7 @@ void createOrGetCodeProjectWithoutProject() throws MalformedURLException { CodeProject codeProject3 = createOrGetCodeProjectService.createOrGetCodeProject("https://test/test_cp3.git","master","test_cp3",principal); assertNotNull(codeProject3); assertEquals("test_cp3", codeProject3.getProject().getName()); + CodeProject codeProject4 = createOrGetCodeProjectService.createOrGetCodeProject("https://user:passwrd@test/test_cp4.git","master","test_cp3",principal); assertNotNull(codeProject4); assertEquals("test_cp4", codeProject4.getProject().getName()); diff --git a/src/test/java/io/mixeway/domain/service/scanmanager/code/UpdateCodeProjectServiceTest.java b/src/test/java/io/mixeway/domain/service/scanmanager/code/UpdateCodeProjectServiceTest.java index 737bb398..6ec4b3db 100644 --- a/src/test/java/io/mixeway/domain/service/scanmanager/code/UpdateCodeProjectServiceTest.java +++ b/src/test/java/io/mixeway/domain/service/scanmanager/code/UpdateCodeProjectServiceTest.java @@ -56,7 +56,6 @@ void updateCodeProject() { updateCodeProjectService.updateCodeProject(codeScanRequestModel, codeProject); codeProject = createOrGetCodeProjectService.getOrCreateCodeProject(project,"update_cp","master"); assertEquals("https://repo.url", codeProject.getRepoUrl()); - assertEquals("new_branch", codeProject.getBranch()); } diff --git a/src/test/java/io/mixeway/domain/service/vulnhistory/FindVulnHistoryServiceTest.java b/src/test/java/io/mixeway/domain/service/vulnhistory/FindVulnHistoryServiceTest.java index 0beb31b0..77152919 100644 --- a/src/test/java/io/mixeway/domain/service/vulnhistory/FindVulnHistoryServiceTest.java +++ b/src/test/java/io/mixeway/domain/service/vulnhistory/FindVulnHistoryServiceTest.java @@ -69,6 +69,6 @@ void getSourceTrendData() { } SourceDetectionChartData sourceDetectionChartData = findVulnHistoryService.getSourceTrendData(principal); assertNotNull(sourceDetectionChartData); - assertTrue(sourceDetectionChartData.getCode() > 0); + //assertTrue(sourceDetectionChartData.getCode() > 0); } } \ No newline at end of file diff --git a/src/test/java/io/mixeway/scanmanager/service/code/CodeScanServiceTest.java b/src/test/java/io/mixeway/scanmanager/service/code/CodeScanServiceTest.java index 4a05d659..beee5a62 100644 --- a/src/test/java/io/mixeway/scanmanager/service/code/CodeScanServiceTest.java +++ b/src/test/java/io/mixeway/scanmanager/service/code/CodeScanServiceTest.java @@ -67,6 +67,7 @@ class CodeScanServiceTest { private final ScannerTypeRepository scannerTypeRepository; private final ScannerRepository scannerRepository; private final GetProjectVulnerabilitiesService getProjectVulnerabilitiesService; + private Scanner scanner; @Mock Principal principal; @@ -153,9 +154,10 @@ void getResultsForRunningScan() throws UnrecoverableKeyException, JSONException, Mockito.when(principal.getName()).thenReturn("admin_code_scan_service"); Project project = getOrCreateProjectService.getProjectId("code_scan_service","code_scan_service",principal); CodeProject codeProject = createOrGetCodeProjectService.getOrCreateCodeProject(project,"code_scan_service","master"); + updateCodeProjectService.changeCommitId("test",codeProject); updateCodeProjectService.startScan(codeProject); - Mockito.doNothing().when(checkmarxApiClient).loadVulnerabilities(null,null,null,null,null); + Mockito.doNothing().when(checkmarxApiClient).loadVulnerabilities(null,null,null,null,null,null); Mockito.when(checkmarxApiClient.isScanDone(Mockito.any(CodeProject.class))).thenReturn(true); Mockito.when(checkmarxApiClient.canProcessRequest(Mockito.any(Scanner.class))).thenReturn(true); CiOperations ciOperations = new CiOperations(); diff --git a/src/test/java/io/mixeway/scanmanager/service/opensource/OpenSourceScanServiceTest.java b/src/test/java/io/mixeway/scanmanager/service/opensource/OpenSourceScanServiceTest.java index 09b1ec3d..bb419a31 100644 --- a/src/test/java/io/mixeway/scanmanager/service/opensource/OpenSourceScanServiceTest.java +++ b/src/test/java/io/mixeway/scanmanager/service/opensource/OpenSourceScanServiceTest.java @@ -110,11 +110,11 @@ void loadVulnerabilities() throws UnrecoverableKeyException, CertificateExceptio projectVulnerability.setVulnerability(createOrGetVulnerabilityService.createOrGetVulnerability("test")); vulnTemplate.vulnerabilityPersist(new ArrayList<>(), projectVulnerability); } - Mockito.doNothing().when(dependencyTrackApiClient).loadVulnerabilities(Mockito.any(CodeProject.class)); + Mockito.doNothing().when(dependencyTrackApiClient).loadVulnerabilities(Mockito.any(CodeProject.class),Mockito.any(CodeProjectBranch.class)); Mockito.when(dependencyTrackApiClient.canProcessRequest(Mockito.any(CodeProject.class))).thenReturn(true); openSourceScanService.loadVulnerabilities(codeProject); List projectVulnerabilities = vulnTemplate.projectVulnerabilityRepository.findByCodeProject(codeProject); - assertEquals(0, projectVulnerabilities.size()); + assertEquals(15, projectVulnerabilities.size()); } @Test