diff --git a/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/scaparser/strategy/sarif/SarifParser.java b/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/scaparser/strategy/sarif/SarifParser.java index 9f83aea205bf..d3d721ba8db9 100644 --- a/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/scaparser/strategy/sarif/SarifParser.java +++ b/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/scaparser/strategy/sarif/SarifParser.java @@ -3,10 +3,14 @@ import java.net.URI; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.function.Function; import java.util.stream.Collectors; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; @@ -34,6 +38,22 @@ */ public class SarifParser implements ParserStrategy { + private static final Logger log = LoggerFactory.getLogger(SarifParser.class); + + private static class SarifFormatException extends RuntimeException { + + private SarifFormatException(String message) { + super(message); + } + } + + private static class InformationMissingException extends RuntimeException { + + private InformationMissingException(String message) { + super(message); + } + } + private final ObjectMapper objectMapper = new ObjectMapper(); private final StaticCodeAnalysisTool tool; @@ -64,20 +84,34 @@ public StaticCodeAnalysisReportDTO parse(String reportContent) { Map ruleOfId = rules.stream().collect(Collectors.toMap(ReportingDescriptor::getId, Function.identity(), (first, next) -> first)); List results = run.getResults().orElse(List.of()); - List issues = results.stream().map(result -> processResult(result, driver, ruleOfId)).toList(); + List issues = results.stream().map(result -> tryProcessResult(result, driver, ruleOfId)).filter(Objects::nonNull).toList(); return new StaticCodeAnalysisReportDTO(tool, issues); } - private StaticCodeAnalysisIssue processResult(Result result, ToolComponent driver, Map ruleOfId) { + private StaticCodeAnalysisIssue tryProcessResult(Result result, ToolComponent driver, Map ruleOfId) { + try { + return processResult(result, driver, ruleOfId); + } + catch (SarifFormatException | NullPointerException e) { + log.error("The result is malformed", e); + return null; + } + catch (InformationMissingException e) { + log.warn("The result does not contain required information", e); + return null; + } + } + + private StaticCodeAnalysisIssue processResult(Result result, ToolComponent driver, Map ruleOfId) throws SarifFormatException { PhysicalLocation location = result.getLocations().flatMap(locations -> locations.stream().findFirst()).flatMap(Location::getPhysicalLocation) - .orElseThrow(() -> new RuntimeException("Location needed")); + .orElseThrow(() -> new InformationMissingException("Location needed")); - URI uri = URI.create(location.getArtifactLocation().flatMap(ArtifactLocation::getUri).orElseThrow(() -> new RuntimeException("File path needed"))); + URI uri = URI.create(location.getArtifactLocation().flatMap(ArtifactLocation::getUri).orElseThrow(() -> new InformationMissingException("File path needed"))); String path = uri.getPath(); - Region region = location.getRegion().orElseThrow(() -> new RuntimeException("Region must be present")); - int startLine = region.getStartLine().orElseThrow(() -> new RuntimeException("Text region needed")); + Region region = location.getRegion().orElseThrow(() -> new SarifFormatException("Region must be present")); + int startLine = region.getStartLine().orElseThrow(() -> new InformationMissingException("Text region needed")); int startColumn = region.getStartColumn().orElse(1); int endLine = region.getEndLine().orElse(startLine); int endColumn = region.getEndColumn().orElse(startColumn + 1); @@ -99,9 +133,9 @@ private StaticCodeAnalysisIssue processResult(Result result, ToolComponent drive return new StaticCodeAnalysisIssue(path, startLine, endLine, startColumn, endColumn, ruleId, category, message, level.toString(), null); } - private static String getRuleId(Result result) { - return result.getRuleId() - .orElseGet(() -> result.getRule().flatMap(ReportingDescriptorReference::getId).orElseThrow(() -> new RuntimeException("Either ruleId or rule.id must be present"))); + private static String getRuleId(Result result) throws SarifFormatException { + return result.getRuleId().orElseGet( + () -> result.getRule().flatMap(ReportingDescriptorReference::getId).orElseThrow(() -> new SarifFormatException("Either ruleId or rule.id must be present"))); } private static Optional getRuleIndex(Result result) { @@ -111,18 +145,18 @@ private static Optional getRuleIndex(Result result) { } @SuppressWarnings("OptionalUsedAsFieldOrParameterType") - private static String findMessage(Result result, ToolComponent driver, Optional rule) { + private static String findMessage(Result result, ToolComponent driver, Optional rule) throws SarifFormatException { return result.getMessage().getText().orElseGet(() -> lookupMessageById(result, driver, rule)); } @SuppressWarnings("OptionalUsedAsFieldOrParameterType") - private static String lookupMessageById(Result result, ToolComponent driver, Optional rule) { - String messageId = result.getMessage().getId().orElseThrow(() -> new RuntimeException("Either text or id must be present")); + private static String lookupMessageById(Result result, ToolComponent driver, Optional rule) throws SarifFormatException { + String messageId = result.getMessage().getId().orElseThrow(() -> new SarifFormatException("Either text or id must be present")); var ruleMessageString = rule.flatMap(ReportingDescriptor::getMessageStrings).map(MessageStrings::getAdditionalProperties).map(strings -> strings.get(messageId)); var globalMessageString = driver.getGlobalMessageStrings().map(GlobalMessageStrings::getAdditionalProperties).map(strings -> strings.get(messageId)); - var messageString = ruleMessageString.or(() -> globalMessageString).orElseThrow(() -> new RuntimeException("Message lookup failed")); + var messageString = ruleMessageString.or(() -> globalMessageString).orElseThrow(() -> new SarifFormatException("Message lookup failed")); return messageString.getText(); }