diff --git a/.github/workflows/notification-service.yml b/.github/workflows/notification-service.yml
index 442d473..85519df 100644
--- a/.github/workflows/notification-service.yml
+++ b/.github/workflows/notification-service.yml
@@ -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
diff --git a/notification_service/pom.xml b/notification_service/pom.xml
index aff6c17..c58ca5d 100644
--- a/notification_service/pom.xml
+++ b/notification_service/pom.xml
@@ -63,6 +63,40 @@
+
+
+
+ com.github.spotbugs
+ spotbugs-maven-plugin
+ 4.8.3.1
+
+ Max
+ High
+
+
+ com.h3xstream.findsecbugs
+ findsecbugs-plugin
+ 1.13.0
+
+
+
+
+
+ check
+
+
+
+
+
+
+ org.owasp
+ dependency-check-maven
+ 9.0.9
+
+ 7
+ HTML,JSON
+
+
diff --git a/notification_service/src/main/java/ch/hesso/pi/notification/service/AirQualityService.java b/notification_service/src/main/java/ch/hesso/pi/notification/service/AirQualityService.java
index dbdec71..ee9c499 100644
--- a/notification_service/src/main/java/ch/hesso/pi/notification/service/AirQualityService.java
+++ b/notification_service/src/main/java/ch/hesso/pi/notification/service/AirQualityService.java
@@ -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);
}