google-site-verification: google61fe8ba583a51912.html
CodeQL SARIF in Java

Introduction to CodeQL and SARIF

CodeQL is a semantic code analysis engine that lets you query code as data. SARIF (Static Analysis Results Interchange Format) is a standard format for output from static analysis tools. This guide covers generating, parsing, and working with SARIF files in Java.

Maven Dependencies

<properties> <sarif.version>2.1.0</sarif.version> <codeql.version>2.14.5</codeql.version> <jackson.version>2.15.2</jackson.version> </properties> <dependencies> <!-- SARIF SDK --> <dependency> <groupId>com.microsoft</groupId> <artifactId>sarif-java</artifactId> <version>${sarif.version}</version> </dependency> <!-- CodeQL --> <dependency> <groupId>com.github.codeql</groupId> <artifactId>codeql-java</artifactId> <version>${codeql.version}</version> </dependency> <!-- JSON Processing --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>${jackson.version}</version> </dependency> <!-- File Operations --> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.13.0</version> </dependency> </dependencies>

SARIF Data Models

Core SARIF Objects

public class SarifModels { // SARIF result severity levels public enum SeverityLevel { ERROR, WARNING, NOTE, NONE } // SARIF result kind public enum ResultKind { FAIL("fail"), PASS("pass"), REVIEW("review"), OPEN("open"), NOT_APPLICABLE("notApplicable"); private final String value; ResultKind(String value) { this.value = value; } public String getValue() { return value; } } // CodeQL-specific metadata public static class CodeQLMetadata { private String queryId; private String queryName; private String querySuite; private String precision; private List<String> tags; private Map<String, String> properties; // Constructors, getters, setters public CodeQLMetadata() {} public CodeQLMetadata(String queryId, String queryName, String querySuite) { this.queryId = queryId; this.queryName = queryName; this.querySuite = querySuite; this.tags = new ArrayList<>(); this.properties = new HashMap<>(); } public String getQueryId() { return queryId; } public void setQueryId(String queryId) { this.queryId = queryId; } public String getQueryName() { return queryName; } public void setQueryName(String queryName) { this.queryName = queryName; } public String getQuerySuite() { return querySuite; } public void setQuerySuite(String querySuite) { this.querySuite = querySuite; } public String getPrecision() { return precision; } public void setPrecision(String precision) { this.precision = precision; } public List<String> getTags() { return tags; } public void setTags(List<String> tags) { this.tags = tags; } public Map<String, String> getProperties() { return properties; } public void setProperties(Map<String, String> properties) { this.properties = properties; } } // Custom rule metadata public static class RuleMetadata { private String id; private String name; private String shortDescription; private String fullDescription; private String helpUri; private SeverityLevel defaultSeverity; private List<String> tags; // Constructors, getters, setters public RuleMetadata() {} public RuleMetadata(String id, String name, String shortDescription, SeverityLevel defaultSeverity) { this.id = id; this.name = name; this.shortDescription = shortDescription; this.defaultSeverity = defaultSeverity; this.tags = new ArrayList<>(); } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getShortDescription() { return shortDescription; } public void setShortDescription(String shortDescription) { this.shortDescription = shortDescription; } public String getFullDescription() { return fullDescription; } public void setFullDescription(String fullDescription) { this.fullDescription = fullDescription; } public String getHelpUri() { return helpUri; } public void setHelpUri(String helpUri) { this.helpUri = helpUri; } public SeverityLevel getDefaultSeverity() { return defaultSeverity; } public void setDefaultSeverity(SeverityLevel defaultSeverity) { this.defaultSeverity = defaultSeverity; } public List<String> getTags() { return tags; } public void setTags(List<String> tags) { this.tags = tags; } } }

SARIF Report Generation

Basic SARIF Generator

@Component public class SarifReportGenerator { private static final String SARIF_VERSION = "2.1.0"; private static final String SCHEMA_URL = "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json"; private final ObjectMapper objectMapper; public SarifReportGenerator() { this.objectMapper = new ObjectMapper(); this.objectMapper.enable(SerializationFeature.INDENT_OUTPUT); } public SarifReport createEmptyReport() { SarifReport report = new SarifReport(); report.setVersion(SARIF_VERSION); report.setSchema(SCHEMA_URL); report.setRuns(new ArrayList<>()); return report; } public Run createRun(String toolName, String toolVersion) { Run run = new Run(); // Tool information Tool tool = new Tool(); ToolComponent driver = new ToolComponent(); driver.setName(toolName); driver.setVersion(toolVersion); driver.setInformationUri("https://example.com/tool"); tool.setDriver(driver); run.setTool(tool); // Results and rules run.setResults(new ArrayList<>()); run.setRules(new HashMap<>()); // Additional properties run.setProperties(new HashMap<>()); return run; } public void addRuleToRun(Run run, RuleMetadata ruleMetadata) { ReportingDescriptor rule = new ReportingDescriptor(); rule.setId(ruleMetadata.getId()); rule.setName(ruleMetadata.getName()); // Description MultiformatMessageString shortDescription = new MultiformatMessageString(); shortDescription.setText(ruleMetadata.getShortDescription()); rule.setShortDescription(shortDescription); if (ruleMetadata.getFullDescription() != null) { MultiformatMessageString fullDescription = new MultiformatMessageString(); fullDescription.setText(ruleMetadata.getFullDescription()); rule.setFullDescription(fullDescription); } // Help URI if (ruleMetadata.getHelpUri() != null) { rule.setHelpUri(ruleMetadata.getHelpUri()); } // Properties rule.setProperties(new HashMap<>()); rule.getProperties().put("defaultSeverity", ruleMetadata.getDefaultSeverity().name()); if (!ruleMetadata.getTags().isEmpty()) { rule.getProperties().put("tags", ruleMetadata.getTags()); } run.getRules().put(ruleMetadata.getId(), rule); } public Result createResult(String ruleId, String message, SeverityLevel severity, ResultKind kind) { Result result = new Result(); result.setRuleId(ruleId); // Message Message messageObj = new Message(); messageObj.setText(message); result.setMessage(messageObj); // Severity and kind result.setLevel(severity.name().toLowerCase()); result.setKind(kind.getValue()); // Locations will be added separately result.setLocations(new ArrayList<>()); // Properties result.setProperties(new HashMap<>()); return result; } public Location createLocation(String filePath, int startLine, int startColumn, int endLine, int endColumn) { Location location = new Location(); // Physical location PhysicalLocation physicalLocation = new PhysicalLocation(); ArtifactLocation artifactLocation = new ArtifactLocation(); artifactLocation.setUri(filePath); physicalLocation.setArtifactLocation(artifactLocation); // Region Region region = new Region(); region.setStartLine(startLine); region.setStartColumn(startColumn); region.setEndLine(endLine); region.setEndColumn(endColumn); physicalLocation.setRegion(region); location.setPhysicalLocation(physicalLocation); return location; } public void addCodeQLMetadata(Result result, CodeQLMetadata metadata) { if (result.getProperties() == null) { result.setProperties(new HashMap<>()); } Map<String, Object> codeqlProps = new HashMap<>(); codeqlProps.put("queryId", metadata.getQueryId()); codeqlProps.put("queryName", metadata.getQueryName()); codeqlProps.put("querySuite", metadata.getQuerySuite()); if (metadata.getPrecision() != null) { codeqlProps.put("precision", metadata.getPrecision()); } if (!metadata.getTags().isEmpty()) { codeqlProps.put("tags", metadata.getTags()); } if (!metadata.getProperties().isEmpty()) { codeqlProps.put("properties", metadata.getProperties()); } result.getProperties().put("codeql", codeqlProps); } public void writeReportToFile(SarifReport report, Path outputPath) throws IOException { objectMapper.writeValue(outputPath.toFile(), report); } public String toJsonString(SarifReport report) throws JsonProcessingException { return objectMapper.writeValueAsString(report); } }

CodeQL Integration

CodeQL Results Processor

@Component public class CodeQLResultsProcessor { private final SarifReportGenerator sarifGenerator; public CodeQLResultsProcessor(SarifReportGenerator sarifGenerator) { this.sarifGenerator = sarifGenerator; } public SarifReport processCodeQLResults(Path codeqlResultsDir, String toolName, String toolVersion) throws IOException { SarifReport report = sarifGenerator.createEmptyReport(); Run run = sarifGenerator.createRun(toolName, toolVersion); // Process all SARIF files in the results directory Files.walk(codeqlResultsDir) .filter(path -> path.toString().endsWith(".sarif")) .forEach(sarifFile -> processSarifFile(sarifFile, run)); report.getRuns().add(run); return report; } private void processSarifFile(Path sarifFile, Run run) { try { ObjectMapper mapper = new ObjectMapper(); SarifReport fileReport = mapper.readValue(sarifFile.toFile(), SarifReport.class); if (fileReport.getRuns() != null) { fileReport.getRuns().forEach(fileRun -> { // Merge results if (fileRun.getResults() != null) { run.getResults().addAll(fileRun.getResults()); } // Merge rules if (fileRun.getRules() != null) { if (run.getRules() == null) { run.setRules(new HashMap<>()); } run.getRules().putAll(fileRun.getRules()); } }); } } catch (IOException e) { throw new RuntimeException("Failed to process SARIF file: " + sarifFile, e); } } public void filterResultsBySeverity(SarifReport report, SeverityLevel minSeverity) { for (Run run : report.getRuns()) { if (run.getResults() != null) { run.setResults( run.getResults().stream() .filter(result -> meetsSeverityThreshold(result, minSeverity)) .collect(Collectors.toList()) ); } } } private boolean meetsSeverityThreshold(Result result, SeverityLevel minSeverity) { String resultSeverity = result.getLevel(); if (resultSeverity == null) { return false; } SeverityLevel severity = SeverityLevel.valueOf(resultSeverity.toUpperCase()); return severity.ordinal() <= minSeverity.ordinal(); } public void groupResultsByRule(SarifReport report) { for (Run run : report.getRuns()) { if (run.getResults() != null) { Map<String, List<Result>> resultsByRule = run.getResults().stream() .collect(Collectors.groupingBy(Result::getRuleId)); // You can process grouped results here resultsByRule.forEach((ruleId, results) -> { System.out.printf("Rule %s: %d results%n", ruleId, results.size()); }); } } } }

Custom Analysis Results

Security Vulnerability Reporter

@Component public class SecurityVulnerabilityReporter { private final SarifReportGenerator sarifGenerator; private final Map<String, RuleMetadata> securityRules; public SecurityVulnerabilityReporter(SarifReportGenerator sarifGenerator) { this.sarifGenerator = sarifGenerator; this.securityRules = initializeSecurityRules(); } private Map<String, RuleMetadata> initializeSecurityRules() { Map<String, RuleMetadata> rules = new HashMap<>(); // SQL Injection rule rules.put("SQLI001", new RuleMetadata( "SQLI001", "SqlInjectionVulnerability", "Potential SQL injection vulnerability", SeverityLevel.ERROR )); // Path Traversal rule rules.put("PT001", new RuleMetadata( "PT001", "PathTraversalVulnerability", "Potential path traversal vulnerability", SeverityLevel.ERROR )); // Hardcoded Password rule rules.put("HCP001", new RuleMetadata( "HCP001", "HardcodedPassword", "Hardcoded password detected", SeverityLevel.WARNING )); // Insecure Deserialization rule rules.put("ID001", new RuleMetadata( "ID001", "InsecureDeserialization", "Potential insecure deserialization", SeverityLevel.ERROR )); return rules; } public SarifReport generateSecurityReport(List<SecurityFinding> findings) { SarifReport report = sarifGenerator.createEmptyReport(); Run run = sarifGenerator.createRun("JavaSecurityScanner", "1.0.0"); // Add security rules to the run securityRules.values().forEach(rule -> sarifGenerator.addRuleToRun(run, rule)); // Convert findings to SARIF results List<Result> results = findings.stream() .map(this::convertFindingToResult) .collect(Collectors.toList()); run.setResults(results); report.getRuns().add(run); return report; } private Result convertFindingToResult(SecurityFinding finding) { RuleMetadata rule = securityRules.get(finding.getRuleId()); if (rule == null) { throw new IllegalArgumentException("Unknown rule ID: " + finding.getRuleId()); } Result result = sarifGenerator.createResult( finding.getRuleId(), finding.getMessage(), rule.getDefaultSeverity(), ResultKind.FAIL ); // Add location Location location = sarifGenerator.createLocation( finding.getFilePath(), finding.getStartLine(), finding.getStartColumn(), finding.getEndLine(), finding.getEndColumn() ); result.getLocations().add(location); // Add additional properties if (result.getProperties() == null) { result.setProperties(new HashMap<>()); } result.getProperties().put("confidence", finding.getConfidence()); result.getProperties().put("cweId", finding.getCweId()); // Add code flow if available if (finding.getCodeFlow() != null) { result.setCodeFlows(createCodeFlows(finding.getCodeFlow())); } return result; } private List<CodeFlow> createCodeFlows(List<CodeFlowStep> steps) { CodeFlow codeFlow = new CodeFlow(); ThreadFlow threadFlow = new ThreadFlow(); List<ThreadFlowLocation> locations = steps.stream() .map(this::createThreadFlowLocation) .collect(Collectors.toList()); threadFlow.setLocations(locations); codeFlow.setThreadFlows(Arrays.asList(threadFlow)); return Arrays.asList(codeFlow); } private ThreadFlowLocation createThreadFlowLocation(CodeFlowStep step) { ThreadFlowLocation location = new ThreadFlowLocation(); Location sarifLocation = sarifGenerator.createLocation( step.getFilePath(), step.getLine(), step.getColumn(), step.getLine(), step.getColumn() ); location.setLocation(sarifLocation); // Add step-specific properties if (step.getMessage() != null) { Message message = new Message(); message.setText(step.getMessage()); location.setMessage(message); } return location; } public static class SecurityFinding { private String ruleId; private String message; private String filePath; private int startLine; private int startColumn; private int endLine; private int endColumn; private String confidence; private String cweId; private List<CodeFlowStep> codeFlow; // Constructors, getters, setters public SecurityFinding() {} public SecurityFinding(String ruleId, String message, String filePath, int startLine, int startColumn) { this.ruleId = ruleId; this.message = message; this.filePath = filePath; this.startLine = startLine; this.startColumn = startColumn; this.endLine = startLine; this.endColumn = startColumn; this.codeFlow = new ArrayList<>(); } // Getters and setters... public String getRuleId() { return ruleId; } public void setRuleId(String ruleId) { this.ruleId = ruleId; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public String getFilePath() { return filePath; } public void setFilePath(String filePath) { this.filePath = filePath; } public int getStartLine() { return startLine; } public void setStartLine(int startLine) { this.startLine = startLine; } public int getStartColumn() { return startColumn; } public void setStartColumn(int startColumn) { this.startColumn = startColumn; } public int getEndLine() { return endLine; } public void setEndLine(int endLine) { this.endLine = endLine; } public int getEndColumn() { return endColumn; } public void setEndColumn(int endColumn) { this.endColumn = endColumn; } public String getConfidence() { return confidence; } public void setConfidence(String confidence) { this.confidence = confidence; } public String getCweId() { return cweId; } public void setCweId(String cweId) { this.cweId = cweId; } public List<CodeFlowStep> getCodeFlow() { return codeFlow; } public void setCodeFlow(List<CodeFlowStep> codeFlow) { this.codeFlow = codeFlow; } } public static class CodeFlowStep { private String filePath; private int line; private int column; private String message; // Constructors, getters, setters public CodeFlowStep() {} public CodeFlowStep(String filePath, int line, int column) { this.filePath = filePath; this.line = line; this.column = column; } public String getFilePath() { return filePath; } public void setFilePath(String filePath) { this.filePath = filePath; } public int getLine() { return line; } public void setLine(int line) { this.line = line; } public int getColumn() { return column; } public void setColumn(int column) { this.column = column; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } } }

SARIF Report Analysis

SARIF Report Analyzer

@Component public class SarifReportAnalyzer { public AnalysisResult analyzeSarifReport(SarifReport report) { AnalysisResult result = new AnalysisResult(); for (Run run : report.getRuns()) { RunAnalysis runAnalysis = analyzeRun(run); result.addRunAnalysis(runAnalysis); } return result; } private RunAnalysis analyzeRun(Run run) { RunAnalysis analysis = new RunAnalysis(); if (run.getResults() != null) { // Count by severity Map<String, Long> severityCounts = run.getResults().stream() .collect(Collectors.groupingBy( result -> result.getLevel() != null ? result.getLevel() : "unknown", Collectors.counting() )); analysis.setSeverityCounts(severityCounts); // Count by rule Map<String, Long> ruleCounts = run.getResults().stream() .collect(Collectors.groupingBy( Result::getRuleId, Collectors.counting() )); analysis.setRuleCounts(ruleCounts); // Find most common issues analysis.setMostCommonRules(findMostCommonRules(ruleCounts)); // Calculate statistics analysis.setTotalIssues(run.getResults().size()); analysis.setErrorCount(severityCounts.getOrDefault("error", 0L)); analysis.setWarningCount(severityCounts.getOrDefault("warning", 0L)); } return analysis; } private List<String> findMostCommonRules(Map<String, Long> ruleCounts) { return ruleCounts.entrySet().stream() .sorted(Map.Entry.<String, Long>comparingByValue().reversed()) .limit(10) .map(Map.Entry::getKey) .collect(Collectors.toList()); } public List<Result> findResultsByRule(SarifReport report, String ruleId) { List<Result> results = new ArrayList<>(); for (Run run : report.getRuns()) { if (run.getResults() != null) { results.addAll( run.getResults().stream() .filter(result -> ruleId.equals(result.getRuleId())) .collect(Collectors.toList()) ); } } return results; } public Map<String, List<Result>> groupResultsByFile(SarifReport report) { Map<String, List<Result>> resultsByFile = new HashMap<>(); for (Run run : report.getRuns()) { if (run.getResults() != null) { for (Result result : run.getResults()) { if (result.getLocations() != null && !result.getLocations().isEmpty()) { String filePath = extractFilePath(result.getLocations().get(0)); resultsByFile.computeIfAbsent(filePath, k -> new ArrayList<>()) .add(result); } } } } return resultsByFile; } private String extractFilePath(Location location) { if (location.getPhysicalLocation() != null && location.getPhysicalLocation().getArtifactLocation() != null) { return location.getPhysicalLocation().getArtifactLocation().getUri(); } return "unknown"; } public static class AnalysisResult { private List<RunAnalysis> runAnalyses = new ArrayList<>(); private Map<String, Object> summary = new HashMap<>(); public void addRunAnalysis(RunAnalysis runAnalysis) { runAnalyses.add(runAnalysis); } // Getters and setters public List<RunAnalysis> getRunAnalyses() { return runAnalyses; } public void setRunAnalyses(List<RunAnalysis> runAnalyses) { this.runAnalyses = runAnalyses; } public Map<String, Object> getSummary() { return summary; } public void setSummary(Map<String, Object> summary) { this.summary = summary; } } public static class RunAnalysis { private Map<String, Long> severityCounts = new HashMap<>(); private Map<String, Long> ruleCounts = new HashMap<>(); private List<String> mostCommonRules = new ArrayList<>(); private long totalIssues; private long errorCount; private long warningCount; // Getters and setters public Map<String, Long> getSeverityCounts() { return severityCounts; } public void setSeverityCounts(Map<String, Long> severityCounts) { this.severityCounts = severityCounts; } public Map<String, Long> getRuleCounts() { return ruleCounts; } public void setRuleCounts(Map<String, Long> ruleCounts) { this.ruleCounts = ruleCounts; } public List<String> getMostCommonRules() { return mostCommonRules; } public void setMostCommonRules(List<String> mostCommonRules) { this.mostCommonRules = mostCommonRules; } public long getTotalIssues() { return totalIssues; } public void setTotalIssues(long totalIssues) { this.totalIssues = totalIssues; } public long getErrorCount() { return errorCount; } public void setErrorCount(long errorCount) { this.errorCount = errorCount; } public long getWarningCount() { return warningCount; } public void setWarningCount(long warningCount) { this.warningCount = warningCount; } } }

SARIF Report Rendering

HTML Report Generator

@Component public class SarifHtmlRenderer { private final TemplateEngine templateEngine; public SarifHtmlRenderer() { this.templateEngine = new ThymeleafTemplateEngine(); } public String generateHtmlReport(SarifReport report, SarifReportAnalyzer.AnalysisResult analysis) { Context context = new Context(); context.setVariable("report", report); context.setVariable("analysis", analysis); context.setVariable("timestamp", Instant.now()); return templateEngine.process("sarif-report", context); } public void writeHtmlReport(SarifReport report, Path outputPath) throws IOException { SarifReportAnalyzer analyzer = new SarifReportAnalyzer(); SarifReportAnalyzer.AnalysisResult analysis = analyzer.analyzeSarifReport(report); String html = generateHtmlReport(report, analysis); Files.writeString(outputPath, html, StandardCharsets.UTF_8); } public String generateResultsTable(List<Result> results) { StringBuilder html = new StringBuilder(); html.append("<table class=\"sarif-results\">"); html.append("<thead><tr><th>Rule</th><th>Message</th><th>Location</th><th>Severity</th></tr></thead>"); html.append("<tbody>"); for (Result result : results) { html.append("<tr>"); html.append("<td>").append(escapeHtml(result.getRuleId())).append("</td>"); html.append("<td>").append(escapeHtml(result.getMessage().getText())).append("</td>"); html.append("<td>").append(formatLocation(result)).append("</td>"); html.append("<td class=\"severity-").append(result.getLevel()).append("\">") .append(result.getLevel()).append("</td>"); html.append("</tr>"); } html.append("</tbody></table>"); return html.toString(); } private String formatLocation(Result result) { if (result.getLocations() == null || result.getLocations().isEmpty()) { return "Unknown location"; } Location location = result.getLocations().get(0); if (location.getPhysicalLocation() == null) { return "Unknown location"; } ArtifactLocation artifact = location.getPhysicalLocation().getArtifactLocation(); Region region = location.getPhysicalLocation().getRegion(); StringBuilder sb = new StringBuilder(); if (artifact != null && artifact.getUri() != null) { sb.append(artifact.getUri()); } if (region != null) { sb.append(":").append(region.getStartLine()); if (region.getStartColumn() != null) { sb.append(":").append(region.getStartColumn()); } } return sb.toString(); } private String escapeHtml(String text) { if (text == null) { return ""; } return text.replace("&", "&amp;") .replace("<", "&lt;") .replace(">", "&gt;") .replace("\"", "&quot;") .replace("'", "&#39;"); } // Simple Thymeleaf-like template engine for demonstration private static class ThymeleafTemplateEngine { public String process(String templateName, Context context) { // In real implementation, this would use actual Thymeleaf return generateBasicHtmlReport(context); } private String generateBasicHtmlReport(Context context) { SarifReport report = (SarifReport) context.getVariable("report"); SarifReportAnalyzer.AnalysisResult analysis = (SarifReportAnalyzer.AnalysisResult) context.getVariable("analysis"); StringBuilder html = new StringBuilder(); html.append(""" <!DOCTYPE html> <html> <head> <title>SARIF Report</title> <style> body { font-family: Arial, sans-serif; margin: 20px; } .summary { background: #f5f5f5; padding: 15px; border-radius: 5px; } .severity-error { color: #d32f2f; font-weight: bold; } .severity-warning { color: #f57c00; font-weight: bold; } .severity-note { color: #1976d2; } table { width: 100%; border-collapse: collapse; } th, td { padding: 8px; text-align: left; border-bottom: 1px solid #ddd; } th { background-color: #f2f2f2; } </style> </head> <body> <h1>SARIF Analysis Report</h1> <div class="summary"> <h2>Summary</h2> <p>Total Issues: %d</p> <p>Errors: %d</p> <p>Warnings: %d</p> </div> """.formatted( analysis.getRunAnalyses().stream().mapToLong(RunAnalysis::getTotalIssues).sum(), analysis.getRunAnalyses().stream().mapToLong(RunAnalysis::getErrorCount).sum(), analysis.getRunAnalyses().stream().mapToLong(RunAnalysis::getWarningCount).sum() )); // Add results tables for each run for (int i = 0; i < report.getRuns().size(); i++) { Run run = report.getRuns().get(i); html.append("<h2>Run ").append(i + 1).append(": ").append(run.getTool().getDriver().getName()).append("</h2>"); if (run.getResults() != null && !run.getResults().isEmpty()) { html.append(generateResultsTable(run.getResults())); } else { html.append("<p>No results found.</p>"); } } html.append("</body></html>"); return html.toString(); } } }

Integration with CI/CD

GitHub Actions Integration

name: CodeQL SARIF Processing on: push: branches: [ main, develop ] pull_request: branches: [ main ] jobs: codeql-analysis: runs-on: ubuntu-latest permissions: security-events: write steps: - name: Checkout repository uses: actions/checkout@v3 - name: Set up JDK 17 uses: actions/setup-java@v3 with: java-version: '17' distribution: 'temurin' - name: Initialize CodeQL uses: github/codeql-action/init@v2 with: languages: java - name: Build application run: mvn compile -DskipTests - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v2 with: category: "/language:java" - name: Process SARIF Results run: | java -cp target/classes com.example.SarifProcessor \ --input results/java.sarif \ --output processed-results.sarif \ --format html - name: Upload SARIF Results uses: github/codeql-action/upload-sarif@v2 with: sarif_file: processed-results.sarif - name: Generate HTML Report run: | java -cp target/classes com.example.HtmlReportGenerator \ --input processed-results.sarif \ --output report.html - name: Upload HTML Report uses: actions/upload-artifact@v3 with: name: codeql-report path: report.html

Conclusion

This comprehensive CodeQL SARIF implementation in Java provides:

  1. SARIF Generation - Create standardized static analysis reports
  2. CodeQL Integration - Process and enhance CodeQL results
  3. Security Reporting - Generate security-focused SARIF reports
  4. Report Analysis - Analyze and statistics from SARIF files
  5. HTML Rendering - Convert SARIF to human-readable HTML reports
  6. CI/CD Integration - GitHub Actions workflow integration

The implementation enables seamless processing of static analysis results, providing actionable insights and beautiful reports for development teams.

Secure Java Dependency Management, Vulnerability Scanning & Software Supply Chain Protection (SBOM, SCA, CI Security & License Compliance)

https://macronepal.com/blog/github-code-scanning-in-java-complete-guide/
Explains GitHub Code Scanning for Java using tools like CodeQL to automatically analyze source code and detect security vulnerabilities directly inside CI/CD pipelines before deployment.

https://macronepal.com/blog/license-compliance-in-java-comprehensive-guide/
Explains software license compliance in Java projects, ensuring dependencies follow legal requirements (MIT, Apache, GPL, etc.) and preventing license violations in enterprise software.

https://macronepal.com/blog/container-security-for-java-uncovering-vulnerabilities-with-grype/
Explains using Grype to scan Java container images and filesystems for known CVEs in OS packages and application dependencies to improve container security.

https://macronepal.com/blog/syft-sbom-generation-in-java-comprehensive-software-bill-of-materials-for-jvm-applications/
Explains using Syft to generate SBOMs (Software Bill of Materials) for Java applications, listing all dependencies, libraries, and components for supply chain transparency.

https://macronepal.com/blog/comprehensive-dependency-analysis-generating-and-scanning-sboms-with-trivy-for-java/
Explains using Trivy to generate SBOMs and scan Java dependencies and container images for vulnerabilities, integrating security checks into CI/CD pipelines.

https://macronepal.com/blog/dependabot-for-java-in-java/
Explains GitHub Dependabot for Java projects, which automatically detects vulnerable dependencies and creates pull requests to update them securely.

https://macronepal.com/blog/parasoft-jtest-in-java-comprehensive-guide-to-code-analysis-and-testing/
Explains Parasoft Jtest, a static analysis and testing tool for Java that helps detect bugs, security issues, and code quality problems early in development.

https://macronepal.com/blog/snyk-open-source-in-java-comprehensive-dependency-vulnerability-management-2/
Explains Snyk Open Source for Java, which continuously scans dependencies for vulnerabilities and provides automated fix suggestions and monitoring.

https://macronepal.com/blog/owasp-dependency-check-in-java-complete-vulnerability-scanning-guide/
Explains OWASP Dependency-Check, which scans Java dependencies against the National Vulnerability Database (NVD) to detect known security vulnerabilities.

https://macronepal.com/blog/securing-your-dependencies-a-java-developers-guide-to-whitesource-mend-bolt/
Explains Mend (WhiteSource) Bolt for Java, a dependency management and SCA tool that provides vulnerability detection, license compliance, and security policy enforcement in enterprise environments.

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper