Skip to content

Commit

Permalink
Merge pull request #149 from axonivy/improve
Browse files Browse the repository at this point in the history
Improve performance of home page
  • Loading branch information
alexsuter authored Dec 24, 2024
2 parents 94e5127 + 5ccd473 commit 6f26322
Show file tree
Hide file tree
Showing 8 changed files with 235 additions and 113 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import io.ivyteam.devops.branch.Branch;
import io.ivyteam.devops.branch.BranchRepository;
import io.ivyteam.devops.repo.Repo;
import io.ivyteam.devops.securityscanner.ScanTypeEnum;
import io.ivyteam.devops.securityscanner.ScanType;
import io.ivyteam.devops.securityscanner.SecurityScannerApiHelper;
import io.ivyteam.devops.settings.SettingsManager;

Expand Down Expand Up @@ -63,7 +63,7 @@ public boolean run() {
}
if (!repo.isVulnAlertOn() && ghRepo.isPrivate()) {
LOGGER.info("Enable Vulnerability-alerts");
SecurityScannerApiHelper.enableAlerts(ghRepo.getUrl(), gitHub.token(), ScanTypeEnum.DEPENDABOT.getValue());
SecurityScannerApiHelper.enableAlerts(ghRepo.getUrl(), gitHub.token(), ScanType.DEPENDABOT.getValue());
changed = true;
}
if (repo.hooks()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
import io.ivyteam.devops.pullrequest.PullRequestRepository;
import io.ivyteam.devops.repo.Repo;
import io.ivyteam.devops.repo.RepoRepository;
import io.ivyteam.devops.securityscanner.ScanTypeEnum;
import io.ivyteam.devops.securityscanner.ScanType;
import io.ivyteam.devops.securityscanner.SecurityScannerApiHelper;
import io.ivyteam.devops.securityscanner.SecurityScannerRepository;
import io.ivyteam.devops.user.UserRepository;
Expand Down Expand Up @@ -102,11 +102,11 @@ public synchronized void run() {
synch(repo);
var helper = new SecurityScannerApiHelper(securityScanners, repo, gitHub.token());
if (repo.isVulnerabilityAlertsEnabled()) {
helper.synch(ScanTypeEnum.DEPENDABOT.getValue());
helper.synch(ScanType.DEPENDABOT);
}
if (!repo.isPrivate()) {
helper.synch(ScanTypeEnum.CODE_SCANNING.getValue());
helper.synch(ScanTypeEnum.SECRET_SCANNING.getValue());
helper.synch(ScanType.CODE_SCANNING);
helper.synch(ScanType.SECRET_SCANNING);
}

}
Expand Down
91 changes: 45 additions & 46 deletions src/main/java/io/ivyteam/devops/repo/ReposView.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@

import io.ivyteam.devops.branch.BranchRepository;
import io.ivyteam.devops.pullrequest.PullRequestRepository;
import io.ivyteam.devops.securityscanner.ScanTypeEnum;
import io.ivyteam.devops.securityscanner.ScanType;
import io.ivyteam.devops.securityscanner.SecurityScanner;
import io.ivyteam.devops.securityscanner.SecurityScannerRepository;
import io.ivyteam.devops.securityscanner.SecurityScannerRepository.Key;
import io.ivyteam.devops.view.View;

@Route("")
Expand All @@ -31,6 +32,7 @@ public class ReposView extends View {

public ReposView(RepoRepository repos, PullRequestRepository prs, BranchRepository branches,
SecurityScannerRepository securityscanners) {

var repositories = repos.all();
grid = new Grid<>(repositories);
title.setText("Repositories (" + repositories.size() + ")");
Expand Down Expand Up @@ -69,17 +71,12 @@ public ReposView(RepoRepository repos, PullRequestRepository prs, BranchReposito

grid
.addComponentColumn(repo -> {
if (repo.archived() || repo.privateRepo()) {
return null;
}
if (repo.license() != null) {
var icon = createIcon(VaadinIcon.CHECK);
icon.getElement().getThemeList().add("badge success");
return icon;
}
var icon = createIcon(VaadinIcon.CLOSE);
icon.getElement().getThemeList().add("badge error");
return icon;
return null;
})
.setHeader("License")
.setWidth("10%")
Expand All @@ -92,6 +89,11 @@ public ReposView(RepoRepository repos, PullRequestRepository prs, BranchReposito
icon.setTooltipText("Archived");
layout.add(icon);
}
return layout;
}).setWidth("75px");

grid.addComponentColumn(repo -> {
var layout = new HorizontalLayout();
if (repo.privateRepo()) {
var icon = createIcon(VaadinIcon.LOCK);
icon.setTooltipText("Private");
Expand All @@ -100,43 +102,49 @@ public ReposView(RepoRepository repos, PullRequestRepository prs, BranchReposito
return layout;
}).setWidth("75px");

var scanners = securityscanners.all();

grid.addComponentColumn(repo -> {
var layout = new HorizontalLayout();
var dependabot = securityscanners.getByRepoAndScantype(repo.name(), ScanTypeEnum.DEPENDABOT.getValue());
if (dependabot != null) {
layout.add(createSecurityScannerAnchor(dependabot, dependabot.link_dependabot(),
ScanTypeEnum.DEPENDABOT.getValue()));
var scanner = scanners.get(new Key(repo.name(), ScanType.DEPENDABOT));
if (scanner != null) {
layout.add(toSecurityScannerLink(scanner));
}
return layout;
}).setHeader("Dependabot").setWidth("100px").setSortable(true)
.setComparator(Comparator.comparing(
r -> getSortingNr(securityscanners.getByRepoAndScantype(r.name(), ScanTypeEnum.DEPENDABOT.getValue()))));
})
.setHeader("Dependabot")
.setWidth("100px")
.setSortable(true)
.setComparator(
Comparator.comparing(repo -> getSortingNr(scanners.get(new Key(repo.name(), ScanType.DEPENDABOT)))));

grid.addComponentColumn(repo -> {
var layout = new HorizontalLayout();
var codeScan = securityscanners.getByRepoAndScantype(repo.name(), ScanTypeEnum.CODE_SCANNING.getValue());
if (codeScan != null) {
layout.add(
createSecurityScannerAnchor(codeScan, codeScan.link_codeScan(), ScanTypeEnum.CODE_SCANNING.getValue()));
var scanner = scanners.get(new Key(repo.name(), ScanType.CODE_SCANNING));
if (scanner != null) {
layout.add(toSecurityScannerLink(scanner));
}
return layout;
}).setHeader("CodeScan").setWidth("100px").setSortable(true)
.setComparator(Comparator.comparing(
r -> getSortingNr(securityscanners.getByRepoAndScantype(r.name(), ScanTypeEnum.CODE_SCANNING.getValue()))));
})
.setHeader("CodeScan")
.setWidth("100px")
.setSortable(true)
.setComparator(
Comparator.comparing(repo -> getSortingNr(scanners.get(new Key(repo.name(), ScanType.CODE_SCANNING)))));

grid.addComponentColumn(repo -> {
var layout = new HorizontalLayout();
var secretScan = securityscanners.getByRepoAndScantype(repo.name(), ScanTypeEnum.SECRET_SCANNING.getValue());
if (secretScan != null) {
layout.add(
createSecurityScannerAnchor(secretScan, secretScan.link_secretScan(),
ScanTypeEnum.SECRET_SCANNING.getValue()));
var scanner = scanners.get(new Key(repo.name(), ScanType.SECRET_SCANNING));
if (scanner != null) {
layout.add(toSecurityScannerLink(scanner));
}
return layout;
}).setHeader("SecretScan").setWidth("100px").setSortable(true)
.setComparator(Comparator.comparing(
r -> getSortingNr(
securityscanners.getByRepoAndScantype(r.name(), ScanTypeEnum.SECRET_SCANNING.getValue()))));
})
.setHeader("SecretScan")
.setWidth("100px")
.setSortable(true)
.setComparator(
Comparator.comparing(repo -> getSortingNr(scanners.get(new Key(repo.name(), ScanType.SECRET_SCANNING)))));

grid.setHeightFull();

Expand Down Expand Up @@ -218,28 +226,21 @@ private int getSortingNr(SecurityScanner s) {
if (s == null) {
return -1;
}
if (s.critical() != 0) {
return (int) (s.critical() + Math.pow(10, 9));
}
if (s.high() != 0) {
return (int) (s.high() + Math.pow(10, 6));
}
if (s.medium() != 0) {
return (int) (s.medium() + Math.pow(10, 3));
}
return s.low();
return s.sort();
}

private Anchor createSecurityScannerAnchor(SecurityScanner ss, String link, String name) {
private Anchor toSecurityScannerLink(SecurityScanner ss) {
int summary = ss.critical() + ss.high() + ss.medium() + ss.low();
var text = name + "-> C: " + ss.critical() + " | H: " + ss.high() + " | M: " + ss.medium() + " | L: " + ss.low();
var text = ss.scantype().getValue() + "-> C: " + ss.critical() + " | H: " + ss.high() + " | M: " + ss.medium()
+ " | L: "
+ ss.low();

Icon icon = VaadinIcon.QUESTION_CIRCLE.create();
var icon = VaadinIcon.QUESTION_CIRCLE.create();
icon.setSize("14px");
icon.setTooltipText(text);
icon.getStyle().set("margin-left", "4px");

var a = new Anchor(link, String.valueOf(summary), AnchorTarget.BLANK);
var a = new Anchor(ss.link(), String.valueOf(summary), AnchorTarget.BLANK);
a.add(icon);

if (ss.critical() + ss.high() > 0) {
Expand All @@ -250,8 +251,6 @@ private Anchor createSecurityScannerAnchor(SecurityScanner ss, String link, Stri
a.getElement().getThemeList().add("badge pill small success");
icon.setIcon(VaadinIcon.CHECK);
}

return a;
}

}
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
package io.ivyteam.devops.securityscanner;

public enum ScanTypeEnum {
public enum ScanType {

DEPENDABOT("dependabot", "/security/dependabot/"),
SECRET_SCANNING("secret-scanning", "/security/secret-scanning/"),
CODE_SCANNING("code-scanning", "/security/code-scanning/");

private final String value;
private final String urlSuffix;

ScanTypeEnum(String value, String urlSuffix) {
ScanType(String value, String urlSuffix) {
this.value = value;
this.urlSuffix = urlSuffix;
}
Expand All @@ -20,4 +21,13 @@ public String getValue() {
public String getUrlSuffix() {
return urlSuffix;
}

public static ScanType fromValue(String value) {
for (ScanType type : values()) {
if (type.value.equals(value)) {
return type;
}
}
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,80 @@

public record SecurityScanner(
String repo,
String scantype,
ScanType scantype,
int critical,
int high,
int medium,
int low) {

private final static String URL_PREFIX = "https://github.com/";

public String link_dependabot() {
return URL_PREFIX + repo + ScanTypeEnum.DEPENDABOT.getUrlSuffix();
public String link() {
return switch (scantype) {
case DEPENDABOT -> URL_PREFIX + repo + ScanType.DEPENDABOT.getUrlSuffix();
case SECRET_SCANNING -> URL_PREFIX + repo + ScanType.SECRET_SCANNING.getUrlSuffix();
case CODE_SCANNING -> URL_PREFIX + repo + ScanType.CODE_SCANNING.getUrlSuffix();
};
}

public String link_secretScan() {
return URL_PREFIX + repo + ScanTypeEnum.SECRET_SCANNING.getUrlSuffix();
public int sort() {
if (critical != 0) {
return (int) (critical + Math.pow(10, 9));
}
if (high != 0) {
return (int) (high + Math.pow(10, 6));
}
if (medium != 0) {
return (int) (medium + Math.pow(10, 3));
}
return low;
}

public String link_codeScan() {
return URL_PREFIX + repo + ScanTypeEnum.CODE_SCANNING.getUrlSuffix();
public static Builder create() {
return new Builder();
}

public static class Builder {

private String repo;
private ScanType scantype;
private int critical;
private int high;
private int medium;
private int low;

public Builder repo(String repo) {
this.repo = repo;
return this;
}

public Builder scantype(ScanType scantype) {
this.scantype = scantype;
return this;
}

public Builder critical(int critical) {
this.critical = critical;
return this;
}

public Builder high(int high) {
this.high = high;
return this;
}

public Builder medium(int medium) {
this.medium = medium;
return this;
}

public Builder low(int low) {
this.low = low;
return this;
}

public SecurityScanner build() {
return new SecurityScanner(repo, scantype, critical, high, medium, low);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ public static void enableAlerts(URL url, String token, String scantype) {
}
}

private static String getAlerts(URL url, String token, String scantype) {
var apiUrl = toUri(url, "/" + scantype + "/alerts?per_page=100");
private static String getAlerts(URL url, String token, ScanType scantype) {
var apiUrl = toUri(url, "/" + scantype.getValue() + "/alerts?per_page=100");
try (var client = HttpClient.newHttpClient()) {
var request = HttpRequest.newBuilder()
.uri(apiUrl)
Expand All @@ -76,32 +76,32 @@ private static String getAlerts(URL url, String token, String scantype) {
if (response.statusCode() == HttpURLConnection.HTTP_NOT_FOUND) {
return null;
} else {
LOGGER.warn("get " + scantype + " is failed: " + response.statusCode() + ", api/url: " + apiUrl);
LOGGER.warn("get " + scantype.getValue() + " is failed: " + response.statusCode() + ", api/url: " + apiUrl);
}
} catch (Exception ex) {
LOGGER.warn("Could not get " + scantype + " alerts", ex);
LOGGER.warn("Could not get " + scantype.getValue() + " alerts", ex);
}
return null;
}

private static SecurityScanner parseAlerts(String json, String repoName, String scantype) {
private static SecurityScanner parseAlerts(String json, String repoName, ScanType scantype) {
try {
JsonNode root = MAPPER.readTree(json);
Map<String, Long> severityCounts = new HashMap<>();

if (scantype.equals(ScanTypeEnum.DEPENDABOT.getValue())) {
if (scantype.equals(ScanType.DEPENDABOT)) {
for (JsonNode node : root) {
if (node.path("state").asText().equals(ALERT_REQUIRED_STATE)) {
severityCounts.merge(node.path("security_vulnerability").path("severity").asText(), 1L, Long::sum);
}
}
} else if (scantype.equals(ScanTypeEnum.CODE_SCANNING.getValue())) {
} else if (scantype.equals(ScanType.CODE_SCANNING)) {
for (JsonNode node : root) {
if (node.path("state").asText().equals(ALERT_REQUIRED_STATE)) {
severityCounts.merge(node.path("rule").path("security_severity_level").asText(), 1L, Long::sum);
}
}
} else if (scantype.equals(ScanTypeEnum.SECRET_SCANNING.getValue())) {
} else if (scantype.equals(ScanType.SECRET_SCANNING)) {
for (JsonNode node : root) {
if (node.path("state").asText().equals(ALERT_REQUIRED_STATE)) {
severityCounts.merge((node.path("url").asText() != null ? "high" : null), 1L, Long::sum);
Expand All @@ -120,7 +120,7 @@ private static SecurityScanner parseAlerts(String json, String repoName, String
return null;
}

public void synch(String scantype) throws IOException {
public void synch(ScanType scantype) throws IOException {
var json = SecurityScannerApiHelper.getAlerts(repo.getUrl(), token, scantype);
if (json == null) {
return;
Expand Down
Loading

0 comments on commit 6f26322

Please sign in to comment.