Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 39 additions & 14 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,21 @@ jobs:
cache: maven

- name: Maven Verify (Build + Tests + JaCoCo)
run: ./mvnw -B -T 1C -ntp verify
# -e fuer volle Stacktraces, --fail-at-end damit alle Module
# durchlaufen statt beim ersten Fehler abzubrechen. Kein -T 1C,
# bis die Backend-Tests stabil sind (parallele Modul-Ausfuehrung
# macht Surefire-Output beim Debuggen unleserlich).
run: ./mvnw -B -e -ntp --fail-at-end verify

- name: Upload Surefire-Reports on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: surefire-reports-${{ github.run_number }}
path: |
**/target/surefire-reports/**
**/target/failsafe-reports/**
retention-days: 14

- name: Upload Backend-JAR (fuer E2E)
uses: actions/upload-artifact@v4
Expand Down Expand Up @@ -177,19 +191,10 @@ jobs:
--health-timeout=5s
--health-retries=15

keycloak:
image: quay.io/keycloak/keycloak:24.0
env:
KEYCLOAK_ADMIN: admin
KEYCLOAK_ADMIN_PASSWORD: admin
KC_HEALTH_ENABLED: 'true'
ports:
- 8080:8080
options: >-
--health-cmd="curl -fsS http://localhost:8080/health/ready || exit 1"
--health-interval=10s
--health-timeout=5s
--health-retries=30
# Keycloak laeuft NICHT als services-Container: das Image braucht
# `start-dev` als Argument, und GHA-Services unterstuetzen weder
# `command` noch CMD-Override. Stattdessen `docker run` als Step
# (siehe "Start Keycloak").

env:
CVM_SERVER_PORT: '8081'
Expand Down Expand Up @@ -227,6 +232,16 @@ jobs:
name: frontend-dist
path: cvm-frontend/dist/cvm-frontend/browser

- name: Start Keycloak (start-dev)
run: |
set -euo pipefail
docker run -d --name keycloak \
-p 8080:8080 \
-e KEYCLOAK_ADMIN=admin \
-e KEYCLOAK_ADMIN_PASSWORD=admin \
-e KC_HEALTH_ENABLED=true \
quay.io/keycloak/keycloak:24.0 start-dev

- name: Import Keycloak-Realm
run: |
set -euo pipefail
Expand All @@ -237,6 +252,11 @@ jobs:
break
fi
sleep 2
if [ "$i" = "60" ]; then
echo "Keycloak nicht ready. Container-Log:"
docker logs keycloak | tail -100
exit 1
fi
done
TOKEN=$(curl -fsS -X POST \
-d "grant_type=password" \
Expand Down Expand Up @@ -301,6 +321,10 @@ jobs:
working-directory: cvm-frontend
run: npx playwright test

- name: Sammele Keycloak-Log
if: failure()
run: docker logs keycloak > keycloak.log 2>&1 || true

- name: Upload Playwright-Report
if: failure()
uses: actions/upload-artifact@v4
Expand All @@ -311,4 +335,5 @@ jobs:
cvm-frontend/test-results/
backend.log
frontend.log
keycloak.log
retention-days: 14
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.ahs.cvm.persistence;

import com.ahs.cvm.persistence.support.DockerAvailability;
import java.util.UUID;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.test.context.DynamicPropertyRegistry;
Expand All @@ -17,6 +18,15 @@
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
public abstract class AbstractPersistenceIntegrationsTest {

/**
* Default-Mandant, der von Flyway-Migration V0023 als
* {@code is_default = TRUE} angelegt wird. Persistenz-Tests haben
* keine Aspect-Infrastruktur, die tenant_id automatisch fuellt -
* Fixtures setzen die Mandanten-Zuordnung deshalb explizit hierueber.
*/
protected static final UUID DEFAULT_TENANT_ID =
UUID.fromString("00000000-0000-0000-0000-000000000001");

@SuppressWarnings("resource")
static final PostgreSQLContainer<?> POSTGRES = new PostgreSQLContainer<>(
DockerImageName.parse("pgvector/pgvector:pg16")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,45 +75,53 @@ void assessmentSupersededErlaubt() {
}

private Assessment bereiteAssessmentVor() {
Product produkt = productRepository.save(
Product.builder().name("PortalCore-Test").key("pc-imm").build());
ProductVersion pv = productVersionRepository.save(
ProductVersion.builder()
.product(produkt)
.version("1.0.0-imm")
.build());
Environment env = environmentRepository.save(
Environment.builder()
.key("REF-IMM")
.name("Referenz Immutable")
.stage(EnvironmentStage.REF)
.build());
Scan scan = scanRepository.save(
Scan.builder()
.productVersion(pv)
.sbomFormat("CycloneDX")
.sbomChecksum("sha256:imm")
.scannedAt(Instant.now())
.build());
Product produkt = productRepository.save(Product.builder()
.tenantId(DEFAULT_TENANT_ID)
.name("PortalCore-Test")
.key("pc-imm")
.build());
ProductVersion pv = productVersionRepository.save(ProductVersion.builder()
.tenantId(DEFAULT_TENANT_ID)
.product(produkt)
.version("1.0.0-imm")
.build());
Environment env = environmentRepository.save(Environment.builder()
.tenantId(DEFAULT_TENANT_ID)
.key("REF-IMM")
.name("Referenz Immutable")
.stage(EnvironmentStage.REF)
.build());
Scan scan = scanRepository.save(Scan.builder()
.tenantId(DEFAULT_TENANT_ID)
.productVersion(pv)
.sbomFormat("CycloneDX")
.sbomChecksum("sha256:imm")
.scannedAt(Instant.now())
.build());
Component comp = componentRepository.save(
Component.builder()
.purl("pkg:maven/org.test/imm@1.0")
.name("imm")
.version("1.0")
.build());
ComponentOccurrence occ = occurrenceRepository.save(
ComponentOccurrence.builder().scan(scan).component(comp).direct(true).build());
ComponentOccurrence occ = occurrenceRepository.save(ComponentOccurrence.builder()
.tenantId(DEFAULT_TENANT_ID)
.scan(scan)
.component(comp)
.direct(true)
.build());
Cve cve = cveRepository.save(
Cve.builder().cveId("CVE-2026-22610").source("NVD").build());
Finding finding = findingRepository.save(
Finding.builder()
.scan(scan)
.componentOccurrence(occ)
.cve(cve)
.detectedAt(Instant.now())
.build());
Finding finding = findingRepository.save(Finding.builder()
.tenantId(DEFAULT_TENANT_ID)
.scan(scan)
.componentOccurrence(occ)
.cve(cve)
.detectedAt(Instant.now())
.build());

Assessment assessment = Assessment.builder()
.tenantId(DEFAULT_TENANT_ID)
.finding(finding)
.productVersion(pv)
.environment(env)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class ProductRepositoryIntegrationsTest extends AbstractPersistenceIntegrationsT
@DisplayName("Product: save setzt id und createdAt via @PrePersist")
void produktSpeichernSetztTechnischeFelder() {
Product portalcore = Product.builder()
.tenantId(DEFAULT_TENANT_ID)
.name("PortalCore-Test")
.key("portalcore-test")
.description("Referenz-Produkt")
Expand All @@ -39,11 +40,15 @@ void produktSpeichernSetztTechnischeFelder() {
@Test
@DisplayName("ProductVersion: findByProductIdAndVersion liefert eindeutigen Treffer")
void produktVersionLookup() {
Product produkt = productRepository.save(
Product.builder().name("SmileKH-Test").key("smile-test").build());
Product produkt = productRepository.save(Product.builder()
.tenantId(DEFAULT_TENANT_ID)
.name("SmileKH-Test")
.key("smile-test")
.build());

ProductVersion version = productVersionRepository.save(
ProductVersion.builder()
.tenantId(DEFAULT_TENANT_ID)
.product(produkt)
.version("1.14.2-test")
.gitCommit("a3f9beef")
Expand Down
Loading