GitHub Code Scanning in Java: Automated Security and Quality Analysis

GitHub Code Scanning provides automated security vulnerability scanning and code quality analysis directly within your GitHub repositories. For Java projects, it integrates with tools like CodeQL, SonarCloud, and third-party scanners to identify issues early in the development lifecycle.

Understanding GitHub Code Scanning Architecture

Key Components:

  • CodeQL - GitHub's semantic code analysis engine
  • SARIF (Static Analysis Results Interchange Format) support
  • Security alerts and vulnerability reporting
  • Pull request integration with status checks
  • Custom query support for project-specific rules

Core Implementation Patterns

1. GitHub Actions Configuration

Configure comprehensive code scanning workflows for Java projects.

.github/workflows/codeql-analysis.yml:

name: "CodeQL Advanced Analysis"
on:
push:
branches: [ main, develop, feature/** ]
pull_request:
branches: [ main ]
schedule:
- cron: '0 0 * * 0'  # Weekly scan
env:
JAVA_VERSION: '17'
MAVEN_OPTS: '--add-opens java.base/java.lang=ALL-UNNAMED'
jobs:
analyze:
name: Analyze Java Code
runs-on: ubuntu-latest
permissions:
security-events: write
actions: read
contents: read
strategy:
fail-fast: false
matrix:
language: [ 'java' ]
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Java
uses: actions/setup-java@v3
with:
java-version: ${{ env.JAVA_VERSION }}
distribution: 'temurin'
cache: 'maven'
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
queries: security-and-quality,security-extended
config-file: ./.github/codeql/codeql-config.yml
- name: Build with Maven
run: |
mvn -B clean compile test-compile -DskipTests
# Build for autobuilder
mvn -B package -DskipTests --file pom.xml
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
with:
category: "/language:${{ matrix.language }}"
output: codeql-results.sarif
upload-database: true
- name: Upload SARIF results
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: codeql-results.sarif
wait-for-processing: true
security-scan:
name: Security Vulnerability Scan
runs-on: ubuntu-latest
permissions:
security-events: write
contents: read
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Run OWASP Dependency Check
uses: dependency-check/Dependency-Check@main
with:
project: 'my-java-app'
path: '.'
format: 'SARIF'
out: 'dependency-check-results.sarif'
- name: Upload Dependency Check Results
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: dependency-check-results.sarif
quality-scan:
name: Code Quality Analysis
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Java
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
- name: Run SpotBugs Analysis
run: |
mvn -B spotbugs:spotbugs
mvn -B spotbugs:spotbugs -Dspotbugs.includeTests=true
- name: Run PMD Analysis
run: |
mvn -B pmd:pmd
mvn -B pmd:pmd -Dpmd.includeTests=true
- name: Generate SARIF from SpotBugs
uses: advanced-security/spotbugs-sarif@v1
with:
spotbugs-version: '4.7.3'
path: target/spotbugs.xml
output: spotbugs-results.sarif
- name: Upload Quality Results
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: spotbugs-results.sarif

.github/codeql/codeql-config.yml:

name: "Custom Java CodeQL Configuration"
paths:
- src/main/java
- src/test/java
paths-ignore:
- '**/generated/**'
- '**/target/**'
- '**/test/resources/**'
- '**/build/**'
queries:
- uses: security-and-quality
- uses: security-extended
- name: Custom Java queries
uses: ./.github/codeql/custom-queries
query-filters:
- exclude:
id: java/example/too-many-parameters
- include:
problem.severity: error
languages:
- java
packs:
- codeql/java-queries

2. CodeQL Custom Queries

Implement project-specific CodeQL queries for custom security and quality rules.

.github/codeql/custom-queries/java/security/SqlInjection.ql:

/**
* @name Potential SQL injection
* @description Detects potential SQL injection vulnerabilities in Java code
* @kind path-problem
* @problem.severity error
* @security-severity 9.8
* @precision high
* @id java/sql-injection
* @tags security
*       external/cwe/cwe-089
*/
import java
import semmle.code.java.dataflow.DataFlow
import semmle.code.java.dataflow.TaintTracking
import SqlInjectionQuery
from SqlInjectionQuery query, Expr sink
where query.hasFlowTo(sink)
select sink, "Potential SQL injection vulnerability", sink,
"User input reaches this SQL query execution point"

.github/codeql/custom-queries/java/quality/ThreadSafeCollection.ql:

/**
* @name Non-thread-safe collection usage
* @description Detects potential thread safety issues with collections
* @kind problem
* @problem.severity warning
* @precision medium
* @id java/non-thread-safe-collection
* @tags maintainability
*       reliability
*/
import java
from MethodAccess access, Method method
where
method.hasName("add") or
method.hasName("remove") or
method.hasName("put") or
method.hasName("get")
and method.getDeclaringType().hasQualifiedName("java.util", "ArrayList")
or method.getDeclaringType().hasQualifiedName("java.util", "HashMap")
or method.getDeclaringType().hasQualifiedName("java.util", "HashSet")
and exists(Field field | field.getType() = method.getDeclaringType() |
access.getQualifier() = field.getAnAccess() |
not field.isVolatile() |
not field.isSynchronized()
)
select access, "Non-thread-safe collection operation in potentially shared context"

.github/codeql/custom-queries/java/security/UnvalidatedRedirect.ql:

/**
* @name Unvalidated redirect
* @description Detects potential unvalidated redirect vulnerabilities
* @kind path-problem
* @problem.severity warning
* @security-severity 6.1
* @precision medium
* @id java/unvalidated-redirect
* @tags security
*       external/cwe/cwe-601
*/
import java
import semmle.code.java.dataflow.DataFlow
import semmle.code.java.dataflow.TaintTracking
class RedirectSink extends DataFlow::Node {
RedirectSink() {
exists(MethodAccess ma |
ma.getMethod().hasName("sendRedirect") and
ma.getMethod().getDeclaringType().hasQualifiedName("javax.servlet.http", "HttpServletResponse") and
this.asExpr() = ma.getArgument(0)
)
}
}
class UserInputSource extends DataFlow::Node {
UserInputSource() {
exists(Method m |
m.hasName("getParameter") and
m.getDeclaringType().hasQualifiedName("javax.servlet.http", "HttpServletRequest") and
this.asExpr() = m.getACall()
)
}
}
from UserInputSource source, RedirectSink sink, DataFlow::PathNode path
where DataFlow::localFlow(path, source, sink)
select sink, "Potential unvalidated redirect from user input", path

3. Security Scanning Integration

Integrate multiple security scanning tools with GitHub Code Scanning.

Security Scanning Service:

@Service
@Slf4j
public class SecurityScanningService {
private final CodeQLAnalysisService codeqlService;
private final DependencyScanService dependencyScanService;
private final SastScanService sastScanService;
private final GitHubSecurityClient githubClient;
public SecurityScanningService(CodeQLAnalysisService codeqlService,
DependencyScanService dependencyScanService,
SastScanService sastScanService,
GitHubSecurityClient githubClient) {
this.codeqlService = codeqlService;
this.dependencyScanService = dependencyScanService;
this.sastScanService = sastScanService;
this.githubClient = githubClient;
}
/**
* Perform comprehensive security scan
*/
public SecurityScanResult performSecurityScan(String repository, String commitHash) {
log.info("Starting security scan for repository: {}, commit: {}", repository, commitHash);
SecurityScanResult result = new SecurityScanResult();
result.setRepository(repository);
result.setCommitHash(commitHash);
result.setScanDate(Instant.now());
try {
// Run CodeQL analysis
CodeQLResult codeqlResult = codeqlService.analyzeRepository(repository, commitHash);
result.setCodeqlResults(codeqlResult);
// Run dependency vulnerability scan
DependencyScanResult dependencyResult = dependencyScanService.scanDependencies(repository);
result.setDependencyResults(dependencyResult);
// Run SAST scan
SastScanResult sastResult = sastScanService.performSastScan(repository);
result.setSastResults(sastResult);
// Upload results to GitHub Security
uploadSecurityResults(result);
result.setStatus(SecurityScanStatus.COMPLETED);
log.info("Security scan completed for repository: {}", repository);
} catch (Exception e) {
log.error("Security scan failed for repository: {}", repository, e);
result.setStatus(SecurityScanStatus.FAILED);
result.setErrorMessage(e.getMessage());
}
return result;
}
/**
* Check security gate status
*/
public SecurityGateStatus checkSecurityGate(String repository, String commitHash) {
SecurityScanResult scanResult = performSecurityScan(repository, commitHash);
SecurityGateStatus gateStatus = new SecurityGateStatus();
gateStatus.setRepository(repository);
gateStatus.setCommitHash(commitHash);
gateStatus.setCheckTime(Instant.now());
// Evaluate security criteria
gateStatus.setPassed(evaluateSecurityCriteria(scanResult));
gateStatus.setCriticalIssues(scanResult.getCriticalIssues());
gateStatus.setHighIssues(scanResult.getHighIssues());
gateStatus.setMediumIssues(scanResult.getMediumIssues());
gateStatus.setBlockingIssues(identifyBlockingIssues(scanResult));
// Update GitHub status check
updateGitHubSecurityStatus(repository, commitHash, gateStatus);
return gateStatus;
}
/**
* Generate security report
*/
public SecurityReport generateSecurityReport(String repository, String branch, int days) {
List<SecurityScanResult> historicalScans = getHistoricalScans(repository, branch, days);
SecurityTrends trends = analyzeSecurityTrends(historicalScans);
SecurityReport report = new SecurityReport();
report.setRepository(repository);
report.setBranch(branch);
report.setReportDate(Instant.now());
report.setAnalysisPeriod(days);
report.setCurrentSecurityState(assessCurrentSecurityState(historicalScans));
report.setSecurityTrends(trends);
report.setRecommendations(generateSecurityRecommendations(trends));
report.setRiskAssessment(assessSecurityRisk(historicalScans));
return report;
}
private boolean evaluateSecurityCriteria(SecurityScanResult result) {
// Block on critical security issues
if (result.getCriticalIssues() > 0) {
return false;
}
// Block on high severity issues exceeding threshold
if (result.getHighIssues() > getSecurityThreshold("high_issues")) {
return false;
}
// Check for specific high-risk vulnerability patterns
if (hasHighRiskVulnerabilities(result)) {
return false;
}
return true;
}
private void uploadSecurityResults(SecurityScanResult result) {
// Convert to SARIF format
SarifReport sarifReport = convertToSarif(result);
// Upload to GitHub Security
githubClient.uploadSecurityScanResults(
result.getRepository(),
result.getCommitHash(),
sarifReport
);
log.info("Uploaded security results for commit: {}", result.getCommitHash());
}
private void updateGitHubSecurityStatus(String repository, String commitHash, 
SecurityGateStatus gateStatus) {
GitHubStatus status = new GitHubStatus();
status.setContext("security/gate");
status.setState(gateStatus.isPassed() ? "success" : "failure");
status.setDescription(generateSecurityStatusDescription(gateStatus));
status.setTargetUrl(generateSecurityReportUrl(repository, commitHash));
githubClient.createStatus(repository, commitHash, status);
}
// Additional security scanning methods...
}
@Data
public class SecurityScanResult {
private String repository;
private String commitHash;
private Instant scanDate;
private SecurityScanStatus status;
private String errorMessage;
private CodeQLResult codeqlResults;
private DependencyScanResult dependencyResults;
private SastScanResult sastResults;
private int criticalIssues;
private int highIssues;
private int mediumIssues;
private int lowIssues;
private List<SecurityIssue> blockingIssues;
public int getTotalIssues() {
return criticalIssues + highIssues + mediumIssues + lowIssues;
}
public boolean hasCriticalIssues() {
return criticalIssues > 0;
}
}
@Data
public class SecurityGateStatus {
private String repository;
private String commitHash;
private Instant checkTime;
private boolean passed;
private int criticalIssues;
private int highIssues;
private int mediumIssues;
private List<SecurityIssue> blockingIssues;
private String rejectionReason;
public boolean isBlocked() {
return !passed || !blockingIssues.isEmpty();
}
}
@Data
public class SecurityReport {
private String repository;
private String branch;
private Instant reportDate;
private int analysisPeriod;
private SecurityState currentSecurityState;
private SecurityTrends securityTrends;
private List<SecurityRecommendation> recommendations;
private RiskAssessment riskAssessment;
public enum SecurityState {
EXCELLENT, GOOD, FAIR, POOR, CRITICAL
}
}

4. Dependency Vulnerability Scanning

Implement comprehensive dependency vulnerability scanning.

Dependency Scanning Service:

@Service
@Slf4j
public class DependencyScanService {
private final OWASPDependencyCheckService owaspService;
private final SnykScanService snykService;
private final GitHubAdvisoryService advisoryService;
private final VulnerabilityDatabase vulnerabilityDb;
public DependencyScanService(OWASPDependencyCheckService owaspService,
SnykScanService snykService,
GitHubAdvisoryService advisoryService,
VulnerabilityDatabase vulnerabilityDb) {
this.owaspService = owaspService;
this.snykService = snykService;
this.advisoryService = advisoryService;
this.vulnerabilityDb = vulnerabilityDb;
}
/**
* Scan project dependencies for vulnerabilities
*/
public DependencyScanResult scanDependencies(String repository) {
log.info("Starting dependency scan for repository: {}", repository);
DependencyScanResult result = new DependencyScanResult();
result.setRepository(repository);
result.setScanDate(Instant.now());
try {
// Parse project dependencies
List<ProjectDependency> dependencies = parseDependencies(repository);
result.setDependencies(dependencies);
// Scan with multiple vulnerability databases
List<VulnerabilityFinding> owaspFindings = owaspService.scanDependencies(dependencies);
List<VulnerabilityFinding> snykFindings = snykService.scanDependencies(dependencies);
List<VulnerabilityFinding> githubFindings = advisoryService.checkAdvisories(dependencies);
// Merge and deduplicate findings
List<VulnerabilityFinding> allFindings = mergeFindings(
owaspFindings, snykFindings, githubFindings);
result.setVulnerabilities(allFindings);
// Calculate risk metrics
calculateRiskMetrics(result);
// Generate remediation advice
result.setRemediationAdvice(generateRemediationAdvice(allFindings));
result.setStatus(ScanStatus.COMPLETED);
log.info("Dependency scan completed for repository: {}", repository);
} catch (Exception e) {
log.error("Dependency scan failed for repository: {}", repository, e);
result.setStatus(ScanStatus.FAILED);
result.setErrorMessage(e.getMessage());
}
return result;
}
/**
* Check for vulnerable dependencies in pull request
*/
public PullRequestDependencyCheck checkPullRequestDependencies(PullRequestEvent event) {
List<ProjectDependency> currentDependencies = parseDependencies(event.getBaseCommit());
List<ProjectDependency> prDependencies = parseDependencies(event.getHeadCommit());
PullRequestDependencyCheck check = new PullRequestDependencyCheck();
check.setPullRequestId(event.getPrNumber());
check.setRepository(event.getRepository());
check.setCheckDate(Instant.now());
// Identify new and updated dependencies
List<DependencyChange> changes = identifyDependencyChanges(
currentDependencies, prDependencies);
check.setDependencyChanges(changes);
// Check new dependencies for vulnerabilities
List<VulnerabilityFinding> newVulnerabilities = scanNewDependencies(changes);
check.setNewVulnerabilities(newVulnerabilities);
// Check for dependency upgrades that fix vulnerabilities
List<VulnerabilityFix> vulnerabilityFixes = identifyVulnerabilityFixes(changes);
check.setVulnerabilityFixes(vulnerabilityFixes);
// Generate PR comment
String prComment = generateDependencyCheckComment(check);
check.setPrComment(prComment);
return check;
}
/**
* Generate dependency security report
*/
public DependencySecurityReport generateSecurityReport(String repository) {
DependencyScanResult scanResult = scanDependencies(repository);
List<DependencyScanResult> historicalScans = getHistoricalDependencyScans(repository, 90);
DependencySecurityReport report = new DependencySecurityReport();
report.setRepository(repository);
report.setReportDate(Instant.now());
report.setCurrentState(scanResult);
report.setHistoricalTrends(analyzeDependencyTrends(historicalScans));
report.setRiskAssessment(assessDependencyRisk(scanResult));
report.setActionPlan(generateDependencyActionPlan(scanResult));
return report;
}
/**
* Monitor dependencies for new vulnerabilities
*/
public List<VulnerabilityAlert> monitorDependencies(String repository) {
DependencyScanResult lastScan = getLastDependencyScan(repository);
List<VulnerabilityFinding> newVulnerabilities = checkForNewVulnerabilities(lastScan);
List<VulnerabilityAlert> alerts = newVulnerabilities.stream()
.map(this::createVulnerabilityAlert)
.collect(Collectors.toList());
// Send alerts if new vulnerabilities found
if (!alerts.isEmpty()) {
sendVulnerabilityAlerts(repository, alerts);
}
return alerts;
}
private List<ProjectDependency> parseDependencies(String repository) {
// Parse Maven pom.xml or Gradle build files
try {
Path pomPath = Paths.get(repository, "pom.xml");
if (Files.exists(pomPath)) {
return parseMavenDependencies(pomPath);
}
Path gradlePath = Paths.get(repository, "build.gradle");
if (Files.exists(gradlePath)) {
return parseGradleDependencies(gradlePath);
}
throw new DependencyScanException("No dependency file found in repository: " + repository);
} catch (Exception e) {
throw new DependencyScanException("Failed to parse dependencies", e);
}
}
private List<ProjectDependency> parseMavenDependencies(Path pomPath) throws Exception {
List<ProjectDependency> dependencies = new ArrayList<>();
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(pomPath.toFile());
NodeList dependencyNodes = document.getElementsByTagName("dependency");
for (int i = 0; i < dependencyNodes.getLength(); i++) {
Element dependencyElement = (Element) dependencyNodes.item(i);
String groupId = getElementText(dependencyElement, "groupId");
String artifactId = getElementText(dependencyElement, "artifactId");
String version = getElementText(dependencyElement, "version");
String scope = getElementText(dependencyElement, "scope");
if (groupId != null && artifactId != null && version != null) {
ProjectDependency dependency = new ProjectDependency();
dependency.setGroupId(groupId);
dependency.setArtifactId(artifactId);
dependency.setVersion(version);
dependency.setScope(scope != null ? scope : "compile");
dependencies.add(dependency);
}
}
return dependencies;
}
// Additional dependency scanning methods...
}
@Data
public class DependencyScanResult {
private String repository;
private Instant scanDate;
private ScanStatus status;
private String errorMessage;
private List<ProjectDependency> dependencies;
private List<VulnerabilityFinding> vulnerabilities;
private int criticalVulnerabilities;
private int highVulnerabilities;
private int mediumVulnerabilities;
private int lowVulnerabilities;
private DependencyRiskLevel overallRisk;
private List<RemediationAdvice> remediationAdvice;
public int getTotalVulnerabilities() {
return criticalVulnerabilities + highVulnerabilities + 
mediumVulnerabilities + lowVulnerabilities;
}
public boolean hasCriticalVulnerabilities() {
return criticalVulnerabilities > 0;
}
}
@Data
public class ProjectDependency {
private String groupId;
private String artifactId;
private String version;
private String scope;
private String type; // direct, transitive
private List<LicenseInfo> licenses;
public String getCoordinates() {
return groupId + ":" + artifactId + ":" + version;
}
}
@Data
public class VulnerabilityFinding {
private String id;
private String cveId;
private String description;
private VulnerabilitySeverity severity;
private double cvssScore;
private List<String> affectedVersions;
private String fixedVersion;
private List<String> references;
private ProjectDependency affectedDependency;
private Instant publishedDate;
private List<String> attackVectors;
public boolean isFixAvailable() {
return fixedVersion != null && !fixedVersion.isEmpty();
}
}

5. SAST (Static Application Security Testing) Integration

Integrate multiple SAST tools for comprehensive security analysis.

SAST Scanning Service:

@Service
@Slf4j
public class SastScanService {
private final SpotBugsService spotBugsService;
private final PMDService pmdService;
private final CheckstyleService checkstyleService;
private final SonarQubeService sonarQubeService;
private final SARIFConverter sarifConverter;
public SastScanService(SpotBugsService spotBugsService,
PMDService pmdService,
CheckstyleService checkstyleService,
SonarQubeService sonarQubeService,
SARIFConverter sarifConverter) {
this.spotBugsService = spotBugsService;
this.pmdService = pmdService;
this.checkstyleService = checkstyleService;
this.sonarQubeService = sonarQubeService;
this.sarifConverter = sarifConverter;
}
/**
* Perform comprehensive SAST scan
*/
public SastScanResult performSastScan(String repository) {
log.info("Starting SAST scan for repository: {}", repository);
SastScanResult result = new SastScanResult();
result.setRepository(repository);
result.setScanDate(Instant.now());
try {
// Run multiple SAST tools
SpotBugsResult spotBugsResult = spotBugsService.analyze(repository);
PMDResult pmdResult = pmdService.analyze(repository);
CheckstyleResult checkstyleResult = checkstyleService.analyze(repository);
SonarQubeResult sonarResult = sonarQubeService.analyze(repository);
// Merge results
result.setSpotBugsResults(spotBugsResult);
result.setPmdResults(pmdResult);
result.setCheckstyleResults(checkstyleResult);
result.setSonarQubeResults(sonarResult);
// Aggregate findings
List<SastFinding> allFindings = aggregateFindings(
spotBugsResult, pmdResult, checkstyleResult, sonarResult);
result.setFindings(allFindings);
// Calculate metrics
calculateSastMetrics(result);
// Generate SARIF report for GitHub
SarifReport sarifReport = sarifConverter.convertToSarif(allFindings);
result.setSarifReport(sarifReport);
result.setStatus(ScanStatus.COMPLETED);
log.info("SAST scan completed for repository: {}", repository);
} catch (Exception e) {
log.error("SAST scan failed for repository: {}", repository, e);
result.setStatus(ScanStatus.FAILED);
result.setErrorMessage(e.getMessage());
}
return result;
}
/**
* Scan specific security patterns
*/
public SecurityPatternScanResult scanSecurityPatterns(String repository) {
SecurityPatternScanResult result = new SecurityPatternScanResult();
result.setRepository(repository);
result.setScanDate(Instant.now());
// Scan for specific security anti-patterns
result.setSqlInjection(findSqlInjectionVulnerabilities(repository));
result.setXssVulnerabilities(findXssVulnerabilities(repository));
result.setInsecureDeserialization(findInsecureDeserialization(repository));
result.setHardcodedSecrets(findHardcodedSecrets(repository));
result.setInsecureCrypto(findInsecureCryptoUsage(repository));
result.setMassAssignment(findMassAssignmentVulnerabilities(repository));
return result;
}
/**
* Generate SAST quality gate
*/
public SastQualityGate evaluateQualityGate(String repository, String commitHash) {
SastScanResult scanResult = performSastScan(repository);
SastQualityGate gate = new SastQualityGate();
gate.setRepository(repository);
gate.setCommitHash(commitHash);
gate.setEvaluationDate(Instant.now());
// Evaluate against quality criteria
gate.setPassed(evaluateSastCriteria(scanResult));
gate.setCriticalFindings(scanResult.getCriticalFindings());
gate.setHighFindings(scanResult.getHighFindings());
gate.setBlockingIssues(identifyBlockingSastIssues(scanResult));
gate.setQualityScore(calculateSastQualityScore(scanResult));
return gate;
}
private List<SastFinding> aggregateFindings(SpotBugsResult spotBugs, PMDResult pmd,
CheckstyleResult checkstyle, SonarQubeResult sonar) {
List<SastFinding> findings = new ArrayList<>();
findings.addAll(convertSpotBugsFindings(spotBugs));
findings.addAll(convertPmdFindings(pmd));
findings.addAll(convertCheckstyleFindings(checkstyle));
findings.addAll(convertSonarFindings(sonar));
// Deduplicate findings
return deduplicateFindings(findings);
}
private List<SastFinding> findSqlInjectionVulnerabilities(String repository) {
List<SastFinding> sqlInjectionFindings = new ArrayList<>();
// Pattern 1: String concatenation in SQL queries
sqlInjectionFindings.addAll(findPattern(
repository, 
"Statement.executeQuery.*\\+.*",
"Potential SQL injection via string concatenation"
));
// Pattern 2: PreparedStatement without parameterization
sqlInjectionFindings.addAll(findPattern(
repository,
"PreparedStatement.*setString.*\\+",
"Potential SQL injection in PreparedStatement"
));
// Pattern 3: JPA with unparameterized queries
sqlInjectionFindings.addAll(findPattern(
repository,
"@Query\\(\".*\\+.*\"\\)",
"Potential SQL injection in JPA @Query"
));
return sqlInjectionFindings;
}
private List<SastFinding> findHardcodedSecrets(String repository) {
List<SastFinding> secretFindings = new ArrayList<>();
// AWS keys
secretFindings.addAll(findPattern(
repository,
"AKIA[0-9A-Z]{16}",
"Hardcoded AWS access key"
));
// API keys
secretFindings.addAll(findPattern(
repository,
"api[_-]?key[\\s]*=[\\s]*['\"][^'\"\\s]+['\"]",
"Hardcoded API key"
));
// Database passwords
secretFindings.addAll(findPattern(
repository,
"password[\\s]*=[\\s]*['\"][^'\"\\s]+['\"]",
"Hardcoded database password"
));
// JWT secrets
secretFindings.addAll(findPattern(
repository,
"JWT.*secret[\\s]*=[\\s]*['\"][^'\"\\s]+['\"]",
"Hardcoded JWT secret"
));
return secretFindings;
}
// Additional SAST scanning methods...
}
@Data
public class SastScanResult {
private String repository;
private Instant scanDate;
private ScanStatus status;
private String errorMessage;
private SpotBugsResult spotBugsResults;
private PMDResult pmdResults;
private CheckstyleResult checkstyleResults;
private SonarQubeResult sonarQubeResults;
private List<SastFinding> findings;
private SarifReport sarifReport;
private int criticalFindings;
private int highFindings;
private int mediumFindings;
private int lowFindings;
private int infoFindings;
private double qualityScore;
private double securityScore;
private double maintainabilityScore;
public int getTotalFindings() {
return criticalFindings + highFindings + mediumFindings + lowFindings + infoFindings;
}
}
@Data
public class SastFinding {
private String id;
private String tool; // spotbugs, pmd, checkstyle, sonarqube
private String ruleId;
private String category; // security, performance, maintainability, reliability
private FindingSeverity severity;
private String filePath;
private int lineNumber;
private int columnNumber;
private String message;
private String description;
private List<String> remediationSteps;
private List<String> references;
private double confidence;
private String cweId;
private String owaspCategory;
public String getFormattedLocation() {
return String.format("%s:%d:%d", filePath, lineNumber, columnNumber);
}
}

6. GitHub Security Integration

Integrate with GitHub Security features and APIs.

GitHub Security Client:
```java
@Service
@Slf4j
public class GitHubSecurityClient {
private final GitHubClient githubClient;
private final String apiToken;
private final ObjectMapper objectMapper;

public GitHubSecurityClient(GitHubConfig config) {
this.githubClient = new GitHubClient(config);
this.apiToken = config.getApiToken();
this.objectMapper = new ObjectMapper();
}
/**
* Upload SARIF results to GitHub Security
*/
public void uploadSarifResults(String repository, String commitHash, SarifReport sarifReport) {
try {
String sarifJson = objectMapper.writeValueAsString(sarifReport);
GitHubApiResponse response = githubClient.post(
String.format("/repos/%s/code-scanning/sarifs", repository),
Map.of(
"commit_sha", commitHash,
"ref", "refs/heads/main",
"sarif", sarifJson,
"checkout_uri", "file:///github/workspace",
"started_at", Instant.now().toString(),
"tool_name", "custom-security-scan"
)
);
if (response.isSuccessful()) {
log.info("Successfully uploaded SARIF results for commit: {}", commitHash);
} else {
log.error("Failed to upload SARIF results: {}", response.getErrorMessage());
}
} catch (Exception e) {
log.error("Failed to upload SARIF results to GitHub Security", e);
throw new GitHubSecurityException("SARIF upload failed", e);
}
}
/**
* Get code scanning alerts for repository
*/
public List<CodeScanningAlert> getCodeScanningAlerts(String repository, String branch) {
try {
GitHubApiResponse response = githubClient.get(
String.format("/repos/%s/code-scanning/alerts?ref=%s", repository, branch)
);
if (response.isSuccessful()) {
return objectMapper.readValue(
response.getBody(),
new TypeReference<List<CodeScanningAlert>>() {}
);
} else {
log.error("Failed to fetch code scanning alerts: {}", response.getErrorMessage());
return Collections.emptyList();
}
} catch (Exception e) {
log.error("Failed to fetch code scanning alerts", e);
return Collections.emptyList();
}
}
/**
* Update code scanning alert status
*/
public void updateAlertStatus(String repository, int alertId, AlertStatus status, String reason) {
try {
GitHubApiResponse response = githubClient.patch(
String.format("/repos/%s/code-scanning/alerts/%d", repository, alertId),
Map.of(
"state", status.name().toLowerCase(),
"dismissed_reason", reason
)
);
if (response.isSuccessful()) {
log.info("Updated alert {} status to {}", alertId, status);
} else {
log.error("Failed to update alert status: {}", response.getErrorMessage());
}
} catch (Exception e) {
log.error("Failed to update alert status", e);
}
}
/**
* Create security advisory
*/
public SecurityAdvisory createSecurityAdvisory(String repository, SecurityAdvisory advisory) {
try {
GitHubApiResponse response = githubClient.post(
String.format("/repos/%s/security-advisories", repository),
advisory
);
if (response.isSuccessful()) {
return objectMapper.readValue(response.getBody(), SecurityAdvisory.class);
} else {
log.error("Failed to create security advisory: {}", response.getErrorMessage());
throw new GitHubSecurityException("Failed to create security advisory");
}
} catch (Exception e) {
log.error("Failed to create security advisory", e);
throw new GitHubSecurityException("Security advisory creation failed", e);
}
}
/**
* Get dependency graph insights
*/
public DependencyGraphInsights getDependencyGraphInsights(String repository) {
try {
GitHubApiResponse response = githubClient.get(
String.format("/repos/%s/dependency-graph/insights", repository)
);
if (response.isSuccessful())

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