ci(notification-service): add SAST, dependency scan and DAST security gates

Add CodeQL (SAST), SpotBugs+FindSecBugs (SAST via verify), OWASP Dependency Check
and OWASP ZAP baseline scan (DAST) to the CI/CD pipeline.
Docker deploy is gated behind ci, sast-codeql and dast jobs.
Fix DM_DEFAULT_ENCODING spotted by SpotBugs: use StandardCharsets.UTF_8 in Basic Auth encoding.
This commit is contained in:
khalil-bot
2026-05-28 16:24:39 +02:00
parent ad9fa0083b
commit 8cba5f7710
3 changed files with 155 additions and 5 deletions

View File

@@ -31,14 +31,129 @@ jobs:
distribution: temurin
cache: maven
- name: Run tests
- name: Build & test (SpotBugs included via verify)
run: mvn verify -q
# ── 2. Docker build & push ───────────────────────────────────────────────────
# ── 2. SAST CodeQL ─────────────────────────────────────────────────────────
sast-codeql:
name: SAST CodeQL
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
steps:
- uses: actions/checkout@v4
- name: Setup Java 17
uses: actions/setup-java@v4
with:
java-version: 17
distribution: temurin
cache: maven
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: java
queries: security-and-quality
- name: Build for CodeQL
run: mvn compile -q -f notification_service/pom.xml
- name: Analyze
uses: github/codeql-action/analyze@v3
with:
category: /language:java
# ── 3. Dependency vulnerability scan (OWASP) ─────────────────────────────────
dependency-check:
name: Dependency vulnerability scan
runs-on: ubuntu-latest
defaults:
run:
working-directory: notification_service
steps:
- uses: actions/checkout@v4
- name: Setup Java 17
uses: actions/setup-java@v4
with:
java-version: 17
distribution: temurin
cache: maven
- name: Cache NVD database
uses: actions/cache@v4
with:
path: ~/.m2/repository/org/owasp/dependency-check-data
key: nvd-${{ runner.os }}-${{ hashFiles('notification_service/pom.xml') }}
restore-keys: nvd-${{ runner.os }}-
- name: OWASP Dependency Check
run: mvn dependency-check:check -q
continue-on-error: true
- name: Upload dependency check report
if: always()
uses: actions/upload-artifact@v4
with:
name: dependency-check-report
path: notification_service/target/dependency-check-report.*
retention-days: 14
# ── 4. DAST OWASP ZAP ──────────────────────────────────────────────────────
dast:
name: DAST OWASP ZAP
runs-on: ubuntu-latest
needs: ci
steps:
- uses: actions/checkout@v4
- name: Setup Java 17
uses: actions/setup-java@v4
with:
java-version: 17
distribution: temurin
cache: maven
- name: Build JAR
run: mvn package -DskipTests -q -f notification_service/pom.xml
- name: Start service
run: |
java -jar notification_service/target/notification-service-*.jar &
timeout 60 bash -c 'until curl -sf http://localhost:8080/actuator/health; do sleep 2; done'
env:
TELEGRAM_BOT_TOKEN: dummy-token
TELEGRAM_CHAT_ID: "0"
AIR_QUALITY_API_URL: http://localhost:9999
API_USERNAME: dummy
API_PASSWORD: dummy
MOCK_MODE: "true"
- name: ZAP Baseline Scan
uses: zaproxy/action-baseline@v0.12.0
with:
target: http://localhost:8080
fail_action: false
allow_issue_writing: false
- name: Upload ZAP report
if: always()
uses: actions/upload-artifact@v4
with:
name: zap-report
path: report_html.html
retention-days: 14
# ── 5. Docker build & push ───────────────────────────────────────────────────
docker:
name: Docker build & push
runs-on: ubuntu-latest
needs: ci
needs: [ci, sast-codeql, dast]
if: github.ref == 'refs/heads/main'
outputs:
sha_tag: ${{ steps.tag.outputs.sha }}
@@ -80,7 +195,7 @@ jobs:
${{ steps.tag.outputs.sha }}
${{ steps.tag.outputs.extra }}
# ── 3. Deploy to physical server (SSH) ───────────────────────────────────────
# ── 6. Deploy to physical server (SSH) ───────────────────────────────────────
deploy:
name: Deploy
runs-on: ubuntu-latest

View File

@@ -63,6 +63,40 @@
</excludes>
</configuration>
</plugin>
<!-- SAST: SpotBugs + FindSecBugs -->
<plugin>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-maven-plugin</artifactId>
<version>4.8.3.1</version>
<configuration>
<effort>Max</effort>
<threshold>High</threshold>
<plugins>
<plugin>
<groupId>com.h3xstream.findsecbugs</groupId>
<artifactId>findsecbugs-plugin</artifactId>
<version>1.13.0</version>
</plugin>
</plugins>
</configuration>
<executions>
<execution>
<goals><goal>check</goal></goals>
</execution>
</executions>
</plugin>
<!-- Dependency vulnerability scan: OWASP -->
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<version>9.0.9</version>
<configuration>
<failBuildOnCVSS>7</failBuildOnCVSS>
<formats>HTML,JSON</formats>
</configuration>
</plugin>
</plugins>
</build>

View File

@@ -12,6 +12,7 @@ import org.springframework.util.StringUtils;
import org.springframework.web.client.RestClient;
import org.springframework.web.client.RestClientException;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.List;
@@ -41,7 +42,7 @@ public class AirQualityService {
var request = restClient.get().uri(url);
if (StringUtils.hasText(username) && StringUtils.hasText(password)) {
String encoded = Base64.getEncoder().encodeToString((username + ":" + password).getBytes());
String encoded = Base64.getEncoder().encodeToString((username + ":" + password).getBytes(StandardCharsets.UTF_8));
request = request.header(HttpHeaders.AUTHORIZATION, "Basic " + encoded);
}