From e3d3fc0a5b0ab30464a5abfee013e08f61f99293 Mon Sep 17 00:00:00 2001 From: Oliver Wolff <23139298+cuioss@users.noreply.github.com> Date: Tue, 26 Aug 2025 18:16:11 +0200 Subject: [PATCH 01/24] fix: Add npm cache to all workflows to prevent 429 errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add npm caching to maven.yml workflow (all jobs) - Add npm caching to maven-release.yml workflow - Add npm caching to integration-tests.yml workflow - Add npm caching to benchmark.yml workflow This prevents "429 Too Many Requests" errors when downloading npm packages from registry.npmjs.org during builds. ๐Ÿค– Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- .github/workflows/benchmark.yml | 8 ++++++++ .github/workflows/integration-tests.yml | 8 ++++++++ .github/workflows/maven-release.yml | 8 ++++++++ .github/workflows/maven.yml | 25 +++++++++++++++++++++++++ 4 files changed, 49 insertions(+) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 4d40e60d..0e192fdf 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -45,6 +45,14 @@ jobs: java-version: '21' distribution: 'temurin' cache: maven + + - name: Cache npm packages + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + with: + path: ~/.npm + key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json', '**/package.json') }} + restore-keys: | + ${{ runner.os }}-npm- - name: Build api-sheriff-library run: | diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 8d779e08..9d8841ac 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -25,6 +25,14 @@ jobs: java-version: '21' distribution: 'temurin' cache: maven + + - name: Cache npm packages + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + with: + path: ~/.npm + key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json', '**/package.json') }} + restore-keys: | + ${{ runner.os }}-npm- - name: Build with Maven (Default Profile) run: ./mvnw --no-transfer-progress clean install -Dmaven.test.skip=true diff --git a/.github/workflows/maven-release.yml b/.github/workflows/maven-release.yml index c412ea83..11a7d09f 100644 --- a/.github/workflows/maven-release.yml +++ b/.github/workflows/maven-release.yml @@ -42,6 +42,14 @@ jobs: gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }} gpg-passphrase: MAVEN_GPG_PASSPHRASE cache: maven + + - name: Cache npm packages + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + with: + path: ~/.npm + key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json', '**/package.json') }} + restore-keys: | + ${{ runner.os }}-npm- - name: Configure Git author run: | diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 48bfb51f..76c752b2 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -27,6 +27,15 @@ jobs: java-version: ${{ matrix.version }} distribution: 'temurin' cache: maven + + - name: Cache npm packages + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + with: + path: ~/.npm + key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json', '**/package.json') }} + restore-keys: | + ${{ runner.os }}-npm- + - name: Build with Maven, Java ${{ matrix.version }} run: ./mvnw --no-transfer-progress verify -Dmaven.compiler.release=${{ matrix.version }} @@ -57,6 +66,14 @@ jobs: path: ~/.sonar/cache key: ${{ runner.os }}-sonar restore-keys: ${{ runner.os }}-sonar + + - name: Cache npm packages + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + with: + path: ~/.npm + key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json', '**/package.json') }} + restore-keys: | + ${{ runner.os }}-npm- - uses: radcortez/project-metadata-action@203f7ffba8db2669b2c9b4d4c2e90b186c588fa5 # 1.1 name: Retrieve project metadata from '.github/project.yml' @@ -94,6 +111,14 @@ jobs: gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }} gpg-passphrase: MAVEN_GPG_PASSPHRASE cache: maven + + - name: Cache npm packages + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + with: + path: ~/.npm + key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json', '**/package.json') }} + restore-keys: | + ${{ runner.os }}-npm- - name: Extract project version id: project From 17311ab26ff990309b508b51c1fdf0cbc5f27566 Mon Sep 17 00:00:00 2001 From: Oliver Wolff <23139298+cuioss@users.noreply.github.com> Date: Tue, 3 Mar 2026 16:48:35 +0100 Subject: [PATCH 02/24] chore: Align project structure with OAuthSheriff patterns Structural refactoring to adopt OAuthSheriff's evolved build infrastructure, benchmarking architecture, and CI/CD patterns. P1 - Foundation upgrades: - Parent POM: cui-java-parent 1.1.4 -> 1.4.4 - Quarkus: 3.23.3 -> 3.32.1, Node v20 -> v22, npm 10.5 -> 10.9.2 - BOM renamed: bom -> api-sheriff-bom, jjwt 0.12.6 -> 0.13.0 - DevUI SPI: quarkus-vertx-http-dev-ui-spi -> quarkus-devui-deployment-spi - Added .mvn/jvm.config for JDK 22+ compatibility P2 - Benchmarking architecture: - Renamed benchmark-library -> benchmark-core - Renamed benchmark-integration-quarkus -> benchmark-integration-wrk - Added benchmarking-common dependency (0.4.1) for shared infrastructure - Replaced old JMH integration code with WRK-based WrkResultPostProcessor - Replaced 15 bash scripts with single Python benchmark-pages.py - Removed all HTML/JSON template files (now generated by benchmarking-common) - Upgraded: gson 2.13.2, hdrhistogram 2.2.2, commons-io 2.21.0 P3 - CI/CD workflow modernization: - Expanded .github/project.yml with full build configuration - Replaced inline workflows with reusable ones from cuioss-organization v0.6.2 - Modernized benchmark.yml: GitHub App tokens, Python script, direct git push - Added dependabot-auto-merge, dependency-review, scorecards, claude workflows P5 - Documentation: - Restructured CLAUDE.md to stub referencing agents.md - Created agents.md with full development guidance - Removed obsolete doc/ai-rules.md Co-Authored-By: Claude Opus 4.6 --- .github/project.yml | 26 +- .github/workflows/benchmark.yml | 186 +++---- .github/workflows/claude.yml | 52 ++ .github/workflows/dependabot-auto-merge.yml | 14 + .github/workflows/dependency-review.yml | 15 + .github/workflows/integration-tests.yml | 58 +- .github/workflows/maven-release.yml | 94 ---- .github/workflows/maven.yml | 146 +---- .github/workflows/release.yml | 26 + .github/workflows/scorecards.yml | 23 + .mvn/jvm.config | 1 + CLAUDE.md | 312 ++++++----- agents.md | 259 +++++++++ api-sheriff-library/pom.xml | 2 +- .../api-sheriff-quarkus-deployment/pom.xml | 2 +- api-sheriff-quarkus-parent/pom.xml | 17 +- .../pom.xml | 66 +-- .../api/benchmark/BenchmarkOptionsHelper.java | 0 .../api/benchmark/BenchmarkRunner.java | 0 .../benchmark-integration-quarkus/pom.xml | 505 ------------------ .../benchmark/BenchmarkOptionsHelper.java | 201 ------- .../quarkus/benchmark/BenchmarkRunner.java | 104 ---- .../benchmark-integration-wrk/pom.xml | 239 +++++++++ .../wrk/benchmark/WrkResultPostProcessor.java | 368 +++++++++++++ .../benchmark/WrkResultPostProcessorTest.java | 271 ++++++++++ .../src/test/resources/wrk-health-results.txt | 29 + .../src/test/resources/wrk-jwt-results.txt | 29 + benchmarking/doc/index-visualizer.html | 107 ---- .../doc/integration-benchmark-visualizer.html | 175 ------ benchmarking/doc/integration-index.html | 96 ---- .../doc/integration-performance-trends.html | 267 --------- benchmarking/doc/performance-run.json | 29 - benchmarking/doc/performance-trends.html | 248 --------- benchmarking/doc/resources/common.css | 387 -------------- benchmarking/doc/resources/navigation.js | 69 --- benchmarking/doc/step-metrics-visualizer.html | 476 ----------------- .../doc/templates/index-visualizer.html | 107 ---- .../integration-benchmark-visualizer.html | 175 ------ .../doc/templates/integration-index.html | 96 ---- .../integration-performance-trends.html | 267 --------- .../doc/templates/performance-run.json | 29 - .../doc/templates/performance-trends.html | 248 --------- .../doc/templates/resources/common.css | 387 -------------- .../doc/templates/resources/navigation.js | 69 --- .../templates/step-metrics-visualizer.html | 476 ----------------- benchmarking/pom.xml | 66 ++- benchmarking/scripts/benchmark-pages.py | 229 ++++++++ .../scripts/create-performance-tracking.sh | 91 ---- .../create-unified-performance-badge.sh | 165 ------ .../scripts/create-unified-trend-badge.sh | 136 ----- benchmarking/scripts/lib/badge-utils.sh | 71 --- benchmarking/scripts/lib/metrics-utils.sh | 113 ---- benchmarking/scripts/prepare-github-pages.sh | 85 --- benchmarking/scripts/prepare-step-metrics.sh | 30 -- .../scripts/process-all-benchmarks.sh | 132 ----- .../scripts/process-integration-benchmarks.sh | 146 ----- .../process-integration-jmh-benchmarks.sh | 170 ------ .../scripts/process-micro-benchmarks.sh | 101 ---- benchmarking/scripts/serve-local.js | 72 --- benchmarking/scripts/serve-local.sh | 34 -- .../update-integration-performance-trends.sh | 128 ----- .../scripts/update-performance-trends.sh | 128 ----- .../data/badges/performance-badge.json | 1 - .../templates/data/badges/trend-badge.json | 1 - .../templates/data/integration-metrics.json | 19 - .../templates/data/integration-result.json | 222 -------- benchmarking/templates/data/jmh-result.json | 259 --------- .../data/jwt-validation-metrics.json | 357 ------------- .../templates/data/performance-tracking.json | 84 --- .../tracking/performance-20250801-073012.json | 29 - benchmarking/templates/index-visualizer.html | 107 ---- .../integration-benchmark-visualizer.html | 175 ------ benchmarking/templates/integration-index.html | 96 ---- .../integration-performance-trends.html | 267 --------- benchmarking/templates/performance-run.json | 29 - .../templates/performance-trends.html | 248 --------- benchmarking/templates/resources/common.css | 387 -------------- .../templates/resources/navigation.js | 69 --- .../templates/step-metrics-visualizer.html | 476 ----------------- bom/pom.xml | 4 +- doc/ai-rules.md | 369 ------------- pom.xml | 40 +- 82 files changed, 1974 insertions(+), 9915 deletions(-) create mode 100644 .github/workflows/claude.yml create mode 100644 .github/workflows/dependabot-auto-merge.yml create mode 100644 .github/workflows/dependency-review.yml delete mode 100644 .github/workflows/maven-release.yml create mode 100644 .github/workflows/release.yml create mode 100644 .github/workflows/scorecards.yml create mode 100644 .mvn/jvm.config create mode 100644 agents.md rename benchmarking/{benchmark-library => benchmark-core}/pom.xml (83%) rename benchmarking/{benchmark-library => benchmark-core}/src/main/java/de/cuioss/sheriff/api/benchmark/BenchmarkOptionsHelper.java (100%) rename benchmarking/{benchmark-library => benchmark-core}/src/main/java/de/cuioss/sheriff/api/benchmark/BenchmarkRunner.java (100%) delete mode 100644 benchmarking/benchmark-integration-quarkus/pom.xml delete mode 100644 benchmarking/benchmark-integration-quarkus/src/main/java/de/cuioss/sheriff/api/quarkus/benchmark/BenchmarkOptionsHelper.java delete mode 100644 benchmarking/benchmark-integration-quarkus/src/main/java/de/cuioss/sheriff/api/quarkus/benchmark/BenchmarkRunner.java create mode 100644 benchmarking/benchmark-integration-wrk/pom.xml create mode 100644 benchmarking/benchmark-integration-wrk/src/main/java/de/cuioss/sheriff/api/wrk/benchmark/WrkResultPostProcessor.java create mode 100644 benchmarking/benchmark-integration-wrk/src/test/java/de/cuioss/sheriff/api/wrk/benchmark/WrkResultPostProcessorTest.java create mode 100644 benchmarking/benchmark-integration-wrk/src/test/resources/wrk-health-results.txt create mode 100644 benchmarking/benchmark-integration-wrk/src/test/resources/wrk-jwt-results.txt delete mode 100644 benchmarking/doc/index-visualizer.html delete mode 100644 benchmarking/doc/integration-benchmark-visualizer.html delete mode 100644 benchmarking/doc/integration-index.html delete mode 100644 benchmarking/doc/integration-performance-trends.html delete mode 100644 benchmarking/doc/performance-run.json delete mode 100644 benchmarking/doc/performance-trends.html delete mode 100644 benchmarking/doc/resources/common.css delete mode 100644 benchmarking/doc/resources/navigation.js delete mode 100644 benchmarking/doc/step-metrics-visualizer.html delete mode 100644 benchmarking/doc/templates/index-visualizer.html delete mode 100644 benchmarking/doc/templates/integration-benchmark-visualizer.html delete mode 100644 benchmarking/doc/templates/integration-index.html delete mode 100644 benchmarking/doc/templates/integration-performance-trends.html delete mode 100644 benchmarking/doc/templates/performance-run.json delete mode 100644 benchmarking/doc/templates/performance-trends.html delete mode 100644 benchmarking/doc/templates/resources/common.css delete mode 100644 benchmarking/doc/templates/resources/navigation.js delete mode 100644 benchmarking/doc/templates/step-metrics-visualizer.html create mode 100644 benchmarking/scripts/benchmark-pages.py delete mode 100755 benchmarking/scripts/create-performance-tracking.sh delete mode 100755 benchmarking/scripts/create-unified-performance-badge.sh delete mode 100755 benchmarking/scripts/create-unified-trend-badge.sh delete mode 100644 benchmarking/scripts/lib/badge-utils.sh delete mode 100644 benchmarking/scripts/lib/metrics-utils.sh delete mode 100755 benchmarking/scripts/prepare-github-pages.sh delete mode 100755 benchmarking/scripts/prepare-step-metrics.sh delete mode 100755 benchmarking/scripts/process-all-benchmarks.sh delete mode 100755 benchmarking/scripts/process-integration-benchmarks.sh delete mode 100755 benchmarking/scripts/process-integration-jmh-benchmarks.sh delete mode 100755 benchmarking/scripts/process-micro-benchmarks.sh delete mode 100755 benchmarking/scripts/serve-local.js delete mode 100755 benchmarking/scripts/serve-local.sh delete mode 100755 benchmarking/scripts/update-integration-performance-trends.sh delete mode 100755 benchmarking/scripts/update-performance-trends.sh delete mode 100644 benchmarking/templates/data/badges/performance-badge.json delete mode 100644 benchmarking/templates/data/badges/trend-badge.json delete mode 100644 benchmarking/templates/data/integration-metrics.json delete mode 100644 benchmarking/templates/data/integration-result.json delete mode 100644 benchmarking/templates/data/jmh-result.json delete mode 100644 benchmarking/templates/data/jwt-validation-metrics.json delete mode 100644 benchmarking/templates/data/performance-tracking.json delete mode 100644 benchmarking/templates/data/tracking/performance-20250801-073012.json delete mode 100644 benchmarking/templates/index-visualizer.html delete mode 100644 benchmarking/templates/integration-benchmark-visualizer.html delete mode 100644 benchmarking/templates/integration-index.html delete mode 100644 benchmarking/templates/integration-performance-trends.html delete mode 100644 benchmarking/templates/performance-run.json delete mode 100644 benchmarking/templates/performance-trends.html delete mode 100644 benchmarking/templates/resources/common.css delete mode 100644 benchmarking/templates/resources/navigation.js delete mode 100644 benchmarking/templates/step-metrics-visualizer.html delete mode 100644 doc/ai-rules.md diff --git a/.github/project.yml b/.github/project.yml index 420390ab..3c4a6e9b 100644 --- a/.github/project.yml +++ b/.github/project.yml @@ -1,6 +1,28 @@ name: api-sheriff -pages-reference: api-sheriff -sonar-project-key: cuioss_API-Sheriff +description: An API-Gateway focused on Security and a lightweight approach + release: current-version: 1.0.0 next-version: 1.1.0-SNAPSHOT + create-github-release: true + +maven-build: + java-versions: '["21","25"]' + java-version: '21' + enable-snapshot-deploy: true + maven-profiles-snapshot: 'release-snapshot,javadoc' + maven-profiles-release: 'release,javadoc' + npm-cache: true + +sonar: + project-key: cuioss_API-Sheriff + enabled: true + skip-on-dependabot: true + +pages: + reference: api-sheriff + deploy-at-release: true + +github-automation: + auto-merge-build-versions: true + auto-merge-build-timeout: 300 diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 0e192fdf..6d2ef666 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -8,8 +8,9 @@ on: tags: [ "*" ] workflow_dispatch: -# Declare default permissions as read only -permissions: read-all +# Declare default permissions as read only (principle of least privilege) +permissions: + contents: read # Prevent concurrent benchmark runs to avoid interference concurrency: @@ -30,138 +31,117 @@ jobs: steps: - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 + uses: step-security/harden-runner@a90bcbc6539c36a85cdfeb73f7e2f433735f215b # v2.15.0 with: egress-policy: audit + - name: Create GitHub App token for deployment + id: app-token + uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1 + with: + app-id: ${{ secrets.RELEASE_APP_ID }} + private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} + repositories: ${{ github.event.repository.name }},cuioss.github.io + owner: cuioss + - name: Checkout code - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 0 # Fetch all history for proper versioning + persist-credentials: false # Prevent token from overriding app token during deploy - name: Set up JDK 21 - uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 + uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 with: java-version: '21' distribution: 'temurin' cache: maven - + - name: Cache npm packages - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3 with: path: ~/.npm key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json', '**/package.json') }} restore-keys: | ${{ runner.os }}-npm- - - name: Build api-sheriff-library + - name: Build api-sheriff run: | - # Build library module first to ensure test artifact is available for benchmarking + # Build all modules first to ensure artifacts are available for benchmarking ./mvnw --no-transfer-progress clean install -DskipTests - - name: Run Micro Benchmarks + - name: Fetch Previous History + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + repository: cuioss/cuioss.github.io + ref: main + path: previous-pages + sparse-checkout: | + api-sheriff/benchmarks/micro/history + api-sheriff/benchmarks/integration/history + continue-on-error: true + + - name: Prepare Historical Data for Benchmarks run: | - # Create directory for benchmark results - mkdir -p benchmark-results + python3 benchmarking/scripts/benchmark-pages.py prepare-history \ + --previous-pages-dir previous-pages/api-sheriff/benchmarks \ + --output-dir "${GITHUB_WORKSPACE}/benchmark-history" + - name: Run Micro Benchmarks + run: | # Run micro benchmarks using configuration from pom.xml - ./mvnw --no-transfer-progress clean verify -pl benchmarking/benchmark-library -Pbenchmark - - # Move micro benchmark results to expected location for upload - if [ -d "benchmarking/benchmark-library/target/benchmark-results" ]; then - echo "Moving micro benchmark results to upload location..." - cp -v benchmarking/benchmark-library/target/benchmark-results/* benchmark-results/ || echo "Failed to copy micro benchmark results" - ls -la benchmark-results/ - else - echo "Warning: benchmarking/benchmark-library/target/benchmark-results directory not found!" - echo "Looking for result files:" - find benchmarking/benchmark-library -name "*.json" -type f - fi - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.7.1 - - - name: Run Integration Benchmarks + # Pass history directory as system property for trend calculation + ./mvnw --no-transfer-progress clean verify -pl benchmarking/benchmark-core -Pbenchmark \ + -Dbenchmark.history.dir="${GITHUB_WORKSPACE}/benchmark-history/micro" + + # Verify artifacts were generated + echo "Micro benchmark artifacts generated:" + ls -la benchmarking/benchmark-core/target/benchmark-results/ + + - name: Run Integration Benchmarks with WRK + run: | + # Run WRK-based integration benchmarks with native image + echo "Running WRK integration benchmarks with native Quarkus..." + ./mvnw --no-transfer-progress clean verify -pl benchmarking/benchmark-integration-wrk -Pbenchmark \ + -Dbenchmark.history.dir="${GITHUB_WORKSPACE}/benchmark-history/integration" + + # Verify artifacts were generated + echo "Integration benchmark artifacts generated:" + ls -la benchmarking/benchmark-integration-wrk/target/benchmark-results/ + + - name: Assemble benchmark artifacts for deployment run: | - # Run integration benchmarks with native image using profile that includes container startup - echo "๐Ÿš€ Running integration benchmarks with native Quarkus..." - ./mvnw --no-transfer-progress clean verify -pl benchmarking/benchmark-integration-quarkus -Pbenchmark-testing -DskipTests - - # Check what was actually created - echo "๐Ÿ“ Checking benchmark-integration-quarkus/target directory structure:" - ls -la benchmarking/benchmark-integration-quarkus/target/ || echo "Target directory not found" - - echo "๐Ÿ“ Checking benchmark-integration-quarkus/target/benchmark-results directory:" - ls -la benchmarking/benchmark-integration-quarkus/target/benchmark-results/ || echo "Benchmark results directory not found" - - echo "๐Ÿ” Finding all JSON files in benchmark-integration-quarkus:" - find benchmarking/benchmark-integration-quarkus -name "*.json" -type f | head -20 - - # Move integration benchmark results to expected location for upload - if [ -d "benchmarking/benchmark-integration-quarkus/target/benchmark-results" ]; then - echo "Moving integration benchmark results to upload location..." - # Copy ALL json files from benchmark-results directory - for file in benchmarking/benchmark-integration-quarkus/target/benchmark-results/*.json; do - if [ -f "$file" ]; then - echo "Copying: $(basename "$file")" - cp "$file" benchmark-results/ - fi - done - else - echo "โŒ Directory benchmarking/benchmark-integration-quarkus/target/benchmark-results does not exist!" - fi - - # Add timestamp to results - echo "{ \"timestamp\": \"$(date -u +"%Y-%m-%dT%H:%M:%SZ")\", \"commit\": \"${{ github.sha }}\" }" > benchmark-results/metadata.json - - # Verify that benchmark results were generated - echo "๐Ÿ“Š Final contents of benchmark-results directory:" - ls -la benchmark-results/ - echo "๐Ÿ” Searching for any benchmark-result files in entire workspace:" - find . -name "*benchmark-result*.json" -type f || echo "No benchmark result files found anywhere" + python3 benchmarking/scripts/benchmark-pages.py assemble \ + --micro-results benchmarking/benchmark-core/target/benchmark-results/gh-pages-ready \ + --integration-results benchmarking/benchmark-integration-wrk/target/benchmark-results/gh-pages-ready \ + --previous-pages-dir previous-pages/api-sheriff/benchmarks \ + --output-dir gh-pages \ + --commit-sha "${{ github.sha }}" - name: Upload benchmark results - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: benchmark-results - path: benchmark-results/ + path: gh-pages/ retention-days: 90 # Keep results for 90 days - - name: Process All Benchmarks - run: | - # Get current date for badge timestamp in Berlin time - TIMESTAMP=$(TZ='Europe/Berlin' date +"%Y-%m-%d") - TIMESTAMP_WITH_TIME=$(TZ='Europe/Berlin' date +"%Y-%m-%d %H:%M %Z") - - # Create gh-pages directory - mkdir -p gh-pages - - # Process all benchmarks using orchestration script - bash benchmarking/scripts/process-all-benchmarks.sh \ - benchmark-results \ - benchmarking/doc/templates \ - gh-pages \ - "${{ github.sha }}" \ - "$TIMESTAMP" \ - "$TIMESTAMP_WITH_TIME" - - echo "๐Ÿ“Š Benchmark processing completed" - - # Display processing results for debugging - if [ -f "gh-pages/processing-results.json" ]; then - echo "๐Ÿ“‹ Processing Summary:" - jq -r ' - "๐Ÿ”ฌ Micro Benchmarks: " + .processing.micro.status + " - " + .processing.micro.message, - "๐Ÿ”— Integration Benchmarks: " + .processing.integration.status + " - " + .processing.integration.message, - "โŒ Errors: " + (.errors | length | tostring) - ' gh-pages/processing-results.json - fi + - name: Checkout cuioss.github.io for deployment + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + repository: cuioss/cuioss.github.io + path: _pages-deploy + sparse-checkout: api-sheriff/benchmarks + token: ${{ steps.app-token.outputs.token }} - name: Deploy to cuioss.github.io - uses: JamesIves/github-pages-deploy-action@6c2d9db40f9296374acc17b90404b6e8864128c8 # v4.7.3 - with: - folder: gh-pages - repository-name: cuioss/cuioss.github.io - target-folder: api-sheriff/benchmarks - branch: main - token: ${{ secrets.PAGES_DEPLOY_TOKEN }} \ No newline at end of file + run: | + TARGET_DIR="_pages-deploy/api-sheriff/benchmarks" + rm -rf "$TARGET_DIR" + mkdir -p "$TARGET_DIR" + cp -r gh-pages/* "$TARGET_DIR/" + cd _pages-deploy + git config user.name "cuioss-release-bot[bot]" + git config user.email "cuioss-release-bot[bot]@users.noreply.github.com" + git add . + git diff --staged --quiet || git commit -m "Deploy benchmark results from ${{ github.sha }}" + git push diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml new file mode 100644 index 00000000..eb402e12 --- /dev/null +++ b/.github/workflows/claude.yml @@ -0,0 +1,52 @@ +name: Claude Code + +on: + issue_comment: + types: [created] + pull_request_review_comment: + types: [created] + issues: + types: [opened, assigned] + pull_request_review: + types: [submitted] + +# Declare default permissions as read only (principle of least privilege) +permissions: + contents: read + +jobs: + claude: + if: | + (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) || + (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) || + (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) || + (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude'))) + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: read + issues: read + id-token: write + actions: read # Required for Claude to read CI results on PRs + steps: + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + fetch-depth: 1 + - name: Set up JDK 21 + uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 + with: + java-version: '21' + distribution: 'temurin' + cache: maven + - name: Run Claude Code + id: claude + uses: anthropics/claude-code-action@220272d38887a1caed373da96a9ffdb0919c26cc # beta + with: + claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} + + # This is an optional setting that allows Claude to read CI results on PRs + additional_permissions: | + actions: read + + allowed_tools: "Bash(./mvnw*),Bash(./mvnw -Ppre-commit clean verify -DskipTests),Bash(./mvnw clean verify),Bash(./mvnw clean install),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl bom),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl api-sheriff-library),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl api-sheriff-quarkus-parent),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl api-sheriff-quarkus-parent/api-sheriff-quarkus),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl api-sheriff-quarkus-parent/api-sheriff-quarkus-deployment),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl benchmarking),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl benchmarking/benchmark-core),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl benchmarking/benchmark-integration-wrk),Bash(./mvnw clean install -pl bom),Bash(./mvnw clean install -pl api-sheriff-library),Bash(./mvnw clean install -pl api-sheriff-quarkus-parent),Bash(./mvnw clean install -pl api-sheriff-quarkus-parent/api-sheriff-quarkus),Bash(./mvnw clean install -pl api-sheriff-quarkus-parent/api-sheriff-quarkus-deployment),Bash(./mvnw clean install -pl api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests),Bash(./mvnw clean install -pl benchmarking),Bash(./mvnw clean install -pl benchmarking/benchmark-core),Bash(./mvnw clean install -pl benchmarking/benchmark-integration-wrk),Bash(git*),Bash(find*),Bash(gh*),Bash(java*)" diff --git a/.github/workflows/dependabot-auto-merge.yml b/.github/workflows/dependabot-auto-merge.yml new file mode 100644 index 00000000..2eee5027 --- /dev/null +++ b/.github/workflows/dependabot-auto-merge.yml @@ -0,0 +1,14 @@ +name: Dependabot Auto-merge + +on: + pull_request: + +permissions: + contents: read + +jobs: + auto-merge: + uses: cuioss/cuioss-organization/.github/workflows/reusable-dependabot-auto-merge.yml@8fce8938a4e92b4164650d083dbbf9c5601c6dfb # v0.6.2 + permissions: + contents: write + pull-requests: write diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml new file mode 100644 index 00000000..2daca4b4 --- /dev/null +++ b/.github/workflows/dependency-review.yml @@ -0,0 +1,15 @@ +name: Dependency Review + +on: + pull_request: + branches: [main] + +permissions: + contents: read + +jobs: + dependency-review: + uses: cuioss/cuioss-organization/.github/workflows/reusable-dependency-review.yml@8fce8938a4e92b4164650d083dbbf9c5601c6dfb # v0.6.2 + permissions: + contents: read + pull-requests: write diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 9d8841ac..d7ddbb7b 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -1,46 +1,28 @@ +# Runs integration/E2E tests via Maven with report deployment to cuioss.github.io. name: Integration Tests on: - pull_request: - branches: [ "main" ] push: - tags: [ "*" ] + branches: [main, "feature/*", "fix/*", "chore/*", "dependabot/**"] + pull_request: + branches: [main] workflow_dispatch: +permissions: + contents: read + jobs: integration-tests: - runs-on: ubuntu-latest - - steps: - - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 - with: - egress-policy: audit - - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - - name: Set up JDK 21 - uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 - with: - java-version: '21' - distribution: 'temurin' - cache: maven - - - name: Cache npm packages - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 - with: - path: ~/.npm - key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json', '**/package.json') }} - restore-keys: | - ${{ runner.os }}-npm- - - - name: Build with Maven (Default Profile) - run: ./mvnw --no-transfer-progress clean install -Dmaven.test.skip=true - - - name: Run Integration Tests Distroless - run: ./mvnw --no-transfer-progress clean verify -Pintegration-tests -pl api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests - - # JFR profile disabled in CI - only available for local development - # The JFR native container has startup issues in GitHub Actions environment - # - name: Run Integration Tests ubi9-quarkus-micro-image / jfr - # run: ./mvnw --no-transfer-progress clean verify -Pjfr -pl api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests \ No newline at end of file + # Run on push events, OR on pull_request only if from a fork + # This prevents duplicate runs: push handles internal branches, PR handles forks + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name + uses: cuioss/cuioss-organization/.github/workflows/reusable-maven-integration-tests.yml@8fce8938a4e92b4164650d083dbbf9c5601c6dfb # v0.6.2 + with: + report-name: api-sheriff-integration-tests + maven-args-input: | + verify -Pintegration-tests -pl api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests -am + reports-folder: | + api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/target/failsafe-reports + secrets: + RELEASE_APP_ID: ${{ secrets.RELEASE_APP_ID }} + RELEASE_APP_PRIVATE_KEY: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} diff --git a/.github/workflows/maven-release.yml b/.github/workflows/maven-release.yml deleted file mode 100644 index 11a7d09f..00000000 --- a/.github/workflows/maven-release.yml +++ /dev/null @@ -1,94 +0,0 @@ -name: Maven Release - -on: - pull_request: - types: [ closed ] - paths: - - '.github/project.yml' - workflow_dispatch: - -jobs: - release: - runs-on: ubuntu-latest - name: release - - steps: - - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 - with: - egress-policy: audit - - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - persist-credentials: false # otherwise, the validation used is the PA_TOKEN, instead of your personal access token. - fetch-depth: 0 # otherwise, there would be errors pushing refs to the destination repository. - - - uses: radcortez/project-metadata-action@203f7ffba8db2669b2c9b4d4c2e90b186c588fa5 # 1.1 - name: Retrieve project metadata from '.github/project.yml' - id: metadata - with: - github-token: ${{secrets.GITHUB_TOKEN}} - metadata-file-path: '.github/project.yml' - local-file: true - - - name: Set up JDK 21 - uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 - with: - java-version: '21' - distribution: 'temurin' - server-id: central - server-username: MAVEN_USERNAME - server-password: MAVEN_PASSWORD - gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }} - gpg-passphrase: MAVEN_GPG_PASSPHRASE - cache: maven - - - name: Cache npm packages - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 - with: - path: ~/.npm - key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json', '**/package.json') }} - restore-keys: | - ${{ runner.os }}-npm- - - - name: Configure Git author - run: | - git config --local user.email "action@github.com" - git config --local user.name "Cuioss Robot Action" - - - name: Maven release ${{steps.metadata.outputs.current-version}} - run: | - git checkout -b release - ./mvnw -B --no-transfer-progress -Prelease release:clean release:prepare -DreleaseVersion=${{steps.metadata.outputs.current-version}} -DdevelopmentVersion=${{steps.metadata.outputs.next-version}} - ./mvnw -B --no-transfer-progress -Prelease,javadoc site:site site:stage - git checkout ${{vars.GITHUB_BASE_REF}} - git rebase release - ./mvnw -B --no-transfer-progress -Prelease release:perform -DskipTests - env: - MAVEN_USERNAME: ${{ secrets.OSS_SONATYPE_USERNAME }} - MAVEN_PASSWORD: ${{ secrets.OSS_SONATYPE_PASSWORD }} - MAVEN_GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} - - - name: Deploy Maven Site to cuioss.github.io -> ${{steps.metadata.outputs.pages-reference}}๐Ÿš€ - uses: JamesIves/github-pages-deploy-action@6c2d9db40f9296374acc17b90404b6e8864128c8 # v4.7.3 - with: - folder: target/site - repository-name: cuioss/cuioss.github.io - target-folder: ${{steps.metadata.outputs.pages-reference}} - branch: main - token: ${{ secrets.PAGES_DEPLOY_TOKEN }} - - - name: Push changes to ${{github.ref_name}} - uses: ad-m/github-push-action@d91a481090679876dfc4178fef17f286781251df # v0.8.0 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - branch: ${{github.ref_name}} - force: true - - - name: Push tag ${{steps.metadata.outputs.current-version}} - uses: ad-m/github-push-action@d91a481090679876dfc4178fef17f286781251df # v0.8.0 - with: - branch: ${{github.ref_name}} - github_token: ${{ secrets.GITHUB_TOKEN }} - tags: true - force: true \ No newline at end of file diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 76c752b2..bac04657 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -1,134 +1,26 @@ -name: Master Build +# Configuration is read from .github/project.yml - no inputs needed! +# Path filtering is handled inside the reusable workflow via project.yml settings. +name: Maven Build on: push: - branches: [ "main", "feature/*" ] + branches: [main, "feature/*", "fix/*", "chore/*", "release/*", "dependabot/**"] pull_request: - branches: [ "main" ] + branches: [main] + workflow_dispatch: + +permissions: + contents: read jobs: build: - - runs-on: ubuntu-latest - strategy: - matrix: - version: [ 21,24 ] - - steps: - - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 - with: - egress-policy: audit - - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - name: Set up JDK ${{ matrix.version }} - uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 - with: - java-version: ${{ matrix.version }} - distribution: 'temurin' - cache: maven - - - name: Cache npm packages - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 - with: - path: ~/.npm - key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json', '**/package.json') }} - restore-keys: | - ${{ runner.os }}-npm- - - - name: Build with Maven, Java ${{ matrix.version }} - run: ./mvnw --no-transfer-progress verify -Dmaven.compiler.release=${{ matrix.version }} - - sonar-build: - needs: build - runs-on: ubuntu-latest - - steps: - - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 - with: - egress-policy: audit - - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - fetch-depth: 0 - - - name: Set up JDK 21 for Sonar-build - uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 - with: - java-version: '21' - distribution: 'temurin' - cache: maven - - - name: Cache SonarCloud packages - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 - with: - path: ~/.sonar/cache - key: ${{ runner.os }}-sonar - restore-keys: ${{ runner.os }}-sonar - - - name: Cache npm packages - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 - with: - path: ~/.npm - key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json', '**/package.json') }} - restore-keys: | - ${{ runner.os }}-npm- - - - uses: radcortez/project-metadata-action@203f7ffba8db2669b2c9b4d4c2e90b186c588fa5 # 1.1 - name: Retrieve project metadata from '.github/project.yml' - id: metadata - with: - github-token: ${{secrets.GITHUB_TOKEN}} - metadata-file-path: '.github/project.yml' - local-file: true - - - name: Build and analyze - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - run: ./mvnw -B --no-transfer-progress verify -Psonar -Dsonar.projectKey=${{steps.metadata.outputs.sonar-project-key}} sonar:sonar - - deploy-snapshot: - needs: sonar-build - if: github.ref == 'refs/heads/main' - runs-on: ubuntu-latest - steps: - - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 - with: - egress-policy: audit - - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - name: Set up JDK 17 for snapshot release - uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 - with: - java-version: '21' - distribution: 'temurin' - server-id: central - server-username: MAVEN_USERNAME - server-password: MAVEN_PASSWORD - gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }} - gpg-passphrase: MAVEN_GPG_PASSPHRASE - cache: maven - - - name: Cache npm packages - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 - with: - path: ~/.npm - key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json', '**/package.json') }} - restore-keys: | - ${{ runner.os }}-npm- - - - name: Extract project version - id: project - run: echo ::set-output name=version::$(./mvnw --no-transfer-progress help:evaluate -Dexpression=project.version -q -DforceStdout) - - - name: Deploy Snapshot with Maven, version ${{ steps.project.outputs.version }} - if: ${{endsWith(steps.project.outputs.version, '-SNAPSHOT')}} - run: | - ./mvnw -B --no-transfer-progress -Prelease-snapshot,javadoc deploy -Dmaven.test.skip=true - env: - MAVEN_USERNAME: ${{ secrets.OSS_SONATYPE_USERNAME }} - MAVEN_PASSWORD: ${{ secrets.OSS_SONATYPE_PASSWORD }} - MAVEN_GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} \ No newline at end of file + # Run on push events, OR on pull_request only if from a fork + # This prevents duplicate runs: push handles internal branches, PR handles forks + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name + uses: cuioss/cuioss-organization/.github/workflows/reusable-maven-build.yml@8fce8938a4e92b4164650d083dbbf9c5601c6dfb # v0.6.2 + secrets: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + OSS_SONATYPE_USERNAME: ${{ secrets.OSS_SONATYPE_USERNAME }} + OSS_SONATYPE_PASSWORD: ${{ secrets.OSS_SONATYPE_PASSWORD }} + GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }} + GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..6e1f4cae --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,26 @@ +# Configuration is read from .github/project.yml - no inputs needed! +name: Release + +on: + pull_request: + types: [closed] + paths: + - '.github/project.yml' + workflow_dispatch: + +permissions: + contents: read + +jobs: + release: + permissions: + contents: write + if: github.event.pull_request.merged == true || github.event_name == 'workflow_dispatch' + uses: cuioss/cuioss-organization/.github/workflows/reusable-maven-release.yml@8fce8938a4e92b4164650d083dbbf9c5601c6dfb # v0.6.2 + secrets: + RELEASE_APP_ID: ${{ secrets.RELEASE_APP_ID }} + RELEASE_APP_PRIVATE_KEY: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} + OSS_SONATYPE_USERNAME: ${{ secrets.OSS_SONATYPE_USERNAME }} + OSS_SONATYPE_PASSWORD: ${{ secrets.OSS_SONATYPE_PASSWORD }} + GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }} + GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml new file mode 100644 index 00000000..9f0dd7a8 --- /dev/null +++ b/.github/workflows/scorecards.yml @@ -0,0 +1,23 @@ +name: Scorecard supply-chain security + +on: + branch_protection_rule: + schedule: + - cron: '20 7 * * 2' + push: + branches: [main] + +permissions: + contents: read + +jobs: + analysis: + uses: cuioss/cuioss-organization/.github/workflows/reusable-scorecards.yml@8fce8938a4e92b4164650d083dbbf9c5601c6dfb # v0.6.2 + permissions: + security-events: write + id-token: write + contents: read + actions: read + issues: read + pull-requests: read + checks: read diff --git a/.mvn/jvm.config b/.mvn/jvm.config new file mode 100644 index 00000000..81b88d81 --- /dev/null +++ b/.mvn/jvm.config @@ -0,0 +1 @@ +--enable-native-access=ALL-UNNAMED diff --git a/CLAUDE.md b/CLAUDE.md index ceee8dd4..4d31dc9d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,138 +1,198 @@ -# CLAUDE.md +# Claude Code Configuration -This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. +All AI development guidelines for this project are located in: **`agents.md`** -## Project Overview +This file contains: +- Dev environment tips and build commands +- Testing instructions and pre-commit validation +- Code style and logging standards +- Framework-specific standards (Quarkus, CDI) +- OpenRewrite marker handling +- Custom commands -API Sheriff is a security-focused API Gateway with a lightweight approach, currently in pre-1.0 development phase. The project follows CUI (CUIoss) standards and is built using Maven with Java 21+. +Please refer to `agents.md` for complete guidance when working on this API Sheriff project. -## Build Commands +- Use `.plan/temp/` for ALL temporary files (covered by `Write(.plan/**)` permission - avoids permission prompts) -### Core Build Operations -- **Build project**: `./mvnw clean install` -- **Build without tests**: `./mvnw clean install -DskipTests` -- **Run tests only**: `./mvnw test` -- **Run single test**: `./mvnw test -Dtest=ClassName#methodName` +## Git Workflow -### Quality and Pre-Commit Process -**CRITICAL**: Always run these commands before committing: +All cuioss repositories have branch protection on `main`. Direct pushes to `main` are never allowed. Always use this workflow: -1. **Quality verification** (fix all errors/warnings): +1. Create a feature branch: `git checkout -b ` +2. Commit changes: `git add && git commit -m ""` +3. Push the branch: `git push -u origin ` +4. Create a PR: `gh pr create --repo cuioss/API-Sheriff --head --base main --title "" --body "<body>"` +5. Wait for CI + Gemini review (waits until checks complete): `gh pr checks --watch` +6. **Handle Gemini review comments** โ€” fetch with `gh api repos/cuioss/API-Sheriff/pulls/<pr-number>/comments` and for each: + - If clearly valid and fixable: fix it, commit, push, then reply explaining the fix and resolve the comment + - If disagree or out of scope: reply explaining why, then resolve the comment + - If uncertain (not 100% confident): **ask the user** before acting + - Every comment MUST get a reply (reason for fix or reason for not fixing) and MUST be resolved +7. Do **NOT** enable auto-merge unless explicitly instructed. Wait for user approval. +8. Return to main: `git checkout main && git pull` + +## Custom Commands + +### verifyCuiLoggingGuidelines + +Verify that the codebase complies with CUI logging standards by: + +1. **Analyze CUI logging standards** from `/Users/oliver/git/cui-llm-rules/standards/logging` +2. **Scan for logging violations** in the api-sheriff-library module: + - Direct string usage in INFO/WARN/ERROR logging calls + - Missing LogRecord definitions for structured messages + - Incorrect parameter substitution patterns (should use '%s', not '{}' or '%d') + - Wrong exception parameter ordering (exception should come first) +3. **Check LogRecord compliance**: + - All INFO/WARN/ERROR logs must use LogRecord constants + - Proper identifier ranges: INFO (001-099), WARN (100-199), ERROR (200-299) + - DSL-Style Constants Pattern with static imports +4. **Validate documentation** in `doc/LogMessages.adoc` matches LogRecord definitions +5. **Run logging-related tests** to verify LogAsserts work with LogRecord format +6. **Generate compliance report** with: + - Compliance percentage + - List of violations found + - Recommendations for fixes + - Testing verification results + +**Usage:** When user says "verifyCuiLoggingGuidelines", execute this comprehensive logging standards audit. + +### fixOpenRewriteMarkers <module-path> + +Fix all OpenRewrite TODO markers in a module following CUI standards: + +**CRITICAL UNDERSTANDING**: Markers like `/*~~(TODO: INFO needs LogRecord)~~>*/` indicate **ACTUAL BUGS**, not just style issues. + +**Execution Steps**: + +1. **Locate All Markers**: ```bash - ./mvnw -Ppre-commit clean verify -DskipTests + grep -r "~~(TODO:" <module-path>/src --include="*.java" ``` -2. **Final verification** (must pass completely): + - Count markers: `grep -r "~~(TODO:" <module-path>/src --include="*.java" | wc -l` + - Group by type: INFO needs LogRecord, WARN needs LogRecord, placeholder mismatches, etc. + +2. **Analyze and Fix Each Marker**: + + **Production Code (src/main/java)**: + - **Placeholder Mismatches**: Fix bugs like `LOGGER.info("value: %s", x, y)` (2 params, 1 placeholder) + - Add missing `%s` placeholders or remove extra parameters + - **Wrong Format Specifiers**: Change `%.2f`, `{:.2f}`, `{}`, `%d` โ†’ **ALWAYS use `%s`** + - **Missing LogRecords**: Create LogRecord constants for INFO/WARN/ERROR messages + - **Generic Exceptions**: Replace `Exception` with specific types (IOException, IllegalStateException) + - **RuntimeException**: Replace with specific exception types + + **Test Code (src/test/java)**: + - **Diagnostic Logging** (performance tests, concurrency tests): + - Add class-level suppression comment: + ```java + // cui-rewrite:disable CuiLogRecordPatternRecipe + // This is a test/utility class that outputs diagnostic information for analysis + ``` + - **NEVER create LogRecords for test diagnostic output** + - **Placeholder Mismatches**: Fix bugs even in tests (change to %s) + - **RuntimeException Throws**: Replace with AssertionError for test failures + - **Generic Exception Catches**: Replace with specific types + InterruptedException/BrokenBarrierException + +3. **Remove Markers After Fixing**: + + **macOS (BSD sed)**: ```bash - ./mvnw clean install + find <module-path>/src -name "*.java" -exec sed -i '' 's|/\*~~(TODO: INFO needs LogRecord)~~>\*/||g; s|/\*~~(TODO: WARN needs LogRecord)~~>\*/||g; s|/\*~~(TODO: ERROR needs LogRecord)~~>\*/||g' {} + ``` -### CI/CD Commands -- **Sonar analysis**: `./mvnw verify -Psonar sonar:sonar` -- **Deploy snapshot**: `./mvnw -Prelease-snapshot,javadoc deploy` -- **Coverage report**: `./mvnw clean verify -Pcoverage` - -## Project Structure - -``` -api-sheriff/ -โ”œโ”€โ”€ src/ -โ”‚ โ”œโ”€โ”€ main/ -โ”‚ โ”‚ โ””โ”€โ”€ java/ -โ”‚ โ”‚ โ””โ”€โ”€ de/cuioss/sheriff/api/ # Main source code -โ”‚ โ””โ”€โ”€ test/ -โ”‚ โ””โ”€โ”€ java/ -โ”‚ โ””โ”€โ”€ de/cuioss/sheriff/api/ # Test code -โ”œโ”€โ”€ doc/ -โ”‚ โ””โ”€โ”€ ai-rules.md # AI development guidelines -โ”œโ”€โ”€ pom.xml # Maven configuration -โ””โ”€โ”€ lombok.config # Lombok configuration -``` - -## Critical Development Rules - -### Pre-1.0 Project Rules (HIGHEST PRIORITY) -- **NEVER deprecate code** - Remove it directly -- **NEVER add @Deprecated annotations** - Delete unnecessary code immediately -- **NEVER enforce backward compatibility** - Make breaking changes freely -- **Clean APIs aggressively** - Remove unused methods, classes, and patterns -- **Focus on final API design** - Design for post-1.0 stability - -### CUI Standards Compliance - -#### Logging -- Use `de.cuioss.tools.logging.CuiLogger` (private static final LOGGER) -- Exception parameter always comes first in logging methods -- Use '%s' for string substitutions (not '{}' or '%d') -- Document all log messages in doc/LogMessages.adoc - -#### Testing -- Use JUnit 5 exclusively -- Follow AAA pattern (Arrange-Act-Assert) -- Minimum 80% code coverage required -- Use cui-test-generator for test data generation -- **Forbidden**: Mockito, PowerMock, Hamcrest - -#### Java Standards -- Java 21+ features encouraged (records, switch expressions, text blocks) -- Use Lombok annotations (@Builder, @Value, @NonNull, @UtilityClass) -- Prefer immutable objects and final fields -- Return empty collections instead of null -- Use Optional for nullable return values - -#### Documentation -- Every public API must have complete Javadoc -- Use AsciiDoc format (.adoc) for documentation -- Include @since tags with version information -- Document thread-safety considerations - -## Dependency Management - -Current minimal dependencies: -- **lombok**: For boilerplate reduction -- **junit-jupiter-api**: For testing -- **Parent POM**: de.cuioss:cui-java-parent:1.1.4 - -**CRITICAL**: Never add dependencies without explicit user approval - -## Integration with IntelliJ IDEA - -The project is configured for IntelliJ IDEA with: -- MCP server integration for enhanced IDE features -- Maven wrapper for consistent builds -- EditorConfig for code formatting - -Use IntelliJ MCP tools when available: -- `mcp__jetbrains__get_file_problems` for code analysis -- `mcp__jetbrains__execute_terminal_command` for running commands -- `mcp__jetbrains__search_in_files_by_text` for efficient code search - -## Security Considerations - -As a security-focused API Gateway: -- All changes must consider security implications -- Never expose sensitive data in logs -- Follow OWASP security guidelines -- Validate all inputs and outputs -- Use secure defaults for all configurations - -## Common Tasks - -### Adding New Features -1. Research existing patterns in the codebase -2. Follow CUI standards for implementation -3. Write comprehensive tests (80%+ coverage) -4. Document public APIs with Javadoc -5. Run pre-commit checks before committing - -### Fixing Issues -1. Identify the issue using IDE diagnostics -2. Apply fix following existing code patterns -3. Add/update tests to prevent regression -4. Verify with `./mvnw clean install` - -### Refactoring -1. Ensure tests pass before starting -2. Make incremental changes -3. Run tests after each change -4. Use IDE refactoring tools when available -5. Clean up aggressively (pre-1.0 rule) \ No newline at end of file + **Linux (GNU sed)**: + ```bash + find <module-path>/src -name "*.java" -exec sed -i 's|/\*~~(TODO: INFO needs LogRecord)~~>\*/||g; s|/\*~~(TODO: WARN needs LogRecord)~~>\*/||g; s|/\*~~(TODO: ERROR needs LogRecord)~~>\*/||g' {} + + ``` + + - Verify removal: `grep -r "~~(TODO:" <module-path>/src --include="*.java" | wc -l` (should be 0) + +4. **Verify Fixes**: + ```bash + cd <module-path> && ../mvnw -Ppre-commit clean verify + ``` + - All tests must pass + - No compilation errors + - Markers may reappear if bugs not truly fixed + - If markers reappear, repeat steps 2-4 + +5. **Final Validation**: + - Run full test suite: `cd <module-path> && ../mvnw clean install` + - Confirm zero markers: `grep -r "~~(TODO:" <module-path>/src --include="*.java"` + - Verify test count matches previous successful run (no tests accidentally broken) + +**Common Bugs to Watch For**: +- `LOGGER.info("value %s", x, y)` โ†’ Missing placeholder for `y` +- `LOGGER.info("avg %.2f ms", avg)` โ†’ Use `%s` not `%.2f` +- `LOGGER.info("result {}", value)` โ†’ Use `%s` not `{}` +- `catch (Exception e)` โ†’ Use specific exception types +- `catch (RuntimeException e)` โ†’ Use IllegalArgumentException | IllegalStateException +- Test logging creating LogRecords โ†’ Use suppression comment instead + +**Critical Rules**: +- **NEVER remove markers without fixing bugs** +- **NEVER create LogRecords for test diagnostic logging** +- **ALWAYS use `%s` for ALL string substitutions** (never `%.2f`, `{}`, `%d`) +- **ALWAYS fix placeholder/parameter count mismatches** +- **ALWAYS use specific exception types** (never Exception/RuntimeException) + +**Usage:** When user says "fixOpenRewriteMarkers api-sheriff-library", execute this complete marker fixing workflow. + +### verifyAndCommit <module-name> + +Execute comprehensive quality verification and commit workflow for a specific module: + +1. **Quality Verification Build** (pre-commit profile): + ```bash + ./mvnw -Ppre-commit clean verify -pl <module-name> + ``` + - Runs code quality checks (checkstyle, spotbugs, PMD) + - Performs static analysis + - Validates code formatting and style compliance + - **NO SHORTCUTS** - Fix ALL errors and warnings before proceeding + +2. **Final Verification Build** (full integration): + ```bash + ./mvnw clean install -pl <module-name> + ``` + - Runs complete build with all tests + - Validates full integration and functionality + - Ensures no regressions introduced + - This will take nearly 8 Minutes. Always wait for it to complete. 10 minutes on the outside + - **NO SHORTCUTS** - Fix ALL test failures and build errors + +3. **Error Resolution Loop**: + - If ANY errors or warnings occur in either build, STOP and fix them + - Re-run the failed build command until it passes completely + - DO NOT proceed to next step until current step is 100% clean + - Apply fixes systematically and verify each fix + +4. **Artifact Cleanup Verification**: + ```bash + find <module-name>/src/main/java -name "*.class" -type f + find <module-name>/src/test/java -name "*.class" -type f + find <module-name>/src -name "*.jar" -type f + find <module-name>/src -name "*.war" -type f + find <module-name>/src -name "target" -type d + ``` + - Verify NO class files exist in source directories + - Verify NO jar/war files exist in source directories + - Verify NO target directories exist in source directories + - Ensure NO build artifacts contaminate source code + - Clean up any artifacts found before proceeding + - **FAIL BUILD** if any artifacts are found in src/ directories + +5. **Git Commit**: + - Only proceed to commit when ALL steps pass completely + - Create descriptive commit message explaining the changes + - Include Co-Authored-By: Claude footer + +**Usage:** When user says "verifyAndCommit api-sheriff-library", execute this complete verification and commit workflow for the api-sheriff-library module. + +**Critical Rules:** +- **NEVER skip error fixes** - Every warning and error must be resolved +- **NEVER use shortcuts** - Run complete verification cycles +- **NEVER commit with failing builds** - Only commit when everything passes +- **NEVER commit with source artifacts** - Source directories must be clean of .class files +- **ALWAYS fix issues systematically** - Address root causes, not symptoms diff --git a/agents.md b/agents.md new file mode 100644 index 00000000..b3f20ffb --- /dev/null +++ b/agents.md @@ -0,0 +1,259 @@ +# API Sheriff - AI Agent Guidance + +API Sheriff is a security-focused API Gateway with a lightweight approach for Java/Quarkus applications. This document guides AI coding agents when working with the codebase. + +## Dev Environment Tips + +### Build System +- **Build tool**: Maven 3.9.6 (via wrapper: `./mvnw`) +- **Java version**: Java 21 (LTS) +- **Primary framework**: Quarkus 3.32.1 + +### Project Structure +Multi-module Maven project: +- `api-sheriff-library/` - Core API Sheriff library +- `api-sheriff-quarkus-parent/` - Quarkus framework integration +- `benchmarking/` - Performance benchmarking modules +- `bom/` - Bill of Materials for dependency management + +### Essential Build Commands +```bash +# Development build +./mvnw clean verify + +# Full build with all tests +./mvnw clean install + +# Build single module +./mvnw clean install -pl <module-name> + +# Run single test +./mvnw test -Dtest=ClassName#methodName +``` + +### Code Standards +- **Indentation**: 4 spaces (configured in `.editorconfig`) +- **Line endings**: Unix-style (LF) +- **Encoding**: UTF-8 +- **Java features**: Use modern Java 21 features (records, sealed classes, pattern matching, text blocks) +- **Lombok**: Use `@Builder`, `@Value`, `@NonNull`, `@ToString`, `@EqualsAndHashCode` appropriately + +### Logging Standards +This project uses CUI logging standards with Java Util Logging: +- Logger: `de.cuioss.tools.logging.CuiLogger` (private static final LOGGER) +- **Format specifier**: Always use `%s` for parameter substitution (NEVER `{}`, `%.2f`, `%d`) +- **Structured logging**: Use `de.cuioss.tools.logging.LogRecord` for INFO/WARN/ERROR messages +- **LogRecord ranges**: INFO (001-099), WARN (100-199), ERROR (200-299) +- **Documentation**: All log messages must be documented in `doc/LogMessages.adoc` +- **Exception logging**: Exception parameter always comes first + +## Testing Instructions + +### Testing Framework +- **Primary**: JUnit 5 (Jupiter) +- **Test patterns**: AAA pattern (Arrange-Act-Assert) +- **Coverage requirement**: Minimum 80% line and branch coverage +- **Coverage check**: `./mvnw clean verify -Pcoverage` + +### CUI Test Generator +This project uses CUI Test Generator for all test data generation: +- Provides type-safe, consistent test data generation +- Use `@GeneratorsSource` for complex objects (most preferred) +- Use `@CompositeTypeGeneratorSource` for multiple related types +- Use `@CsvSource` for simple data +- Use `@ValueSource` for single parameter variations +- Use `@MethodSource` as last resort only + +### Parameterized Tests +Mandatory for 3+ similar test variants. Annotation hierarchy (preferred order): +1. `@GeneratorsSource` (most preferred) +2. `@CompositeTypeGeneratorSource` +3. `@CsvSource` +4. `@ValueSource` +5. `@MethodSource` (last resort) + +### Test Execution Commands +```bash +# Run all tests +./mvnw test + +# Run integration tests +./mvnw clean verify -Pintegration-tests -pl api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests -am + +# Run micro-benchmarks +./mvnw clean verify -pl benchmarking/benchmark-core -Pbenchmark + +# Run integration benchmarks +./mvnw clean verify -Pbenchmark -pl benchmarking/benchmark-integration-wrk +``` + +### Pre-Commit Validation + +**CRITICAL**: Execute this sequence before ANY commit: + +1. **Quality verification**: + ```bash + ./mvnw -Ppre-commit clean verify + ``` + - Fix ALL errors and warnings (mandatory) + - Address OpenRewrite markers (see section below) + +2. **Final verification**: + ```bash + ./mvnw clean install + ``` + - Must complete without errors or warnings + - All tests must pass + +3. **Integration tests**: + ```bash + ./mvnw clean verify -Pintegration-tests -pl api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests -am + ``` + +Tasks are complete ONLY after all three steps succeed. + +### OpenRewrite Markers - Critical Understanding + +Pre-commit builds run OpenRewrite recipes that add markers to flag violations. + +**Marker pattern**: `/*~~(TODO: INFO needs LogRecord)~~>*/` or `/*~~(TODO: [message])~~>*/` + +**What markers indicate**: +Markers indicate ACTUAL BUGS: +- Placeholder/parameter count mismatches: `"value: %s"` with 0 parameters +- Wrong format specifiers: Using `%.2f`, `{:.2f}`, `{}`, `%d` instead of `%s` +- Missing LogRecord definitions for production INFO/WARN/ERROR logs +- Generic Exception usage instead of specific types +- RuntimeException catches that should be specific exceptions + +**Handling strategy**: + +Production code violations: +- Fix the actual bug (add missing placeholders, change format to %s) +- Create LogRecord constant for INFO/WARN/ERROR messages +- Replace generic Exception with specific types (IOException, IllegalStateException, etc.) +- Never catch or throw RuntimeException - use specific exception types + +Test code violations: +- For diagnostic/performance logging: Add suppression comment at class level: + ```java + // cui-rewrite:disable CuiLogRecordPatternRecipe + // This is a test/utility class that outputs diagnostic information for analysis + ``` +- For exception handling: Replace RuntimeException with AssertionError in test failures +- For format bugs: Fix placeholder mismatches even in tests (change to %s) + +**Never commit code with markers present.** + +## Pre-1.0 Project Rules + +This project is PRE-1.0 (current version: 1.0.0-SNAPSHOT). Therefore: +- **Never deprecate code** - Remove it directly if not needed +- **Never add transitional comments** like "TODO: Remove in v2.0" +- **Never enforce backward compatibility** - Make breaking changes freely +- **Never add @Deprecated annotations** - Delete unnecessary code immediately +- **Clean APIs aggressively** - Remove unused methods, classes, and patterns +- **Focus on final API design** - Design for post-1.0 stability + +## Custom Commands + +This project includes custom commands for common workflows: + +### verifyCuiLoggingGuidelines +Comprehensive logging standards audit: +1. Analyze CUI logging standards from `/Users/oliver/git/cui-llm-rules/standards/logging` +2. Scan for logging violations in api-sheriff-library module +3. Check LogRecord compliance +4. Validate documentation in `doc/LogMessages.adoc` +5. Run logging-related tests +6. Generate compliance report + +### fixOpenRewriteMarkers <module-path> +Fix all OpenRewrite TODO markers in a module: +1. Locate all markers with grep +2. Analyze and fix each marker (production vs test code) +3. Remove markers after fixing +4. Verify fixes with pre-commit build +5. Final validation with full test suite + +### verifyAndCommit <module-name> +Execute comprehensive quality verification and commit workflow for a specific module: +1. Quality verification build (pre-commit profile) +2. Final verification build (full integration) +3. Error resolution loop +4. Artifact cleanup verification +5. Git commit + +## Slash Commands + +The project includes custom slash commands in `.claude/commands/`: + +- `/verify-project [push]` - Comprehensive project verification +- `/verify-integration-tests` - Integration tests with Quarkus/Keycloak log analysis +- `/verify-micro-benchmark` - JMH micro-benchmark verification +- `/verify-integration-benchmark` - WRK-based integration benchmark verification +- `/verify-all [push]` - End-to-end verification of all commands in sequence + +All commands read execution duration from `doc/commands.md` and update it if changed >10%. + +## Documentation Standards + +- **Format**: AsciiDoc with `.adoc` extension +- **Key documents**: + - `README.adoc` - Project overview + - `doc/Build.adoc` - Build instructions + - `doc/Requirements.adoc` - Functional requirements + - `doc/Specification.adoc` - Technical specifications + - `doc/LogMessages.adoc` - Logging reference +- **Cross-references**: Use `xref:` syntax (not `<<>>`) +- **Blank lines**: Required before all lists +- **Header**: Include TOC and section numbering +- **Source highlighting**: Use `:source-highlighter: highlight.js` + +### Javadoc Standards +- Every public and protected class/interface must be documented +- Include clear purpose statement in class documentation +- Document all public methods with parameters, returns, and exceptions +- Include `@since` tag with version information +- Document thread-safety considerations +- Include usage examples for complex classes and methods +- Every package must have package-info.java +- Use `{@link}` for references to classes, methods, and fields + +## CDI and Quarkus Standards + +- Use constructor injection (mandatory over field injection) +- Single constructor rule: No `@Inject` needed for single constructors +- Use `final` fields for injected dependencies +- Use `@ApplicationScoped` for stateless services +- Use `@QuarkusTest` for CDI context testing +- Use `@QuarkusIntegrationTest` for packaged app testing +- HTTPS required for all integration tests + +## Security Considerations + +As a security-focused API Gateway: +- All changes must consider security implications +- Never expose sensitive data in logs +- Follow OWASP security guidelines +- Validate all inputs and outputs +- Use secure defaults for all configurations + +## General Process Rules + +1. **Use `.plan/temp/` for ALL temporary files** - Covered by `Write(.plan/**)` permission (avoids permission prompts) +2. **If in doubt, ask the user** - Never make assumptions +3. **Always research topics** - Use available tools (WebSearch, WebFetch, etc.) to find recent best practices +4. **Never guess or be creative** - If you cannot find best practices, ask the user +5. **Do not proliferate documents** - Always use context-relevant documents, never create without user approval +6. **Never add dependencies without approval** - Always ask before adding any dependency + +## Important Files + +Key reference files for development: +- `doc/LogMessages.adoc` - Complete logging reference +- `doc/Build.adoc` - Build and deployment instructions +- `doc/Requirements.adoc` - Functional requirements +- `doc/Specification.adoc` - Technical specifications +- `.editorconfig` - Code formatting configuration +- `lombok.config` - Lombok configuration diff --git a/api-sheriff-library/pom.xml b/api-sheriff-library/pom.xml index 4e19ccc1..9453dfa6 100644 --- a/api-sheriff-library/pom.xml +++ b/api-sheriff-library/pom.xml @@ -23,7 +23,7 @@ <dependencies> <dependency> <groupId>de.cuioss.sheriff.api</groupId> - <artifactId>bom</artifactId> + <artifactId>api-sheriff-bom</artifactId> <version>${project.version}</version> <type>pom</type> <scope>import</scope> diff --git a/api-sheriff-quarkus-parent/api-sheriff-quarkus-deployment/pom.xml b/api-sheriff-quarkus-parent/api-sheriff-quarkus-deployment/pom.xml index bdb23e0a..ec7b9b8f 100644 --- a/api-sheriff-quarkus-parent/api-sheriff-quarkus-deployment/pom.xml +++ b/api-sheriff-quarkus-parent/api-sheriff-quarkus-deployment/pom.xml @@ -76,7 +76,7 @@ <!-- DevUI integration --> <dependency> <groupId>io.quarkus</groupId> - <artifactId>quarkus-vertx-http-dev-ui-spi</artifactId> + <artifactId>quarkus-devui-deployment-spi</artifactId> </dependency> <!-- Test dependencies --> diff --git a/api-sheriff-quarkus-parent/pom.xml b/api-sheriff-quarkus-parent/pom.xml index c237529a..ec5a38f5 100644 --- a/api-sheriff-quarkus-parent/pom.xml +++ b/api-sheriff-quarkus-parent/pom.xml @@ -28,11 +28,10 @@ - Configure logging.properties in each module's test resources - Suppress JVM warnings with -XX:+IgnoreUnrecognizedVMOptions --> - <junit-platform.version>1.13.1</junit-platform.version> - <version.weld-junit5>5.0.1.Final</version.weld-junit5> + <version.weld-junit5>5.0.3.Final</version.weld-junit5> <version.easymock>5.6.0</version.easymock> <!-- Default empty argLine for JaCoCo compatibility - JaCoCo will override this when active --> - <argLine></argLine> + <argLine /> </properties> <dependencyManagement> @@ -46,29 +45,29 @@ </dependency> <dependency> <groupId>de.cuioss.sheriff.api</groupId> - <artifactId>bom</artifactId> + <artifactId>api-sheriff-bom</artifactId> <version>${project.version}</version> <type>pom</type> <scope>import</scope> </dependency> - <!-- JUnit BOM is already imported by quarkus-bom --> - <!-- Explicitly override JUnit versions to ensure all components are compatible--> + <!-- Override JUnit Platform versions to match Jupiter (cui-java-parent provides + version.junit.jupiter, but the Quarkus BOM pins older Platform versions) --> <dependency> <groupId>org.junit.platform</groupId> <artifactId>junit-platform-commons</artifactId> - <version>${junit-platform.version}</version> + <version>${version.junit.jupiter}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.junit.platform</groupId> <artifactId>junit-platform-engine</artifactId> - <version>${junit-platform.version}</version> + <version>${version.junit.jupiter}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.junit.platform</groupId> <artifactId>junit-platform-launcher</artifactId> - <version>${junit-platform.version}</version> + <version>${version.junit.jupiter}</version> <scope>test</scope> </dependency> <!-- Additional dependencies --> diff --git a/benchmarking/benchmark-library/pom.xml b/benchmarking/benchmark-core/pom.xml similarity index 83% rename from benchmarking/benchmark-library/pom.xml rename to benchmarking/benchmark-core/pom.xml index 8b8c780a..2907ad21 100644 --- a/benchmarking/benchmark-library/pom.xml +++ b/benchmarking/benchmark-core/pom.xml @@ -10,36 +10,39 @@ <relativePath>../pom.xml</relativePath> </parent> - <artifactId>benchmark-library</artifactId> + <artifactId>benchmark-core</artifactId> <packaging>jar</packaging> - <name>API Sheriff Benchmark Library</name> + <name>API Sheriff Benchmark Core</name> <description>Benchmarking module for API Sheriff functionality</description> <properties> - <maven.jar.plugin.automatic.module.name>de.cuioss.sheriff.api.benchmark</maven.jar.plugin.automatic.module.name> - <sonar.skip>true</sonar.skip> + <maven.jar.plugin.automatic.module.name>de.cuioss.sheriff.api.benchmark.core</maven.jar.plugin.automatic.module.name> + <version.benchmarking-common>0.4.1</version.benchmarking-common> <version.mockwebserver3>5.0.0-alpha.12</version.mockwebserver3> <!-- Default benchmark runner --> <benchmark.runner>de.cuioss.sheriff.api.benchmark.BenchmarkRunner</benchmark.runner> - + <!-- JMH Configuration Properties - Optimized for fast execution (<10 minutes) --> + <jmh.include>de\.cuioss\.sheriff\.api\.benchmark\..*</jmh.include> <jmh.result.format>JSON</jmh.result.format> - <jmh.result.filePrefix>${benchmark.results.dir}/micro-benchmark-result</jmh.result.filePrefix> - <jmh.iterations>3</jmh.iterations> - <jmh.warmupIterations>1</jmh.warmupIterations> + <jmh.result.filePrefix>target/benchmark-results/micro-result</jmh.result.filePrefix> + <jmh.iterations>5</jmh.iterations> + <jmh.warmupIterations>3</jmh.warmupIterations> <jmh.forks>1</jmh.forks> <!-- Reduced from 200 to 100 threads to avoid contention and improve P99 latency --> <jmh.threads>100</jmh.threads> <jmh.time>4s</jmh.time> <jmh.warmupTime>1s</jmh.warmupTime> + <!-- Benchmark history directory for trend analysis (passed from CI) --> + <benchmark.history.dir /> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>de.cuioss.sheriff.api</groupId> - <artifactId>bom</artifactId> + <artifactId>api-sheriff-bom</artifactId> <version>${project.version}</version> <type>pom</type> <scope>import</scope> @@ -50,6 +53,11 @@ <version>${project.version}</version> <classifier>generators</classifier> </dependency> + <dependency> + <groupId>de.cuioss.sheriff.oauth</groupId> + <artifactId>benchmarking-common</artifactId> + <version>${version.benchmarking-common}</version> + </dependency> <dependency> <groupId>com.squareup.okhttp3</groupId> <artifactId>mockwebserver3</artifactId> @@ -69,6 +77,10 @@ <groupId>de.cuioss.sheriff.api</groupId> <artifactId>api-sheriff-library</artifactId> </dependency> + <dependency> + <groupId>de.cuioss.sheriff.oauth</groupId> + <artifactId>benchmarking-common</artifactId> + </dependency> <!-- Test dependencies from library module --> <dependency> @@ -218,21 +230,6 @@ <groupId>org.codehaus.mojo</groupId> <artifactId>exec-maven-plugin</artifactId> <executions> - <execution> - <id>create-benchmark-dir</id> - <phase>compile</phase> - <goals> - <goal>exec</goal> - </goals> - <configuration> - <skip>${skip.benchmark}</skip> - <executable>mkdir</executable> - <arguments> - <argument>-p</argument> - <argument>${benchmark.results.dir}</argument> - </arguments> - </configuration> - </execution> <execution> <id>run-benchmarks</id> <phase>verify</phase> @@ -245,6 +242,7 @@ <arguments> <argument>-classpath</argument> <argument>${project.build.outputDirectory}${path.separator}${project.build.directory}/dependency/*</argument> + <argument>-Djmh.include=${jmh.include}</argument> <argument>-Djmh.result.format=${jmh.result.format}</argument> <argument>-Djmh.result.filePrefix=${jmh.result.filePrefix}</argument> <argument>-Djmh.iterations=${jmh.iterations}</argument> @@ -253,8 +251,8 @@ <argument>-Djmh.threads=${jmh.threads}</argument> <argument>-Djmh.time=${jmh.time}</argument> <argument>-Djmh.warmupTime=${jmh.warmupTime}</argument> - <argument>-Dbenchmark.results.dir=${benchmark.results.dir}</argument> - <argument>-Djava.util.logging.config.file=src/main/resources/benchmark-logging.properties</argument> + <argument>-Dbenchmark.history.dir=${benchmark.history.dir}</argument> + <argument>-Djava.util.logging.config.file=benchmark-logging.properties</argument> <argument>-XX:+UnlockDiagnosticVMOptions</argument> <argument>-XX:+DebugNonSafepoints</argument> <argument>${benchmark.runner}</argument> @@ -268,21 +266,7 @@ <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> - <executions> - <execution> - <id>copy-dependencies</id> - <phase>package</phase> - <goals> - <goal>copy-dependencies</goal> - </goals> - <configuration> - <outputDirectory>${project.build.directory}/dependency</outputDirectory> - <overWriteReleases>false</overWriteReleases> - <overWriteSnapshots>false</overWriteSnapshots> - <overWriteIfNewer>true</overWriteIfNewer> - </configuration> - </execution> - </executions> + <!-- Configuration inherited from parent pluginManagement --> </plugin> </plugins> </build> diff --git a/benchmarking/benchmark-library/src/main/java/de/cuioss/sheriff/api/benchmark/BenchmarkOptionsHelper.java b/benchmarking/benchmark-core/src/main/java/de/cuioss/sheriff/api/benchmark/BenchmarkOptionsHelper.java similarity index 100% rename from benchmarking/benchmark-library/src/main/java/de/cuioss/sheriff/api/benchmark/BenchmarkOptionsHelper.java rename to benchmarking/benchmark-core/src/main/java/de/cuioss/sheriff/api/benchmark/BenchmarkOptionsHelper.java diff --git a/benchmarking/benchmark-library/src/main/java/de/cuioss/sheriff/api/benchmark/BenchmarkRunner.java b/benchmarking/benchmark-core/src/main/java/de/cuioss/sheriff/api/benchmark/BenchmarkRunner.java similarity index 100% rename from benchmarking/benchmark-library/src/main/java/de/cuioss/sheriff/api/benchmark/BenchmarkRunner.java rename to benchmarking/benchmark-core/src/main/java/de/cuioss/sheriff/api/benchmark/BenchmarkRunner.java diff --git a/benchmarking/benchmark-integration-quarkus/pom.xml b/benchmarking/benchmark-integration-quarkus/pom.xml deleted file mode 100644 index b926ec61..00000000 --- a/benchmarking/benchmark-integration-quarkus/pom.xml +++ /dev/null @@ -1,505 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project xmlns="http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> - <modelVersion>4.0.0</modelVersion> - <parent> - <groupId>de.cuioss.sheriff.api</groupId> - <artifactId>benchmarking</artifactId> - <version>1.0.0-SNAPSHOT</version> - <relativePath>../pom.xml</relativePath> - </parent> - - <artifactId>benchmark-integration-quarkus</artifactId> - <packaging>jar</packaging> - <name>API Sheriff Quarkus Integration Benchmarks</name> - <description>JMH benchmarks for Quarkus integration testing against live services</description> - - <properties> - <maven.jar.plugin.automatic.module.name>de.cuioss.sheriff.api.quarkus.benchmark</maven.jar.plugin.automatic.module.name> - <sonar.skip>true</sonar.skip> - - <!-- Default benchmark runner --> - <benchmark.runner>de.cuioss.sheriff.api.quarkus.benchmark.BenchmarkRunner</benchmark.runner> - - <!-- JMH Configuration Properties - Optimized for integration testing --> - <jmh.result.format>JSON</jmh.result.format> - <jmh.result.filePrefix>${benchmark.results.dir}/integration-benchmark-result</jmh.result.filePrefix> - <jmh.iterations>5</jmh.iterations> - <jmh.warmupIterations>1</jmh.warmupIterations> - <jmh.forks>2</jmh.forks> - <jmh.threads>24</jmh.threads> - <jmh.time>10s</jmh.time> - <jmh.warmupTime>1s</jmh.warmupTime> - - <!-- Integration test service URLs - aligned with docker-compose.yml ports --> - <integration.service.url>https://localhost:10443</integration.service.url> - <keycloak.url>https://localhost:1443</keycloak.url> - <quarkus.metrics.url>https://localhost:10443</quarkus.metrics.url> - </properties> - - <dependencies> - <!-- API Sheriff library dependency --> - <dependency> - <groupId>de.cuioss.sheriff.api</groupId> - <artifactId>api-sheriff-library</artifactId> - <version>${project.version}</version> - </dependency> - - <!-- Quarkus dependencies for CDI --> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-core</artifactId> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-arc</artifactId> - </dependency> - - <!-- JMH dependencies --> - <dependency> - <groupId>org.openjdk.jmh</groupId> - <artifactId>jmh-core</artifactId> - </dependency> - <dependency> - <groupId>org.openjdk.jmh</groupId> - <artifactId>jmh-generator-annprocess</artifactId> - </dependency> - - <!-- CUI utilities --> - <dependency> - <groupId>de.cuioss</groupId> - <artifactId>cui-java-tools</artifactId> - <scope>compile</scope> - </dependency> - - <!-- JSON processing --> - <dependency> - <groupId>com.google.code.gson</groupId> - <artifactId>gson</artifactId> - </dependency> - - <!-- HdrHistogram for accurate latency recording --> - <dependency> - <groupId>org.hdrhistogram</groupId> - <artifactId>HdrHistogram</artifactId> - </dependency> - - <!-- Lombok --> - <dependency> - <groupId>org.projectlombok</groupId> - <artifactId>lombok</artifactId> - <scope>provided</scope> - </dependency> - - <!-- Apache Commons IO for TeeOutputStream --> - <dependency> - <groupId>commons-io</groupId> - <artifactId>commons-io</artifactId> - </dependency> - - - <!-- JUnit for basic testing --> - <dependency> - <groupId>org.junit.jupiter</groupId> - <artifactId>junit-jupiter</artifactId> - <scope>test</scope> - </dependency> - - <!-- Awaitility for better async testing --> - <dependency> - <groupId>org.awaitility</groupId> - <artifactId>awaitility</artifactId> - <scope>test</scope> - </dependency> - </dependencies> - - <build> - <plugins> - <!-- Configure surefire for unit tests --> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-surefire-plugin</artifactId> - <configuration> - <skipTests>false</skipTests> - <argLine>-XX:+IgnoreUnrecognizedVMOptions -Djava.awt.headless=true</argLine> - </configuration> - </plugin> - - <!-- Enable annotation processing for JMH --> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-compiler-plugin</artifactId> - <configuration> - <annotationProcessorPaths> - <path> - <groupId>org.openjdk.jmh</groupId> - <artifactId>jmh-generator-annprocess</artifactId> - <version>${version.jmh}</version> - </path> - <path> - <groupId>org.projectlombok</groupId> - <artifactId>lombok</artifactId> - <version>${version.lombok}</version> - </path> - </annotationProcessorPaths> - <release>21</release> - </configuration> - </plugin> - - <!-- Execute benchmark tests when skip.benchmark is false --> - <plugin> - <groupId>org.codehaus.mojo</groupId> - <artifactId>exec-maven-plugin</artifactId> - <executions> - <execution> - <id>create-benchmark-dir</id> - <phase>compile</phase> - <goals> - <goal>exec</goal> - </goals> - <configuration> - <skip>${skip.benchmark}</skip> - <executable>mkdir</executable> - <arguments> - <argument>-p</argument> - <argument>${benchmark.results.dir}</argument> - </arguments> - </configuration> - </execution> - <execution> - <id>run-benchmarks</id> - <phase>integration-test</phase> - <goals> - <goal>exec</goal> - </goals> - <configuration> - <skip>${skip.benchmark}</skip> - <executable>java</executable> - <arguments> - <argument>-Djava.util.logging.manager=java.util.logging.LogManager</argument> - <argument>-classpath</argument> - <argument>${project.build.outputDirectory}${path.separator}${project.build.directory}/dependency/*</argument> - <argument>-Djmh.result.format=${jmh.result.format}</argument> - <argument>-Djmh.result.filePrefix=${jmh.result.filePrefix}</argument> - <argument>-Djmh.iterations=${jmh.iterations}</argument> - <argument>-Djmh.warmupIterations=${jmh.warmupIterations}</argument> - <argument>-Djmh.forks=${jmh.forks}</argument> - <argument>-Djmh.threads=${jmh.threads}</argument> - <argument>-Djmh.time=${jmh.time}</argument> - <argument>-Djmh.warmupTime=${jmh.warmupTime}</argument> - <argument>-Dbenchmark.results.dir=${benchmark.results.dir}</argument> - <argument>-Dintegration.service.url=${integration.service.url}</argument> - <argument>-Dkeycloak.url=${keycloak.url}</argument> - <argument>-Dquarkus.metrics.url=${quarkus.metrics.url}</argument> - <argument>-Djava.util.logging.manager=java.util.logging.LogManager</argument> - <argument>-Djava.util.logging.config.file=src/main/resources/benchmark-logging.properties</argument> - <argument>-XX:+UnlockDiagnosticVMOptions</argument> - <argument>-XX:+DebugNonSafepoints</argument> - <argument>${benchmark.runner}</argument> - </arguments> - </configuration> - </execution> - </executions> - </plugin> - - <!-- Build classpath for benchmark execution --> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-dependency-plugin</artifactId> - <executions> - <execution> - <id>copy-dependencies</id> - <phase>package</phase> - <goals> - <goal>copy-dependencies</goal> - </goals> - <configuration> - <outputDirectory>${project.build.directory}/dependency</outputDirectory> - <overWriteReleases>false</overWriteReleases> - <overWriteSnapshots>false</overWriteSnapshots> - <overWriteIfNewer>true</overWriteIfNewer> - </configuration> - </execution> - </executions> - </plugin> - </plugins> - </build> - - <profiles> - <profile> - <id>benchmark-testing</id> - <properties> - <skip.benchmark>false</skip.benchmark> - <benchmark.results.dir>target/benchmark-results</benchmark.results.dir> - </properties> - <build> - <plugins> - <plugin> - <groupId>org.codehaus.mojo</groupId> - <artifactId>exec-maven-plugin</artifactId> - <executions> - <!-- Build integration tests (using smart native build script) --> - <execution> - <id>maven-build-integration-tests</id> - <phase>pre-integration-test</phase> - <goals> - <goal>exec</goal> - </goals> - <configuration> - <executable>../../mvnw</executable> - <arguments> - <argument>compile</argument> - <argument>exec:exec@build-native-if-needed</argument> - <argument>exec:exec@docker-build-distroless</argument> - <argument>-Pintegration-tests</argument> - <argument>-DskipTests</argument> - </arguments> - <workingDirectory>${project.basedir}/../../api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests</workingDirectory> - </configuration> - </execution> - <!-- Start integration test containers (keep running for benchmarks) --> - <execution> - <id>start-integration-containers</id> - <phase>pre-integration-test</phase> - <goals> - <goal>exec</goal> - </goals> - <configuration> - <executable>../../api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/scripts/start-integration-container.sh</executable> - <workingDirectory>${project.basedir}</workingDirectory> - </configuration> - </execution> - <!-- Metrics processing moved to BenchmarkRunner.java directly --> - <!-- Generate HTTP metrics from benchmark results --> - <execution> - <id>generate-http-metrics</id> - <phase>post-integration-test</phase> - <goals> - <goal>exec</goal> - </goals> - <configuration> - <executable>bash</executable> - <arguments> - <argument>-c</argument> - <argument>cd target && java -cp "classes:dependency/*" de.cuioss.sheriff.api.quarkus.benchmark.metrics.MetricsPostProcessor benchmark-results || echo "Comprehensive metrics generation failed - continuing"</argument> - </arguments> - <workingDirectory>${project.basedir}</workingDirectory> - </configuration> - </execution> - <!-- Stop integration test containers --> - <execution> - <id>stop-integration-containers</id> - <phase>post-integration-test</phase> - <goals> - <goal>exec</goal> - </goals> - <configuration> - <executable>../../api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/scripts/stop-integration-container.sh</executable> - <workingDirectory>${project.basedir}</workingDirectory> - <!-- Don't fail build if cleanup fails --> - <successCodes> - <successCode>0</successCode> - <successCode>1</successCode> - </successCodes> - </configuration> - </execution> - </executions> - </plugin> - </plugins> - </build> - </profile> - - <profile> - <id>rebuild-container</id> - <build> - <plugins> - <plugin> - <groupId>org.codehaus.mojo</groupId> - <artifactId>exec-maven-plugin</artifactId> - <executions> - <!-- Clean integration tests to force container rebuild --> - <execution> - <id>clean-integration-tests-for-rebuild</id> - <phase>clean</phase> - <goals> - <goal>exec</goal> - </goals> - <configuration> - <executable>../../mvnw</executable> - <arguments> - <argument>clean</argument> - </arguments> - <workingDirectory>${project.basedir}/../../api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests</workingDirectory> - </configuration> - </execution> - </executions> - </plugin> - </plugins> - </build> - </profile> - - <profile> - <id>benchmark-jfr</id> - <properties> - <skip.benchmark>false</skip.benchmark> - <benchmark.results.dir>target/benchmark-results</benchmark.results.dir> - <jfr.enabled>true</jfr.enabled> - </properties> - <build> - <plugins> - <plugin> - <groupId>org.codehaus.mojo</groupId> - <artifactId>exec-maven-plugin</artifactId> - <executions> - <!-- Create benchmark and JFR results directories --> - <execution> - <id>create-jfr-dirs</id> - <phase>pre-integration-test</phase> - <goals> - <goal>exec</goal> - </goals> - <configuration> - <executable>bash</executable> - <arguments> - <argument>-c</argument> - <argument>mkdir -p ${benchmark.results.dir}/jfr-recordings ${benchmark.results.dir}/jfr-reports</argument> - </arguments> - </configuration> - </execution> - <!-- Build JFR integration tests (without running containers) --> - <execution> - <id>maven-build-jfr-tests</id> - <phase>pre-integration-test</phase> - <goals> - <goal>exec</goal> - </goals> - <configuration> - <executable>bash</executable> - <arguments> - <argument>-c</argument> - <argument>cd ../../api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests && ../../mvnw clean compile quarkus:build -Pintegration-tests -DskipTests && DOCKERFILE=Dockerfile.native.jfr DOCKER_IMAGE_TAG=jfr DOCKER_BUILDKIT=1 docker compose build api-sheriff-integration-tests</argument> - </arguments> - <workingDirectory>${project.basedir}</workingDirectory> - </configuration> - </execution> - <!-- Start JFR integration test containers --> - <execution> - <id>start-jfr-containers</id> - <phase>pre-integration-test</phase> - <goals> - <goal>exec</goal> - </goals> - <configuration> - <executable>bash</executable> - <arguments> - <argument>-c</argument> - <argument>DOCKER_IMAGE_TAG=jfr DOCKERFILE=Dockerfile.native.jfr ../../api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/scripts/start-integration-container.sh</argument> - </arguments> - <workingDirectory>${project.basedir}</workingDirectory> - </configuration> - </execution> - <!-- Run benchmarks with JFR profiling enabled --> - <execution> - <id>run-benchmarks-jfr</id> - <phase>integration-test</phase> - <goals> - <goal>exec</goal> - </goals> - <configuration> - <executable>java</executable> - <arguments> - <argument>-Djava.util.logging.manager=java.util.logging.LogManager</argument> - <argument>-classpath</argument> - <argument>${project.build.outputDirectory}${path.separator}${project.build.directory}/dependency/*</argument> - <argument>-Djmh.result.format=${jmh.result.format}</argument> - <argument>-Djmh.result.filePrefix=${jmh.result.filePrefix}</argument> - <argument>-Djmh.iterations=${jmh.iterations}</argument> - <argument>-Djmh.warmupIterations=${jmh.warmupIterations}</argument> - <argument>-Djmh.forks=${jmh.forks}</argument> - <argument>-Djmh.threads=${jmh.threads}</argument> - <argument>-Djmh.time=${jmh.time}</argument> - <argument>-Djmh.warmupTime=${jmh.warmupTime}</argument> - <argument>-Dbenchmark.results.dir=${benchmark.results.dir}</argument> - <argument>-Dintegration.service.url=${integration.service.url}</argument> - <argument>-Dkeycloak.url=${keycloak.url}</argument> - <argument>-Dquarkus.metrics.url=${quarkus.metrics.url}</argument> - <argument>-Djava.util.logging.manager=java.util.logging.LogManager</argument> - <argument>-Djava.util.logging.config.file=src/main/resources/benchmark-logging.properties</argument> - <argument>-XX:+UnlockDiagnosticVMOptions</argument> - <argument>-XX:+DebugNonSafepoints</argument> - <argument>-XX:StartFlightRecording=settings=profile,filename=${benchmark.results.dir}/jfr-recordings/benchmark.jfr,dumponexit=true</argument> - <argument>${benchmark.runner}</argument> - </arguments> - </configuration> - </execution> - <!-- Verify JFR files from container volume mount --> - <execution> - <id>verify-jfr-files</id> - <phase>post-integration-test</phase> - <goals> - <goal>exec</goal> - </goals> - <configuration> - <executable>bash</executable> - <arguments> - <argument>-c</argument> - <argument>echo "JFR files in ${benchmark.results.dir}/jfr-recordings:" && ls -la ${benchmark.results.dir}/jfr-recordings/ || echo "No JFR directory found"</argument> - </arguments> - </configuration> - </execution> - <!-- Generate JFR reports --> - <execution> - <id>generate-jfr-reports</id> - <phase>post-integration-test</phase> - <goals> - <goal>exec</goal> - </goals> - <configuration> - <executable>bash</executable> - <arguments> - <argument>-c</argument> - <argument>for jfr in ${benchmark.results.dir}/jfr-recordings/*.jfr; do if [ -f "$jfr" ] && [ -s "$jfr" ]; then echo "Generating summary for $(basename "$jfr")"; jfr summary "$jfr" > "${benchmark.results.dir}/jfr-reports/$(basename "$jfr" .jfr)-summary.txt" || echo "Failed to generate summary for $(basename "$jfr")"; else echo "Skipping empty or non-existent file: $(basename "$jfr")"; fi; done</argument> - </arguments> - </configuration> - </execution> - <!-- Generate HTTP metrics from benchmark results (JFR profile) --> - <execution> - <id>generate-http-metrics-jfr</id> - <phase>post-integration-test</phase> - <goals> - <goal>exec</goal> - </goals> - <configuration> - <executable>bash</executable> - <arguments> - <argument>-c</argument> - <argument>cd target && java -cp "classes:dependency/*" de.cuioss.sheriff.api.quarkus.benchmark.metrics.MetricsPostProcessor benchmark-results || echo "Comprehensive metrics generation failed - continuing"</argument> - </arguments> - <workingDirectory>${project.basedir}</workingDirectory> - </configuration> - </execution> - <!-- Stop integration test containers --> - <execution> - <id>stop-jfr-containers</id> - <phase>post-integration-test</phase> - <goals> - <goal>exec</goal> - </goals> - <configuration> - <executable>../../api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/scripts/stop-integration-container.sh</executable> - <workingDirectory>${project.basedir}</workingDirectory> - <!-- Don't fail build if cleanup fails --> - <successCodes> - <successCode>0</successCode> - <successCode>1</successCode> - </successCodes> - </configuration> - </execution> - </executions> - </plugin> - </plugins> - </build> - </profile> - </profiles> -</project> \ No newline at end of file diff --git a/benchmarking/benchmark-integration-quarkus/src/main/java/de/cuioss/sheriff/api/quarkus/benchmark/BenchmarkOptionsHelper.java b/benchmarking/benchmark-integration-quarkus/src/main/java/de/cuioss/sheriff/api/quarkus/benchmark/BenchmarkOptionsHelper.java deleted file mode 100644 index 337223c1..00000000 --- a/benchmarking/benchmark-integration-quarkus/src/main/java/de/cuioss/sheriff/api/quarkus/benchmark/BenchmarkOptionsHelper.java +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright 2025 the original author or authors. - * <p> - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * <p> - * https://www.apache.org/licenses/LICENSE-2.0 - * <p> - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.cuioss.sheriff.api.quarkus.benchmark; - -import org.openjdk.jmh.results.format.ResultFormatType; -import org.openjdk.jmh.runner.options.TimeValue; - -import java.io.File; -import java.util.concurrent.TimeUnit; - -/** - * Shared utility class for building JMH benchmark options. - * Consolidates common option parsing logic for benchmark runners. - * - * @author API Sheriff Team - */ -public final class BenchmarkOptionsHelper { - - private BenchmarkOptionsHelper() { - // Utility class - } - - /** - * Gets the result format from system property or defaults to JSON. - * - * @return the result format type - */ - public static ResultFormatType getResultFormat() { - String format = System.getProperty("jmh.result.format", "JSON"); - try { - return ResultFormatType.valueOf(format.toUpperCase()); - } catch (IllegalArgumentException e) { - return ResultFormatType.JSON; - } - } - - /** - * Gets the result file path from system property or returns the default. - * Ensures parent directory exists. - * - * @param defaultFileName the default file name to use if property not set - * @return the result file path - */ - public static String getResultFile(String defaultFileName) { - String filePrefix = System.getProperty("jmh.result.filePrefix"); - if (filePrefix != null && !filePrefix.isEmpty()) { - String resultFile = filePrefix + ".json"; - // Ensure parent directory exists - File file = new File(resultFile); - File parentDir = file.getParentFile(); - if (parentDir != null && !parentDir.exists()) { - parentDir.mkdirs(); - } - return resultFile; - } - return defaultFileName; - } - - /** - * Gets the measurement time from system property or uses the provided default. - * - * @param defaultTime the default time value (e.g., "2s", "5s") - * @return the parsed time value - */ - public static TimeValue getMeasurementTime(String defaultTime) { - String time = System.getProperty("jmh.time", defaultTime); - return parseTimeValue(time); - } - - /** - * Gets the warmup time from system property or uses the provided default. - * - * @param defaultTime the default time value (e.g., "2s", "3s") - * @return the parsed time value - */ - public static TimeValue getWarmupTime(String defaultTime) { - String time = System.getProperty("jmh.warmupTime", defaultTime); - return parseTimeValue(time); - } - - /** - * Gets the thread count from system property or uses the provided default. - * Supports "MAX" to use all available processors. - * - * @param defaultCount the default thread count - * @return the thread count - */ - public static int getThreadCount(int defaultCount) { - String threads = System.getProperty("jmh.threads"); - if (threads != null) { - if ("MAX".equalsIgnoreCase(threads)) { - return Runtime.getRuntime().availableProcessors(); - } - try { - return Integer.parseInt(threads); - } catch (NumberFormatException e) { - // Fall through to default - } - } - return defaultCount; - } - - /** - * Gets the number of forks from system property or uses the provided default. - * - * @param defaultForks the default number of forks - * @return the number of forks - */ - public static int getForks(int defaultForks) { - return Integer.parseInt(System.getProperty("jmh.forks", String.valueOf(defaultForks))); - } - - /** - * Gets the warmup iterations from system property or uses the provided default. - * - * @param defaultIterations the default number of warmup iterations - * @return the number of warmup iterations - */ - public static int getWarmupIterations(int defaultIterations) { - return Integer.parseInt(System.getProperty("jmh.warmupIterations", String.valueOf(defaultIterations))); - } - - /** - * Gets the measurement iterations from system property or uses the provided default. - * - * @param defaultIterations the default number of measurement iterations - * @return the number of measurement iterations - */ - public static int getMeasurementIterations(int defaultIterations) { - return Integer.parseInt(System.getProperty("jmh.measurementIterations", String.valueOf(defaultIterations))); - } - - /** - * Parse a time value string (e.g., "2s", "100ms", "1m"). - * - * @param timeStr the time string to parse - * @return the parsed TimeValue - */ - private static TimeValue parseTimeValue(String timeStr) { - if (timeStr == null || timeStr.isEmpty()) { - return TimeValue.seconds(1); - } - - timeStr = timeStr.trim().toLowerCase(); - - // Extract numeric part and unit - StringBuilder numPart = new StringBuilder(); - StringBuilder unitPart = new StringBuilder(); - boolean foundUnit = false; - - for (char c : timeStr.toCharArray()) { - if (Character.isDigit(c) || c == '.') { - if (!foundUnit) { - numPart.append(c); - } - } else { - foundUnit = true; - unitPart.append(c); - } - } - - try { - long value = Long.parseLong(numPart.toString()); - String unit = unitPart.toString(); - - switch (unit) { - case "ms": - case "milliseconds": - case "millis": - return TimeValue.milliseconds(value); - case "s": - case "sec": - case "seconds": - return TimeValue.seconds(value); - case "m": - case "min": - case "minutes": - return TimeValue.minutes(value); - default: - // Default to seconds if no unit or unknown unit - return TimeValue.seconds(value); - } - } catch (NumberFormatException e) { - // Default fallback - return TimeValue.seconds(1); - } - } -} \ No newline at end of file diff --git a/benchmarking/benchmark-integration-quarkus/src/main/java/de/cuioss/sheriff/api/quarkus/benchmark/BenchmarkRunner.java b/benchmarking/benchmark-integration-quarkus/src/main/java/de/cuioss/sheriff/api/quarkus/benchmark/BenchmarkRunner.java deleted file mode 100644 index 9687eca7..00000000 --- a/benchmarking/benchmark-integration-quarkus/src/main/java/de/cuioss/sheriff/api/quarkus/benchmark/BenchmarkRunner.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2025 the original author or authors. - * <p> - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * <p> - * https://www.apache.org/licenses/LICENSE-2.0 - * <p> - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.cuioss.sheriff.api.quarkus.benchmark; - -import java.util.Collection; -import java.util.concurrent.TimeUnit; - -import org.openjdk.jmh.annotations.Benchmark; -import org.openjdk.jmh.annotations.BenchmarkMode; -import org.openjdk.jmh.annotations.Fork; -import org.openjdk.jmh.annotations.Level; -import org.openjdk.jmh.annotations.Measurement; -import org.openjdk.jmh.annotations.Mode; -import org.openjdk.jmh.annotations.OutputTimeUnit; -import org.openjdk.jmh.annotations.Scope; -import org.openjdk.jmh.annotations.Setup; -import org.openjdk.jmh.annotations.State; -import org.openjdk.jmh.annotations.Warmup; -import org.openjdk.jmh.results.RunResult; -import org.openjdk.jmh.runner.Runner; -import org.openjdk.jmh.runner.options.Options; -import org.openjdk.jmh.runner.options.OptionsBuilder; - -import de.cuioss.sheriff.api.ApiSheriff; - -/** - * JMH benchmark suite for API Sheriff Quarkus integration performance testing. - * - * @author API Sheriff Team - */ -@State(Scope.Benchmark) -@BenchmarkMode(Mode.Throughput) -@OutputTimeUnit(TimeUnit.SECONDS) -@Fork(value = 1, jvmArgs = {"-Xmx2G", "-server"}) -@Warmup(iterations = 3, time = 2, timeUnit = TimeUnit.SECONDS) -@Measurement(iterations = 5, time = 2, timeUnit = TimeUnit.SECONDS) -public class BenchmarkRunner { - - private ApiSheriff apiSheriff; - - @Setup(Level.Trial) - public void setup() { - // Simple placeholder implementation for benchmarking - apiSheriff = new ApiSheriff(); - } - - @Benchmark - public String benchmarkGetStatus() { - return apiSheriff.getStatus(); - } - - /** - * Main method to run the benchmarks. - * - * @param args command line arguments - * @throws Exception if benchmark execution fails - */ - public static void main(String[] args) throws Exception { - // Configure JMH options using helper for system property configuration - Options options = new OptionsBuilder() - .include(System.getProperty("jmh.include", "de\\.cuioss\\.sheriff\\.api\\.quarkus\\.benchmark\\..*")) - .forks(BenchmarkOptionsHelper.getForks(1)) - .warmupIterations(BenchmarkOptionsHelper.getWarmupIterations(1)) - .measurementIterations(BenchmarkOptionsHelper.getMeasurementIterations(2)) - .measurementTime(BenchmarkOptionsHelper.getMeasurementTime("5s")) - .warmupTime(BenchmarkOptionsHelper.getWarmupTime("1s")) - .threads(BenchmarkOptionsHelper.getThreadCount(10)) - .resultFormat(BenchmarkOptionsHelper.getResultFormat()) - .result(BenchmarkOptionsHelper.getResultFile(getBenchmarkResultsDir() + "/integration-benchmark-result.json")) - .build(); - - // Run the benchmarks - Collection<RunResult> results = new Runner(options).run(); - - // Check if benchmarks ran successfully - if (results.isEmpty()) { - throw new IllegalStateException("No benchmark results were produced"); - } - - System.out.println("Benchmark completed successfully with " + results.size() + " results"); - } - - /** - * Gets the benchmark results directory from system property or defaults to target/benchmark-results. - * - * @return the benchmark results directory path - */ - private static String getBenchmarkResultsDir() { - return System.getProperty("benchmark.results.dir", "target/benchmark-results"); - } -} \ No newline at end of file diff --git a/benchmarking/benchmark-integration-wrk/pom.xml b/benchmarking/benchmark-integration-wrk/pom.xml new file mode 100644 index 00000000..2bdb4710 --- /dev/null +++ b/benchmarking/benchmark-integration-wrk/pom.xml @@ -0,0 +1,239 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>de.cuioss.sheriff.api</groupId> + <artifactId>benchmarking</artifactId> + <version>1.0.0-SNAPSHOT</version> + </parent> + + <artifactId>benchmark-integration-wrk</artifactId> + <name>API Sheriff WRK-based Integration Benchmarks</name> + <description>WRK-based HTTP benchmarks for API Sheriff endpoints with integration test infrastructure</description> + + <properties> + <!-- Skip benchmarks by default (enable with -Pbenchmark) --> + <skip.benchmark>true</skip.benchmark> + + <!-- Skip container lifecycle management (useful when containers are already running) --> + <skip.container.lifecycle>false</skip.container.lifecycle> + + <!-- Scripts location --> + <integration.scripts.dir>${project.basedir}/../../api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/scripts</integration.scripts.dir> + + <!-- Docker compose directory for WRK benchmarks --> + <integration.compose.dir>${project.basedir}/../../api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests</integration.compose.dir> + + <!-- Integration test service URLs (host access via published ports) --> + <integration.service.url>https://localhost:10443</integration.service.url> + <keycloak.url>https://localhost:1443</keycloak.url> + <quarkus.metrics.url>https://localhost:10443</quarkus.metrics.url> + + <!-- WRK Configuration Properties --> + <wrk.duration>60s</wrk.duration> + <wrk.threads>5</wrk.threads> + <wrk.connections>50</wrk.connections> + <wrk.timeout>2s</wrk.timeout> + <wrk.latency>true</wrk.latency> + <wrk.script.dir>${project.basedir}/src/main/resources/wrk-scripts</wrk.script.dir> + <wrk.results.dir>${project.build.directory}/benchmark-results</wrk.results.dir> + <wrk.output.dir>${wrk.results.dir}/wrk</wrk.output.dir> + + <!-- Benchmark history directory for trend analysis --> + <benchmark.history.dir>${wrk.results.dir}/history</benchmark.history.dir> + <wrk.jwt.token_count>100</wrk.jwt.token_count> + + <!-- benchmarking-common version --> + <version.benchmarking-common>0.4.1</version.benchmarking-common> + </properties> + + <dependencyManagement> + <dependencies> + <dependency> + <groupId>de.cuioss.sheriff.oauth</groupId> + <artifactId>benchmarking-common</artifactId> + <version>${version.benchmarking-common}</version> + </dependency> + </dependencies> + </dependencyManagement> + + <dependencies> + <!-- Core benchmark common utilities --> + <dependency> + <groupId>de.cuioss.sheriff.oauth</groupId> + <artifactId>benchmarking-common</artifactId> + </dependency> + + <!-- Gson for JSON processing --> + <dependency> + <groupId>com.google.code.gson</groupId> + <artifactId>gson</artifactId> + </dependency> + + <!-- CUI Java Tools for logging --> + <dependency> + <groupId>de.cuioss</groupId> + <artifactId>cui-java-tools</artifactId> + </dependency> + + <!-- JUnit for basic testing --> + <dependency> + <groupId>org.junit.jupiter</groupId> + <artifactId>junit-jupiter</artifactId> + <scope>test</scope> + </dependency> + + <!-- Awaitility for better async testing --> + <dependency> + <groupId>org.awaitility</groupId> + <artifactId>awaitility</artifactId> + <scope>test</scope> + </dependency> + </dependencies> + + <build> + <plugins> + <!-- Configure surefire for unit tests --> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <configuration> + <skipTests>false</skipTests> + <argLine>-XX:+IgnoreUnrecognizedVMOptions -Djava.awt.headless=true</argLine> + </configuration> + </plugin> + + <!-- Execute wrk benchmarks when skip.benchmark is false --> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>exec-maven-plugin</artifactId> + </plugin> + + <!-- Build classpath for benchmark execution --> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-dependency-plugin</artifactId> + <!-- Configuration inherited from parent pluginManagement --> + </plugin> + </plugins> + </build> + + <profiles> + <profile> + <id>benchmark</id> + <properties> + <skip.benchmark>false</skip.benchmark> + </properties> + <build> + <plugins> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>exec-maven-plugin</artifactId> + <executions> + <!-- Build integration tests (using smart native build script) --> + <execution> + <id>maven-build-integration-tests</id> + <phase>pre-integration-test</phase> + <goals> + <goal>exec</goal> + </goals> + <configuration> + <skip>${skip.container.lifecycle}</skip> + <executable>../../mvnw</executable> + <arguments> + <argument>compile</argument> + <argument>exec:exec@build-native-if-needed</argument> + <argument>exec:exec@docker-build-distroless</argument> + <argument>-Pintegration-tests</argument> + <argument>-DskipTests</argument> + </arguments> + <workingDirectory>${project.basedir}/../../api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests</workingDirectory> + </configuration> + </execution> + + <!-- Start integration test containers --> + <execution> + <id>start-integration-containers</id> + <phase>pre-integration-test</phase> + <goals> + <goal>exec</goal> + </goals> + <configuration> + <skip>${skip.container.lifecycle}</skip> + <executable>${integration.scripts.dir}/start-integration-container.sh</executable> + <workingDirectory>${project.basedir}</workingDirectory> + <environmentVariables> + <LOG_TARGET_DIR>${wrk.results.dir}</LOG_TARGET_DIR> + </environmentVariables> + </configuration> + </execution> + + <!-- Create benchmark results directory --> + <execution> + <id>create-benchmark-dirs</id> + <phase>pre-integration-test</phase> + <goals> + <goal>exec</goal> + </goals> + <configuration> + <executable>mkdir</executable> + <arguments> + <argument>-p</argument> + <argument>${wrk.results.dir}</argument> + <argument>${wrk.output.dir}</argument> + </arguments> + </configuration> + </execution> + + <!-- Stop integration test containers --> + <execution> + <id>stop-integration-containers</id> + <phase>post-integration-test</phase> + <goals> + <goal>exec</goal> + </goals> + <configuration> + <skip>${skip.container.lifecycle}</skip> + <executable>${integration.scripts.dir}/stop-integration-container.sh</executable> + <workingDirectory>${project.basedir}</workingDirectory> + <!-- Don't fail build if cleanup fails --> + <successCodes> + <successCode>0</successCode> + <successCode>1</successCode> + </successCodes> + </configuration> + </execution> + + <!-- Clean integration tests to force container rebuild --> + <execution> + <id>clean-integration-tests-for-rebuild</id> + <phase>clean</phase> + <goals> + <goal>exec</goal> + </goals> + <configuration> + <skip>${skip.container.lifecycle}</skip> + <executable>../../mvnw</executable> + <arguments> + <argument>clean</argument> + </arguments> + <workingDirectory>${project.basedir}/../../api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests</workingDirectory> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> + </profile> + + <!-- Quick benchmark profile for faster testing --> + <profile> + <id>quick</id> + <properties> + <wrk.duration>30s</wrk.duration> + <skip.container.lifecycle>true</skip.container.lifecycle> + </properties> + </profile> + </profiles> +</project> diff --git a/benchmarking/benchmark-integration-wrk/src/main/java/de/cuioss/sheriff/api/wrk/benchmark/WrkResultPostProcessor.java b/benchmarking/benchmark-integration-wrk/src/main/java/de/cuioss/sheriff/api/wrk/benchmark/WrkResultPostProcessor.java new file mode 100644 index 00000000..c46853ca --- /dev/null +++ b/benchmarking/benchmark-integration-wrk/src/main/java/de/cuioss/sheriff/api/wrk/benchmark/WrkResultPostProcessor.java @@ -0,0 +1,368 @@ +/* + * Copyright 2025 the original author or authors. + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * <p> + * https://www.apache.org/licenses/LICENSE-2.0 + * <p> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.cuioss.sheriff.api.wrk.benchmark; + +import de.cuioss.benchmarking.common.config.BenchmarkType; +import de.cuioss.benchmarking.common.converter.WrkBenchmarkConverter; +import de.cuioss.benchmarking.common.metrics.PrometheusMetricsManager; +import de.cuioss.benchmarking.common.model.BenchmarkData; +import de.cuioss.benchmarking.common.output.OutputDirectoryStructure; +import de.cuioss.benchmarking.common.report.GitHubPagesGenerator; +import de.cuioss.benchmarking.common.report.ReportGenerator; +import de.cuioss.tools.logging.CuiLogger; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.time.Instant; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Stream; + +import static de.cuioss.benchmarking.common.util.BenchmarkingLogMessages.ERROR; +import static de.cuioss.benchmarking.common.util.BenchmarkingLogMessages.INFO; + +/** + * Post-processor for WRK benchmark results. + * <p> + * This class converts WRK output files to the central BenchmarkData format + * and uses the unified report generation infrastructure from cui-benchmarking-common. + */ +public class WrkResultPostProcessor { + + private static final CuiLogger LOGGER = new CuiLogger(WrkResultPostProcessor.class); + + // File naming constants + public static final String WRK_OUTPUT_FILE_SUFFIX = "-results.txt"; + public static final String WRK_HEALTH_OUTPUT_FILE = "wrk-health-results.txt"; + public static final String WRK_JWT_OUTPUT_FILE = "wrk-jwt-results.txt"; + public static final String BENCHMARK_NAME_HEALTH = "healthCheck"; + public static final String BENCHMARK_NAME_JWT = "jwtValidation"; + public static final String PROMETHEUS_METRICS_DIR = "prometheus"; + public static final String GH_PAGES_DATA_DIR = "gh-pages-ready/data"; + public static final String HEALTH_METRICS_FILE = BENCHMARK_NAME_HEALTH + "-metrics.json"; + public static final String JWT_METRICS_FILE = BENCHMARK_NAME_JWT + "-metrics.json"; + + private final WrkBenchmarkConverter converter = new WrkBenchmarkConverter(); + private final ReportGenerator reportGenerator = new ReportGenerator(); + private final GitHubPagesGenerator gitHubPagesGenerator = new GitHubPagesGenerator(); + private final PrometheusMetricsManager prometheusMetricsManager = new PrometheusMetricsManager(); + + // Map to store benchmark metadata (name -> timestamps) + private final Map<String, BenchmarkMetadata> benchmarkMetadataMap = new HashMap<>(); + + /** + * Holds metadata for a benchmark execution. + */ + private record BenchmarkMetadata(String name, Instant startTime, Instant endTime) { + } + + /** + * Main entry point for processing WRK benchmark results. + * Usage: + * - args[0]=inputDir, args[1]=outputDir (optional) + * + * @param args Command line arguments + */ + public static void main(String[] args) { + if (args.length == 0) { + LOGGER.error(ERROR.WRK_USAGE_ERROR); + System.exit(1); + } + + try { + Path inputDir = Path.of(args[0]); + WrkResultPostProcessor processor = new WrkResultPostProcessor(); + + // Normal processing mode + Path outputDir = args.length > 1 ? + Path.of(args[1]) : + inputDir.getParent().resolve("benchmark-results"); + + processor.process(inputDir, outputDir); + + LOGGER.info(INFO.RESULTS_AVAILABLE, outputDir); + + } catch (IOException e) { + LOGGER.error(e, ERROR.WRK_PROCESSOR_FAILED); + System.exit(1); + } + } + + /** + * Processes WRK output files and generates reports. + * + * @param inputDir Directory containing WRK output files + * @param outputDir Directory to write reports to + * @throws IOException if processing fails + */ + public void process(Path inputDir, Path outputDir) throws IOException { + LOGGER.info(INFO.WRK_PROCESSING_START); + + // Parse all WRK result files to extract metadata + parseBenchmarkMetadata(inputDir); + + // Validate input directory + if (!Files.exists(inputDir)) { + throw new IllegalArgumentException("Input directory does not exist: " + inputDir); + } + + if (!Files.isDirectory(inputDir)) { + throw new IllegalArgumentException("Input path is not a directory: " + inputDir); + } + + // Check for WRK output files in wrk subdirectory + Path wrkDir = inputDir.resolve("wrk"); + boolean hasWrkFiles = false; + if (Files.exists(wrkDir)) { + try (Stream<Path> files = Files.list(wrkDir)) { + hasWrkFiles = files.anyMatch(p -> p.getFileName().toString().endsWith(".txt")); + } + } + + if (!hasWrkFiles) { + LOGGER.error(ERROR.NO_WRK_FILES, wrkDir); + } + + // Convert WRK output to BenchmarkData from wrk subdirectory + BenchmarkData benchmarkData; + if (!Files.exists(wrkDir)) { + LOGGER.error(ERROR.WRK_DIR_NOT_EXIST, wrkDir); + benchmarkData = BenchmarkData.builder() + .metadata(BenchmarkData.Metadata.builder() + .reportVersion("2.0") + .timestamp(Instant.now().toString()) + .displayTimestamp(Instant.now().toString()) + .benchmarkType("Integration Performance") + .build()) + .overview(BenchmarkData.Overview.builder() + .throughput("0 ops/s") + .latency("0ms") + .throughputBenchmarkName("N/A") + .latencyBenchmarkName("N/A") + .performanceScore(0) + .performanceGrade("F") + .performanceGradeClass("grade-f") + .build()) + .benchmarks(List.of()) + .build(); + } else { + benchmarkData = converter.convert(wrkDir); + } + + if (benchmarkData.getBenchmarks() == null || benchmarkData.getBenchmarks().isEmpty()) { + LOGGER.error(ERROR.NO_BENCHMARK_DATA); + } + + // Generate reports using new OutputDirectoryStructure (no duplication) + Files.createDirectories(outputDir); + + // Create OutputDirectoryStructure for organized file generation + OutputDirectoryStructure structure = new OutputDirectoryStructure(outputDir); + structure.ensureDirectories(); + + // Generate HTML reports directly to gh-pages-ready directory + String deploymentPath = structure.getDeploymentDir().toString(); + reportGenerator.generateIndexPage(benchmarkData, BenchmarkType.INTEGRATION, deploymentPath); + reportGenerator.generateTrendsPage(deploymentPath); + reportGenerator.copySupportFiles(deploymentPath); + + // Collect real-time Prometheus metrics for the benchmark execution + collectPrometheusMetrics(benchmarkData, structure); + + // Generate GitHub Pages deployment-specific assets (404.html, robots.txt, sitemap.xml) + gitHubPagesGenerator.generateDeploymentAssets(structure); + } + + /** + * Collect real-time metrics from Prometheus for the benchmark execution. + * + * @param benchmarkData The benchmark data containing benchmark names + * @param structure The output directory structure + */ + private void collectPrometheusMetrics(BenchmarkData benchmarkData, OutputDirectoryStructure structure) { + if (benchmarkMetadataMap.isEmpty()) { + LOGGER.error(ERROR.NO_PROMETHEUS_METADATA); + return; + } + + if (benchmarkData.getBenchmarks() != null) { + for (BenchmarkData.Benchmark benchmark : benchmarkData.getBenchmarks()) { + BenchmarkMetadata metadata = findMetadataForBenchmark(benchmark.getName()); + + if (metadata == null) { + LOGGER.error(ERROR.NO_METADATA_FOR_BENCHMARK, benchmark.getName()); + continue; + } + + prometheusMetricsManager.collectMetricsForWrkBenchmark( + metadata.name, + metadata.startTime, + metadata.endTime, + structure.getBenchmarkResultsDir().toString() + ); + } + } + + copyPrometheusMetricsToDeployment(structure); + } + + /** + * Copies Prometheus metrics from the raw prometheus directory to the deployment data directory. + * + * @param structure The output directory structure + */ + private void copyPrometheusMetricsToDeployment(OutputDirectoryStructure structure) { + try { + Path prometheusRawDir = structure.getPrometheusRawDir(); + Path deploymentDataDir = structure.getDataDir(); + + if (!Files.exists(prometheusRawDir)) { + return; + } + + try (Stream<Path> files = Files.list(prometheusRawDir)) { + files.filter(file -> file.getFileName().toString().endsWith(".json")) + .forEach(sourceFile -> { + try { + Path targetFile = deploymentDataDir.resolve(sourceFile.getFileName()); + Files.copy(sourceFile, targetFile, StandardCopyOption.REPLACE_EXISTING); + } catch (IOException e) { + LOGGER.error(e, ERROR.FAILED_COPY_PROMETHEUS, sourceFile); + } + }); + } + } catch (IOException e) { + LOGGER.error(e, ERROR.FAILED_COPY_PROMETHEUS_DIR); + } + } + + /** + * Parse benchmark metadata from WRK result files. + * + * @param inputDir The directory containing benchmark results + * @throws IOException if reading files fails + */ + private void parseBenchmarkMetadata(Path inputDir) throws IOException { + Path wrkDir = inputDir.resolve("wrk"); + if (!Files.exists(wrkDir)) { + return; + } + + try (Stream<Path> files = Files.list(wrkDir)) { + List<Path> wrkFiles = files + .filter(p -> p.getFileName().toString().endsWith(WRK_OUTPUT_FILE_SUFFIX)) + .toList(); + + if (wrkFiles.isEmpty()) { + String message = "CRITICAL: No WRK result files (*%s) found in %s. Ensure benchmarks were run successfully." + .formatted(WRK_OUTPUT_FILE_SUFFIX, inputDir); + LOGGER.error(ERROR.NO_WRK_FILES, inputDir); + throw new IllegalStateException(message); + } + + for (Path wrkFile : wrkFiles) { + parseSingleBenchmarkMetadata(wrkFile); + } + + if (benchmarkMetadataMap.isEmpty()) { + String message = "CRITICAL: No valid benchmark metadata found in any result files"; + LOGGER.error(ERROR.NO_BENCHMARK_DATA); + throw new IllegalStateException(message); + } + } + } + + /** + * Parse metadata from a single WRK result file. + * + * @param resultFile Path to the WRK result file + */ + private void parseSingleBenchmarkMetadata(Path resultFile) { + try { + List<String> lines = Files.readAllLines(resultFile); + String benchmarkName = null; + Instant startTime = null; + Instant endTime = null; + boolean inMetadata = false; + + for (String line : lines) { + if ("=== BENCHMARK METADATA ===".equals(line)) { + inMetadata = true; + } else if ("=== WRK OUTPUT ===".equals(line)) { + inMetadata = false; + } else if (inMetadata || line.startsWith("end_time:")) { + if (line.startsWith("benchmark_name: ")) { + benchmarkName = line.substring(16).trim(); + } else if (line.startsWith("start_time: ")) { + long epochSeconds = Long.parseLong(line.substring(12).trim()); + startTime = Instant.ofEpochSecond(epochSeconds); + } else if (line.startsWith("end_time: ")) { + long epochSeconds = Long.parseLong(line.substring(10).trim()); + endTime = Instant.ofEpochSecond(epochSeconds); + } + } + } + + if (benchmarkName == null || startTime == null || endTime == null) { + LOGGER.error(ERROR.INCOMPLETE_METADATA, resultFile, benchmarkName, startTime, endTime); + return; + } + + BenchmarkMetadata metadata = new BenchmarkMetadata(benchmarkName, startTime, endTime); + benchmarkMetadataMap.put(benchmarkName, metadata); + + } catch (IOException | NumberFormatException e) { + LOGGER.error(ERROR.FAILED_PARSE_METADATA, resultFile, e.getMessage()); + } + } + + /** + * Find metadata for a benchmark based on its result file name. + * + * @param benchmarkFileName The benchmark file name from BenchmarkData + * @return The matching metadata or null if not found + */ + private BenchmarkMetadata findMetadataForBenchmark(String benchmarkFileName) { + if (benchmarkMetadataMap.containsKey(benchmarkFileName)) { + return benchmarkMetadataMap.get(benchmarkFileName); + } + + String baseName = benchmarkFileName; + if (baseName.endsWith(".txt")) { + baseName = baseName.substring(0, baseName.length() - 4); + } + if (baseName.endsWith("-results")) { + baseName = baseName.substring(0, baseName.length() - 8); + } + + for (Map.Entry<String, BenchmarkMetadata> entry : benchmarkMetadataMap.entrySet()) { + if (entry.getKey().equals(baseName) || + entry.getKey().contains(baseName) || + baseName.contains(entry.getKey())) { + return entry.getValue(); + } + } + + if (benchmarkMetadataMap.size() == 1) { + return benchmarkMetadataMap.values().iterator().next(); + } + + return null; + } +} diff --git a/benchmarking/benchmark-integration-wrk/src/test/java/de/cuioss/sheriff/api/wrk/benchmark/WrkResultPostProcessorTest.java b/benchmarking/benchmark-integration-wrk/src/test/java/de/cuioss/sheriff/api/wrk/benchmark/WrkResultPostProcessorTest.java new file mode 100644 index 00000000..21803047 --- /dev/null +++ b/benchmarking/benchmark-integration-wrk/src/test/java/de/cuioss/sheriff/api/wrk/benchmark/WrkResultPostProcessorTest.java @@ -0,0 +1,271 @@ +/* + * Copyright 2025 the original author or authors. + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * <p> + * https://www.apache.org/licenses/LICENSE-2.0 + * <p> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.cuioss.sheriff.api.wrk.benchmark; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; + +import static de.cuioss.sheriff.api.wrk.benchmark.WrkResultPostProcessor.*; +import static org.junit.jupiter.api.Assertions.*; + +/** + * Unit tests for {@link WrkResultPostProcessor}. + * Tests that the processor correctly parses WRK output format, + * not specific values that change with each benchmark run. + */ +class WrkResultPostProcessorTest { + + @TempDir + Path tempDir; + + private WrkResultPostProcessor processor; + + @BeforeEach + void setUp() { + processor = new WrkResultPostProcessor(); + } + + @Test + void comprehensiveStructureGeneration() throws Exception { + // Copy real benchmark outputs to temp directory wrk subdirectory + Path wrkDir = tempDir.resolve("wrk"); + Files.createDirectories(wrkDir); + Path healthSource = Path.of("src/test/resources/wrk-health-results.txt"); + Path jwtSource = Path.of("src/test/resources/wrk-jwt-results.txt"); + Files.copy(healthSource, wrkDir.resolve(WRK_HEALTH_OUTPUT_FILE)); + Files.copy(jwtSource, wrkDir.resolve(WRK_JWT_OUTPUT_FILE)); + + // Process results + Path outputDir = tempDir.resolve("output"); + processor.process(tempDir, outputDir); + + // Verify comprehensive structure matching JMH benchmarks + verifyComprehensiveStructure(); + } + + @Test + void parseWrkHealthOutput() throws Exception { + Path wrkDir = tempDir.resolve("wrk"); + Files.createDirectories(wrkDir); + Path sourceFile = Path.of("src/test/resources/wrk-health-results.txt"); + Path targetFile = wrkDir.resolve(WRK_HEALTH_OUTPUT_FILE); + Files.copy(sourceFile, targetFile); + + Path outputDir = tempDir.resolve("output"); + processor.process(tempDir, outputDir); + + Path jsonFile = outputDir.resolve("gh-pages-ready/data/benchmark-data.json"); + assertTrue(Files.exists(jsonFile), "Benchmark data file should be created"); + + String jsonContent = Files.readString(jsonFile); + JsonObject json = JsonParser.parseString(jsonContent).getAsJsonObject(); + + assertTrue(json.has("metadata")); + JsonObject metadata = json.getAsJsonObject("metadata"); + assertTrue(metadata.has("timestamp")); + assertTrue(metadata.has("displayTimestamp")); + assertEquals("Integration Performance", metadata.get("benchmarkType").getAsString()); + assertEquals("2.0", metadata.get("reportVersion").getAsString()); + + assertTrue(json.has("benchmarks")); + JsonObject healthBenchmark = json.getAsJsonArray("benchmarks").get(0).getAsJsonObject(); + assertEquals(BENCHMARK_NAME_HEALTH, healthBenchmark.get("name").getAsString()); + assertTrue(healthBenchmark.has("mode")); + assertTrue(healthBenchmark.has("score")); + assertTrue(healthBenchmark.has("scoreUnit")); + + JsonObject percentiles = healthBenchmark.getAsJsonObject("percentiles"); + assertTrue(percentiles.has("50.0")); + assertTrue(percentiles.has("75.0")); + assertTrue(percentiles.has("90.0")); + assertTrue(percentiles.has("99.0")); + + double p50 = percentiles.get("50.0").getAsDouble(); + double p75 = percentiles.get("75.0").getAsDouble(); + double p90 = percentiles.get("90.0").getAsDouble(); + double p99 = percentiles.get("99.0").getAsDouble(); + + assertTrue(p50 <= p75, "P50 should be <= P75"); + assertTrue(p75 <= p90, "P75 should be <= P90"); + assertTrue(p90 <= p99, "P90 should be <= P99"); + } + + @Test + void parseWrkJwtOutput() throws Exception { + Path wrkDir = tempDir.resolve("wrk"); + Files.createDirectories(wrkDir); + Path sourceFile = Path.of("src/test/resources/wrk-jwt-results.txt"); + Path targetFile = wrkDir.resolve(WRK_JWT_OUTPUT_FILE); + Files.copy(sourceFile, targetFile); + + Path outputDir = tempDir.resolve("output"); + processor.process(tempDir, outputDir); + + Path jsonFile = outputDir.resolve("gh-pages-ready/data/benchmark-data.json"); + String jsonContent = Files.readString(jsonFile); + JsonObject json = JsonParser.parseString(jsonContent).getAsJsonObject(); + + JsonObject jwtBenchmark = null; + var benchmarks = json.getAsJsonArray("benchmarks"); + for (int i = 0; i < benchmarks.size(); i++) { + var bench = benchmarks.get(i).getAsJsonObject(); + String benchName = bench.get("name").getAsString(); + if (BENCHMARK_NAME_JWT.equals(benchName) || "jwt-validation".equals(benchName)) { + jwtBenchmark = bench; + break; + } + } + + assertNotNull(jwtBenchmark, "JWT Validation benchmark should be present"); + assertTrue(jwtBenchmark.has("mode")); + assertTrue(jwtBenchmark.has("score")); + assertTrue(jwtBenchmark.has("scoreUnit")); + + JsonObject percentiles = jwtBenchmark.getAsJsonObject("percentiles"); + assertTrue(percentiles.has("50.0")); + assertTrue(percentiles.has("75.0")); + assertTrue(percentiles.has("90.0")); + assertTrue(percentiles.has("99.0")); + + double p50 = percentiles.get("50.0").getAsDouble(); + double p75 = percentiles.get("75.0").getAsDouble(); + double p90 = percentiles.get("90.0").getAsDouble(); + double p99 = percentiles.get("99.0").getAsDouble(); + + assertTrue(p50 <= p75, "P50 should be <= P75"); + assertTrue(p75 <= p90, "P75 should be <= P90"); + assertTrue(p90 <= p99, "P90 should be <= P99"); + } + + @Test + void missingFileHandling() throws Exception { + Path wrkDir = tempDir.resolve("wrk"); + Files.createDirectories(wrkDir); + Path outputDir = tempDir.resolve("output"); + assertThrows(IllegalStateException.class, () -> processor.process(tempDir, outputDir)); + + Path jsonFile = outputDir.resolve("gh-pages-ready/data/benchmark-data.json"); + assertFalse(Files.exists(jsonFile), "JSON should not be created with missing inputs"); + } + + @Test + void parseRealWrkFormatVariations() throws Exception { + String wrkOutput = """ + === BENCHMARK METADATA === + benchmark_name: format-test + start_time: 1700000000 + start_time_iso: 2023-11-14T22:13:20Z + === WRK OUTPUT === + + Running 10s test @ https://localhost:10443/test + 4 threads and 20 connections + Thread Stats Avg Stdev Max +/- Stdev + Latency 849.00us 500.00us 10.00ms 90.00% + Req/Sec 5.00k 1.00k 10.00k 75.00% + Latency Distribution + 50% 805.00us + 75% 1.08ms + 90% 1.54ms + 99% 4.01ms + 100000 requests in 10.00s, 50.00MB read + Requests/sec: 10000.00 + Transfer/sec: 5.00MB + + === BENCHMARK COMPLETE === + end_time: 1700000010 + end_time_iso: 2023-11-14T22:13:30Z + duration_seconds: 10 + """; + + Path wrkDir = tempDir.resolve("wrk"); + Files.createDirectories(wrkDir); + Path testFile = wrkDir.resolve(WRK_HEALTH_OUTPUT_FILE); + Files.writeString(testFile, wrkOutput); + + Path outputDir = tempDir.resolve("output"); + processor.process(tempDir, outputDir); + + Path jsonFile = outputDir.resolve("gh-pages-ready/data/benchmark-data.json"); + JsonObject json = JsonParser.parseString(Files.readString(jsonFile)).getAsJsonObject(); + JsonObject benchmark = json.getAsJsonArray("benchmarks").get(0).getAsJsonObject(); + + assertTrue(benchmark.has("name")); + assertTrue(benchmark.has("mode")); + assertTrue(benchmark.has("score")); + assertTrue(benchmark.has("scoreUnit")); + + JsonObject percentiles = benchmark.getAsJsonObject("percentiles"); + double p50 = percentiles.get("50.0").getAsDouble(); + assertTrue(p50 > 0, "P50 should be positive"); + } + + /** + * Verify that WRK generates the same comprehensive structure as JMH benchmarks + */ + private void verifyComprehensiveStructure() throws IOException { + Path outputDir = tempDir.resolve("output"); + Path ghPagesDir = outputDir.resolve("gh-pages-ready"); + assertTrue(Files.exists(ghPagesDir), "GitHub Pages directory should be created"); + + assertTrue(Files.exists(ghPagesDir.resolve("index.html")), "index.html should be created"); + assertTrue(Files.exists(ghPagesDir.resolve("trends.html")), "trends.html should be created"); + + assertTrue(Files.exists(ghPagesDir.resolve("report-styles.css")), "CSS file should exist"); + assertTrue(Files.exists(ghPagesDir.resolve("data-loader.js")), "JavaScript file should exist"); + + Path badgesDir = ghPagesDir.resolve("badges"); + assertTrue(Files.exists(badgesDir), "Badges directory should be created"); + + Path dataFile = ghPagesDir.resolve("data/benchmark-data.json"); + assertTrue(Files.exists(dataFile), "benchmark-data.json should be created"); + + String jsonContent = Files.readString(dataFile); + JsonObject json = JsonParser.parseString(jsonContent).getAsJsonObject(); + + assertTrue(json.has("metadata"), "Should have metadata section"); + JsonObject metadata = json.getAsJsonObject("metadata"); + assertTrue(metadata.has("timestamp"), "Should have timestamp"); + assertTrue(metadata.has("displayTimestamp"), "Should have displayTimestamp"); + assertTrue(metadata.has("benchmarkType"), "Should have benchmarkType"); + assertTrue(metadata.has("reportVersion"), "Should have reportVersion"); + + assertTrue(json.has("overview"), "Should have overview section"); + JsonObject overview = json.getAsJsonObject("overview"); + assertTrue(overview.has("performanceScore"), "Should have performance score"); + assertTrue(overview.has("performanceGrade"), "Should have performance grade"); + + assertTrue(json.has("benchmarks"), "Should have benchmarks array"); + assertTrue(json.getAsJsonArray("benchmarks").size() > 0, "Should have at least one benchmark"); + + assertTrue(json.has("chartData"), "Should have chart data section"); + assertTrue(json.has("trends"), "Should have trends section"); + + JsonObject benchmark = json.getAsJsonArray("benchmarks").get(0).getAsJsonObject(); + assertTrue(benchmark.has("name"), "Benchmark should have name"); + assertTrue(benchmark.has("mode"), "Benchmark should have mode"); + assertTrue(benchmark.has("score"), "Benchmark should have score"); + assertTrue(benchmark.has("scoreUnit"), "Benchmark should have scoreUnit"); + assertTrue(benchmark.has("percentiles"), "Benchmark should have percentiles"); + } +} diff --git a/benchmarking/benchmark-integration-wrk/src/test/resources/wrk-health-results.txt b/benchmarking/benchmark-integration-wrk/src/test/resources/wrk-health-results.txt new file mode 100644 index 00000000..2e8969f0 --- /dev/null +++ b/benchmarking/benchmark-integration-wrk/src/test/resources/wrk-health-results.txt @@ -0,0 +1,29 @@ +=== BENCHMARK METADATA === +benchmark_name: healthCheck +start_time: 1758797205 +start_time_iso: 2025-09-25T12:46:45+02:00 +=== WRK OUTPUT === + +Loaded 100 tokens from environment +Loaded 100 tokens from environment +Loaded 100 tokens from environment +Loaded 100 tokens from environment +Loaded 100 tokens from environment +Running 5s test @ https://localhost:10443/q/health/live/jwt/validate + 4 threads and 20 connections + Thread Stats Avg Stdev Max +/- Stdev + Latency 4.51ms 6.70ms 41.04ms 87.50% + Req/Sec 2.14k 387.08 2.60k 89.00% + Latency Distribution + 50% 1.69ms + 75% 3.18ms + 90% 14.60ms + 99% 29.99ms + 42606 requests in 5.01s, 11.01MB read +Requests/sec: 8511.49 +Transfer/sec: 2.20MB + +=== BENCHMARK COMPLETE === +end_time: 1758797211 +end_time_iso: 2025-09-25T12:46:51+02:00 +duration_seconds: 6 diff --git a/benchmarking/benchmark-integration-wrk/src/test/resources/wrk-jwt-results.txt b/benchmarking/benchmark-integration-wrk/src/test/resources/wrk-jwt-results.txt new file mode 100644 index 00000000..1e208227 --- /dev/null +++ b/benchmarking/benchmark-integration-wrk/src/test/resources/wrk-jwt-results.txt @@ -0,0 +1,29 @@ +=== BENCHMARK METADATA === +benchmark_name: jwt-validation +start_time: 1758797251 +start_time_iso: 2025-09-25T12:47:31+02:00 +=== WRK OUTPUT === + +Loaded 100 tokens from environment +Loaded 100 tokens from environment +Loaded 100 tokens from environment +Loaded 100 tokens from environment +Loaded 100 tokens from environment +Running 5s test @ https://localhost:10443/jwt/validate + 4 threads and 20 connections + Thread Stats Avg Stdev Max +/- Stdev + Latency 4.33ms 6.30ms 42.53ms 87.28% + Req/Sec 2.16k 283.91 2.54k 85.00% + Latency Distribution + 50% 1.73ms + 75% 2.97ms + 90% 14.05ms + 99% 28.27ms + 43069 requests in 5.01s, 11.13MB read +Requests/sec: 8592.89 +Transfer/sec: 2.22MB + +=== BENCHMARK COMPLETE === +end_time: 1758797257 +end_time_iso: 2025-09-25T12:47:37+02:00 +duration_seconds: 6 diff --git a/benchmarking/doc/index-visualizer.html b/benchmarking/doc/index-visualizer.html deleted file mode 100644 index 7e26d42c..00000000 --- a/benchmarking/doc/index-visualizer.html +++ /dev/null @@ -1,107 +0,0 @@ -<!DOCTYPE html> -<html lang="en"> -<head> - <meta charset="UTF-8"> - <meta name="viewport" content="width=device-width, initial-scale=1.0"> - <title>JWT Micro Benchmark Results - - - - -
-
-

JWT Micro Benchmark Results

-

Unit-level performance testing of JWT validation components

- -
- -
- - -
-
- - - - - \ No newline at end of file diff --git a/benchmarking/doc/integration-benchmark-visualizer.html b/benchmarking/doc/integration-benchmark-visualizer.html deleted file mode 100644 index e3c70d09..00000000 --- a/benchmarking/doc/integration-benchmark-visualizer.html +++ /dev/null @@ -1,175 +0,0 @@ - - - - - - JWT Integration Benchmark Results - - - - -
-
-

JWT Integration Benchmark Results

-

End-to-end performance testing with Keycloak and native Quarkus

- -
- -
-

Integration Test Environment

-
-
-
Test Type
-
Native Container
-
-
-
Services
-
Keycloak + Quarkus
-
-
-
Protocol
-
HTTPS/TLS
-
-
-
Benchmark Format
-
JMH Results
-
-
-
- -
- - -
-
- - - - - \ No newline at end of file diff --git a/benchmarking/doc/integration-index.html b/benchmarking/doc/integration-index.html deleted file mode 100644 index 7c33b0ae..00000000 --- a/benchmarking/doc/integration-index.html +++ /dev/null @@ -1,96 +0,0 @@ - - - - - - JWT Integration Benchmark Results - - - - -
-
-

JWT Integration Benchmark Results

-

End-to-end performance testing with containerized Quarkus application and Keycloak

- -
- -
- - -
-
- - - - - \ No newline at end of file diff --git a/benchmarking/doc/integration-performance-trends.html b/benchmarking/doc/integration-performance-trends.html deleted file mode 100644 index ba41cf31..00000000 --- a/benchmarking/doc/integration-performance-trends.html +++ /dev/null @@ -1,267 +0,0 @@ - - - - - - Integration Benchmark Performance Trends - - - - - -
-
-

Integration Benchmark Performance Trends

-

Performance metrics and trends for integration benchmarks over the last 10 runs

- -
- -
-

Loading integration performance data...

-
- - - - - - -
- - - - \ No newline at end of file diff --git a/benchmarking/doc/performance-run.json b/benchmarking/doc/performance-run.json deleted file mode 100644 index 26862c15..00000000 --- a/benchmarking/doc/performance-run.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "timestamp": "${TIMESTAMP}", - "commit": "${COMMIT_HASH}", - "performance": { - "score": ${PERFORMANCE_SCORE}, - "throughput": { - "value": ${THROUGHPUT_VALUE}, - "unit": "ops/s" - }, - "averageTime": { - "value": ${AVERAGE_TIME_SEC}, - "unit": "s" - }, - "errorResilience": { - "value": ${ERROR_RESILIENCE_VALUE}, - "unit": "ops/s" - } - }, - "rawMetrics": { - "throughputOpsPerSec": ${THROUGHPUT_OPS_PER_SEC}, - "avgTimeInMicros": ${AVG_TIME_MICROS}, - "errorResilienceOpsPerSec": ${ERROR_RESILIENCE_OPS_PER_SEC} - }, - "environment": { - "javaVersion": "${JAVA_VERSION}", - "jvmArgs": "${JVM_ARGS}", - "osName": "${OS_NAME}" - } -} \ No newline at end of file diff --git a/benchmarking/doc/performance-trends.html b/benchmarking/doc/performance-trends.html deleted file mode 100644 index 5202e8d7..00000000 --- a/benchmarking/doc/performance-trends.html +++ /dev/null @@ -1,248 +0,0 @@ - - - - - - JWT Validation Performance Trends - - - - - -
-
-

JWT Validation Performance Trends

-

Performance metrics and trends over the last 10 benchmark runs

- -
- -
-

Loading performance data...

-
- - - - - - - -
- - - - - diff --git a/benchmarking/doc/resources/common.css b/benchmarking/doc/resources/common.css deleted file mode 100644 index eb48eaf4..00000000 --- a/benchmarking/doc/resources/common.css +++ /dev/null @@ -1,387 +0,0 @@ -/* CUI JWT Benchmarking - Common Styles */ - -/* Base Styles */ -body { - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif; - margin: 0; - padding: 0; - background-color: #f8f9fa; - color: #343a40; -} - -/* Layout */ -.container { - max-width: 1400px; - margin: 0 auto; - background: white; - border-radius: 8px; - box-shadow: 0 2px 10px rgba(0,0,0,0.1); - padding: 30px; -} - -/* Typography */ -h1 { - color: #343a40; - margin-bottom: 10px; - font-size: 2.5rem; - font-weight: 300; -} - -h2 { - color: #495057; - font-size: 1.8rem; - font-weight: 400; - margin-bottom: 15px; -} - -h3 { - color: #495057; - font-size: 1.4rem; - font-weight: 500; - margin-bottom: 10px; -} - -.subtitle { - color: #6c757d; - margin-bottom: 20px; - font-size: 1.1rem; -} - -/* Header & Navigation */ -.header { - margin-bottom: 30px; - text-align: center; - padding: 20px; - background-color: #f8f9fa; - border-bottom: 1px solid #dee2e6; - border-radius: 8px 8px 0 0; - margin: -30px -30px 30px -30px; -} - -.navigation { - display: flex; - justify-content: center; - align-items: center; - gap: 10px; - margin: 15px 0; - flex-wrap: wrap; -} - -/* Badges & Buttons */ -.badge { - display: inline-block; - padding: 6px 12px; - margin: 3px; - border-radius: 4px; - font-size: 12px; - font-weight: 600; - text-decoration: none; - transition: all 0.2s; - border: none; - cursor: pointer; -} - -.badge:hover { - transform: translateY(-1px); - box-shadow: 0 2px 5px rgba(0,0,0,0.2); -} - -.badge-primary { - background-color: #007bff; - color: white; -} - -.badge-secondary { - background-color: #6c757d; - color: white; -} - -.badge-success { - background-color: #28a745; - color: white; -} - -.badge-info { - background-color: #17a2b8; - color: white; -} - -.badge-warning { - background-color: #ffc107; - color: #212529; -} - -.badge-current { - background-color: #343a40; - color: white; - cursor: default; -} - -/* Form Controls */ -.controls { - display: flex; - justify-content: center; - align-items: center; - gap: 20px; - margin-bottom: 30px; - padding: 20px; - background-color: #f8f9fa; - border-radius: 8px; -} - -.control-group { - display: flex; - flex-direction: column; - align-items: center; - gap: 8px; -} - -.control-label { - font-weight: 500; - color: #495057; - font-size: 0.9rem; - text-transform: uppercase; - letter-spacing: 0.5px; -} - -select { - padding: 8px 16px; - border: 2px solid #dee2e6; - border-radius: 6px; - background: white; - font-size: 1rem; - min-width: 200px; - transition: border-color 0.2s; -} - -select:focus { - outline: none; - border-color: #007bff; -} - -/* Cards & Sections */ -.metric-card, .stat-card { - background: white; - padding: 20px; - border-radius: 6px; - text-align: center; - border-left: 4px solid #007bff; - box-shadow: 0 1px 3px rgba(0,0,0,0.1); -} - -.metric-value, .stat-value { - font-size: 2rem; - font-weight: 600; - color: #343a40; - margin-bottom: 5px; -} - -.metric-label, .stat-label { - font-size: 0.8rem; - color: #6c757d; - text-transform: uppercase; - letter-spacing: 0.5px; - margin-top: 5px; -} - -/* Grid Layouts */ -.metrics-grid, .summary-stats { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); - gap: 20px; - margin: 20px 0; -} - -.charts-container { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 30px; - margin-top: 20px; -} - -/* Chart Styles */ -.chart-section { - background: #ffffff; - border: 1px solid #e9ecef; - border-radius: 8px; - padding: 20px; - box-shadow: 0 1px 3px rgba(0,0,0,0.1); -} - -.chart-title { - font-size: 1.2rem; - font-weight: 600; - color: #343a40; - margin-bottom: 15px; - text-align: center; - padding-bottom: 10px; - border-bottom: 2px solid #f8f9fa; -} - -.chart-container { - position: relative; - height: 400px; - width: 100%; -} - -/* Content Areas */ -.content { - flex: 1; - overflow: hidden; - position: relative; -} - -.content iframe { - width: 100%; - height: 100%; - border: none; - min-height: 600px; -} - -/* Info Boxes */ -.test-info { - text-align: center; - margin-bottom: 20px; - padding: 15px; - background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); - color: white; - border-radius: 8px; -} - -.test-timestamp { - font-size: 0.9rem; - opacity: 0.9; -} - -.step-details { - margin-top: 20px; - padding: 15px; - background: #e3f2fd; - border-radius: 8px; - border-left: 4px solid #2196f3; -} - -.step-details h4 { - margin: 0 0 10px 0; - color: #1976d2; -} - -/* Legends */ -.percentile-legend { - display: flex; - justify-content: center; - gap: 20px; - margin-bottom: 15px; - font-size: 0.9rem; -} - -.legend-item { - display: flex; - align-items: center; - gap: 5px; -} - -.legend-color { - width: 16px; - height: 16px; - border-radius: 3px; -} - -/* Trend Indicators */ -.trend-indicator { - font-size: 0.9rem; - margin-top: 5px; - font-weight: 500; -} - -.trend-up { color: #28a745; } -.trend-down { color: #dc3545; } -.trend-stable { color: #6c757d; } - -/* Status Messages */ -.loading { - text-align: center; - padding: 40px; - color: #6c757d; -} - -.error { - background: #f8d7da; - color: #721c24; - border: 1px solid #f5c6cb; - border-radius: 4px; - padding: 20px; - margin: 20px 0; - text-align: center; -} - -.error h3 { - margin-top: 0; -} - -/* Footer */ -.footer { - margin-top: 40px; - padding-top: 20px; - border-top: 1px solid #dee2e6; - color: #6c757d; - font-size: 0.9rem; - text-align: center; -} - -/* Responsive Design */ -@media (max-width: 1200px) { - .container { - max-width: 95%; - padding: 20px; - } - - .charts-container { - grid-template-columns: 1fr; - } -} - -@media (max-width: 768px) { - .header { - padding: 15px; - } - - h1 { - font-size: 2rem; - } - - .navigation { - flex-direction: column; - gap: 8px; - } - - .controls { - flex-direction: column; - } - - .metrics-grid, .summary-stats { - grid-template-columns: 1fr; - } - - .badge { - font-size: 11px; - padding: 4px 8px; - } -} - -@media (max-width: 480px) { - .container { - padding: 15px; - margin: 10px; - border-radius: 6px; - } - - .header { - margin: -15px -15px 20px -15px; - } - - .percentile-legend { - flex-direction: column; - gap: 10px; - } -} \ No newline at end of file diff --git a/benchmarking/doc/resources/navigation.js b/benchmarking/doc/resources/navigation.js deleted file mode 100644 index c43f014a..00000000 --- a/benchmarking/doc/resources/navigation.js +++ /dev/null @@ -1,69 +0,0 @@ -// CUI JWT Benchmarking - Shared Navigation Component - -class BenchmarkNavigation { - constructor(currentPage = '') { - this.currentPage = currentPage; - this.pages = [ - { id: 'micro', title: 'Micro Benchmarks', file: 'index-visualizer.html', description: 'JMH unit-level performance testing' }, - { id: 'integration', title: 'Integration Benchmarks', file: 'integration-benchmark-visualizer.html', description: 'End-to-end containerized testing' }, - { id: 'step-metrics', title: 'Step Metrics', file: 'step-metrics-visualizer.html', description: 'Detailed step-by-step analysis' }, - { id: 'trends', title: 'Performance Trends', file: 'performance-trends.html', description: 'Historical performance tracking' } - ]; - } - - // Generate navigation HTML - generateNavigation() { - return this.pages.map(page => { - const isCurrent = page.id === this.currentPage; - const badgeClass = isCurrent ? 'badge-current' : 'badge-primary'; - const title = isCurrent ? `Current: ${page.description}` : page.description; - - return ` - ${page.title}${isCurrent ? ' (Current)' : ''} - `; - }).join('\n '); - } - - // Inject navigation into header - injectNavigation() { - const headerElement = document.querySelector('.header'); - if (headerElement) { - const existingNav = headerElement.querySelector('.navigation'); - if (existingNav) { - existingNav.innerHTML = this.generateNavigation(); - } else { - const navDiv = document.createElement('div'); - navDiv.className = 'navigation'; - navDiv.innerHTML = this.generateNavigation(); - headerElement.appendChild(navDiv); - } - } - } - - // Initialize navigation when DOM is loaded - init() { - if (document.readyState === 'loading') { - document.addEventListener('DOMContentLoaded', () => this.injectNavigation()); - } else { - this.injectNavigation(); - } - } -} - -// Utility function to get current page type from filename or path -function getCurrentPageType() { - const path = window.location.pathname; - const filename = path.split('/').pop() || 'index-visualizer.html'; - - if (filename.includes('integration-benchmark-visualizer')) return 'integration'; - if (filename.includes('integration')) return 'integration'; - if (filename.includes('step-metrics')) return 'step-metrics'; - if (filename.includes('performance-trends')) return 'trends'; - if (filename.includes('index-visualizer')) return 'micro'; - return 'micro'; // default -} - -// Auto-initialize navigation -const currentPage = getCurrentPageType(); -const navigation = new BenchmarkNavigation(currentPage); -navigation.init(); \ No newline at end of file diff --git a/benchmarking/doc/step-metrics-visualizer.html b/benchmarking/doc/step-metrics-visualizer.html deleted file mode 100644 index 2c89aa8c..00000000 --- a/benchmarking/doc/step-metrics-visualizer.html +++ /dev/null @@ -1,476 +0,0 @@ - - - - - - JWT Validation Step Metrics Visualizer - - - - -
-
-

JWT Validation Step Metrics

-

Interactive visualization of performance metrics for each validation step

- -
- -
-

Loading metrics data...

-
- - - - - -
- - - - - \ No newline at end of file diff --git a/benchmarking/doc/templates/index-visualizer.html b/benchmarking/doc/templates/index-visualizer.html deleted file mode 100644 index 7e26d42c..00000000 --- a/benchmarking/doc/templates/index-visualizer.html +++ /dev/null @@ -1,107 +0,0 @@ - - - - - - JWT Micro Benchmark Results - - - - -
-
-

JWT Micro Benchmark Results

-

Unit-level performance testing of JWT validation components

- -
- -
- - -
-
- - - - - \ No newline at end of file diff --git a/benchmarking/doc/templates/integration-benchmark-visualizer.html b/benchmarking/doc/templates/integration-benchmark-visualizer.html deleted file mode 100644 index e3c70d09..00000000 --- a/benchmarking/doc/templates/integration-benchmark-visualizer.html +++ /dev/null @@ -1,175 +0,0 @@ - - - - - - JWT Integration Benchmark Results - - - - -
-
-

JWT Integration Benchmark Results

-

End-to-end performance testing with Keycloak and native Quarkus

- -
- -
-

Integration Test Environment

-
-
-
Test Type
-
Native Container
-
-
-
Services
-
Keycloak + Quarkus
-
-
-
Protocol
-
HTTPS/TLS
-
-
-
Benchmark Format
-
JMH Results
-
-
-
- -
- - -
-
- - - - - \ No newline at end of file diff --git a/benchmarking/doc/templates/integration-index.html b/benchmarking/doc/templates/integration-index.html deleted file mode 100644 index 7c33b0ae..00000000 --- a/benchmarking/doc/templates/integration-index.html +++ /dev/null @@ -1,96 +0,0 @@ - - - - - - JWT Integration Benchmark Results - - - - -
-
-

JWT Integration Benchmark Results

-

End-to-end performance testing with containerized Quarkus application and Keycloak

- -
- -
- - -
-
- - - - - \ No newline at end of file diff --git a/benchmarking/doc/templates/integration-performance-trends.html b/benchmarking/doc/templates/integration-performance-trends.html deleted file mode 100644 index ba41cf31..00000000 --- a/benchmarking/doc/templates/integration-performance-trends.html +++ /dev/null @@ -1,267 +0,0 @@ - - - - - - Integration Benchmark Performance Trends - - - - - -
-
-

Integration Benchmark Performance Trends

-

Performance metrics and trends for integration benchmarks over the last 10 runs

- -
- -
-

Loading integration performance data...

-
- - - - - - -
- - - - \ No newline at end of file diff --git a/benchmarking/doc/templates/performance-run.json b/benchmarking/doc/templates/performance-run.json deleted file mode 100644 index 26862c15..00000000 --- a/benchmarking/doc/templates/performance-run.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "timestamp": "${TIMESTAMP}", - "commit": "${COMMIT_HASH}", - "performance": { - "score": ${PERFORMANCE_SCORE}, - "throughput": { - "value": ${THROUGHPUT_VALUE}, - "unit": "ops/s" - }, - "averageTime": { - "value": ${AVERAGE_TIME_SEC}, - "unit": "s" - }, - "errorResilience": { - "value": ${ERROR_RESILIENCE_VALUE}, - "unit": "ops/s" - } - }, - "rawMetrics": { - "throughputOpsPerSec": ${THROUGHPUT_OPS_PER_SEC}, - "avgTimeInMicros": ${AVG_TIME_MICROS}, - "errorResilienceOpsPerSec": ${ERROR_RESILIENCE_OPS_PER_SEC} - }, - "environment": { - "javaVersion": "${JAVA_VERSION}", - "jvmArgs": "${JVM_ARGS}", - "osName": "${OS_NAME}" - } -} \ No newline at end of file diff --git a/benchmarking/doc/templates/performance-trends.html b/benchmarking/doc/templates/performance-trends.html deleted file mode 100644 index 5202e8d7..00000000 --- a/benchmarking/doc/templates/performance-trends.html +++ /dev/null @@ -1,248 +0,0 @@ - - - - - - JWT Validation Performance Trends - - - - - -
-
-

JWT Validation Performance Trends

-

Performance metrics and trends over the last 10 benchmark runs

- -
- -
-

Loading performance data...

-
- - - - - - - -
- - - - - diff --git a/benchmarking/doc/templates/resources/common.css b/benchmarking/doc/templates/resources/common.css deleted file mode 100644 index eb48eaf4..00000000 --- a/benchmarking/doc/templates/resources/common.css +++ /dev/null @@ -1,387 +0,0 @@ -/* CUI JWT Benchmarking - Common Styles */ - -/* Base Styles */ -body { - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif; - margin: 0; - padding: 0; - background-color: #f8f9fa; - color: #343a40; -} - -/* Layout */ -.container { - max-width: 1400px; - margin: 0 auto; - background: white; - border-radius: 8px; - box-shadow: 0 2px 10px rgba(0,0,0,0.1); - padding: 30px; -} - -/* Typography */ -h1 { - color: #343a40; - margin-bottom: 10px; - font-size: 2.5rem; - font-weight: 300; -} - -h2 { - color: #495057; - font-size: 1.8rem; - font-weight: 400; - margin-bottom: 15px; -} - -h3 { - color: #495057; - font-size: 1.4rem; - font-weight: 500; - margin-bottom: 10px; -} - -.subtitle { - color: #6c757d; - margin-bottom: 20px; - font-size: 1.1rem; -} - -/* Header & Navigation */ -.header { - margin-bottom: 30px; - text-align: center; - padding: 20px; - background-color: #f8f9fa; - border-bottom: 1px solid #dee2e6; - border-radius: 8px 8px 0 0; - margin: -30px -30px 30px -30px; -} - -.navigation { - display: flex; - justify-content: center; - align-items: center; - gap: 10px; - margin: 15px 0; - flex-wrap: wrap; -} - -/* Badges & Buttons */ -.badge { - display: inline-block; - padding: 6px 12px; - margin: 3px; - border-radius: 4px; - font-size: 12px; - font-weight: 600; - text-decoration: none; - transition: all 0.2s; - border: none; - cursor: pointer; -} - -.badge:hover { - transform: translateY(-1px); - box-shadow: 0 2px 5px rgba(0,0,0,0.2); -} - -.badge-primary { - background-color: #007bff; - color: white; -} - -.badge-secondary { - background-color: #6c757d; - color: white; -} - -.badge-success { - background-color: #28a745; - color: white; -} - -.badge-info { - background-color: #17a2b8; - color: white; -} - -.badge-warning { - background-color: #ffc107; - color: #212529; -} - -.badge-current { - background-color: #343a40; - color: white; - cursor: default; -} - -/* Form Controls */ -.controls { - display: flex; - justify-content: center; - align-items: center; - gap: 20px; - margin-bottom: 30px; - padding: 20px; - background-color: #f8f9fa; - border-radius: 8px; -} - -.control-group { - display: flex; - flex-direction: column; - align-items: center; - gap: 8px; -} - -.control-label { - font-weight: 500; - color: #495057; - font-size: 0.9rem; - text-transform: uppercase; - letter-spacing: 0.5px; -} - -select { - padding: 8px 16px; - border: 2px solid #dee2e6; - border-radius: 6px; - background: white; - font-size: 1rem; - min-width: 200px; - transition: border-color 0.2s; -} - -select:focus { - outline: none; - border-color: #007bff; -} - -/* Cards & Sections */ -.metric-card, .stat-card { - background: white; - padding: 20px; - border-radius: 6px; - text-align: center; - border-left: 4px solid #007bff; - box-shadow: 0 1px 3px rgba(0,0,0,0.1); -} - -.metric-value, .stat-value { - font-size: 2rem; - font-weight: 600; - color: #343a40; - margin-bottom: 5px; -} - -.metric-label, .stat-label { - font-size: 0.8rem; - color: #6c757d; - text-transform: uppercase; - letter-spacing: 0.5px; - margin-top: 5px; -} - -/* Grid Layouts */ -.metrics-grid, .summary-stats { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); - gap: 20px; - margin: 20px 0; -} - -.charts-container { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 30px; - margin-top: 20px; -} - -/* Chart Styles */ -.chart-section { - background: #ffffff; - border: 1px solid #e9ecef; - border-radius: 8px; - padding: 20px; - box-shadow: 0 1px 3px rgba(0,0,0,0.1); -} - -.chart-title { - font-size: 1.2rem; - font-weight: 600; - color: #343a40; - margin-bottom: 15px; - text-align: center; - padding-bottom: 10px; - border-bottom: 2px solid #f8f9fa; -} - -.chart-container { - position: relative; - height: 400px; - width: 100%; -} - -/* Content Areas */ -.content { - flex: 1; - overflow: hidden; - position: relative; -} - -.content iframe { - width: 100%; - height: 100%; - border: none; - min-height: 600px; -} - -/* Info Boxes */ -.test-info { - text-align: center; - margin-bottom: 20px; - padding: 15px; - background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); - color: white; - border-radius: 8px; -} - -.test-timestamp { - font-size: 0.9rem; - opacity: 0.9; -} - -.step-details { - margin-top: 20px; - padding: 15px; - background: #e3f2fd; - border-radius: 8px; - border-left: 4px solid #2196f3; -} - -.step-details h4 { - margin: 0 0 10px 0; - color: #1976d2; -} - -/* Legends */ -.percentile-legend { - display: flex; - justify-content: center; - gap: 20px; - margin-bottom: 15px; - font-size: 0.9rem; -} - -.legend-item { - display: flex; - align-items: center; - gap: 5px; -} - -.legend-color { - width: 16px; - height: 16px; - border-radius: 3px; -} - -/* Trend Indicators */ -.trend-indicator { - font-size: 0.9rem; - margin-top: 5px; - font-weight: 500; -} - -.trend-up { color: #28a745; } -.trend-down { color: #dc3545; } -.trend-stable { color: #6c757d; } - -/* Status Messages */ -.loading { - text-align: center; - padding: 40px; - color: #6c757d; -} - -.error { - background: #f8d7da; - color: #721c24; - border: 1px solid #f5c6cb; - border-radius: 4px; - padding: 20px; - margin: 20px 0; - text-align: center; -} - -.error h3 { - margin-top: 0; -} - -/* Footer */ -.footer { - margin-top: 40px; - padding-top: 20px; - border-top: 1px solid #dee2e6; - color: #6c757d; - font-size: 0.9rem; - text-align: center; -} - -/* Responsive Design */ -@media (max-width: 1200px) { - .container { - max-width: 95%; - padding: 20px; - } - - .charts-container { - grid-template-columns: 1fr; - } -} - -@media (max-width: 768px) { - .header { - padding: 15px; - } - - h1 { - font-size: 2rem; - } - - .navigation { - flex-direction: column; - gap: 8px; - } - - .controls { - flex-direction: column; - } - - .metrics-grid, .summary-stats { - grid-template-columns: 1fr; - } - - .badge { - font-size: 11px; - padding: 4px 8px; - } -} - -@media (max-width: 480px) { - .container { - padding: 15px; - margin: 10px; - border-radius: 6px; - } - - .header { - margin: -15px -15px 20px -15px; - } - - .percentile-legend { - flex-direction: column; - gap: 10px; - } -} \ No newline at end of file diff --git a/benchmarking/doc/templates/resources/navigation.js b/benchmarking/doc/templates/resources/navigation.js deleted file mode 100644 index c43f014a..00000000 --- a/benchmarking/doc/templates/resources/navigation.js +++ /dev/null @@ -1,69 +0,0 @@ -// CUI JWT Benchmarking - Shared Navigation Component - -class BenchmarkNavigation { - constructor(currentPage = '') { - this.currentPage = currentPage; - this.pages = [ - { id: 'micro', title: 'Micro Benchmarks', file: 'index-visualizer.html', description: 'JMH unit-level performance testing' }, - { id: 'integration', title: 'Integration Benchmarks', file: 'integration-benchmark-visualizer.html', description: 'End-to-end containerized testing' }, - { id: 'step-metrics', title: 'Step Metrics', file: 'step-metrics-visualizer.html', description: 'Detailed step-by-step analysis' }, - { id: 'trends', title: 'Performance Trends', file: 'performance-trends.html', description: 'Historical performance tracking' } - ]; - } - - // Generate navigation HTML - generateNavigation() { - return this.pages.map(page => { - const isCurrent = page.id === this.currentPage; - const badgeClass = isCurrent ? 'badge-current' : 'badge-primary'; - const title = isCurrent ? `Current: ${page.description}` : page.description; - - return ` - ${page.title}${isCurrent ? ' (Current)' : ''} - `; - }).join('\n '); - } - - // Inject navigation into header - injectNavigation() { - const headerElement = document.querySelector('.header'); - if (headerElement) { - const existingNav = headerElement.querySelector('.navigation'); - if (existingNav) { - existingNav.innerHTML = this.generateNavigation(); - } else { - const navDiv = document.createElement('div'); - navDiv.className = 'navigation'; - navDiv.innerHTML = this.generateNavigation(); - headerElement.appendChild(navDiv); - } - } - } - - // Initialize navigation when DOM is loaded - init() { - if (document.readyState === 'loading') { - document.addEventListener('DOMContentLoaded', () => this.injectNavigation()); - } else { - this.injectNavigation(); - } - } -} - -// Utility function to get current page type from filename or path -function getCurrentPageType() { - const path = window.location.pathname; - const filename = path.split('/').pop() || 'index-visualizer.html'; - - if (filename.includes('integration-benchmark-visualizer')) return 'integration'; - if (filename.includes('integration')) return 'integration'; - if (filename.includes('step-metrics')) return 'step-metrics'; - if (filename.includes('performance-trends')) return 'trends'; - if (filename.includes('index-visualizer')) return 'micro'; - return 'micro'; // default -} - -// Auto-initialize navigation -const currentPage = getCurrentPageType(); -const navigation = new BenchmarkNavigation(currentPage); -navigation.init(); \ No newline at end of file diff --git a/benchmarking/doc/templates/step-metrics-visualizer.html b/benchmarking/doc/templates/step-metrics-visualizer.html deleted file mode 100644 index 2c89aa8c..00000000 --- a/benchmarking/doc/templates/step-metrics-visualizer.html +++ /dev/null @@ -1,476 +0,0 @@ - - - - - - JWT Validation Step Metrics Visualizer - - - - -
-
-

JWT Validation Step Metrics

-

Interactive visualization of performance metrics for each validation step

- -
- -
-

Loading metrics data...

-
- - - - - -
- - - - - \ No newline at end of file diff --git a/benchmarking/pom.xml b/benchmarking/pom.xml index 8325242c..b47101ba 100644 --- a/benchmarking/pom.xml +++ b/benchmarking/pom.xml @@ -16,8 +16,8 @@ Parent module for all benchmarking related modules including library and integration benchmarks - benchmark-library - benchmark-integration-quarkus + benchmark-core + benchmark-integration-wrk @@ -25,27 +25,19 @@ 1.37 - 2.10.1 - 2.1.12 - 2.15.1 + 2.13.2 + 2.2.2 + 2.21.0 true - - target/benchmark-results + + + + true - - - io.quarkus - quarkus-bom - ${version.quarkus} - pom - import - - - org.openjdk.jmh jmh-core @@ -57,8 +49,6 @@ ${version.jmh} provided - - com.google.code.gson gson @@ -74,13 +64,45 @@ commons-io ${version.commons-io} + + de.cuioss.sheriff.api + api-sheriff-bom + ${project.version} + pom + import + - - + + org.codehaus.mojo + exec-maven-plugin + + ${skip.benchmark} + + + + org.apache.maven.plugins + maven-dependency-plugin + + + copy-dependencies + package + + copy-dependencies + + + ${project.build.directory}/dependency + false + false + true + runtime + + + + @@ -93,4 +115,4 @@ - \ No newline at end of file + diff --git a/benchmarking/scripts/benchmark-pages.py b/benchmarking/scripts/benchmark-pages.py new file mode 100644 index 00000000..c5ff3da7 --- /dev/null +++ b/benchmarking/scripts/benchmark-pages.py @@ -0,0 +1,229 @@ +#!/usr/bin/env python3 +"""Benchmark CI pipeline helper for GitHub Pages deployment. + +Manages benchmark history and assembles deployment artifacts for cuioss.github.io. + +Subcommands: + prepare-history Copy fetched history to working directories for Maven trend calculation. + assemble Merge history, enforce retention, and combine artifacts for deployment. + +Usage in CI: + # Before Maven benchmark runs: + python3 benchmarking/scripts/benchmark-pages.py prepare-history \ + --previous-pages-dir previous-pages/api-sheriff/benchmarks \ + --output-dir "$GITHUB_WORKSPACE/benchmark-history" + + # After all Maven benchmark runs: + python3 benchmarking/scripts/benchmark-pages.py assemble \ + --micro-results benchmarking/benchmark-core/target/benchmark-results/gh-pages-ready \ + --integration-results benchmarking/benchmark-integration-wrk/target/benchmark-results/gh-pages-ready \ + --previous-pages-dir previous-pages/api-sheriff/benchmarks \ + --output-dir gh-pages \ + --commit-sha "$COMMIT_SHA" +""" + +import argparse +import json +import shutil +import sys +from datetime import datetime, timezone +from pathlib import Path + +# Badge files produced by each benchmark type and their names in the root badges/ directory. +_BADGE_MAPPING = { + "micro": { + "performance-badge.json": "performance-badge.json", + "trend-badge.json": "trend-badge.json", + "last-run-badge.json": "last-run-badge.json", + }, + "integration": { + "integration-performance-badge.json": "integration-performance-badge.json", + "integration-trend-badge.json": "integration-trend-badge.json", + "last-run-badge.json": "integration-last-run-badge.json", + }, +} + +_BENCHMARK_TYPES = ("micro", "integration") +_DEFAULT_MAX_HISTORY = 10 + + +def _copy_json_files(src_dir: Path, dst_dir: Path, *, skip_existing: bool = False) -> int: + """Copy all .json files from src to dst. Returns count of files copied.""" + dst_dir.mkdir(parents=True, exist_ok=True) + copied = 0 + for f in src_dir.glob("*.json"): + dst = dst_dir / f.name + if skip_existing and dst.exists(): + continue + shutil.copy2(f, dst) + copied += 1 + return copied + + +def _enforce_retention(history_dir: Path, max_files: int) -> int: + """Keep only the newest max_files JSON files (sorted by name descending). Returns count removed.""" + if not history_dir.is_dir(): + return 0 + files = sorted(history_dir.glob("*.json"), reverse=True) + removed = 0 + for old_file in files[max_files:]: + old_file.unlink() + removed += 1 + return removed + + +def prepare_history(args: argparse.Namespace) -> None: + """Copy previously deployed history files to working directories for Maven trend calculation.""" + previous_dir = Path(args.previous_pages_dir) + output_dir = Path(args.output_dir) + + if not previous_dir.is_dir(): + print(f"No previous pages directory found at {previous_dir}, skipping history preparation") + return + + for benchmark_type in _BENCHMARK_TYPES: + history_src = previous_dir / benchmark_type / "history" + if not history_src.is_dir(): + continue + count = _copy_json_files(history_src, output_dir / benchmark_type) + print(f"Prepared {count} {benchmark_type} history files") + + +def assemble(args: argparse.Namespace) -> None: + """Merge history, enforce retention, and combine artifacts for deployment. + + Note: History archiving (current run -> history/) is handled by Maven's + HistoricalDataManager.archiveCurrentRun() during the benchmark verify phase. + This function only merges previously deployed history and enforces retention. + """ + now = datetime.now(timezone.utc) + output_dir = Path(args.output_dir) + previous_dir = Path(args.previous_pages_dir) if args.previous_pages_dir else None + commit_sha = args.commit_sha + max_history = args.max_history + + # Collect configured benchmark modules + modules: list[tuple[str, Path]] = [] + if args.micro_results: + modules.append(("micro", Path(args.micro_results))) + if args.integration_results: + modules.append(("integration", Path(args.integration_results))) + + if not modules: + print("Error: at least one of --micro-results or --integration-results is required", + file=sys.stderr) + sys.exit(1) + + # 1. Merge previous history (skip files that already exist to avoid overwriting current run) + if previous_dir and previous_dir.is_dir(): + for name, results_dir in modules: + prev_history = previous_dir / name / "history" + if not prev_history.is_dir(): + continue + history_dir = results_dir / "history" + count = _copy_json_files(prev_history, history_dir, skip_existing=True) + print(f"Merged {count} previous {name} history files") + + # 2. Enforce retention policy per module + for name, results_dir in modules: + removed = _enforce_retention(results_dir / "history", max_history) + if removed: + print(f"Removed {removed} old {name} history files (retention: {max_history})") + + # 3. Combine into output directory + output_dir.mkdir(parents=True, exist_ok=True) + badges_dir = output_dir / "badges" + badges_dir.mkdir(exist_ok=True) + + for name, results_dir in modules: + if not results_dir.is_dir(): + print(f"Warning: {name} results not found at {results_dir}, skipping") + continue + + # Copy full module output into type subdirectory + shutil.copytree(results_dir, output_dir / name, dirs_exist_ok=True) + print(f"Copied {name} benchmark artifacts to {output_dir / name}") + + # Promote badges to root badges/ directory with mapped names + module_badges = results_dir / "badges" + if module_badges.is_dir() and name in _BADGE_MAPPING: + for src_name, dst_name in _BADGE_MAPPING[name].items(): + src = module_badges / src_name + if src.is_file(): + shutil.copy2(src, badges_dir / dst_name) + + # 4. Write deployment metadata + metadata = { + "timestamp": now.strftime("%Y-%m-%dT%H:%M:%SZ"), + "commit": commit_sha, + } + (output_dir / "metadata.json").write_text(json.dumps(metadata, indent=2) + "\n") + + # Summary + print(f"\nAssembled deployment artifacts in {output_dir}/") + for entry in sorted(output_dir.iterdir()): + kind = "dir" if entry.is_dir() else "file" + print(f" {entry.name}/ " if entry.is_dir() else f" {entry.name}") + + +def main() -> None: + parser = argparse.ArgumentParser( + description="Benchmark CI pipeline helper for GitHub Pages deployment.", + ) + subparsers = parser.add_subparsers(dest="command", required=True) + + # prepare-history + prep = subparsers.add_parser( + "prepare-history", + help="Copy fetched history to working directories for Maven trend calculation.", + ) + prep.add_argument( + "--previous-pages-dir", required=True, + help="Path to previously deployed pages (e.g. previous-pages/api-sheriff/benchmarks)", + ) + prep.add_argument( + "--output-dir", required=True, + help="Output directory for history files (passed to Maven as benchmark.history.dir parent)", + ) + + # assemble + asm = subparsers.add_parser( + "assemble", + help="Merge history, enforce retention, and combine all benchmark artifacts for deployment.", + ) + asm.add_argument( + "--micro-results", + help="Path to micro benchmark gh-pages-ready directory", + ) + asm.add_argument( + "--integration-results", + help="Path to integration benchmark gh-pages-ready directory", + ) + asm.add_argument( + "--previous-pages-dir", + help="Path to previously deployed pages for history merging", + ) + asm.add_argument( + "--output-dir", required=True, + help="Output directory for combined deployment artifacts", + ) + asm.add_argument( + "--commit-sha", required=True, + help="Git commit SHA for metadata and history archive naming", + ) + asm.add_argument( + "--max-history", type=int, default=_DEFAULT_MAX_HISTORY, + help=f"Maximum number of history entries to retain (default: {_DEFAULT_MAX_HISTORY})", + ) + + args = parser.parse_args() + + command_handlers = { + "prepare-history": prepare_history, + "assemble": assemble, + } + command_handlers[args.command](args) + + +if __name__ == "__main__": + main() diff --git a/benchmarking/scripts/create-performance-tracking.sh b/benchmarking/scripts/create-performance-tracking.sh deleted file mode 100755 index 765cc10d..00000000 --- a/benchmarking/scripts/create-performance-tracking.sh +++ /dev/null @@ -1,91 +0,0 @@ -#!/bin/bash -# Create performance tracking data from benchmark results -# Usage: create-performance-tracking.sh - -set -e - -JMH_RESULT_FILE="$1" -TEMPLATES_DIR="$2" -OUTPUT_DIR="$3" -COMMIT_HASH="$4" - -if [ ! -f "$JMH_RESULT_FILE" ]; then - echo "Error: JMH result file not found: $JMH_RESULT_FILE" - exit 1 -fi - -echo "Creating performance tracking data..." - -# Load utility libraries -SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" -source "$SCRIPT_DIR/lib/metrics-utils.sh" - -# Get environment info -eval $(get_environment_info) - -# Create performance tracking directory -mkdir -p "$OUTPUT_DIR/data/tracking" -mkdir -p "$OUTPUT_DIR/badges" - -# Run the unified performance badge script to get metrics and capture in a metrics file -METRICS_FILE="$OUTPUT_DIR/data/tracking/metrics-temp.sh" -SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" - -# Detect benchmark type -BENCHMARK_TYPE=$(detect_benchmark_type "$JMH_RESULT_FILE") - -bash "$SCRIPT_DIR/create-unified-performance-badge.sh" "$BENCHMARK_TYPE" "$JMH_RESULT_FILE" "$OUTPUT_DIR/badges" > "$METRICS_FILE.log" 2>&1 - -# Read the badge output immediately after script execution -BADGE_OUTPUT_CONTENT=$(cat "$METRICS_FILE.log") - -# Extract metrics from badge script output and create a sourceable metrics file -{ - echo "# Performance metrics extracted from create-unified-performance-badge.sh" - echo "$BADGE_OUTPUT_CONTENT" | grep "PERFORMANCE_SCORE=" | head -1 || echo "PERFORMANCE_SCORE=0" - echo "$BADGE_OUTPUT_CONTENT" | grep "THROUGHPUT_OPS_PER_SEC=" | head -1 || echo "THROUGHPUT_OPS_PER_SEC=0" - echo "$BADGE_OUTPUT_CONTENT" | grep "AVERAGE_TIME_SEC=" | head -1 || echo "AVERAGE_TIME_SEC=0" - echo "$BADGE_OUTPUT_CONTENT" | grep "THROUGHPUT_DISPLAY=" | head -1 || echo "THROUGHPUT_DISPLAY=0" - echo "$BADGE_OUTPUT_CONTENT" | grep "ERROR_RESILIENCE_OPS_PER_SEC=" | head -1 || echo "ERROR_RESILIENCE_OPS_PER_SEC=0" - echo "$BADGE_OUTPUT_CONTENT" | grep "AVG_TIME_MICROS=" | head -1 || echo "AVG_TIME_MICROS=0" -} > "$METRICS_FILE" - -# Source the metrics file for more robust parsing -source "$METRICS_FILE" || { - echo "Error: Failed to source metrics from create-unified-performance-badge.sh" - exit 1 -} - -# Clean up temporary files -rm -f "$METRICS_FILE" "$METRICS_FILE.log" - -if [ -z "$PERFORMANCE_SCORE" ] || [ "$PERFORMANCE_SCORE" = "0" ]; then - echo "Warning: Could not extract valid performance metrics for tracking" - exit 1 -fi - -# Create performance run JSON from template using envsubst for safe variable substitution -export TIMESTAMP="$(date -u +"%Y-%m-%dT%H:%M:%SZ")" -export COMMIT_HASH="$COMMIT_HASH" -export PERFORMANCE_SCORE="$PERFORMANCE_SCORE" -export THROUGHPUT_VALUE="$THROUGHPUT_OPS_PER_SEC" -export AVERAGE_TIME_SEC="$AVERAGE_TIME_SEC" -export THROUGHPUT_DISPLAY="$THROUGHPUT_DISPLAY" -export ERROR_RESILIENCE_VALUE="$ERROR_RESILIENCE_OPS_PER_SEC" -export THROUGHPUT_OPS_PER_SEC="$THROUGHPUT_OPS_PER_SEC" -export AVG_TIME_MICROS="$AVG_TIME_MICROS" -export ERROR_RESILIENCE_OPS_PER_SEC="$ERROR_RESILIENCE_OPS_PER_SEC" -export JAVA_VERSION="$JAVA_VERSION" -export JVM_ARGS="$JVM_ARGS_VALUE" -export OS_NAME="$OS_NAME" - -TIMESTAMP_FILE=$(date -u +"%Y%m%d-%H%M%S") -envsubst < "$TEMPLATES_DIR/performance-run.json" > "$OUTPUT_DIR/data/tracking/performance-$TIMESTAMP_FILE.json" - -echo "Created performance tracking file: data/tracking/performance-$TIMESTAMP_FILE.json" - -# Export metrics for use by calling script -echo "PERF_SCORE=$PERFORMANCE_SCORE" -echo "PERF_THROUGHPUT=$THROUGHPUT_DISPLAY" -echo "PERF_LATENCY=$AVERAGE_TIME_SEC" -echo "PERF_RESILIENCE=$ERROR_RESILIENCE_OPS_PER_SEC" diff --git a/benchmarking/scripts/create-unified-performance-badge.sh b/benchmarking/scripts/create-unified-performance-badge.sh deleted file mode 100755 index d7fbcd9a..00000000 --- a/benchmarking/scripts/create-unified-performance-badge.sh +++ /dev/null @@ -1,165 +0,0 @@ -#!/bin/bash -# Unified Performance Badge Creation Script -# Handles both micro-benchmarks and integration benchmarks -# Usage: create-unified-performance-badge.sh [commit-hash] [timestamp] [timestamp-with-time] - -set -e - -# Load utility libraries -SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" -source "$SCRIPT_DIR/lib/badge-utils.sh" -source "$SCRIPT_DIR/lib/metrics-utils.sh" - -BENCHMARK_TYPE="$1" # "micro" or "integration" -RESULT_FILE="$2" -OUTPUT_DIR="$3" -COMMIT_HASH="${4:-unknown}" -TIMESTAMP="${5:-$(date +"%Y-%m-%d")}" -TIMESTAMP_WITH_TIME="${6:-$(date +"%Y-%m-%d %H:%M %Z")}" - -if [ ! -f "$RESULT_FILE" ]; then - echo "Error: Result file not found: $RESULT_FILE" - exit 1 -fi - -# Create output directory -mkdir -p "$OUTPUT_DIR" - -echo "Creating unified performance badge for $BENCHMARK_TYPE benchmarks..." - - -# Process micro benchmarks -process_micro_benchmarks() { - echo "Processing micro-benchmark results..." - - # Extract throughput data - local throughput_entry=$(jq -r '.[] | select(.benchmark == "de.cuioss.jwt.validation.benchmark.standard.SimpleCoreValidationBenchmark.measureThroughput")' "$RESULT_FILE" 2>/dev/null) - local throughput_score=$(echo "$throughput_entry" | jq -r '.primaryMetric.score' 2>/dev/null || echo "0") - local throughput_unit=$(echo "$throughput_entry" | jq -r '.primaryMetric.scoreUnit' 2>/dev/null || echo "") - - # Extract average time data - local avg_time_entry=$(jq -r '.[] | select(.benchmark == "de.cuioss.jwt.validation.benchmark.standard.SimpleCoreValidationBenchmark.measureAverageTime")' "$RESULT_FILE" 2>/dev/null) - local avg_time_score=$(echo "$avg_time_entry" | jq -r '.primaryMetric.score' 2>/dev/null || echo "0") - local avg_time_unit=$(echo "$avg_time_entry" | jq -r '.primaryMetric.scoreUnit' 2>/dev/null || echo "") - - # Extract error resilience data - local error_resilience_entry=$(jq -r '.[] | select(.benchmark == "de.cuioss.jwt.validation.benchmark.standard.SimpleErrorLoadBenchmark.validateMixedTokens0")' "$RESULT_FILE" 2>/dev/null) - local error_resilience_score=$(echo "$error_resilience_entry" | jq -r '.primaryMetric.score' 2>/dev/null || echo "0") - local error_resilience_unit=$(echo "$error_resilience_entry" | jq -r '.primaryMetric.scoreUnit' 2>/dev/null || echo "") - - # Convert units - local throughput_ops_per_sec=$(convert_to_ops_per_sec "$throughput_score" "$throughput_unit") - local avg_time_ms=$(convert_to_milliseconds "$avg_time_score" "$avg_time_unit") - local error_resilience_ops_per_sec=$(convert_to_ops_per_sec "$error_resilience_score" "$error_resilience_unit") - - # Calculate performance score - local performance_score=$(calculate_performance_score "$throughput_ops_per_sec" "$avg_time_ms" "$error_resilience_ops_per_sec") - - # Format for display - local formatted_score=$(printf "%.0f" "$performance_score") - local throughput_display=$(format_throughput_display "$throughput_ops_per_sec") - local formatted_avg_time_ms=$(printf "%.0f" "$avg_time_ms") - - # Create performance badge - create_badge "Performance Score" "${formatted_score} (${throughput_display} ops/s, ${formatted_avg_time_ms}ms)" "brightgreen" "performance-badge.json" - - echo "Created micro-benchmark performance badge: Score=$formatted_score (Throughput=${throughput_display} ops/s, AvgTime=${formatted_avg_time_ms}ms)" - - # Export metrics for performance tracking - echo "PERFORMANCE_SCORE=$formatted_score" - echo "THROUGHPUT_OPS_PER_SEC=$throughput_ops_per_sec" - echo "AVERAGE_TIME_SEC=$(echo "scale=6; $avg_time_ms / 1000" | bc -l)" - echo "THROUGHPUT_DISPLAY=$throughput_display" - echo "ERROR_RESILIENCE_OPS_PER_SEC=$error_resilience_ops_per_sec" - echo "AVG_TIME_MICROS=$(echo "scale=0; $avg_time_ms * 1000" | bc -l)" -} - -# Process integration benchmarks -process_integration_benchmarks() { - echo "Processing integration benchmark results..." - - # Calculate average integration throughput (handle both ops/s and ops/ms) - local avg_throughput=$(jq -r ' - [.[] | select(.benchmark and .mode == "thrpt")] | - if length > 0 then - map( - if .primaryMetric.scoreUnit == "ops/ms" then - .primaryMetric.score * 1000 # Convert ops/ms to ops/s - else - .primaryMetric.score - end - ) | add / length | . * 100 | round / 100 - else - 0 - end - ' "$RESULT_FILE") - - # Calculate average integration latency (convert to milliseconds) - local avg_latency_ms=$(jq -r ' - [.[] | select(.benchmark and (.mode == "avgt" or .primaryMetric.scoreUnit == "ms/op"))] | - if length > 0 then - (map(.primaryMetric.score) | add / length | . * 1000 | round / 1000) - else - 0 - end - ' "$RESULT_FILE") - - # Calculate integration performance score - local integration_score=$(calculate_performance_score "$avg_throughput" "$avg_latency_ms" "0") - - # Format for display - local formatted_score=$(printf "%.0f" "$integration_score") - local throughput_display=$(format_throughput_display "$avg_throughput") - local formatted_latency_ms=$(printf "%.0f" "$avg_latency_ms") - - # Determine badge color - local badge_color=$(get_performance_badge_color "$integration_score") - - # Create integration performance badge (different name from micro benchmarks) - create_badge "Integration Performance" "${formatted_score} (${throughput_display} ops/s, ${formatted_latency_ms}ms)" "$badge_color" "integration-performance-badge.json" - - # Create additional integration-specific badges - local throughput_color=$(get_throughput_badge_color "$avg_throughput") - local latency_color=$(get_latency_badge_color "$avg_latency_ms") - - create_badge "Throughput" "${throughput_display} ops/s" "$throughput_color" "throughput-badge.json" - create_badge "Latency" "${formatted_latency_ms}ms" "$latency_color" "latency-badge.json" - - echo "Created integration benchmark badges: Score=$formatted_score (Throughput=${throughput_display} ops/s, Latency=${formatted_latency_ms}ms)" - - # Export metrics for performance tracking - echo "PERFORMANCE_SCORE=$formatted_score" - echo "THROUGHPUT_OPS_PER_SEC=$avg_throughput" - echo "AVERAGE_TIME_SEC=$(echo "scale=6; $avg_latency_ms / 1000" | bc -l)" - echo "THROUGHPUT_DISPLAY=$throughput_display" - echo "ERROR_RESILIENCE_OPS_PER_SEC=0" - echo "AVG_TIME_MICROS=$(echo "scale=0; $avg_latency_ms * 1000" | bc -l)" -} - -# Create simple badges for both types -create_simple_badges() { - echo "Creating simple informational badges..." - - # Create combined badge for all benchmarks - create_badge "JWT Benchmarks" "Updated $TIMESTAMP" "brightgreen" "all-benchmarks.json" - - # Create last benchmark run badge with time - create_badge "Last Benchmark Run" "$TIMESTAMP_WITH_TIME" "blue" "last-run-badge.json" - - echo "Simple badges created successfully" -} - -# Main processing logic -if [ "$BENCHMARK_TYPE" = "micro" ]; then - process_micro_benchmarks -elif [ "$BENCHMARK_TYPE" = "integration" ]; then - process_integration_benchmarks -else - echo "Error: Invalid benchmark type. Use 'micro' or 'integration'" - exit 1 -fi - -# Always create simple badges -create_simple_badges - -echo "Badge creation completed successfully" \ No newline at end of file diff --git a/benchmarking/scripts/create-unified-trend-badge.sh b/benchmarking/scripts/create-unified-trend-badge.sh deleted file mode 100755 index b5591d92..00000000 --- a/benchmarking/scripts/create-unified-trend-badge.sh +++ /dev/null @@ -1,136 +0,0 @@ -#!/bin/bash -# Unified Trend Badge Creation Script -# Handles both micro-benchmarks and integration benchmarks -# Usage: create-unified-trend-badge.sh - -set -e - -BENCHMARK_TYPE="$1" # "micro" or "integration" -TRACKING_FILE="$2" -OUTPUT_DIR="$3" - -if [ ! -f "$TRACKING_FILE" ]; then - echo "Error: Tracking file not found: $TRACKING_FILE" - # Create placeholder badge - mkdir -p "$OUTPUT_DIR" - echo "{\"schemaVersion\":1,\"label\":\"Performance Trend\",\"message\":\"โ†’ No Data\",\"color\":\"lightgrey\"}" > "$OUTPUT_DIR/trend-badge.json" - echo "Created placeholder trend badge: no tracking data" - exit 0 -fi - -# Create output directory -mkdir -p "$OUTPUT_DIR" - -echo "Calculating performance trends for $BENCHMARK_TYPE benchmarks..." - -# Common trend calculation function -calculate_trend() { - local scores="$1" - local score_count="$2" - - if [ "$score_count" -ge 2 ]; then - # Calculate simple trend (percentage change from first to last in the dataset) - local first_score=$(echo "$scores" | head -1) - local last_score=$(echo "$scores" | tail -1) - - # Handle division by zero - local percent_change - if [ "$(echo "$first_score == 0" | bc -l)" -eq 1 ]; then - if [ "$(echo "$last_score == 0" | bc -l)" -eq 1 ]; then - percent_change="0" - else - percent_change="99999" # Treat as massive improvement - fi - else - percent_change=$(echo "scale=2; (($last_score - $first_score) / $first_score) * 100" | bc -l) - fi - - # Determine trend direction and color - local trend_direction="stable" - local trend_color="lightgrey" - local trend_symbol="โ†’" - - if [ $(echo "$percent_change > 2" | bc -l) -eq 1 ]; then - trend_direction="improving" - trend_color="brightgreen" - trend_symbol="โ†—" - elif [ $(echo "$percent_change < -2" | bc -l) -eq 1 ]; then - trend_direction="declining" - trend_color="orange" - trend_symbol="โ†˜" - fi - - local abs_change=$(echo "$percent_change" | sed 's/-//') - local formatted_change=$(printf "%.1f" $abs_change) - - # Create trend badge with benchmark type context - local label="Performance Trend" - local badge_file="trend-badge.json" - if [ "$BENCHMARK_TYPE" = "integration" ]; then - label="Integration Performance Trend" - badge_file="integration-trend-badge.json" - fi - - echo "{\"schemaVersion\":1,\"label\":\"$label\",\"message\":\"$trend_symbol $formatted_change% ($trend_direction)\",\"color\":\"$trend_color\"}" > "$OUTPUT_DIR/$badge_file" - - echo "Created trend badge: $trend_direction ($formatted_change%)" - else - # Not enough data for trend - local label="Performance Trend" - local badge_file="trend-badge.json" - if [ "$BENCHMARK_TYPE" = "integration" ]; then - label="Integration Performance Trend" - badge_file="integration-trend-badge.json" - fi - - echo "{\"schemaVersion\":1,\"label\":\"$label\",\"message\":\"โ†’ Insufficient Data\",\"color\":\"lightgrey\"}" > "$OUTPUT_DIR/$badge_file" - echo "Created trend badge: insufficient data" - fi -} - -# Extract performance scores based on benchmark type -if [ "$BENCHMARK_TYPE" = "micro" ]; then - # Extract scores from micro-benchmark tracking file - SCORES=$(jq -r '.runs[].performance.score' "$TRACKING_FILE" 2>/dev/null | tail -10) - SCORE_COUNT=$(echo "$SCORES" | wc -l) - - if [ "$SCORE_COUNT" -eq 0 ]; then - # Try alternative structure - SCORES=$(jq -r '.runs[].score' "$TRACKING_FILE" 2>/dev/null | tail -10) - SCORE_COUNT=$(echo "$SCORES" | wc -l) - fi - -elif [ "$BENCHMARK_TYPE" = "integration" ]; then - # Extract scores from integration benchmark tracking file - SCORES=$(jq -r '.runs[].integration.performanceScore' "$TRACKING_FILE" 2>/dev/null | tail -10) - SCORE_COUNT=$(echo "$SCORES" | wc -l) - - if [ "$SCORE_COUNT" -eq 0 ]; then - # Try alternative structure - SCORES=$(jq -r '.runs[].performance.score' "$TRACKING_FILE" 2>/dev/null | tail -10) - SCORE_COUNT=$(echo "$SCORES" | wc -l) - fi - -else - echo "Error: Invalid benchmark type. Use 'micro' or 'integration'" - exit 1 -fi - -# Validate extracted scores -if [ "$SCORE_COUNT" -eq 0 ] || [ -z "$SCORES" ]; then - echo "Warning: No performance scores found in tracking file" - label="Performance Trend" - badge_file="trend-badge.json" - if [ "$BENCHMARK_TYPE" = "integration" ]; then - label="Integration Performance Trend" - badge_file="integration-trend-badge.json" - fi - echo "{\"schemaVersion\":1,\"label\":\"$label\",\"message\":\"โ†’ No Data\",\"color\":\"lightgrey\"}" > "$OUTPUT_DIR/$badge_file" - echo "Created placeholder trend badge: no performance data" - exit 0 -fi - -# Calculate and create trend badge -calculate_trend "$SCORES" "$SCORE_COUNT" - -echo "Trend badge creation completed successfully" \ No newline at end of file diff --git a/benchmarking/scripts/lib/badge-utils.sh b/benchmarking/scripts/lib/badge-utils.sh deleted file mode 100644 index 664ce985..00000000 --- a/benchmarking/scripts/lib/badge-utils.sh +++ /dev/null @@ -1,71 +0,0 @@ -#!/bin/bash -# Common badge creation utilities -# Usage: source lib/badge-utils.sh - -# Common badge creation function -create_badge() { - local label="$1" - local message="$2" - local color="$3" - local filename="$4" - local output_dir="${5:-$OUTPUT_DIR}" - - echo "{\"schemaVersion\":1,\"label\":\"$label\",\"message\":\"$message\",\"color\":\"$color\"}" > "$output_dir/$filename" -} - -# Format throughput for display -format_throughput_display() { - local throughput="$1" - - if [ $(echo "$throughput >= 1000" | bc -l) -eq 1 ]; then - throughput_k=$(echo "scale=1; $throughput / 1000" | bc -l) - echo "${throughput_k}k" - else - printf "%.0f" "$throughput" - fi -} - -# Determine badge color based on score -get_performance_badge_color() { - local score="$1" - - if (( $(echo "$score >= 50" | bc -l) )); then - echo "green" - elif (( $(echo "$score >= 25" | bc -l) )); then - echo "yellow" - elif (( $(echo "$score >= 10" | bc -l) )); then - echo "orange" - else - echo "red" - fi -} - -# Get throughput badge color -get_throughput_badge_color() { - local throughput="$1" - - if (( $(echo "$throughput >= 1000" | bc -l) )); then - echo "green" - elif (( $(echo "$throughput >= 500" | bc -l) )); then - echo "yellow" - elif (( $(echo "$throughput >= 100" | bc -l) )); then - echo "orange" - else - echo "red" - fi -} - -# Get latency badge color (lower is better) -get_latency_badge_color() { - local latency_ms="$1" - - if (( $(echo "$latency_ms <= 10" | bc -l) )); then - echo "green" - elif (( $(echo "$latency_ms <= 25" | bc -l) )); then - echo "yellow" - elif (( $(echo "$latency_ms <= 50" | bc -l) )); then - echo "orange" - else - echo "red" - fi -} \ No newline at end of file diff --git a/benchmarking/scripts/lib/metrics-utils.sh b/benchmarking/scripts/lib/metrics-utils.sh deleted file mode 100644 index dbcbc4f6..00000000 --- a/benchmarking/scripts/lib/metrics-utils.sh +++ /dev/null @@ -1,113 +0,0 @@ -#!/bin/bash -# Common metric calculation utilities -# Usage: source lib/metrics-utils.sh - -# Convert various units to operations per second -convert_to_ops_per_sec() { - local value="$1" - local unit="$2" - - if [[ "$unit" == "ops/s" ]]; then - echo "$value" - elif [[ "$unit" == "ops/ms" ]]; then - # Convert ops/ms to ops/s by multiplying by 1000 - echo "scale=2; $value * 1000" | bc -l - elif [[ "$unit" == "s/op" ]]; then - if [ "$(echo "$value == 0" | bc -l)" -eq 1 ]; then - echo "0" - else - echo "scale=2; 1 / $value" | bc -l - fi - elif [[ "$unit" == "ms/op" ]]; then - if [ "$(echo "$value == 0" | bc -l)" -eq 1 ]; then - echo "0" - else - echo "scale=2; 1000 / $value" | bc -l - fi - elif [[ "$unit" == "us/op" ]]; then - if [ "$(echo "$value == 0" | bc -l)" -eq 1 ]; then - echo "0" - else - echo "scale=2; 1000000 / $value" | bc -l - fi - else - echo "0" - fi -} - -# Convert various units to milliseconds -convert_to_milliseconds() { - local value="$1" - local unit="$2" - - if [[ "$unit" == "ms/op" ]]; then - echo "$value" - elif [[ "$unit" == "us/op" ]]; then - echo "scale=3; $value / 1000" | bc -l - elif [[ "$unit" == "s/op" ]]; then - echo "scale=3; $value * 1000" | bc -l - else - echo "0" - fi -} - -# Calculate weighted performance score -calculate_performance_score() { - local throughput="$1" - local latency_ms="$2" - local error_resilience="$3" - - # Convert latency to operations per second equivalent - local latency_ops_per_sec - if [ "$(echo "$latency_ms == 0" | bc -l)" -eq 1 ]; then - latency_ops_per_sec="0" - else - latency_ops_per_sec=$(echo "scale=2; 1000 / $latency_ms" | bc -l) - fi - - # Calculate weighted score - if [ "$error_resilience" != "0" ]; then - # Enhanced formula: (throughput * 0.57) + (latency * 0.40) + (error_resilience * 0.03) - echo "scale=2; ($throughput * 0.57) + ($latency_ops_per_sec * 0.40) + ($error_resilience * 0.03)" | bc -l - else - # Fallback to original formula: (throughput * 0.6) + (latency * 0.4) - echo "scale=2; ($throughput * 0.6) + ($latency_ops_per_sec * 0.4)" | bc -l - fi -} - -# Detect benchmark type from JMH result file -detect_benchmark_type() { - local result_file="$1" - - # Check for API-Sheriff benchmark patterns - if grep -q "de\\.cuioss\\.sheriff\\.api\\.quarkus\\.benchmark" "$result_file"; then - echo "integration" - elif grep -q "de\\.cuioss\\.sheriff\\.api\\.benchmark" "$result_file"; then - echo "micro" - # Legacy cui-jwt patterns - elif grep -q "JwtHealthBenchmark\|JwtValidationBenchmark\|JwtEchoBenchmark" "$result_file"; then - echo "integration" - elif grep -q "SimpleCoreValidationBenchmark\|SimpleErrorLoadBenchmark" "$result_file"; then - echo "micro" - else - echo "integration" # Default to integration - fi -} - -# Extract environment information -get_environment_info() { - local java_version=$(java -version 2>&1 | head -n 1 | cut -d'"' -f2 2>/dev/null || echo "unknown") - local os_name="$(uname -s)" - local jvm_args_value="default" - - # Capture actual JVM arguments if available from environment - if [ -n "$MAVEN_OPTS" ]; then - jvm_args_value="$MAVEN_OPTS" - elif [ -n "$JAVA_OPTS" ]; then - jvm_args_value="$JAVA_OPTS" - fi - - echo "JAVA_VERSION=$java_version" - echo "OS_NAME=$os_name" - echo "JVM_ARGS_VALUE=$jvm_args_value" -} \ No newline at end of file diff --git a/benchmarking/scripts/prepare-github-pages.sh b/benchmarking/scripts/prepare-github-pages.sh deleted file mode 100755 index f219faba..00000000 --- a/benchmarking/scripts/prepare-github-pages.sh +++ /dev/null @@ -1,85 +0,0 @@ -#!/bin/bash -# Prepare GitHub Pages structure and copy benchmark results -# Usage: prepare-github-pages.sh - -set -e - -BENCHMARK_RESULTS_DIR="$1" -TEMPLATES_DIR="$2" -OUTPUT_DIR="$3" - -echo "Preparing unified GitHub Pages structure..." - -# Create directories -mkdir -p "$OUTPUT_DIR" -mkdir -p "$OUTPUT_DIR/data" -mkdir -p "$OUTPUT_DIR/resources" -mkdir -p "$OUTPUT_DIR/badges" - -# Copy all benchmark results to data directory -if [ -d "$BENCHMARK_RESULTS_DIR" ]; then - cp -r "$BENCHMARK_RESULTS_DIR"/* "$OUTPUT_DIR/data"/ - echo "Copied benchmark results to data directory" -else - echo "Warning: Benchmark results directory not found: $BENCHMARK_RESULTS_DIR" -fi - -# Find and copy the main JMH result file -if [ -f "jmh-result.json" ]; then - echo "Using jmh-result.json from project root" - cp jmh-result.json "$OUTPUT_DIR/data/jmh-result.json" -else - # Find the result file in benchmark-results directory - echo "Looking for JMH result files in benchmark-results directory" - if [ -d "$BENCHMARK_RESULTS_DIR" ]; then - find "$BENCHMARK_RESULTS_DIR" -name "jmh-result*.json" -type f -exec cp {} "$OUTPUT_DIR/data/jmh-result.json" \; 2>/dev/null || true - find "$BENCHMARK_RESULTS_DIR" -name "micro-benchmark-result.json" -type f -exec cp {} "$OUTPUT_DIR/data/jmh-result.json" \; 2>/dev/null || true - fi -fi - -# Verify benchmark result file exists -if [ ! -f "$OUTPUT_DIR/data/jmh-result.json" ]; then - echo "ERROR: No benchmark result file found!" - exit 1 -fi - -# Copy all page templates to root directory using original names -cp "$TEMPLATES_DIR/index-visualizer.html" "$OUTPUT_DIR/index-visualizer.html" -echo "Copied micro benchmarks template" - -if [ -f "$TEMPLATES_DIR/integration-index.html" ]; then - cp "$TEMPLATES_DIR/integration-index.html" "$OUTPUT_DIR/integration-index.html" - echo "Copied integration benchmarks template" -fi - -if [ -f "$TEMPLATES_DIR/step-metrics-visualizer.html" ]; then - cp "$TEMPLATES_DIR/step-metrics-visualizer.html" "$OUTPUT_DIR/step-metrics-visualizer.html" - echo "Copied step metrics visualizer template" -fi - -if [ -f "$TEMPLATES_DIR/performance-trends.html" ]; then - cp "$TEMPLATES_DIR/performance-trends.html" "$OUTPUT_DIR/performance-trends.html" - echo "Copied performance trends template" -fi - -if [ -f "$TEMPLATES_DIR/integration-performance-trends.html" ]; then - cp "$TEMPLATES_DIR/integration-performance-trends.html" "$OUTPUT_DIR/integration-performance-trends.html" - echo "Copied integration performance trends template" -fi - -# Copy shared resources -if [ -d "$TEMPLATES_DIR/resources" ]; then - cp -r "$TEMPLATES_DIR/resources"/* "$OUTPUT_DIR/resources"/ - echo "Copied shared resources (CSS, JS)" -fi - -# Ensure jwt-validation-metrics.json is available for step metrics -if [ -f "$TEMPLATES_DIR/data/jwt-validation-metrics.json" ]; then - cp "$TEMPLATES_DIR/data/jwt-validation-metrics.json" "$OUTPUT_DIR/data/" - echo "Copied JWT validation step metrics" -fi - -echo "โœ… Unified GitHub Pages structure prepared successfully" -echo "๐Ÿ“ All pages are now in same directory with shared navigation" -echo "๐Ÿ“Š Data files are in data/ subdirectory" -echo "๐ŸŽจ Shared resources are in resources/ subdirectory" \ No newline at end of file diff --git a/benchmarking/scripts/prepare-step-metrics.sh b/benchmarking/scripts/prepare-step-metrics.sh deleted file mode 100755 index a44150fc..00000000 --- a/benchmarking/scripts/prepare-step-metrics.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash -# Prepare step metrics visualization (integrated into prepare-github-pages.sh) -# Usage: prepare-step-metrics.sh - -set -e - -BENCHMARK_RESULTS_DIR="$1" -TEMPLATES_DIR="$2" -OUTPUT_DIR="$3" - -echo "Preparing step metrics visualization..." - -# Create data directory -mkdir -p "$OUTPUT_DIR/data" - -# Copy step metrics data if it exists in benchmark results -if [ -f "$BENCHMARK_RESULTS_DIR/jwt-validation-metrics.json" ]; then - cp "$BENCHMARK_RESULTS_DIR/jwt-validation-metrics.json" "$OUTPUT_DIR/data/" - echo "Copied jwt-validation-metrics.json to data directory" -else - echo "Warning: jwt-validation-metrics.json not found in $BENCHMARK_RESULTS_DIR" -fi - -# Copy from templates data directory if available -if [ -f "$TEMPLATES_DIR/data/jwt-validation-metrics.json" ]; then - cp "$TEMPLATES_DIR/data/jwt-validation-metrics.json" "$OUTPUT_DIR/data/" - echo "Copied jwt-validation-metrics.json from templates data directory" -fi - -echo "Step metrics data prepared successfully" \ No newline at end of file diff --git a/benchmarking/scripts/process-all-benchmarks.sh b/benchmarking/scripts/process-all-benchmarks.sh deleted file mode 100755 index 2f9f3358..00000000 --- a/benchmarking/scripts/process-all-benchmarks.sh +++ /dev/null @@ -1,132 +0,0 @@ -#!/bin/bash -# Master orchestration script for processing all benchmark types -# Usage: process-all-benchmarks.sh - -set -e - -BENCHMARK_RESULTS_DIR="$1" -TEMPLATES_DIR="$2" -OUTPUT_DIR="$3" -COMMIT_HASH="$4" -TIMESTAMP="$5" -TIMESTAMP_WITH_TIME="$6" - -SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" - -echo "๐Ÿš€ Processing all benchmark results..." -echo "๐Ÿ“ Benchmark Results: $BENCHMARK_RESULTS_DIR" -echo "๐Ÿ“‹ Templates: $TEMPLATES_DIR" -echo "๐Ÿ“ฆ Output: $OUTPUT_DIR" -echo "๐Ÿ”— Commit: $COMMIT_HASH" -echo "๐Ÿ“… Timestamp: $TIMESTAMP" - -# Initialize processing results -RESULTS_FILE="$OUTPUT_DIR/processing-results.json" -mkdir -p "$OUTPUT_DIR" - -# Create initial results structure -cat > "$RESULTS_FILE" << EOF -{ - "timestamp": "$(date -u +"%Y-%m-%dT%H:%M:%SZ")", - "commit": "$COMMIT_HASH", - "processing": { - "micro": { "status": "not_found", "message": "No micro benchmark results" }, - "integration": { "status": "not_found", "message": "No integration benchmark results" } - }, - "errors": [] -} -EOF - -# Create header for badge markdown -echo "## Benchmark Results ($TIMESTAMP)" > "$OUTPUT_DIR/badge-markdown.txt" - -# Prepare basic GitHub Pages structure -echo "๐Ÿ“‹ Preparing GitHub Pages structure..." -bash "$SCRIPT_DIR/prepare-github-pages.sh" "$BENCHMARK_RESULTS_DIR" "$TEMPLATES_DIR" "$OUTPUT_DIR" - -# Process micro benchmarks -echo "๐Ÿ”ฌ Checking for micro benchmark results..." -if [ -f "$BENCHMARK_RESULTS_DIR/micro-benchmark-result.json" ]; then - echo "โœ… Found micro benchmark results, processing..." - - # Copy for legacy compatibility - cp "$BENCHMARK_RESULTS_DIR/micro-benchmark-result.json" "$BENCHMARK_RESULTS_DIR/jmh-result.json" - - # Process micro benchmarks - if bash "$SCRIPT_DIR/process-micro-benchmarks.sh" "$BENCHMARK_RESULTS_DIR/jmh-result.json" "$TEMPLATES_DIR" "$OUTPUT_DIR" "$COMMIT_HASH" "$TIMESTAMP" "$TIMESTAMP_WITH_TIME"; then - # Update results file with success - jq '.processing.micro = {"status": "success", "message": "Micro benchmarks processed successfully"}' "$RESULTS_FILE" > "${RESULTS_FILE}.tmp" && mv "${RESULTS_FILE}.tmp" "$RESULTS_FILE" - echo "โœ… Micro benchmarks processed successfully" - else - # Update results file with error - jq '.processing.micro = {"status": "error", "message": "Failed to process micro benchmarks"} | .errors += ["Micro benchmark processing failed"]' "$RESULTS_FILE" > "${RESULTS_FILE}.tmp" && mv "${RESULTS_FILE}.tmp" "$RESULTS_FILE" - echo "โŒ Failed to process micro benchmarks" - fi -else - echo "โš ๏ธ No micro benchmark results found" - # Create fallback badges for micro benchmarks - mkdir -p "$OUTPUT_DIR/badges" - echo "{\"schemaVersion\":1,\"label\":\"Performance Score\",\"message\":\"No Data\",\"color\":\"red\"}" > "$OUTPUT_DIR/badges/performance-badge.json" - echo "{\"schemaVersion\":1,\"label\":\"Performance Trend\",\"message\":\"โ†’ No Data\",\"color\":\"lightgrey\"}" > "$OUTPUT_DIR/badges/trend-badge.json" -fi - -# Process integration benchmarks -echo "๐Ÿ”— Checking for integration benchmark results..." -# Check for combined file first (preferred approach), then fallback to separate files -if [ -f "$BENCHMARK_RESULTS_DIR/integration-benchmark-result.json" ]; then - echo "โœ… Found combined integration benchmark results, processing..." - - # Process the combined JMH benchmark file for integration tests - if bash "$SCRIPT_DIR/process-integration-jmh-benchmarks.sh" "$BENCHMARK_RESULTS_DIR/integration-benchmark-result.json" "$OUTPUT_DIR" "$COMMIT_HASH" "$TIMESTAMP"; then - # Update results file with success - jq '.processing.integration = {"status": "success", "message": "Integration benchmarks processed successfully"}' "$RESULTS_FILE" > "${RESULTS_FILE}.tmp" && mv "${RESULTS_FILE}.tmp" "$RESULTS_FILE" - echo "โœ… Integration benchmarks processed successfully" - - # Add integration benchmark link to main page - echo "- [Integration Benchmark Results](integration-index.html)" >> "$OUTPUT_DIR/badge-markdown.txt" - else - # Update results file with error - jq '.processing.integration = {"status": "error", "message": "Failed to process integration benchmarks"} | .errors += ["Integration benchmark processing failed"]' "$RESULTS_FILE" > "${RESULTS_FILE}.tmp" && mv "${RESULTS_FILE}.tmp" "$RESULTS_FILE" - echo "โŒ Failed to process integration benchmarks" - fi -elif [ -f "$BENCHMARK_RESULTS_DIR/health-check-results.json" ] && [ -f "$BENCHMARK_RESULTS_DIR/jwt-validation-results.json" ]; then - echo "โœ… Found separate integration benchmark results, processing..." - - # Process integration benchmarks with separate files - if bash "$SCRIPT_DIR/process-integration-benchmarks.sh" "$BENCHMARK_RESULTS_DIR/health-check-results.json" "$BENCHMARK_RESULTS_DIR/jwt-validation-results.json" "$OUTPUT_DIR" "$COMMIT_HASH"; then - # Update results file with success - jq '.processing.integration = {"status": "success", "message": "Integration benchmarks processed successfully"}' "$RESULTS_FILE" > "${RESULTS_FILE}.tmp" && mv "${RESULTS_FILE}.tmp" "$RESULTS_FILE" - echo "โœ… Integration benchmarks processed successfully" - - # Add integration benchmark link to main page - echo "- [Integration Benchmark Results](integration-index.html)" >> "$OUTPUT_DIR/badge-markdown.txt" - else - # Update results file with error - jq '.processing.integration = {"status": "error", "message": "Failed to process integration benchmarks"} | .errors += ["Integration benchmark processing failed"]' "$RESULTS_FILE" > "${RESULTS_FILE}.tmp" && mv "${RESULTS_FILE}.tmp" "$RESULTS_FILE" - echo "โŒ Failed to process integration benchmarks" - fi -else - echo "โš ๏ธ No integration benchmark results found" - # Create fallback badges for integration benchmarks - mkdir -p "$OUTPUT_DIR/badges" - echo "{\"schemaVersion\":1,\"label\":\"Integration Performance\",\"message\":\"No Data\",\"color\":\"red\"}" > "$OUTPUT_DIR/badges/integration-performance-badge.json" - echo "{\"schemaVersion\":1,\"label\":\"Integration Trend\",\"message\":\"โ†’ No Data\",\"color\":\"lightgrey\"}" > "$OUTPUT_DIR/badges/integration-trend-badge.json" -fi - -# Final status report -echo "" -echo "๐Ÿ“Š Processing Summary:" -MICRO_STATUS=$(jq -r '.processing.micro.status' "$RESULTS_FILE") -INTEGRATION_STATUS=$(jq -r '.processing.integration.status' "$RESULTS_FILE") -ERROR_COUNT=$(jq '.errors | length' "$RESULTS_FILE") - -echo " ๐Ÿ”ฌ Micro Benchmarks: $MICRO_STATUS" -echo " ๐Ÿ”— Integration Benchmarks: $INTEGRATION_STATUS" -echo " โŒ Errors: $ERROR_COUNT" - -if [ "$ERROR_COUNT" -gt 0 ]; then - echo "โš ๏ธ Some processing steps failed. Check $RESULTS_FILE for details." - exit 1 -else - echo "โœ… All benchmark processing completed successfully!" -fi \ No newline at end of file diff --git a/benchmarking/scripts/process-integration-benchmarks.sh b/benchmarking/scripts/process-integration-benchmarks.sh deleted file mode 100755 index 5ae4b808..00000000 --- a/benchmarking/scripts/process-integration-benchmarks.sh +++ /dev/null @@ -1,146 +0,0 @@ -#!/bin/bash -# Process integration benchmark results and create badges/visualization -# Usage: process-integration-benchmarks.sh - -set -e - -HEALTH_RESULTS="$1" -JWT_RESULTS="$2" -OUTPUT_DIR="$3" -COMMIT_HASH="$4" - -SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" - -echo "๐Ÿ”— Processing integration benchmark results..." -echo "๐Ÿ’š Health Check Results: $HEALTH_RESULTS" -echo "๐Ÿ” JWT Validation Results: $JWT_RESULTS" - -# Validate input files -if [ ! -f "$HEALTH_RESULTS" ]; then - echo "โŒ Error: Health check results not found: $HEALTH_RESULTS" - exit 1 -fi - -if [ ! -f "$JWT_RESULTS" ]; then - echo "โŒ Error: JWT validation results not found: $JWT_RESULTS" - exit 1 -fi - -# Ensure output directories exist -mkdir -p "$OUTPUT_DIR/badges" -mkdir -p "$OUTPUT_DIR/data" - -# Create combined integration results file for compatibility -echo "๐Ÿ”„ Merging integration benchmark results..." -INTEGRATION_RESULT="$OUTPUT_DIR/data/integration-result.json" - -jq -n --slurpfile health "$HEALTH_RESULTS" --slurpfile jwt "$JWT_RESULTS" ' - { - "timestamp": (now | strftime("%Y-%m-%dT%H:%M:%SZ")), - "commit": "'$COMMIT_HASH'", - "health_check": $health[0], - "jwt_validation": $jwt[0], - "jwt_overhead_ms": ($jwt[0].latency_p95_ms - $health[0].latency_p95_ms) - }' > "$INTEGRATION_RESULT" - -echo "โœ… Integration results merged successfully" - -# Copy integration template to unified structure -TEMPLATES_DIR="$(dirname "$SCRIPT_DIR")/doc/templates" -if [ -f "$TEMPLATES_DIR/integration-index.html" ]; then - cp "$TEMPLATES_DIR/integration-index.html" "$OUTPUT_DIR/integration-index.html" - echo "๐Ÿ“‹ Integration template copied" -else - echo "โš ๏ธ Integration template not found at: $TEMPLATES_DIR/integration-index.html" -fi - -# Extract metrics from integration results -echo "๐Ÿ“Š Extracting integration metrics..." - -HEALTH_LATENCY=$(jq -r '.health_check.latency_p95_ms // 0' "$INTEGRATION_RESULT") -JWT_LATENCY=$(jq -r '.jwt_validation.latency_p95_ms // 0' "$INTEGRATION_RESULT") -JWT_THROUGHPUT=$(jq -r '.jwt_validation.throughput_rps // 0' "$INTEGRATION_RESULT") -JWT_OVERHEAD=$(jq -r '.jwt_overhead_ms // 0' "$INTEGRATION_RESULT") - -echo "Integration Performance Metrics:" -echo " Health Check P95: ${HEALTH_LATENCY}ms" -echo " JWT Validation P95: ${JWT_LATENCY}ms" -echo " JWT Throughput: ${JWT_THROUGHPUT} ops/s" -echo " JWT Overhead: ${JWT_OVERHEAD}ms" - -# Validate extracted metrics -if [ "$HEALTH_LATENCY" = "null" ] || [ "$HEALTH_LATENCY" = "" ]; then HEALTH_LATENCY="0"; fi -if [ "$JWT_LATENCY" = "null" ] || [ "$JWT_LATENCY" = "" ]; then JWT_LATENCY="0"; fi -if [ "$JWT_THROUGHPUT" = "null" ] || [ "$JWT_THROUGHPUT" = "" ]; then JWT_THROUGHPUT="0"; fi -if [ "$JWT_OVERHEAD" = "null" ] || [ "$JWT_OVERHEAD" = "" ]; then JWT_OVERHEAD="0"; fi - -# Create integration performance badges with smart color coding -echo "๐Ÿ† Creating integration performance badges..." - -# JWT P95 Latency Badge -JWT_LATENCY_COLOR="red" -if (( $(echo "$JWT_LATENCY <= 50" | bc -l 2>/dev/null || echo "0") )); then - JWT_LATENCY_COLOR="green" -elif (( $(echo "$JWT_LATENCY <= 100" | bc -l 2>/dev/null || echo "0") )); then - JWT_LATENCY_COLOR="yellow" -elif (( $(echo "$JWT_LATENCY <= 200" | bc -l 2>/dev/null || echo "0") )); then - JWT_LATENCY_COLOR="orange" -fi - -echo "{\"schemaVersion\":1,\"label\":\"JWT P95 Latency\",\"message\":\"${JWT_LATENCY}ms\",\"color\":\"$JWT_LATENCY_COLOR\"}" > "$OUTPUT_DIR/badges/integration-performance-badge.json" - -# JWT Throughput Badge -JWT_THROUGHPUT_COLOR="red" -if (( $(echo "$JWT_THROUGHPUT >= 1000" | bc -l 2>/dev/null || echo "0") )); then - JWT_THROUGHPUT_COLOR="green" -elif (( $(echo "$JWT_THROUGHPUT >= 500" | bc -l 2>/dev/null || echo "0") )); then - JWT_THROUGHPUT_COLOR="yellow" -elif (( $(echo "$JWT_THROUGHPUT >= 100" | bc -l 2>/dev/null || echo "0") )); then - JWT_THROUGHPUT_COLOR="orange" -fi - -# Format throughput for display -if (( $(echo "$JWT_THROUGHPUT >= 1000" | bc -l 2>/dev/null || echo "0") )); then - JWT_THROUGHPUT_DISPLAY=$(echo "scale=1; $JWT_THROUGHPUT / 1000" | bc -l)k -else - JWT_THROUGHPUT_DISPLAY=$(printf "%.0f" "$JWT_THROUGHPUT" 2>/dev/null || echo "$JWT_THROUGHPUT") -fi - -echo "{\"schemaVersion\":1,\"label\":\"JWT Throughput\",\"message\":\"${JWT_THROUGHPUT_DISPLAY} ops/s\",\"color\":\"$JWT_THROUGHPUT_COLOR\"}" > "$OUTPUT_DIR/badges/integration-throughput-badge.json" - -# JWT Overhead Badge -JWT_OVERHEAD_COLOR="red" -if (( $(echo "$JWT_OVERHEAD <= 10" | bc -l 2>/dev/null || echo "0") )); then - JWT_OVERHEAD_COLOR="green" -elif (( $(echo "$JWT_OVERHEAD <= 25" | bc -l 2>/dev/null || echo "0") )); then - JWT_OVERHEAD_COLOR="yellow" -elif (( $(echo "$JWT_OVERHEAD <= 50" | bc -l 2>/dev/null || echo "0") )); then - JWT_OVERHEAD_COLOR="orange" -fi - -echo "{\"schemaVersion\":1,\"label\":\"JWT Overhead\",\"message\":\"${JWT_OVERHEAD}ms\",\"color\":\"$JWT_OVERHEAD_COLOR\"}" > "$OUTPUT_DIR/badges/integration-overhead-badge.json" - -echo "โœ… Integration badges created successfully" - -# Create integration processing results -INTEGRATION_RESULTS_FILE="$OUTPUT_DIR/integration-processing-results.json" -cat > "$INTEGRATION_RESULTS_FILE" << EOF -{ - "timestamp": "$(date -u +"%Y-%m-%dT%H:%M:%SZ")", - "commit": "$COMMIT_HASH", - "integration_benchmarks": { - "health_check_latency_p95_ms": "$HEALTH_LATENCY", - "jwt_validation_latency_p95_ms": "$JWT_LATENCY", - "jwt_throughput_rps": "$JWT_THROUGHPUT", - "jwt_overhead_ms": "$JWT_OVERHEAD", - "health_results_file": "$HEALTH_RESULTS", - "jwt_results_file": "$JWT_RESULTS", - "combined_results_file": "$INTEGRATION_RESULT", - "status": "success" - } -} -EOF - -echo "โœ… Integration benchmark processing completed successfully" -echo "๐Ÿ“„ Results saved to: $INTEGRATION_RESULTS_FILE" -echo "๐Ÿ“„ Combined results available at: $INTEGRATION_RESULT" \ No newline at end of file diff --git a/benchmarking/scripts/process-integration-jmh-benchmarks.sh b/benchmarking/scripts/process-integration-jmh-benchmarks.sh deleted file mode 100755 index 65b41fd0..00000000 --- a/benchmarking/scripts/process-integration-jmh-benchmarks.sh +++ /dev/null @@ -1,170 +0,0 @@ -#!/bin/bash -# Process integration JMH benchmark results -# Usage: process-integration-jmh-benchmarks.sh - -set -e - -INTEGRATION_JMH_RESULTS="$1" -OUTPUT_DIR="$2" -COMMIT_HASH="$3" -TIMESTAMP="$4" - -SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" -TEMPLATES_DIR="$(dirname "$SCRIPT_DIR")/doc/templates" - -echo "๐Ÿ”— Processing integration JMH benchmark results..." -echo "๐Ÿ“Š Integration JMH Results: $INTEGRATION_JMH_RESULTS" -echo "๐Ÿ“ฆ Output Directory: $OUTPUT_DIR" - -# Validate input file -if [ ! -f "$INTEGRATION_JMH_RESULTS" ]; then - echo "โŒ Error: Integration JMH results not found: $INTEGRATION_JMH_RESULTS" - exit 1 -fi - -# Ensure output directories exist -mkdir -p "$OUTPUT_DIR/data" -mkdir -p "$OUTPUT_DIR/badges" - -# Copy the integration benchmark results to the data directory -echo "๐Ÿ“‹ Copying integration benchmark results..." -cp "$INTEGRATION_JMH_RESULTS" "$OUTPUT_DIR/data/integration-benchmark-result.json" - -# Also copy as jmh-result.json for fallback compatibility -cp "$INTEGRATION_JMH_RESULTS" "$OUTPUT_DIR/data/jmh-result.json" - -# Copy the integration visualizer template -echo "๐Ÿ“„ Copying integration visualizer template..." -if [ -f "$TEMPLATES_DIR/integration-benchmark-visualizer.html" ]; then - cp "$TEMPLATES_DIR/integration-benchmark-visualizer.html" "$OUTPUT_DIR/integration-benchmark-visualizer.html" -else - echo "โš ๏ธ Warning: Integration visualizer template not found, using fallback" - # Create a minimal fallback if template doesn't exist - cat > "$OUTPUT_DIR/integration-benchmark-visualizer.html" << 'EOF' - - - - Integration Benchmark Results - - - -

Redirecting to benchmark results...

- - -EOF -fi - -# Create performance tracking data for integration benchmarks -echo "๐Ÿ“Š Creating integration performance tracking..." -TRACKING_OUTPUT=$(bash "$SCRIPT_DIR/create-performance-tracking.sh" "$OUTPUT_DIR/data/integration-benchmark-result.json" "$TEMPLATES_DIR" "$OUTPUT_DIR" "$COMMIT_HASH" 2>&1) -echo "$TRACKING_OUTPUT" - -# Extract metrics from tracking script output -PERF_SCORE=$(echo "$TRACKING_OUTPUT" | grep "PERF_SCORE=" | cut -d'=' -f2 || echo "0") -PERF_THROUGHPUT=$(echo "$TRACKING_OUTPUT" | grep "PERF_THROUGHPUT=" | cut -d'=' -f2 || echo "0") -PERF_LATENCY=$(echo "$TRACKING_OUTPUT" | grep "PERF_LATENCY=" | cut -d'=' -f2 || echo "0") -PERF_RESILIENCE=$(echo "$TRACKING_OUTPUT" | grep "PERF_RESILIENCE=" | cut -d'=' -f2 || echo "0") - -echo "๐ŸŽฏ Extracted Integration Performance Metrics:" -echo " Score: $PERF_SCORE" -echo " Throughput: $PERF_THROUGHPUT" -echo " Latency: $PERF_LATENCY" -echo " Resilience: $PERF_RESILIENCE" - -# Create integration performance badge with actual score and details -if [ -n "$PERF_SCORE" ] && [ "$PERF_SCORE" != "0" ] && [ "$PERF_SCORE" != "" ]; then - # Format latency for display (convert to ms if needed) - LATENCY_MS=$(echo "$PERF_LATENCY * 1000" | bc -l | xargs printf "%.0f") - - # Format the badge message with score, throughput, and latency (like micro benchmarks) - BADGE_MESSAGE="${PERF_SCORE} (${PERF_THROUGHPUT} ops/s, ${LATENCY_MS}ms)" - - # Determine color based on score - SCORE_VALUE=$(echo "$PERF_SCORE" | sed 's/[^0-9.]//g') - if (( $(echo "$SCORE_VALUE >= 5000" | bc -l) )); then - BADGE_COLOR="brightgreen" - elif (( $(echo "$SCORE_VALUE >= 1000" | bc -l) )); then - BADGE_COLOR="green" - elif (( $(echo "$SCORE_VALUE >= 500" | bc -l) )); then - BADGE_COLOR="yellow" - else - BADGE_COLOR="orange" - fi - echo "{\"schemaVersion\":1,\"label\":\"Integration Performance\",\"message\":\"$BADGE_MESSAGE\",\"color\":\"$BADGE_COLOR\"}" > "$OUTPUT_DIR/badges/integration-performance-badge.json" -else - echo "{\"schemaVersion\":1,\"label\":\"Integration Performance\",\"message\":\"No Data\",\"color\":\"red\"}" > "$OUTPUT_DIR/badges/integration-performance-badge.json" -fi - -# Update integration trends using unified tracking system -if [ -n "$PERF_SCORE" ] && [ "$PERF_SCORE" != "0" ] && [ "$PERF_SCORE" != "" ]; then - echo "๐Ÿ“ˆ Updating integration performance trends..." - - # Use unified tracking system for integration benchmarks - # Create a separate tracking file for integration benchmarks - INTEGRATION_TRACKING_DIR="$OUTPUT_DIR" - if bash "$SCRIPT_DIR/update-integration-performance-trends.sh" "$TEMPLATES_DIR" "$INTEGRATION_TRACKING_DIR" "$COMMIT_HASH" "$PERF_SCORE" "$PERF_THROUGHPUT" "$PERF_LATENCY" "$PERF_RESILIENCE"; then - echo "โœ… Integration performance trends updated successfully" - else - echo "โš ๏ธ Failed to update integration performance trends, using fallback..." - # Fallback to old method - TRENDS_FILE="$OUTPUT_DIR/data/integration-trends.json" - if [ -f "$TRENDS_FILE" ]; then - # Read existing trends - PREV_SCORE=$(jq -r '.latest_score // "0"' "$TRENDS_FILE" 2>/dev/null || echo "0") - PREV_SCORE_VALUE=$(echo "$PREV_SCORE" | sed 's/[^0-9.]//g') - SCORE_VALUE=$(echo "$PERF_SCORE" | sed 's/[^0-9.]//g') - - # Calculate trend - if (( $(echo "$SCORE_VALUE > $PREV_SCORE_VALUE + 1" | bc -l) )); then - TREND_SYMBOL="โ†—" - TREND_COLOR="green" - elif (( $(echo "$SCORE_VALUE < $PREV_SCORE_VALUE - 1" | bc -l) )); then - TREND_SYMBOL="โ†˜" - TREND_COLOR="orange" - else - TREND_SYMBOL="โ†’" - TREND_COLOR="blue" - fi - else - TREND_SYMBOL="โ†’" - TREND_COLOR="blue" - fi - - # Update trends file - cat > "$TRENDS_FILE" << EOF -{ - "latest_score": "$PERF_SCORE", - "latest_throughput": "$PERF_THROUGHPUT", - "latest_latency": "$PERF_LATENCY", - "latest_resilience": "$PERF_RESILIENCE", - "updated": "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" -} -EOF - - # Create trend badge - TREND_MESSAGE="${TREND_SYMBOL} ${SCORE_VALUE}%" - echo "{\"schemaVersion\":1,\"label\":\"Integration Trend\",\"message\":\"$TREND_MESSAGE\",\"color\":\"$TREND_COLOR\"}" > "$OUTPUT_DIR/badges/integration-trend-badge.json" - fi -else - echo "{\"schemaVersion\":1,\"label\":\"Integration Trend\",\"message\":\"โ†’ No Data\",\"color\":\"lightgrey\"}" > "$OUTPUT_DIR/badges/integration-trend-badge.json" -fi - -# Create metadata file -cat > "$OUTPUT_DIR/data/integration-metadata.json" << EOF -{ - "timestamp": "$(date -u +"%Y-%m-%dT%H:%M:%SZ")", - "commit": "$COMMIT_HASH", - "generated_at": "$TIMESTAMP", - "metrics": { - "performance_score": "$PERF_SCORE", - "throughput": "$PERF_THROUGHPUT", - "latency": "$PERF_LATENCY", - "resilience": "$PERF_RESILIENCE" - } -} -EOF - -echo "โœ… Integration JMH benchmarks processed successfully" -echo " - Performance Score: $PERF_SCORE" -echo " - Throughput: $PERF_THROUGHPUT" -echo " - Latency: $PERF_LATENCY" \ No newline at end of file diff --git a/benchmarking/scripts/process-micro-benchmarks.sh b/benchmarking/scripts/process-micro-benchmarks.sh deleted file mode 100755 index 3de6edd7..00000000 --- a/benchmarking/scripts/process-micro-benchmarks.sh +++ /dev/null @@ -1,101 +0,0 @@ -#!/bin/bash -# Process micro benchmark results and create badges/tracking -# Usage: process-micro-benchmarks.sh - -set -e - -JMH_RESULT_FILE="$1" -TEMPLATES_DIR="$2" -OUTPUT_DIR="$3" -COMMIT_HASH="$4" -TIMESTAMP="$5" -TIMESTAMP_WITH_TIME="$6" - -SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" - -echo "๐Ÿ”ฌ Processing micro benchmark results..." -echo "๐Ÿ“„ JMH Result File: $JMH_RESULT_FILE" - -if [ ! -f "$JMH_RESULT_FILE" ]; then - echo "โŒ Error: JMH result file not found: $JMH_RESULT_FILE" - exit 1 -fi - -# Ensure output directories exist -mkdir -p "$OUTPUT_DIR/badges" - -# Copy JMH result to output directory for visualization -cp "$JMH_RESULT_FILE" "$OUTPUT_DIR/data/jmh-result.json" - -# Load utility libraries and detect benchmark type -SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" -source "$SCRIPT_DIR/lib/metrics-utils.sh" - -echo "๐Ÿ” Detecting benchmark type..." -BENCHMARK_TYPE=$(detect_benchmark_type "$JMH_RESULT_FILE") - -if [ "$BENCHMARK_TYPE" = "integration" ]; then - echo " โœ“ Detected integration benchmarks" -else - echo " โœ“ Detected micro benchmarks" -fi - -# Create performance badge using unified script (includes simple badges) -echo "๐Ÿ† Creating performance badge for $BENCHMARK_TYPE benchmarks..." -if ! bash "$SCRIPT_DIR/create-unified-performance-badge.sh" "$BENCHMARK_TYPE" "$OUTPUT_DIR/data/jmh-result.json" "$OUTPUT_DIR/badges" "$COMMIT_HASH" "$TIMESTAMP" "$TIMESTAMP_WITH_TIME"; then - echo "โš ๏ธ Failed to create performance badge, creating fallback..." - echo "{\"schemaVersion\":1,\"label\":\"Performance Score\",\"message\":\"Processing Error\",\"color\":\"red\"}" > "$OUTPUT_DIR/badges/performance-badge.json" -fi - -# Performance Tracking System -echo "๐Ÿ“ˆ Setting up performance tracking..." - -# Create performance tracking data -TRACKING_OUTPUT=$(bash "$SCRIPT_DIR/create-performance-tracking.sh" "$OUTPUT_DIR/data/jmh-result.json" "$TEMPLATES_DIR" "$OUTPUT_DIR" "$COMMIT_HASH" 2>&1) -echo "$TRACKING_OUTPUT" - -# Extract metrics from tracking script output -PERF_SCORE=$(echo "$TRACKING_OUTPUT" | grep "PERF_SCORE=" | cut -d'=' -f2 || echo "0") -PERF_THROUGHPUT=$(echo "$TRACKING_OUTPUT" | grep "PERF_THROUGHPUT=" | cut -d'=' -f2 || echo "0") -PERF_LATENCY=$(echo "$TRACKING_OUTPUT" | grep "PERF_LATENCY=" | cut -d'=' -f2 || echo "0") -PERF_RESILIENCE=$(echo "$TRACKING_OUTPUT" | grep "PERF_RESILIENCE=" | cut -d'=' -f2 || echo "0") - -echo "๐Ÿ“Š Extracted Performance Metrics:" -echo " Score: $PERF_SCORE" -echo " Throughput: $PERF_THROUGHPUT" -echo " Latency: $PERF_LATENCY" -echo " Resilience: $PERF_RESILIENCE" - -# Update consolidated tracking and create trend badge -if [ -n "$PERF_SCORE" ] && [ "$PERF_SCORE" != "0" ] && [ "$PERF_SCORE" != "" ]; then - echo "๐Ÿ“ˆ Updating performance trends..." - if bash "$SCRIPT_DIR/update-performance-trends.sh" "$TEMPLATES_DIR" "$OUTPUT_DIR" "$COMMIT_HASH" "$PERF_SCORE" "$PERF_THROUGHPUT" "$PERF_LATENCY" "$PERF_RESILIENCE"; then - echo "โœ… Performance trends updated successfully" - else - echo "โš ๏ธ Failed to update performance trends, creating fallback badge..." - echo "{\"schemaVersion\":1,\"label\":\"Performance Trend\",\"message\":\"โ†’ No Data\",\"color\":\"lightgrey\"}" > "$OUTPUT_DIR/badges/trend-badge.json" - fi -else - echo "โš ๏ธ Could not extract valid performance metrics for trend tracking" - echo "{\"schemaVersion\":1,\"label\":\"Performance Trend\",\"message\":\"โ†’ No Data\",\"color\":\"lightgrey\"}" > "$OUTPUT_DIR/badges/trend-badge.json" -fi - -# Create micro benchmark processing results -MICRO_RESULTS_FILE="$OUTPUT_DIR/micro-processing-results.json" -cat > "$MICRO_RESULTS_FILE" << EOF -{ - "timestamp": "$(date -u +"%Y-%m-%dT%H:%M:%SZ")", - "commit": "$COMMIT_HASH", - "micro_benchmarks": { - "performance_score": "$PERF_SCORE", - "throughput": "$PERF_THROUGHPUT", - "latency": "$PERF_LATENCY", - "resilience": "$PERF_RESILIENCE", - "jmh_result_file": "$JMH_RESULT_FILE", - "status": "success" - } -} -EOF - -echo "โœ… Micro benchmark processing completed successfully" -echo "๐Ÿ“„ Results saved to: $MICRO_RESULTS_FILE" \ No newline at end of file diff --git a/benchmarking/scripts/serve-local.js b/benchmarking/scripts/serve-local.js deleted file mode 100755 index c31e3597..00000000 --- a/benchmarking/scripts/serve-local.js +++ /dev/null @@ -1,72 +0,0 @@ -#!/usr/bin/env node -/** - * Simple HTTP server for local testing of benchmark templates - * Usage: node serve-local.js [port] - */ - -const http = require('http'); -const fs = require('fs'); -const path = require('path'); -const url = require('url'); - -const PORT = process.argv[2] || 8080; -const TEMPLATES_DIR = path.join(__dirname, '..', 'doc', 'templates'); - -// MIME types -const MIME_TYPES = { - '.html': 'text/html', - '.js': 'application/javascript', - '.json': 'application/json', - '.css': 'text/css', - '.png': 'image/png', - '.jpg': 'image/jpeg', - '.gif': 'image/gif', - '.svg': 'image/svg+xml', - '.ico': 'image/x-icon' -}; - -// Create server -const server = http.createServer((req, res) => { - let pathname = url.parse(req.url).pathname; - - // Default to index-visualizer.html - if (pathname === '/') { - pathname = '/index-visualizer.html'; - } - - const filePath = path.join(TEMPLATES_DIR, pathname); - const ext = path.extname(filePath); - - // Check if file exists - fs.stat(filePath, (err, stats) => { - if (err || !stats.isFile()) { - res.writeHead(404, { 'Content-Type': 'text/plain' }); - res.end('404 Not Found'); - return; - } - - // Serve the file - const mimeType = MIME_TYPES[ext] || 'application/octet-stream'; - res.writeHead(200, { - 'Content-Type': mimeType, - 'Access-Control-Allow-Origin': '*' // Allow CORS for local testing - }); - - fs.createReadStream(filePath).pipe(res); - }); -}); - -// Start server -server.listen(PORT, () => { - console.log('๐Ÿš€ Starting local HTTP server for benchmark templates'); - console.log(`๐Ÿ“ Serving from: ${TEMPLATES_DIR}`); - console.log(`๐ŸŒ URL: http://localhost:${PORT}`); - console.log(''); - console.log('Available pages:'); - console.log(` - http://localhost:${PORT}/index-visualizer.html (Micro Benchmarks)`); - console.log(` - http://localhost:${PORT}/integration-index.html (Integration Tests)`); - console.log(` - http://localhost:${PORT}/step-metrics-visualizer.html (Step Metrics)`); - console.log(` - http://localhost:${PORT}/performance-trends.html (Performance Trends)`); - console.log(''); - console.log('Press Ctrl+C to stop the server'); -}); \ No newline at end of file diff --git a/benchmarking/scripts/serve-local.sh b/benchmarking/scripts/serve-local.sh deleted file mode 100755 index 4a1f4cb5..00000000 --- a/benchmarking/scripts/serve-local.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/bash -# Simple HTTP server for local testing of benchmark templates -# Usage: ./serve-local.sh [port] - -PORT="${1:-8080}" -SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" -TEMPLATES_DIR="$(cd "$SCRIPT_DIR/../doc/templates" && pwd)" - -echo "๐Ÿš€ Starting local HTTP server for benchmark templates" -echo "๐Ÿ“ Serving from: $TEMPLATES_DIR" -echo "๐ŸŒ URL: http://localhost:$PORT" -echo "" -echo "Available pages:" -echo " - http://localhost:$PORT/index-visualizer.html (Micro Benchmarks)" -echo " - http://localhost:$PORT/integration-index.html (Integration Tests)" -echo " - http://localhost:$PORT/step-metrics-visualizer.html (Step Metrics)" -echo " - http://localhost:$PORT/performance-trends.html (Performance Trends)" -echo "" -echo "Press Ctrl+C to stop the server" -echo "" - -# Change to templates directory -cd "$TEMPLATES_DIR" - -# Try Python 3 first, then Python 2 -if command -v python3 &> /dev/null; then - python3 -m http.server "$PORT" -elif command -v python &> /dev/null; then - python -m SimpleHTTPServer "$PORT" -else - echo "โŒ Error: Python is not installed. Please install Python to use this script." - echo "Alternative: Use any other HTTP server like 'npx http-server' or 'php -S localhost:$PORT'" - exit 1 -fi \ No newline at end of file diff --git a/benchmarking/scripts/update-integration-performance-trends.sh b/benchmarking/scripts/update-integration-performance-trends.sh deleted file mode 100755 index a865203e..00000000 --- a/benchmarking/scripts/update-integration-performance-trends.sh +++ /dev/null @@ -1,128 +0,0 @@ -#!/bin/bash -# Update consolidated integration performance tracking and calculate trends -# Usage: update-integration-performance-trends.sh - -set -e - -TEMPLATES_DIR="$1" -OUTPUT_DIR="$2" -COMMIT_HASH="$3" -CURRENT_SCORE="$4" -CURRENT_THROUGHPUT="$5" -CURRENT_LATENCY="$6" -CURRENT_RESILIENCE="$7" - -echo "Updating integration performance tracking..." - -# Ensure output directories exist -mkdir -p "$OUTPUT_DIR/data" -mkdir -p "$OUTPUT_DIR/badges" - -# Use separate tracking file for integration benchmarks -TRACKING_FILE="$OUTPUT_DIR/data/integration-performance-tracking.json" -# Try to download from the deployed GitHub Pages URL -GITHUB_PAGES_URL="https://cuioss.github.io/cui-jwt/benchmarks/data/integration-performance-tracking.json" - -# Check if we already have a local tracking file with data -if [ -f "$TRACKING_FILE" ]; then - LOCAL_RUN_COUNT=$(jq '.runs | length' "$TRACKING_FILE" 2>/dev/null || echo "0") - if [ "$LOCAL_RUN_COUNT" -gt "0" ]; then - echo "Using existing local tracking file with $LOCAL_RUN_COUNT runs" - else - # Local file exists but is empty, try to download from GitHub Pages - echo "Local tracking file is empty, checking GitHub Pages..." - TEMP_FILE=$(mktemp) - if curl -f -s "$GITHUB_PAGES_URL" -o "$TEMP_FILE" 2>/dev/null; then - REMOTE_RUN_COUNT=$(jq '.runs | length' "$TEMP_FILE" 2>/dev/null || echo "0") - if [ "$REMOTE_RUN_COUNT" -gt "0" ]; then - echo "Downloaded existing performance tracking file with $REMOTE_RUN_COUNT runs" - mv "$TEMP_FILE" "$TRACKING_FILE" - else - echo "Remote tracking file is also empty, starting fresh" - rm -f "$TEMP_FILE" - echo '{"runs":[]}' > "$TRACKING_FILE" - fi - else - echo "No remote tracking file found, starting fresh" - rm -f "$TEMP_FILE" - echo '{"runs":[]}' > "$TRACKING_FILE" - fi - fi -else - # No local file, try to download from GitHub Pages - echo "No local tracking file, downloading from GitHub Pages..." - if curl -f -s "$GITHUB_PAGES_URL" -o "$TRACKING_FILE" 2>/dev/null; then - REMOTE_RUN_COUNT=$(jq '.runs | length' "$TRACKING_FILE" 2>/dev/null || echo "0") - echo "Downloaded existing performance tracking file with $REMOTE_RUN_COUNT runs" - if [ "$REMOTE_RUN_COUNT" -eq "0" ]; then - echo "Warning: Remote tracking file is empty" - fi - else - echo "No remote tracking file found, starting fresh" - echo '{"runs":[]}' > "$TRACKING_FILE" - fi -fi - -# Convert formatted values to raw numbers -# Remove 'k' suffix and multiply by 1000 if present -if [[ "$CURRENT_THROUGHPUT" == *"k" ]]; then - CURRENT_THROUGHPUT=$(echo "$CURRENT_THROUGHPUT" | sed 's/k$//' | awk '{print $1 * 1000}') -fi -if [[ "$CURRENT_RESILIENCE" == *"k" ]]; then - CURRENT_RESILIENCE=$(echo "$CURRENT_RESILIENCE" | sed 's/k$//' | awk '{print $1 * 1000}') -fi - -# Ensure values are numeric (default to 0 if not) -CURRENT_SCORE=$(echo "$CURRENT_SCORE" | grep -o '[0-9.]*' | head -1 || echo "0") -CURRENT_THROUGHPUT=$(echo "$CURRENT_THROUGHPUT" | grep -o '[0-9.]*' | head -1 || echo "0") -CURRENT_LATENCY=$(echo "$CURRENT_LATENCY" | grep -o '[0-9.]*' | head -1 || echo "0") -CURRENT_RESILIENCE=$(echo "$CURRENT_RESILIENCE" | grep -o '[0-9.]*' | head -1 || echo "0") - -# Add current run to tracking data -CURRENT_RUN=$(cat </dev/null; then - # Add new run and keep only last 10 runs - jq --argjson newrun "$CURRENT_RUN" '.runs += [$newrun] | .runs = (.runs | sort_by(.timestamp) | .[-10:])' "$TRACKING_FILE" > "$TRACKING_FILE.tmp" && mv "$TRACKING_FILE.tmp" "$TRACKING_FILE" -else - echo "Warning: Invalid JSON in tracking file, resetting to default structure." - echo '{"runs":[]}' > "$TRACKING_FILE" - jq --argjson newrun "$CURRENT_RUN" '.runs += [$newrun] | .runs = (.runs | sort_by(.timestamp) | .[-10:])' "$TRACKING_FILE" > "$TRACKING_FILE.tmp" && mv "$TRACKING_FILE.tmp" "$TRACKING_FILE" -fi - -# Log the final state for debugging -FINAL_RUN_COUNT=$(jq '.runs | length' "$TRACKING_FILE" 2>/dev/null || echo "0") -echo "Performance tracking file now contains $FINAL_RUN_COUNT runs" - -# Verify the file is actually written and contains data -if [ -f "$TRACKING_FILE" ]; then - echo "โœ… Performance tracking file exists at: $TRACKING_FILE" - FILE_SIZE=$(wc -c < "$TRACKING_FILE") - echo " File size: $FILE_SIZE bytes" - if [ "$FINAL_RUN_COUNT" -eq "0" ]; then - echo "โš ๏ธ WARNING: Tracking file exists but contains no runs!" - fi -else - echo "โŒ ERROR: Performance tracking file was not created!" -fi - -# Calculate trends and create trend badge using unified script for integration -SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" -bash "$SCRIPT_DIR/create-unified-trend-badge.sh" integration "$TRACKING_FILE" "$OUTPUT_DIR/badges" - -# Integration performance trends template is copied by prepare-github-pages.sh script - -echo "Integration performance tracking updated successfully" diff --git a/benchmarking/scripts/update-performance-trends.sh b/benchmarking/scripts/update-performance-trends.sh deleted file mode 100755 index c7b77af0..00000000 --- a/benchmarking/scripts/update-performance-trends.sh +++ /dev/null @@ -1,128 +0,0 @@ -#!/bin/bash -# Update consolidated performance tracking and calculate trends -# Usage: update-performance-trends.sh - -set -e - -TEMPLATES_DIR="$1" -OUTPUT_DIR="$2" -COMMIT_HASH="$3" -CURRENT_SCORE="$4" -CURRENT_THROUGHPUT="$5" -CURRENT_LATENCY="$6" -CURRENT_RESILIENCE="$7" - -echo "Updating consolidated performance tracking..." - -# Ensure output directories exist -mkdir -p "$OUTPUT_DIR/data" -mkdir -p "$OUTPUT_DIR/badges" - -# Download existing tracking file if it exists -TRACKING_FILE="$OUTPUT_DIR/data/performance-tracking.json" -# Try to download from the deployed GitHub Pages URL -GITHUB_PAGES_URL="https://cuioss.github.io/cui-jwt/benchmarks/data/performance-tracking.json" - -# Check if we already have a local tracking file with data -if [ -f "$TRACKING_FILE" ]; then - LOCAL_RUN_COUNT=$(jq '.runs | length' "$TRACKING_FILE" 2>/dev/null || echo "0") - if [ "$LOCAL_RUN_COUNT" -gt "0" ]; then - echo "Using existing local tracking file with $LOCAL_RUN_COUNT runs" - else - # Local file exists but is empty, try to download from GitHub Pages - echo "Local tracking file is empty, checking GitHub Pages..." - TEMP_FILE=$(mktemp) - if curl -f -s "$GITHUB_PAGES_URL" -o "$TEMP_FILE" 2>/dev/null; then - REMOTE_RUN_COUNT=$(jq '.runs | length' "$TEMP_FILE" 2>/dev/null || echo "0") - if [ "$REMOTE_RUN_COUNT" -gt "0" ]; then - echo "Downloaded existing performance tracking file with $REMOTE_RUN_COUNT runs" - mv "$TEMP_FILE" "$TRACKING_FILE" - else - echo "Remote tracking file is also empty, starting fresh" - rm -f "$TEMP_FILE" - echo '{"runs":[]}' > "$TRACKING_FILE" - fi - else - echo "No remote tracking file found, starting fresh" - rm -f "$TEMP_FILE" - echo '{"runs":[]}' > "$TRACKING_FILE" - fi - fi -else - # No local file, try to download from GitHub Pages - echo "No local tracking file, downloading from GitHub Pages..." - if curl -f -s "$GITHUB_PAGES_URL" -o "$TRACKING_FILE" 2>/dev/null; then - REMOTE_RUN_COUNT=$(jq '.runs | length' "$TRACKING_FILE" 2>/dev/null || echo "0") - echo "Downloaded existing performance tracking file with $REMOTE_RUN_COUNT runs" - if [ "$REMOTE_RUN_COUNT" -eq "0" ]; then - echo "Warning: Remote tracking file is empty" - fi - else - echo "No remote tracking file found, starting fresh" - echo '{"runs":[]}' > "$TRACKING_FILE" - fi -fi - -# Convert formatted values to raw numbers -# Remove 'k' suffix and multiply by 1000 if present -if [[ "$CURRENT_THROUGHPUT" == *"k" ]]; then - CURRENT_THROUGHPUT=$(echo "$CURRENT_THROUGHPUT" | sed 's/k$//' | awk '{print $1 * 1000}') -fi -if [[ "$CURRENT_RESILIENCE" == *"k" ]]; then - CURRENT_RESILIENCE=$(echo "$CURRENT_RESILIENCE" | sed 's/k$//' | awk '{print $1 * 1000}') -fi - -# Ensure values are numeric (default to 0 if not) -CURRENT_SCORE=$(echo "$CURRENT_SCORE" | grep -o '[0-9.]*' | head -1 || echo "0") -CURRENT_THROUGHPUT=$(echo "$CURRENT_THROUGHPUT" | grep -o '[0-9.]*' | head -1 || echo "0") -CURRENT_LATENCY=$(echo "$CURRENT_LATENCY" | grep -o '[0-9.]*' | head -1 || echo "0") -CURRENT_RESILIENCE=$(echo "$CURRENT_RESILIENCE" | grep -o '[0-9.]*' | head -1 || echo "0") - -# Add current run to tracking data -CURRENT_RUN=$(cat </dev/null; then - # Add new run and keep only last 10 runs - jq --argjson newrun "$CURRENT_RUN" '.runs += [$newrun] | .runs = (.runs | sort_by(.timestamp) | .[-10:])' "$TRACKING_FILE" > "$TRACKING_FILE.tmp" && mv "$TRACKING_FILE.tmp" "$TRACKING_FILE" -else - echo "Warning: Invalid JSON in tracking file, resetting to default structure." - echo '{"runs":[]}' > "$TRACKING_FILE" - jq --argjson newrun "$CURRENT_RUN" '.runs += [$newrun] | .runs = (.runs | sort_by(.timestamp) | .[-10:])' "$TRACKING_FILE" > "$TRACKING_FILE.tmp" && mv "$TRACKING_FILE.tmp" "$TRACKING_FILE" -fi - -# Log the final state for debugging -FINAL_RUN_COUNT=$(jq '.runs | length' "$TRACKING_FILE" 2>/dev/null || echo "0") -echo "Performance tracking file now contains $FINAL_RUN_COUNT runs" - -# Verify the file is actually written and contains data -if [ -f "$TRACKING_FILE" ]; then - echo "โœ… Performance tracking file exists at: $TRACKING_FILE" - FILE_SIZE=$(wc -c < "$TRACKING_FILE") - echo " File size: $FILE_SIZE bytes" - if [ "$FINAL_RUN_COUNT" -eq "0" ]; then - echo "โš ๏ธ WARNING: Tracking file exists but contains no runs!" - fi -else - echo "โŒ ERROR: Performance tracking file was not created!" -fi - -# Calculate trends and create trend badge using unified script -SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" -bash "$SCRIPT_DIR/create-unified-trend-badge.sh" micro "$TRACKING_FILE" "$OUTPUT_DIR/badges" - -# Performance trends template is copied by prepare-github-pages.sh script - -echo "Performance tracking updated successfully" diff --git a/benchmarking/templates/data/badges/performance-badge.json b/benchmarking/templates/data/badges/performance-badge.json deleted file mode 100644 index 07d72db2..00000000 --- a/benchmarking/templates/data/badges/performance-badge.json +++ /dev/null @@ -1 +0,0 @@ -{"schemaVersion":1,"label":"Performance Score","message":"52580 (85.5k ops/s, 1ms)","color":"brightgreen"} \ No newline at end of file diff --git a/benchmarking/templates/data/badges/trend-badge.json b/benchmarking/templates/data/badges/trend-badge.json deleted file mode 100644 index cf460fd1..00000000 --- a/benchmarking/templates/data/badges/trend-badge.json +++ /dev/null @@ -1 +0,0 @@ -{"schemaVersion":1,"label":"Performance Trend","message":"โ†— 8.4% (improving)","color":"brightgreen"} \ No newline at end of file diff --git a/benchmarking/templates/data/integration-metrics.json b/benchmarking/templates/data/integration-metrics.json deleted file mode 100644 index ec61c1d5..00000000 --- a/benchmarking/templates/data/integration-metrics.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "timestamp": "2025-08-01T14:30:45.123456Z", - "commit": "abc123456789abcdef123456789abcdef12345678", - "integration": { - "totalBenchmarks": 4, - "throughputBenchmarks": 2, - "avgThroughput": 5894.267573456785, - "avgLatency": 0.010649616666666111, - "performanceScore": 89.45, - "customData": { - "containerType": "native-quarkus", - "keycloakVersion": "26.0.4", - "testEnvironment": "containerized", - "jwtOverheadMs": 9.565, - "healthCheckP95Ms": 6.52, - "jwtValidationP95Ms": 17.40 - } - } -} \ No newline at end of file diff --git a/benchmarking/templates/data/integration-result.json b/benchmarking/templates/data/integration-result.json deleted file mode 100644 index 211096c6..00000000 --- a/benchmarking/templates/data/integration-result.json +++ /dev/null @@ -1,222 +0,0 @@ -[ - { - "jmhVersion": "1.37", - "benchmark": "de.cuioss.jwt.quarkus.benchmark.integration.HealthCheckBenchmark.measureHealthCheck", - "mode": "thrpt", - "threads": 50, - "forks": 1, - "jvm": "/opt/java/openjdk/bin/java", - "jvmArgs": [ - "-Dquarkus.http.port=8080", - "-Djava.util.logging.manager=org.jboss.logmanager.LogManager" - ], - "jdkVersion": "21.0.7", - "vmName": "OpenJDK 64-Bit Server VM", - "vmVersion": "21.0.7+6-LTS", - "warmupIterations": 2, - "warmupTime": "3 s", - "warmupBatchSize": 1, - "measurementIterations": 3, - "measurementTime": "5 s", - "measurementBatchSize": 1, - "primaryMetric": { - "score": 8542.856234567891, - "scoreError": 234.567891234567, - "scoreConfidence": [ - 8308.288343333324, - 8777.424125802458 - ], - "scorePercentiles": { - "0.0": 8234.567891234567, - "50.0": 8542.856234567891, - "90.0": 8851.144577901235, - "95.0": 8928.289749567902, - "99.0": 9005.434921234569, - "99.9": 9043.007507067902, - "99.99": 9050.580092901235, - "99.999": 9053.366385817902, - "99.9999": 9054.759532276235, - "100.0": 9056.152678734568 - }, - "scoreUnit": "ops/s", - "rawData": [ - [ - 8234.567891234567, - 8542.856234567891, - 8851.144577901235 - ] - ] - }, - "secondaryMetrics": {}, - "customData": { - "containerType": "native-quarkus", - "testType": "health-check", - "description": "Health check endpoint performance baseline" - } - }, - { - "jmhVersion": "1.37", - "benchmark": "de.cuioss.jwt.quarkus.benchmark.integration.JwtValidationBenchmark.measureJwtValidation", - "mode": "thrpt", - "threads": 50, - "forks": 1, - "jvm": "/opt/java/openjdk/bin/java", - "jvmArgs": [ - "-Dquarkus.http.port=8080", - "-Djava.util.logging.manager=org.jboss.logmanager.LogManager" - ], - "jdkVersion": "21.0.7", - "vmName": "OpenJDK 64-Bit Server VM", - "vmVersion": "21.0.7+6-LTS", - "warmupIterations": 2, - "warmupTime": "3 s", - "warmupBatchSize": 1, - "measurementIterations": 3, - "measurementTime": "5 s", - "measurementBatchSize": 1, - "primaryMetric": { - "score": 3245.678912345678, - "scoreError": 123.456789123456, - "scoreConfidence": [ - 3122.222123222222, - 3369.135701469134 - ], - "scorePercentiles": { - "0.0": 3098.765432109876, - "50.0": 3245.678912345678, - "90.0": 3392.59239258148, - "95.0": 3443.827160493827, - "99.0": 3495.061928406174, - "99.9": 3520.679312362347, - "99.99": 3533.48800934032, - "99.999": 3540.391851829307, - "99.9999": 3543.844273073801, - "100.0": 3547.296694318294 - }, - "scoreUnit": "ops/s", - "rawData": [ - [ - 3098.765432109876, - 3245.678912345678, - 3392.59239258148 - ] - ] - }, - "secondaryMetrics": {}, - "customData": { - "containerType": "native-quarkus", - "testType": "jwt-validation", - "description": "JWT validation with Keycloak integration" - } - }, - { - "jmhVersion": "1.37", - "benchmark": "de.cuioss.jwt.quarkus.benchmark.integration.HealthCheckBenchmark.measureHealthCheckLatency", - "mode": "avgt", - "threads": 50, - "forks": 1, - "jvm": "/opt/java/openjdk/bin/java", - "jvmArgs": [ - "-Dquarkus.http.port=8080", - "-Djava.util.logging.manager=org.jboss.logmanager.LogManager" - ], - "jdkVersion": "21.0.7", - "vmName": "OpenJDK 64-Bit Server VM", - "vmVersion": "21.0.7+6-LTS", - "warmupIterations": 2, - "warmupTime": "3 s", - "warmupBatchSize": 1, - "measurementIterations": 3, - "measurementTime": "5 s", - "measurementBatchSize": 1, - "primaryMetric": { - "score": 5.867123456789012, - "scoreError": 0.234567891234567, - "scoreConfidence": [ - 5.632555565554445, - 6.101691347923579 - ], - "scorePercentiles": { - "0.0": 5.432109876543209, - "50.0": 5.867123456789012, - "90.0": 6.302137037034815, - "95.0": 6.519643827157716, - "99.0": 6.737150617280618, - "99.9": 6.845904012342069, - "99.99": 6.90028071987227, - "99.999": 6.927469574307375, - "99.9999": 6.941064001524928, - "100.0": 6.95465842874248 - }, - "scoreUnit": "ms/op", - "rawData": [ - [ - 5.432109876543209, - 5.867123456789012, - 6.302137037034815 - ] - ] - }, - "secondaryMetrics": {}, - "customData": { - "containerType": "native-quarkus", - "testType": "health-check-latency", - "description": "Health check endpoint latency baseline" - } - }, - { - "jmhVersion": "1.37", - "benchmark": "de.cuioss.jwt.quarkus.benchmark.integration.JwtValidationBenchmark.measureJwtValidationLatency", - "mode": "avgt", - "threads": 50, - "forks": 1, - "jvm": "/opt/java/openjdk/bin/java", - "jvmArgs": [ - "-Dquarkus.http.port=8080", - "-Djava.util.logging.manager=org.jboss.logmanager.LogManager" - ], - "jdkVersion": "21.0.7", - "vmName": "OpenJDK 64-Bit Server VM", - "vmVersion": "21.0.7+6-LTS", - "warmupIterations": 2, - "warmupTime": "3 s", - "warmupBatchSize": 1, - "measurementIterations": 3, - "measurementTime": "5 s", - "measurementBatchSize": 1, - "primaryMetric": { - "score": 15.432109876543209, - "scoreError": 0.876543210987654, - "scoreConfidence": [ - 14.555566665555555, - 16.308653087530863 - ], - "scorePercentiles": { - "0.0": 14.123456789012345, - "50.0": 15.432109876543209, - "90.0": 16.740762964074073, - "95.0": 17.39508950783395, - "99.0": 18.049416051593827, - "99.9": 18.376579323473765, - "99.99": 18.540160959413734, - "99.999": 18.621951777383719, - "99.9999": 18.662847186368711, - "100.0": 18.703742595353703 - }, - "scoreUnit": "ms/op", - "rawData": [ - [ - 14.123456789012345, - 15.432109876543209, - 16.740762964074073 - ] - ] - }, - "secondaryMetrics": {}, - "customData": { - "containerType": "native-quarkus", - "testType": "jwt-validation-latency", - "description": "JWT validation latency with Keycloak integration" - } - } -] \ No newline at end of file diff --git a/benchmarking/templates/data/jmh-result.json b/benchmarking/templates/data/jmh-result.json deleted file mode 100644 index 551607cf..00000000 --- a/benchmarking/templates/data/jmh-result.json +++ /dev/null @@ -1,259 +0,0 @@ -[ - { - "jmhVersion" : "1.37", - "benchmark" : "de.cuioss.jwt.validation.benchmark.standard.SimpleCoreValidationBenchmark.measureThroughput", - "mode" : "thrpt", - "threads" : 100, - "forks" : 1, - "jvm" : "/Users/oliver/.sdkman/candidates/java/21.0.7-tem/bin/java", - "jvmArgs" : [ - "-Djava.util.logging.config.file=src/main/resources/benchmark-logging.properties", - "-Dbenchmark.results.dir=target/benchmark-results" - ], - "jdkVersion" : "21.0.7", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "21.0.7+6-LTS", - "warmupIterations" : 1, - "warmupTime" : "1 s", - "warmupBatchSize" : 1, - "measurementIterations" : 3, - "measurementTime" : "4 s", - "measurementBatchSize" : 1, - "primaryMetric" : { - "score" : 85537.63015022938, - "scoreError" : 254883.1704119681, - "scoreConfidence" : [ - -169345.54026173873, - 340420.80056219746 - ], - "scorePercentiles" : { - "0.0" : 73495.27601820591, - "50.0" : 82262.2860058696, - "90.0" : 100855.32842661263, - "95.0" : 100855.32842661263, - "99.0" : 100855.32842661263, - "99.9" : 100855.32842661263, - "99.99" : 100855.32842661263, - "99.999" : 100855.32842661263, - "99.9999" : 100855.32842661263, - "100.0" : 100855.32842661263 - }, - "scoreUnit" : "ops/s", - "rawData" : [ - [ - 73495.27601820591, - 82262.2860058696, - 100855.32842661263 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.37", - "benchmark" : "de.cuioss.jwt.validation.benchmark.standard.SimpleErrorLoadBenchmark.validateMixedTokens0", - "mode" : "thrpt", - "threads" : 100, - "forks" : 1, - "jvm" : "/Users/oliver/.sdkman/candidates/java/21.0.7-tem/bin/java", - "jvmArgs" : [ - "-Djava.util.logging.config.file=src/main/resources/benchmark-logging.properties", - "-Dbenchmark.results.dir=target/benchmark-results" - ], - "jdkVersion" : "21.0.7", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "21.0.7+6-LTS", - "warmupIterations" : 1, - "warmupTime" : "1 s", - "warmupBatchSize" : 1, - "measurementIterations" : 3, - "measurementTime" : "4 s", - "measurementBatchSize" : 1, - "primaryMetric" : { - "score" : 113075.3659554129, - "scoreError" : 429927.7193989502, - "scoreConfidence" : [ - -316852.3534435373, - 543003.0853543631 - ], - "scorePercentiles" : { - "0.0" : 87679.28318017177, - "50.0" : 117310.21366746748, - "90.0" : 134236.6010185994, - "95.0" : 134236.6010185994, - "99.0" : 134236.6010185994, - "99.9" : 134236.6010185994, - "99.99" : 134236.6010185994, - "99.999" : 134236.6010185994, - "99.9999" : 134236.6010185994, - "100.0" : 134236.6010185994 - }, - "scoreUnit" : "ops/s", - "rawData" : [ - [ - 87679.28318017177, - 117310.21366746748, - 134236.6010185994 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.37", - "benchmark" : "de.cuioss.jwt.validation.benchmark.standard.SimpleErrorLoadBenchmark.validateMixedTokens50", - "mode" : "thrpt", - "threads" : 100, - "forks" : 1, - "jvm" : "/Users/oliver/.sdkman/candidates/java/21.0.7-tem/bin/java", - "jvmArgs" : [ - "-Djava.util.logging.config.file=src/main/resources/benchmark-logging.properties", - "-Dbenchmark.results.dir=target/benchmark-results" - ], - "jdkVersion" : "21.0.7", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "21.0.7+6-LTS", - "warmupIterations" : 1, - "warmupTime" : "1 s", - "warmupBatchSize" : 1, - "measurementIterations" : 3, - "measurementTime" : "4 s", - "measurementBatchSize" : 1, - "primaryMetric" : { - "score" : 181228.33898605246, - "scoreError" : 572634.4137451742, - "scoreConfidence" : [ - -391406.07475912175, - 753862.7527312266 - ], - "scorePercentiles" : { - "0.0" : 147500.59042516802, - "50.0" : 186601.46421029576, - "90.0" : 209582.96232269364, - "95.0" : 209582.96232269364, - "99.0" : 209582.96232269364, - "99.9" : 209582.96232269364, - "99.99" : 209582.96232269364, - "99.999" : 209582.96232269364, - "99.9999" : 209582.96232269364, - "100.0" : 209582.96232269364 - }, - "scoreUnit" : "ops/s", - "rawData" : [ - [ - 147500.59042516802, - 186601.46421029576, - 209582.96232269364 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.37", - "benchmark" : "de.cuioss.jwt.validation.benchmark.standard.SimpleCoreValidationBenchmark.measureAverageTime", - "mode" : "avgt", - "threads" : 100, - "forks" : 1, - "jvm" : "/Users/oliver/.sdkman/candidates/java/21.0.7-tem/bin/java", - "jvmArgs" : [ - "-Djava.util.logging.config.file=src/main/resources/benchmark-logging.properties", - "-Dbenchmark.results.dir=target/benchmark-results" - ], - "jdkVersion" : "21.0.7", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "21.0.7+6-LTS", - "warmupIterations" : 1, - "warmupTime" : "1 s", - "warmupBatchSize" : 1, - "measurementIterations" : 3, - "measurementTime" : "4 s", - "measurementBatchSize" : 1, - "primaryMetric" : { - "score" : 928.6525007153555, - "scoreError" : 3218.660182413916, - "scoreConfidence" : [ - -2290.0076816985606, - 4147.312683129272 - ], - "scorePercentiles" : { - "0.0" : 808.4349352738636, - "50.0" : 846.3295311978617, - "90.0" : 1131.1930356743412, - "95.0" : 1131.1930356743412, - "99.0" : 1131.1930356743412, - "99.9" : 1131.1930356743412, - "99.99" : 1131.1930356743412, - "99.999" : 1131.1930356743412, - "99.9999" : 1131.1930356743412, - "100.0" : 1131.1930356743412 - }, - "scoreUnit" : "us/op", - "rawData" : [ - [ - 1131.1930356743412, - 808.4349352738636, - 846.3295311978617 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.37", - "benchmark" : "de.cuioss.jwt.validation.benchmark.standard.SimpleCoreValidationBenchmark.measureConcurrentValidation", - "mode" : "avgt", - "threads" : 100, - "forks" : 1, - "jvm" : "/Users/oliver/.sdkman/candidates/java/21.0.7-tem/bin/java", - "jvmArgs" : [ - "-Djava.util.logging.config.file=src/main/resources/benchmark-logging.properties", - "-Dbenchmark.results.dir=target/benchmark-results" - ], - "jdkVersion" : "21.0.7", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "21.0.7+6-LTS", - "warmupIterations" : 1, - "warmupTime" : "1 s", - "warmupBatchSize" : 1, - "measurementIterations" : 3, - "measurementTime" : "4 s", - "measurementBatchSize" : 1, - "primaryMetric" : { - "score" : 904.1837804561357, - "scoreError" : 2009.986557383793, - "scoreConfidence" : [ - -1105.8027769276573, - 2914.170337839929 - ], - "scorePercentiles" : { - "0.0" : 835.4446265863261, - "50.0" : 845.8466213683903, - "90.0" : 1031.2600934136908, - "95.0" : 1031.2600934136908, - "99.0" : 1031.2600934136908, - "99.9" : 1031.2600934136908, - "99.99" : 1031.2600934136908, - "99.999" : 1031.2600934136908, - "99.9999" : 1031.2600934136908, - "100.0" : 1031.2600934136908 - }, - "scoreUnit" : "us/op", - "rawData" : [ - [ - 1031.2600934136908, - 845.8466213683903, - 835.4446265863261 - ] - ] - }, - "secondaryMetrics" : { - } - } -] - - diff --git a/benchmarking/templates/data/jwt-validation-metrics.json b/benchmarking/templates/data/jwt-validation-metrics.json deleted file mode 100644 index 7d71f4e2..00000000 --- a/benchmarking/templates/data/jwt-validation-metrics.json +++ /dev/null @@ -1,357 +0,0 @@ -{ - "measureThroughput": { - "timestamp": "2025-08-01T07:33:36.504762Z", - "steps": { - "token_parsing": { - "sample_count": 1024, - "p50_us": 3.8, - "p95_us": 4.9, - "p99_us": 5.9 - }, - "header_validation": { - "sample_count": 1024, - "p50_us": 0.3, - "p95_us": 1.2, - "p99_us": 1.9 - }, - "claims_validation": { - "sample_count": 1024, - "p50_us": 1.9, - "p95_us": 3.3, - "p99_us": 3.7 - }, - "cache_lookup": { - "sample_count": 1024, - "p50_us": 0, - "p95_us": 0.3, - "p99_us": 0.4 - }, - "issuer_config_resolution": { - "sample_count": 1024, - "p50_us": 0, - "p95_us": 0.2, - "p99_us": 0.3 - }, - "signature_validation": { - "sample_count": 1024, - "p50_us": 53, - "p95_us": 70, - "p99_us": 24864 - }, - "token_format_check": { - "sample_count": 1024, - "p50_us": 0, - "p95_us": 0.2, - "p99_us": 0.3 - }, - "token_building": { - "sample_count": 1024, - "p50_us": 4.6, - "p95_us": 8.8, - "p99_us": 12 - }, - "complete_validation": { - "sample_count": 1024, - "p50_us": 67, - "p95_us": 92, - "p99_us": 40819 - }, - "issuer_extraction": { - "sample_count": 1024, - "p50_us": 0.2, - "p95_us": 0.5, - "p99_us": 1 - }, - "cache_store": { - "sample_count": 1024, - "p50_us": 0.4, - "p95_us": 0.7, - "p99_us": 1.1 - } - } - }, - "validateMixedTokens0": { - "timestamp": "2025-08-01T07:34:12.407553Z", - "steps": { - "issuer_config_resolution": { - "sample_count": 1024, - "p50_us": 0, - "p95_us": 0.2, - "p99_us": 0.4 - }, - "token_building": { - "sample_count": 1024, - "p50_us": 2.2, - "p95_us": 3.7, - "p99_us": 4.9 - }, - "token_parsing": { - "sample_count": 1024, - "p50_us": 3.5, - "p95_us": 4.8, - "p99_us": 6.1 - }, - "issuer_extraction": { - "sample_count": 1024, - "p50_us": 0, - "p95_us": 0.2, - "p99_us": 0.3 - }, - "cache_store": { - "sample_count": 1024, - "p50_us": 0.2, - "p95_us": 0.4, - "p99_us": 0.6 - }, - "cache_lookup": { - "sample_count": 1024, - "p50_us": 0, - "p95_us": 0.2, - "p99_us": 0.3 - }, - "header_validation": { - "sample_count": 1024, - "p50_us": 0.2, - "p95_us": 0.4, - "p99_us": 0.5 - }, - "token_format_check": { - "sample_count": 1024, - "p50_us": 0.1, - "p95_us": 0.3, - "p99_us": 0.4 - }, - "signature_validation": { - "sample_count": 1024, - "p50_us": 52, - "p95_us": 69, - "p99_us": 608 - }, - "complete_validation": { - "sample_count": 1024, - "p50_us": 60, - "p95_us": 81, - "p99_us": 864 - }, - "claims_validation": { - "sample_count": 1024, - "p50_us": 0.7, - "p95_us": 1.2, - "p99_us": 1.7 - } - } - }, - "validateMixedTokens50": { - "timestamp": "2025-08-01T07:34:47.800593Z", - "steps": { - "signature_validation": { - "sample_count": 1024, - "p50_us": 46, - "p95_us": 69, - "p99_us": 91 - }, - "issuer_config_resolution": { - "sample_count": 1024, - "p50_us": 0, - "p95_us": 2.5, - "p99_us": 3.2 - }, - "token_format_check": { - "sample_count": 1024, - "p50_us": 0, - "p95_us": 0.2, - "p99_us": 0.3 - }, - "token_parsing": { - "sample_count": 1024, - "p50_us": 3.5, - "p95_us": 6.1, - "p99_us": 6.8 - }, - "claims_validation": { - "sample_count": 1024, - "p50_us": 1.7, - "p95_us": 3.3, - "p99_us": 4.1 - }, - "token_building": { - "sample_count": 1024, - "p50_us": 2.4, - "p95_us": 4.1, - "p99_us": 5 - }, - "complete_validation": { - "sample_count": 1024, - "p50_us": 35, - "p95_us": 84, - "p99_us": 104 - }, - "issuer_extraction": { - "sample_count": 1024, - "p50_us": 0, - "p95_us": 0.2, - "p99_us": 0.4 - }, - "cache_lookup": { - "sample_count": 1024, - "p50_us": 0, - "p95_us": 0.2, - "p99_us": 0.4 - }, - "header_validation": { - "sample_count": 1024, - "p50_us": 0.2, - "p95_us": 0.4, - "p99_us": 0.5 - }, - "cache_store": { - "sample_count": 1024, - "p50_us": 0.4, - "p95_us": 0.7, - "p99_us": 0.9 - } - } - }, - "measureAverageTime": { - "timestamp": "2025-08-01T07:35:22.250463Z", - "steps": { - "token_format_check": { - "sample_count": 1024, - "p50_us": 0, - "p95_us": 0.2, - "p99_us": 0.3 - }, - "token_building": { - "sample_count": 1024, - "p50_us": 3.2, - "p95_us": 4.6, - "p99_us": 7 - }, - "cache_lookup": { - "sample_count": 1024, - "p50_us": 0, - "p95_us": 0.3, - "p99_us": 0.4 - }, - "cache_store": { - "sample_count": 1024, - "p50_us": 0.1, - "p95_us": 0.4, - "p99_us": 0.6 - }, - "signature_validation": { - "sample_count": 1024, - "p50_us": 68, - "p95_us": 83, - "p99_us": 8645 - }, - "issuer_extraction": { - "sample_count": 1024, - "p50_us": 0, - "p95_us": 0.2, - "p99_us": 0.3 - }, - "issuer_config_resolution": { - "sample_count": 1024, - "p50_us": 0, - "p95_us": 0.2, - "p99_us": 0.3 - }, - "claims_validation": { - "sample_count": 1024, - "p50_us": 1, - "p95_us": 1.4, - "p99_us": 1.8 - }, - "header_validation": { - "sample_count": 1024, - "p50_us": 0.2, - "p95_us": 0.4, - "p99_us": 0.5 - }, - "token_parsing": { - "sample_count": 1024, - "p50_us": 4.3, - "p95_us": 5.3, - "p99_us": 7.3 - }, - "complete_validation": { - "sample_count": 1024, - "p50_us": 78, - "p95_us": 107, - "p99_us": 18042 - } - } - }, - "measureConcurrentValidation": { - "timestamp": "2025-08-01T07:35:57.926454Z", - "steps": { - "issuer_extraction": { - "sample_count": 1024, - "p50_us": 0, - "p95_us": 0.2, - "p99_us": 0.3 - }, - "token_building": { - "sample_count": 1024, - "p50_us": 3, - "p95_us": 4, - "p99_us": 5.3 - }, - "complete_validation": { - "sample_count": 1024, - "p50_us": 63, - "p95_us": 90, - "p99_us": 10203 - }, - "cache_store": { - "sample_count": 1024, - "p50_us": 0.1, - "p95_us": 0.4, - "p99_us": 0.5 - }, - "issuer_config_resolution": { - "sample_count": 1024, - "p50_us": 0, - "p95_us": 0.2, - "p99_us": 0.3 - }, - "token_format_check": { - "sample_count": 1024, - "p50_us": 0.1, - "p95_us": 0.2, - "p99_us": 0.3 - }, - "claims_validation": { - "sample_count": 1024, - "p50_us": 0.9, - "p95_us": 1.1, - "p99_us": 1.5 - }, - "header_validation": { - "sample_count": 1024, - "p50_us": 0.2, - "p95_us": 0.4, - "p99_us": 0.5 - }, - "cache_lookup": { - "sample_count": 1024, - "p50_us": 0, - "p95_us": 0.2, - "p99_us": 0.3 - }, - "signature_validation": { - "sample_count": 1024, - "p50_us": 54, - "p95_us": 74, - "p99_us": 10190 - }, - "token_parsing": { - "sample_count": 1024, - "p50_us": 4.3, - "p95_us": 6.1, - "p99_us": 7.3 - } - } - } -} \ No newline at end of file diff --git a/benchmarking/templates/data/performance-tracking.json b/benchmarking/templates/data/performance-tracking.json deleted file mode 100644 index 754236af..00000000 --- a/benchmarking/templates/data/performance-tracking.json +++ /dev/null @@ -1,84 +0,0 @@ -{ - "runs": [ - { - "timestamp": "2025-07-25T10:15:30Z", - "commit": "a1b2c3d4e5f6789012345678901234567890abcd", - "performance": { - "score": 48520, - "throughput": {"value": 79800, "unit": "ops/s"}, - "averageTime": {"value": 0.001256, "unit": "s"}, - "errorResilience": {"value": 105200, "unit": "ops/s"} - } - }, - { - "timestamp": "2025-07-26T14:22:15Z", - "commit": "b2c3d4e5f6789012345678901234567890abcde1", - "performance": { - "score": 49850, - "throughput": {"value": 82100, "unit": "ops/s"}, - "averageTime": {"value": 0.001218, "unit": "s"}, - "errorResilience": {"value": 108500, "unit": "ops/s"} - } - }, - { - "timestamp": "2025-07-27T09:45:22Z", - "commit": "c3d4e5f6789012345678901234567890abcde12f", - "performance": { - "score": 47200, - "throughput": {"value": 77500, "unit": "ops/s"}, - "averageTime": {"value": 0.001289, "unit": "s"}, - "errorResilience": {"value": 101800, "unit": "ops/s"} - } - }, - { - "timestamp": "2025-07-28T16:33:44Z", - "commit": "d4e5f6789012345678901234567890abcde12f34", - "performance": { - "score": 51200, - "throughput": {"value": 84300, "unit": "ops/s"}, - "averageTime": {"value": 0.001186, "unit": "s"}, - "errorResilience": {"value": 112000, "unit": "ops/s"} - } - }, - { - "timestamp": "2025-07-29T11:28:17Z", - "commit": "e5f6789012345678901234567890abcde12f3456", - "performance": { - "score": 50100, - "throughput": {"value": 82800, "unit": "ops/s"}, - "averageTime": {"value": 0.001207, "unit": "s"}, - "errorResilience": {"value": 109300, "unit": "ops/s"} - } - }, - { - "timestamp": "2025-07-30T13:17:58Z", - "commit": "f6789012345678901234567890abcde12f345678", - "performance": { - "score": 52800, - "throughput": {"value": 87200, "unit": "ops/s"}, - "averageTime": {"value": 0.001147, "unit": "s"}, - "errorResilience": {"value": 115600, "unit": "ops/s"} - } - }, - { - "timestamp": "2025-07-31T15:42:33Z", - "commit": "6789012345678901234567890abcde12f3456789", - "performance": { - "score": 51900, - "throughput": {"value": 85700, "unit": "ops/s"}, - "averageTime": {"value": 0.001167, "unit": "s"}, - "errorResilience": {"value": 113400, "unit": "ops/s"} - } - }, - { - "timestamp": "2025-08-01T07:30:12Z", - "commit": "789012345678901234567890abcde12f3456789a", - "performance": { - "score": 52580, - "throughput": {"value": 85538, "unit": "ops/s"}, - "averageTime": {"value": 0.001169, "unit": "s"}, - "errorResilience": {"value": 113075, "unit": "ops/s"} - } - } - ] -} \ No newline at end of file diff --git a/benchmarking/templates/data/tracking/performance-20250801-073012.json b/benchmarking/templates/data/tracking/performance-20250801-073012.json deleted file mode 100644 index 639b8a73..00000000 --- a/benchmarking/templates/data/tracking/performance-20250801-073012.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "timestamp": "2025-08-01T07:30:12Z", - "commit": "789012345678901234567890abcde12f3456789a", - "performance": { - "score": 52580, - "throughput": { - "value": 85538, - "unit": "ops/s" - }, - "averageTime": { - "value": 0.001169, - "unit": "s" - }, - "errorResilience": { - "value": 113075, - "unit": "ops/s" - } - }, - "rawMetrics": { - "throughputOpsPerSec": 85538, - "avgTimeInMicros": 1169, - "errorResilienceOpsPerSec": 113075 - }, - "environment": { - "javaVersion": "21.0.7", - "jvmArgs": "-Djava.util.logging.config.file=src/main/resources/benchmark-logging.properties -Dbenchmark.results.dir=target/benchmark-results", - "osName": "Linux" - } -} \ No newline at end of file diff --git a/benchmarking/templates/index-visualizer.html b/benchmarking/templates/index-visualizer.html deleted file mode 100644 index 7e26d42c..00000000 --- a/benchmarking/templates/index-visualizer.html +++ /dev/null @@ -1,107 +0,0 @@ - - - - - - JWT Micro Benchmark Results - - - - -
-
-

JWT Micro Benchmark Results

-

Unit-level performance testing of JWT validation components

- -
- -
- - -
-
- - - - - \ No newline at end of file diff --git a/benchmarking/templates/integration-benchmark-visualizer.html b/benchmarking/templates/integration-benchmark-visualizer.html deleted file mode 100644 index e3c70d09..00000000 --- a/benchmarking/templates/integration-benchmark-visualizer.html +++ /dev/null @@ -1,175 +0,0 @@ - - - - - - JWT Integration Benchmark Results - - - - -
-
-

JWT Integration Benchmark Results

-

End-to-end performance testing with Keycloak and native Quarkus

- -
- -
-

Integration Test Environment

-
-
-
Test Type
-
Native Container
-
-
-
Services
-
Keycloak + Quarkus
-
-
-
Protocol
-
HTTPS/TLS
-
-
-
Benchmark Format
-
JMH Results
-
-
-
- -
- - -
-
- - - - - \ No newline at end of file diff --git a/benchmarking/templates/integration-index.html b/benchmarking/templates/integration-index.html deleted file mode 100644 index 7c33b0ae..00000000 --- a/benchmarking/templates/integration-index.html +++ /dev/null @@ -1,96 +0,0 @@ - - - - - - JWT Integration Benchmark Results - - - - -
-
-

JWT Integration Benchmark Results

-

End-to-end performance testing with containerized Quarkus application and Keycloak

- -
- -
- - -
-
- - - - - \ No newline at end of file diff --git a/benchmarking/templates/integration-performance-trends.html b/benchmarking/templates/integration-performance-trends.html deleted file mode 100644 index ba41cf31..00000000 --- a/benchmarking/templates/integration-performance-trends.html +++ /dev/null @@ -1,267 +0,0 @@ - - - - - - Integration Benchmark Performance Trends - - - - - -
-
-

Integration Benchmark Performance Trends

-

Performance metrics and trends for integration benchmarks over the last 10 runs

- -
- -
-

Loading integration performance data...

-
- - - - - - -
- - - - \ No newline at end of file diff --git a/benchmarking/templates/performance-run.json b/benchmarking/templates/performance-run.json deleted file mode 100644 index 26862c15..00000000 --- a/benchmarking/templates/performance-run.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "timestamp": "${TIMESTAMP}", - "commit": "${COMMIT_HASH}", - "performance": { - "score": ${PERFORMANCE_SCORE}, - "throughput": { - "value": ${THROUGHPUT_VALUE}, - "unit": "ops/s" - }, - "averageTime": { - "value": ${AVERAGE_TIME_SEC}, - "unit": "s" - }, - "errorResilience": { - "value": ${ERROR_RESILIENCE_VALUE}, - "unit": "ops/s" - } - }, - "rawMetrics": { - "throughputOpsPerSec": ${THROUGHPUT_OPS_PER_SEC}, - "avgTimeInMicros": ${AVG_TIME_MICROS}, - "errorResilienceOpsPerSec": ${ERROR_RESILIENCE_OPS_PER_SEC} - }, - "environment": { - "javaVersion": "${JAVA_VERSION}", - "jvmArgs": "${JVM_ARGS}", - "osName": "${OS_NAME}" - } -} \ No newline at end of file diff --git a/benchmarking/templates/performance-trends.html b/benchmarking/templates/performance-trends.html deleted file mode 100644 index 5202e8d7..00000000 --- a/benchmarking/templates/performance-trends.html +++ /dev/null @@ -1,248 +0,0 @@ - - - - - - JWT Validation Performance Trends - - - - - -
-
-

JWT Validation Performance Trends

-

Performance metrics and trends over the last 10 benchmark runs

- -
- -
-

Loading performance data...

-
- - - - - - - -
- - - - - diff --git a/benchmarking/templates/resources/common.css b/benchmarking/templates/resources/common.css deleted file mode 100644 index eb48eaf4..00000000 --- a/benchmarking/templates/resources/common.css +++ /dev/null @@ -1,387 +0,0 @@ -/* CUI JWT Benchmarking - Common Styles */ - -/* Base Styles */ -body { - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif; - margin: 0; - padding: 0; - background-color: #f8f9fa; - color: #343a40; -} - -/* Layout */ -.container { - max-width: 1400px; - margin: 0 auto; - background: white; - border-radius: 8px; - box-shadow: 0 2px 10px rgba(0,0,0,0.1); - padding: 30px; -} - -/* Typography */ -h1 { - color: #343a40; - margin-bottom: 10px; - font-size: 2.5rem; - font-weight: 300; -} - -h2 { - color: #495057; - font-size: 1.8rem; - font-weight: 400; - margin-bottom: 15px; -} - -h3 { - color: #495057; - font-size: 1.4rem; - font-weight: 500; - margin-bottom: 10px; -} - -.subtitle { - color: #6c757d; - margin-bottom: 20px; - font-size: 1.1rem; -} - -/* Header & Navigation */ -.header { - margin-bottom: 30px; - text-align: center; - padding: 20px; - background-color: #f8f9fa; - border-bottom: 1px solid #dee2e6; - border-radius: 8px 8px 0 0; - margin: -30px -30px 30px -30px; -} - -.navigation { - display: flex; - justify-content: center; - align-items: center; - gap: 10px; - margin: 15px 0; - flex-wrap: wrap; -} - -/* Badges & Buttons */ -.badge { - display: inline-block; - padding: 6px 12px; - margin: 3px; - border-radius: 4px; - font-size: 12px; - font-weight: 600; - text-decoration: none; - transition: all 0.2s; - border: none; - cursor: pointer; -} - -.badge:hover { - transform: translateY(-1px); - box-shadow: 0 2px 5px rgba(0,0,0,0.2); -} - -.badge-primary { - background-color: #007bff; - color: white; -} - -.badge-secondary { - background-color: #6c757d; - color: white; -} - -.badge-success { - background-color: #28a745; - color: white; -} - -.badge-info { - background-color: #17a2b8; - color: white; -} - -.badge-warning { - background-color: #ffc107; - color: #212529; -} - -.badge-current { - background-color: #343a40; - color: white; - cursor: default; -} - -/* Form Controls */ -.controls { - display: flex; - justify-content: center; - align-items: center; - gap: 20px; - margin-bottom: 30px; - padding: 20px; - background-color: #f8f9fa; - border-radius: 8px; -} - -.control-group { - display: flex; - flex-direction: column; - align-items: center; - gap: 8px; -} - -.control-label { - font-weight: 500; - color: #495057; - font-size: 0.9rem; - text-transform: uppercase; - letter-spacing: 0.5px; -} - -select { - padding: 8px 16px; - border: 2px solid #dee2e6; - border-radius: 6px; - background: white; - font-size: 1rem; - min-width: 200px; - transition: border-color 0.2s; -} - -select:focus { - outline: none; - border-color: #007bff; -} - -/* Cards & Sections */ -.metric-card, .stat-card { - background: white; - padding: 20px; - border-radius: 6px; - text-align: center; - border-left: 4px solid #007bff; - box-shadow: 0 1px 3px rgba(0,0,0,0.1); -} - -.metric-value, .stat-value { - font-size: 2rem; - font-weight: 600; - color: #343a40; - margin-bottom: 5px; -} - -.metric-label, .stat-label { - font-size: 0.8rem; - color: #6c757d; - text-transform: uppercase; - letter-spacing: 0.5px; - margin-top: 5px; -} - -/* Grid Layouts */ -.metrics-grid, .summary-stats { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); - gap: 20px; - margin: 20px 0; -} - -.charts-container { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 30px; - margin-top: 20px; -} - -/* Chart Styles */ -.chart-section { - background: #ffffff; - border: 1px solid #e9ecef; - border-radius: 8px; - padding: 20px; - box-shadow: 0 1px 3px rgba(0,0,0,0.1); -} - -.chart-title { - font-size: 1.2rem; - font-weight: 600; - color: #343a40; - margin-bottom: 15px; - text-align: center; - padding-bottom: 10px; - border-bottom: 2px solid #f8f9fa; -} - -.chart-container { - position: relative; - height: 400px; - width: 100%; -} - -/* Content Areas */ -.content { - flex: 1; - overflow: hidden; - position: relative; -} - -.content iframe { - width: 100%; - height: 100%; - border: none; - min-height: 600px; -} - -/* Info Boxes */ -.test-info { - text-align: center; - margin-bottom: 20px; - padding: 15px; - background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); - color: white; - border-radius: 8px; -} - -.test-timestamp { - font-size: 0.9rem; - opacity: 0.9; -} - -.step-details { - margin-top: 20px; - padding: 15px; - background: #e3f2fd; - border-radius: 8px; - border-left: 4px solid #2196f3; -} - -.step-details h4 { - margin: 0 0 10px 0; - color: #1976d2; -} - -/* Legends */ -.percentile-legend { - display: flex; - justify-content: center; - gap: 20px; - margin-bottom: 15px; - font-size: 0.9rem; -} - -.legend-item { - display: flex; - align-items: center; - gap: 5px; -} - -.legend-color { - width: 16px; - height: 16px; - border-radius: 3px; -} - -/* Trend Indicators */ -.trend-indicator { - font-size: 0.9rem; - margin-top: 5px; - font-weight: 500; -} - -.trend-up { color: #28a745; } -.trend-down { color: #dc3545; } -.trend-stable { color: #6c757d; } - -/* Status Messages */ -.loading { - text-align: center; - padding: 40px; - color: #6c757d; -} - -.error { - background: #f8d7da; - color: #721c24; - border: 1px solid #f5c6cb; - border-radius: 4px; - padding: 20px; - margin: 20px 0; - text-align: center; -} - -.error h3 { - margin-top: 0; -} - -/* Footer */ -.footer { - margin-top: 40px; - padding-top: 20px; - border-top: 1px solid #dee2e6; - color: #6c757d; - font-size: 0.9rem; - text-align: center; -} - -/* Responsive Design */ -@media (max-width: 1200px) { - .container { - max-width: 95%; - padding: 20px; - } - - .charts-container { - grid-template-columns: 1fr; - } -} - -@media (max-width: 768px) { - .header { - padding: 15px; - } - - h1 { - font-size: 2rem; - } - - .navigation { - flex-direction: column; - gap: 8px; - } - - .controls { - flex-direction: column; - } - - .metrics-grid, .summary-stats { - grid-template-columns: 1fr; - } - - .badge { - font-size: 11px; - padding: 4px 8px; - } -} - -@media (max-width: 480px) { - .container { - padding: 15px; - margin: 10px; - border-radius: 6px; - } - - .header { - margin: -15px -15px 20px -15px; - } - - .percentile-legend { - flex-direction: column; - gap: 10px; - } -} \ No newline at end of file diff --git a/benchmarking/templates/resources/navigation.js b/benchmarking/templates/resources/navigation.js deleted file mode 100644 index c43f014a..00000000 --- a/benchmarking/templates/resources/navigation.js +++ /dev/null @@ -1,69 +0,0 @@ -// CUI JWT Benchmarking - Shared Navigation Component - -class BenchmarkNavigation { - constructor(currentPage = '') { - this.currentPage = currentPage; - this.pages = [ - { id: 'micro', title: 'Micro Benchmarks', file: 'index-visualizer.html', description: 'JMH unit-level performance testing' }, - { id: 'integration', title: 'Integration Benchmarks', file: 'integration-benchmark-visualizer.html', description: 'End-to-end containerized testing' }, - { id: 'step-metrics', title: 'Step Metrics', file: 'step-metrics-visualizer.html', description: 'Detailed step-by-step analysis' }, - { id: 'trends', title: 'Performance Trends', file: 'performance-trends.html', description: 'Historical performance tracking' } - ]; - } - - // Generate navigation HTML - generateNavigation() { - return this.pages.map(page => { - const isCurrent = page.id === this.currentPage; - const badgeClass = isCurrent ? 'badge-current' : 'badge-primary'; - const title = isCurrent ? `Current: ${page.description}` : page.description; - - return ` - ${page.title}${isCurrent ? ' (Current)' : ''} - `; - }).join('\n '); - } - - // Inject navigation into header - injectNavigation() { - const headerElement = document.querySelector('.header'); - if (headerElement) { - const existingNav = headerElement.querySelector('.navigation'); - if (existingNav) { - existingNav.innerHTML = this.generateNavigation(); - } else { - const navDiv = document.createElement('div'); - navDiv.className = 'navigation'; - navDiv.innerHTML = this.generateNavigation(); - headerElement.appendChild(navDiv); - } - } - } - - // Initialize navigation when DOM is loaded - init() { - if (document.readyState === 'loading') { - document.addEventListener('DOMContentLoaded', () => this.injectNavigation()); - } else { - this.injectNavigation(); - } - } -} - -// Utility function to get current page type from filename or path -function getCurrentPageType() { - const path = window.location.pathname; - const filename = path.split('/').pop() || 'index-visualizer.html'; - - if (filename.includes('integration-benchmark-visualizer')) return 'integration'; - if (filename.includes('integration')) return 'integration'; - if (filename.includes('step-metrics')) return 'step-metrics'; - if (filename.includes('performance-trends')) return 'trends'; - if (filename.includes('index-visualizer')) return 'micro'; - return 'micro'; // default -} - -// Auto-initialize navigation -const currentPage = getCurrentPageType(); -const navigation = new BenchmarkNavigation(currentPage); -navigation.init(); \ No newline at end of file diff --git a/benchmarking/templates/step-metrics-visualizer.html b/benchmarking/templates/step-metrics-visualizer.html deleted file mode 100644 index 2c89aa8c..00000000 --- a/benchmarking/templates/step-metrics-visualizer.html +++ /dev/null @@ -1,476 +0,0 @@ - - - - - - JWT Validation Step Metrics Visualizer - - - - -
-
-

JWT Validation Step Metrics

-

Interactive visualization of performance metrics for each validation step

- -
- -
-

Loading metrics data...

-
- - - - - -
- - - - - \ No newline at end of file diff --git a/bom/pom.xml b/bom/pom.xml index 1c416487..91dcd57f 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -10,12 +10,12 @@ ../pom.xml - bom + api-sheriff-bom pom API Sheriff BOM Bill of Materials (BOM) for API Sheriff modules - 0.12.6 + 0.13.0 diff --git a/doc/ai-rules.md b/doc/ai-rules.md deleted file mode 100644 index 145779c3..00000000 --- a/doc/ai-rules.md +++ /dev/null @@ -1,369 +0,0 @@ -# AI Development Guidelines - -This file provides guidance to AI tools (IntelliJ Junie, Claude Code, GitHub Copilot, etc.) when working with code in CUI projects. - -## Configuration - -**Standards Base URL**: Configure this based on your development environment: -- **Remote (gitingest)**: `https://gitingest.com/github.com/cuioss/cui-llm-rules/tree/main` -- **Local checkout**: Use relative path to your local standards directory (e.g., `../cui-llm-rules`) - -Replace `{STANDARDS_BASE_URL}` in all references below with your chosen base URL. - -## Context Hierarchy and Priority Framework -**Critical for AI System Decision Making** - -When conflicting information exists, AI systems must follow this priority order: - -1. **Core Process Rules** (CRITICAL - highest priority, non-negotiable) -2. **Project-Specific Context** (CLAUDE.md, .github/copilot-instructions.md, local config) -3. **Standards References** (adaptable based on context and requirements) -4. **General Guidelines** (lowest priority, may be overridden by higher levels) - -### Context-Aware Response Patterns -- **New Project Context**: Emphasize architecture decisions and initial setup standards -- **Legacy Code Context**: Prioritize compatibility, incremental changes, and migration paths -- **Testing Context**: Focus on coverage requirements and quality standards -- **Documentation Context**: Emphasize clarity, completeness, and AsciiDoc standards -- **Security Context**: Apply strictest security standards without compromise - -## Core Process Rules (CRITICAL - READ FIRST) -**Reference**: `{STANDARDS_BASE_URL}/standards/process/general.adoc` - -These rules govern ALL development activities: - -### ๐Ÿšจ PRE-1.0 PROJECT RULE (HIGHEST PRIORITY) -**This project is PRE-1.0 and therefore:** -- **NEVER deprecate code** - Remove it directly if not needed -- **NEVER add transitional comments** like "TODO: Remove in v2.0" -- **NEVER enforce backward compatibility** - Make breaking changes freely -- **NEVER add @Deprecated annotations** - Delete unnecessary code immediately -- **Clean APIs aggressively** - Remove unused methods, classes, and patterns -- **Focus on final API design** - Design for post-1.0 stability, not pre-1.0 transitions - -### General Process Rules -1. **If in doubt, ask the user** - Never make assumptions -2. **Always research topics** - Use available tools (WebSearch, WebFetch, etc.) to find the most recent best practices -3. **Never guess or be creative** - If you cannot find best practices, ask the user -4. **Do not proliferate documents** - Always use context-relevant documents, never create without user approval -5. **Never add dependencies without approval** - Always ask before adding any dependency - -## AI Safety and Validation Framework -**Mandatory for All AI-Generated Content** - -### Safety Constraints (NON-NEGOTIABLE) -- **Never bypass security measures**: AI must not suggest workarounds for security controls -- **Preserve data integrity**: All changes must maintain data consistency -- **Respect privacy**: No exposure of sensitive data in logs or outputs -- **Maintain auditability**: All AI-generated changes must be traceable -- **Follow standards hierarchy**: Respect the context priority framework above - -### Validation Requirements -Before any code implementation: -1. **Standards Compliance Check**: Verify output matches CUI standards -2. **Build Verification**: Ensure generated code compiles and passes pre-commit checks -3. **Security Review**: Check for security anti-patterns and vulnerabilities -4. **Documentation Sync**: Verify documentation reflects any code changes -5. **Test Coverage**: Ensure adequate test coverage for new functionality - -### Error Recovery Patterns -- **Standards Violation**: Provide specific correction guidance with reference links -- **Build Failures**: Include diagnostic steps and reference Build Commands Template -- **Test Failures**: Guide through debugging using Testing Standards -- **Integration Issues**: Escalate to human review with detailed context - -## Task Completion Standards (MANDATORY) -**Reference**: `{STANDARDS_BASE_URL}/standards/process/task-completion-standards.adoc` - -### Pre-Commit Checklist -Execute in sequence before ANY commit: - -1. **Quality Verification**: `./mvnw -Ppre-commit clean verify -DskipTests` - - Fix ALL errors and warnings (mandatory) - - Address code quality, formatting, and linting issues - -2. **Final Verification**: `./mvnw clean install` - - Must complete without errors or warnings - - All tests must pass - - Tasks are complete ONLY after this succeeds - -3. **Run Integration Tests**: `./mvnw clean verify -Pintegration-tests -pl api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests` - - Ensure all integration tests pass - - Verify against the latest standards - -4. **Documentation**: Ensure all changes are documented - - Update Javadoc for public APIs - - Update AsciiDoc documentation if necessary - -5. **Documentation**: Update if changes affect APIs, features, or configuration - -6. **Commit Message**: Follow Git Commit Standards - -### Quality Requirements -- New code requires appropriate test coverage -- Existing tests must continue to pass -- Documentation must be updated for API/feature changes -- Link commits to relevant issues or tasks - -## Build Commands Template -Common Maven commands for CUI projects: -- Build project: `./mvnw clean install` -- Build Single Module: `./mvnw clean install -pl ` -- Run tests: `./mvnw test` -- Run single test: `./mvnw test -Dtest=ClassName#methodName` -- Clean-Up Code: `./mvnw -Ppre-commit clean install -DskipTests` -> Check the console after running the command and fix all errors and warnings, verify until they are all corrected - -## Standards Overview -**Base Reference**: `{STANDARDS_BASE_URL}/standards` - -## Java Standards -**References**: -- Java Code Standards: `{STANDARDS_BASE_URL}/standards/java` -- DSL-Style Constants: `{STANDARDS_BASE_URL}/standards/java/dsl-style-constants.adoc` - -### Language Standards -- Use latest Java LTS version features (Java 17+ minimum) -- Use records for data carriers and DTOs -- Use switch expressions over classic switch statements -- Use text blocks for multi-line strings -- Use var for local variables with obvious types -- Use sealed classes for restricted hierarchies -- Pattern matching in instanceof and switch -- Stream API for complex data transformations -- Use proper access modifiers (prefer package-private over public) -- Mark classes final unless designed for inheritance -- Prefer composition over inheritance -- Return empty collections instead of null -- Use Optional for nullable return values -- Never catch or throw generic Exception or RuntimeException - always use specific exception types -- Use DSL-style nested constants for logging messages -- Follow builder pattern for complex object creation -- Implement fluent interfaces where appropriate -- Use method references over lambdas when possible -- Keep lambda expressions short and clear -- Avoid side effects in streams -- Use immutable objects when possible -- Make fields final by default -- Use enum instead of constants for fixed sets -- Prefer immutable collections (List.of(), Set.of()) -- Avoid magic numbers, use named constants -- Use StringBuilder for string concatenation in loops -- Override toString() for debugging -- Implement equals() and hashCode() together -- Use @Override annotation consistently -- Avoid premature optimization -- See Lombok Usage section for annotation patterns - -### Lombok Usage -**Reference**: `{STANDARDS_BASE_URL}/standards/java/java-code-standards.adoc` -- Use `@Builder` for complex object creation -- Use `@Value` for immutable objects -- Use `@NonNull` for required parameters -- Use `@ToString` and `@EqualsAndHashCode` for value objects -- Use `@UtilityClass` for utility classes -- Make proper use of `lombok.config` settings - -## Logging Standards -**References**: -- Logging Core Standards: `{STANDARDS_BASE_URL}/standards/logging` -- Logging Implementation Guide: `{STANDARDS_BASE_URL}/standards/logging/implementation-guide.adoc` -- Logging Testing Guide: `{STANDARDS_BASE_URL}/standards/logging/testing-guide.adoc` -- Use `de.cuioss.tools.logging.CuiLogger` (private static final LOGGER) -- Logger must be private static final with constant name 'LOGGER' -- Module/artifact: cui-java-tools -- Exception parameter always comes first in logging methods -- Use '%s' for string substitutions (not '{}' or '%d') -- Use `de.cuioss.tools.logging.LogRecord` for template logging -- Follow logging level ranges: INFO (001-99), WARN (100-199), ERROR (200-299), FATAL (300-399) -- All log messages must be documented in doc/LogMessages.adoc -- No log4j, slf4j, System.out, or System.err usage - -## Testing Standards -**References**: -- Testing Core Standards: `{STANDARDS_BASE_URL}/standards/testing` -- Quality Standards: `{STANDARDS_BASE_URL}/standards/testing/quality-standards.adoc` -- CUI Test Generator Guide: `https://gitingest.com/github.com/cuioss/cui-test-generator` (separate repository) -- Use JUnit 5 (`@Test`, `@DisplayName`, `@Nested`) -- Follow AAA pattern (Arrange-Act-Assert) -- One logical assertion per test -- Tests must be independent and not rely on execution order -- Minimum 80% line and branch coverage -- Use Maven profile `-Pcoverage` for coverage verification -- All public APIs must be tested -- Use cui-test-juli-logger for logger testing with `@EnableTestLogger` -- Use assertLogMessagePresentContaining for testing log messages -- Critical paths must have 100% coverage -- Forbidden: Mockito, PowerMock, Hamcrest - use CUI alternatives - -### CUI Test Generator Usage -**Reference**: `https://gitingest.com/github.com/cuioss/cui-test-generator` (separate repository) -- Mandatory for all test data generation in CUI projects -- Primary framework for creating test objects and data -- Provides type-safe, consistent test data generation -- Use cui-test-value-objects for value object contract testing -- Integrates with parameterized tests via @GeneratorsSource -- See Parameterized Tests Standards for annotation hierarchy - -### Parameterized Tests Standards -**Reference**: `{STANDARDS_BASE_URL}/standards/testing/quality-standards.adoc#parameterized-tests-best-practices` -- **Mandatory** for 3+ similar test variants -- Annotation hierarchy (preferred order): - 1. `@GeneratorsSource` - Most preferred for complex objects - 2. `@CompositeTypeGeneratorSource` - For multiple related types - 3. `@CsvSource` - Standard choice for simple data - 4. `@ValueSource` - Single parameter variations - 5. `@MethodSource` - Last resort only -- Use `@ParameterizedTest` with `@DisplayName` -- Consolidate duplicate test methods -- Provide clear test data and expected outcomes -- Document why @MethodSource if used - -## Documentation Standards -**References**: -- General Documentation: `{STANDARDS_BASE_URL}/standards/documentation` -- Javadoc Standards: `{STANDARDS_BASE_URL}/standards/documentation/javadoc-standards.adoc` -- AsciiDoc Standards: `{STANDARDS_BASE_URL}/standards/documentation/asciidoc-standards.adoc` -- README Structure: `{STANDARDS_BASE_URL}/standards/documentation/readme-structure.adoc` - -### Javadoc Standards -- Every public and protected class/interface must be documented -- Include clear purpose statement in class documentation -- Document all public methods with parameters, returns, and exceptions -- Include `@since` tag with version information -- Document thread-safety considerations -- Include usage examples for complex classes and methods -- Every package must have package-info.java -- Use `{@link}` for references to classes, methods, and fields -- Document Builder classes with complete usage examples - -## CDI and Quarkus Standards -**References**: -- CDI Development Patterns: `{STANDARDS_BASE_URL}/standards/cdi-quarkus` -- Quarkus Testing Standards: `{STANDARDS_BASE_URL}/standards/cdi-quarkus/testing-standards.adoc` -- Container Standards: `{STANDARDS_BASE_URL}/standards/cdi-quarkus/container-standards.adoc` -- Use constructor injection (mandatory over field injection) -- Single constructor rule: No `@Inject` needed for single constructors -- Use `final` fields for injected dependencies -- Use `@ApplicationScoped` for stateless services -- Use `@QuarkusTest` for CDI context testing -- Use `@QuarkusIntegrationTest` for packaged app testing -- Container: Use Quarkus distroless base image (91.9MB) -- HTTPS required for all integration tests -- OWASP Docker Top 10 compliance mandatory - -## CSS Standards -**Reference**: `{STANDARDS_BASE_URL}/standards/css` -- Use CSS custom properties (variables) for theming -- Follow BEM methodology for class naming -- Use Stylelint for code quality enforcement -- Use Prettier for consistent formatting -- Mobile-first responsive design approach -- Semantic HTML with accessible CSS patterns -- Performance optimization: minimize CSS bundle size -- Support for modern browsers (last 2 versions) - -## JavaScript Standards -**Reference**: `{STANDARDS_BASE_URL}/standards/javascript` -- Use ES6+ modern JavaScript features -- Use ESLint with strict configuration -- Use Prettier for code formatting -- Use Jest for unit testing framework -- Follow functional programming patterns when appropriate -- Use JSDoc for comprehensive documentation -- Use Lit components for web components (Quarkus DevUI context) -- Maven integration via frontend-maven-plugin -- Cypress for E2E testing - -### General Documentation Standards -- Use AsciiDoc format with `.adoc` extension -- Include proper document header with TOC and section numbering -- Use `:source-highlighter: highlight.js` attribute -- Use `xref:` syntax for cross-references (not `<<>>`) -- Blank lines required before all lists -- Consistent heading hierarchy -- Update main README when adding new documents -- Reference AsciiDoc standards from all relevant documents - -## Process Standards -**Reference**: `{STANDARDS_BASE_URL}/standards/process` -- Follow standardized git commit message format -- Use structured refactoring process for code improvements -- Complete task completion standards for quality assurance -- Maintain Javadoc error resolution process -- Follow Java test maintenance procedures -- Implement logger maintenance standards compliance -- If in doubt, ask the user - never guess or be creative -- Always research topics using available tools - -## Requirements Standards -**References**: -- Requirements Documents: `{STANDARDS_BASE_URL}/standards/requirements` -- Specification Documents: `{STANDARDS_BASE_URL}/standards/requirements/specification-documents.adoc` -- New Project Guide: `{STANDARDS_BASE_URL}/standards/requirements/new-project-guide.adoc` -- All requirements must be traceable to specifications -- Requirements must be specific, measurable, achievable, relevant, time-bound -- Maintain consistent documentation structure across projects -- Link implemented specifications to actual implementation code -- Use standard directory structure: doc/Requirements.adoc, doc/Specification.adoc -- Update specifications when implementation is complete -- See Documentation Standards for AsciiDoc formatting rules - -## AI Tool Specific Instructions - -### For IntelliJ Junie -- Always check for pre-commit profile availability -- Use proper Maven module selection for focused builds -- Leverage IDE integration for testing and debugging -- **Context Management**: Use module-level context awareness for focused assistance -- **Incremental Guidance**: Apply progressive disclosure of standards based on task complexity - -### For Claude Code (Agentic Coding) -- **CLAUDE.md Integration**: Auto-generate and maintain project-specific CLAUDE.md files -- **Permission Management**: Configure safe tool allowlists using `/permissions` command -- **Custom Slash Commands**: Create CUI-specific workflow commands in `.claude/commands/` -- **MCP Integration**: Leverage Model Context Protocol for enhanced capabilities -- Use todo lists for complex multi-step tasks -- Batch tool calls for parallel operations -- Always run lint and typecheck commands after code changes -- **Context Window Optimization**: Prioritize recent and relevant context for token efficiency - -### For GitHub Copilot -- **Repository Instructions**: Maintain `.github/copilot-instructions.md` for repo-specific guidance -- **Setup Steps**: Configure `copilot-setup-steps.yml` for consistent development environments -- **Task Scoping**: Optimize issue descriptions as effective AI prompts -- **Review Iteration**: Structure PR comments for effective AI collaboration using batch reviews -- Context-aware suggestions based on CUI standards -- Follow established patterns in the codebase -- Respect existing code style and architecture - -### For All AI Tools -- **Standards Hierarchy**: Follow the Context Hierarchy and Priority Framework -- **Safety First**: Apply AI Safety and Validation Framework for all outputs -- Always refer to CUI standards documentation before making changes -- Validate against existing patterns in the codebase -- Run tests after any code modifications -- Follow the pre-commit process for code quality -- Document any new public APIs according to Javadoc standards -- Use gitingest.com links for accessing CUI standards repository content -- **Feedback Integration**: Learn from user corrections and adapt instruction effectiveness -- **Escalation Protocol**: When in doubt, ask the user rather than making assumptions - -## Performance and Context Optimization -**Guidelines for Efficient AI Interactions** - -### Context Window Management -- **Prioritize Recent Context**: Weight recent files and conversations higher in decision making -- **Dynamic Context Selection**: Load only relevant standards for current task context -- **Token Economy**: Balance instruction comprehensiveness with context window efficiency -- **Incremental Loading**: Request additional context only when needed for task completion - -### Iterative Improvement Patterns -- **Pattern Recognition**: Identify and codify successful interaction patterns within CUI projects -- **Continuous Calibration**: Adjust instruction effectiveness based on build outcomes and user feedback -- **Workflow Optimization**: Streamline common development workflows through custom commands and templates - -### Integration with Development Workflows -- **CI/CD Awareness**: Understand and respect automated build and deployment processes -- **Quality Gate Integration**: Ensure all outputs pass automated quality checks -- **Collaborative Development**: Optimize for effective human-AI pair programming -- **Knowledge Contribution**: Help maintain and improve team knowledge base and documentation diff --git a/pom.xml b/pom.xml index 825e0e3e..6b47dfda 100644 --- a/pom.xml +++ b/pom.xml @@ -6,8 +6,8 @@ de.cuioss cui-java-parent - 1.1.4 - + 1.4.4 + de.cuioss.sheriff.api api-sheriff-parent @@ -42,38 +42,10 @@ - - 2.5.1 - - - 1.37 - 3.23.3 - - - 1.15.1 - 3.2.0 - - - v20.19.2 - 10.5.0 + 21 + 3.32.1 + v22.22.0 + 10.9.2 - - - - - - org.codehaus.mojo - exec-maven-plugin - ${exec.maven.plugin.version} - - - - com.github.eirslett - frontend-maven-plugin - ${frontend.maven.plugin.version} - - - - \ No newline at end of file From d98b797e4a786ac424935b51e10a7a4583a0a7e5 Mon Sep 17 00:00:00 2001 From: Oliver Wolff <23139298+cuioss@users.noreply.github.com> Date: Tue, 3 Mar 2026 16:56:53 +0100 Subject: [PATCH 03/24] fix: Replace hardcoded local path with portable reference Address Gemini review comment: the verifyCuiLoggingGuidelines command referenced /Users/oliver/git/cui-llm-rules/standards/logging which is not portable. Changed to a repository-relative reference. Co-Authored-By: Claude Opus 4.6 --- CLAUDE.md | 2 +- agents.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 4d31dc9d..17c38623 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -37,7 +37,7 @@ All cuioss repositories have branch protection on `main`. Direct pushes to `main Verify that the codebase complies with CUI logging standards by: -1. **Analyze CUI logging standards** from `/Users/oliver/git/cui-llm-rules/standards/logging` +1. **Analyze CUI logging standards** from the `cui-llm-rules` repository (standards/logging directory) 2. **Scan for logging violations** in the api-sheriff-library module: - Direct string usage in INFO/WARN/ERROR logging calls - Missing LogRecord definitions for structured messages diff --git a/agents.md b/agents.md index b3f20ffb..9f08cdb2 100644 --- a/agents.md +++ b/agents.md @@ -161,7 +161,7 @@ This project includes custom commands for common workflows: ### verifyCuiLoggingGuidelines Comprehensive logging standards audit: -1. Analyze CUI logging standards from `/Users/oliver/git/cui-llm-rules/standards/logging` +1. Analyze CUI logging standards from the `cui-llm-rules` repository (standards/logging directory) 2. Scan for logging violations in api-sheriff-library module 3. Check LogRecord compliance 4. Validate documentation in `doc/LogMessages.adoc` From 56016fc985026e689556eea2bd9d61dbdf66a331 Mon Sep 17 00:00:00 2001 From: Oliver Wolff <23139298+cuioss@users.noreply.github.com> Date: Tue, 3 Mar 2026 17:19:07 +0100 Subject: [PATCH 04/24] chore: Remove agents.md Consolidate all AI guidance back into CLAUDE.md instead of splitting across two files. Co-Authored-By: Claude Opus 4.6 --- agents.md | 259 ------------------------------------------------------ 1 file changed, 259 deletions(-) delete mode 100644 agents.md diff --git a/agents.md b/agents.md deleted file mode 100644 index 9f08cdb2..00000000 --- a/agents.md +++ /dev/null @@ -1,259 +0,0 @@ -# API Sheriff - AI Agent Guidance - -API Sheriff is a security-focused API Gateway with a lightweight approach for Java/Quarkus applications. This document guides AI coding agents when working with the codebase. - -## Dev Environment Tips - -### Build System -- **Build tool**: Maven 3.9.6 (via wrapper: `./mvnw`) -- **Java version**: Java 21 (LTS) -- **Primary framework**: Quarkus 3.32.1 - -### Project Structure -Multi-module Maven project: -- `api-sheriff-library/` - Core API Sheriff library -- `api-sheriff-quarkus-parent/` - Quarkus framework integration -- `benchmarking/` - Performance benchmarking modules -- `bom/` - Bill of Materials for dependency management - -### Essential Build Commands -```bash -# Development build -./mvnw clean verify - -# Full build with all tests -./mvnw clean install - -# Build single module -./mvnw clean install -pl - -# Run single test -./mvnw test -Dtest=ClassName#methodName -``` - -### Code Standards -- **Indentation**: 4 spaces (configured in `.editorconfig`) -- **Line endings**: Unix-style (LF) -- **Encoding**: UTF-8 -- **Java features**: Use modern Java 21 features (records, sealed classes, pattern matching, text blocks) -- **Lombok**: Use `@Builder`, `@Value`, `@NonNull`, `@ToString`, `@EqualsAndHashCode` appropriately - -### Logging Standards -This project uses CUI logging standards with Java Util Logging: -- Logger: `de.cuioss.tools.logging.CuiLogger` (private static final LOGGER) -- **Format specifier**: Always use `%s` for parameter substitution (NEVER `{}`, `%.2f`, `%d`) -- **Structured logging**: Use `de.cuioss.tools.logging.LogRecord` for INFO/WARN/ERROR messages -- **LogRecord ranges**: INFO (001-099), WARN (100-199), ERROR (200-299) -- **Documentation**: All log messages must be documented in `doc/LogMessages.adoc` -- **Exception logging**: Exception parameter always comes first - -## Testing Instructions - -### Testing Framework -- **Primary**: JUnit 5 (Jupiter) -- **Test patterns**: AAA pattern (Arrange-Act-Assert) -- **Coverage requirement**: Minimum 80% line and branch coverage -- **Coverage check**: `./mvnw clean verify -Pcoverage` - -### CUI Test Generator -This project uses CUI Test Generator for all test data generation: -- Provides type-safe, consistent test data generation -- Use `@GeneratorsSource` for complex objects (most preferred) -- Use `@CompositeTypeGeneratorSource` for multiple related types -- Use `@CsvSource` for simple data -- Use `@ValueSource` for single parameter variations -- Use `@MethodSource` as last resort only - -### Parameterized Tests -Mandatory for 3+ similar test variants. Annotation hierarchy (preferred order): -1. `@GeneratorsSource` (most preferred) -2. `@CompositeTypeGeneratorSource` -3. `@CsvSource` -4. `@ValueSource` -5. `@MethodSource` (last resort) - -### Test Execution Commands -```bash -# Run all tests -./mvnw test - -# Run integration tests -./mvnw clean verify -Pintegration-tests -pl api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests -am - -# Run micro-benchmarks -./mvnw clean verify -pl benchmarking/benchmark-core -Pbenchmark - -# Run integration benchmarks -./mvnw clean verify -Pbenchmark -pl benchmarking/benchmark-integration-wrk -``` - -### Pre-Commit Validation - -**CRITICAL**: Execute this sequence before ANY commit: - -1. **Quality verification**: - ```bash - ./mvnw -Ppre-commit clean verify - ``` - - Fix ALL errors and warnings (mandatory) - - Address OpenRewrite markers (see section below) - -2. **Final verification**: - ```bash - ./mvnw clean install - ``` - - Must complete without errors or warnings - - All tests must pass - -3. **Integration tests**: - ```bash - ./mvnw clean verify -Pintegration-tests -pl api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests -am - ``` - -Tasks are complete ONLY after all three steps succeed. - -### OpenRewrite Markers - Critical Understanding - -Pre-commit builds run OpenRewrite recipes that add markers to flag violations. - -**Marker pattern**: `/*~~(TODO: INFO needs LogRecord)~~>*/` or `/*~~(TODO: [message])~~>*/` - -**What markers indicate**: -Markers indicate ACTUAL BUGS: -- Placeholder/parameter count mismatches: `"value: %s"` with 0 parameters -- Wrong format specifiers: Using `%.2f`, `{:.2f}`, `{}`, `%d` instead of `%s` -- Missing LogRecord definitions for production INFO/WARN/ERROR logs -- Generic Exception usage instead of specific types -- RuntimeException catches that should be specific exceptions - -**Handling strategy**: - -Production code violations: -- Fix the actual bug (add missing placeholders, change format to %s) -- Create LogRecord constant for INFO/WARN/ERROR messages -- Replace generic Exception with specific types (IOException, IllegalStateException, etc.) -- Never catch or throw RuntimeException - use specific exception types - -Test code violations: -- For diagnostic/performance logging: Add suppression comment at class level: - ```java - // cui-rewrite:disable CuiLogRecordPatternRecipe - // This is a test/utility class that outputs diagnostic information for analysis - ``` -- For exception handling: Replace RuntimeException with AssertionError in test failures -- For format bugs: Fix placeholder mismatches even in tests (change to %s) - -**Never commit code with markers present.** - -## Pre-1.0 Project Rules - -This project is PRE-1.0 (current version: 1.0.0-SNAPSHOT). Therefore: -- **Never deprecate code** - Remove it directly if not needed -- **Never add transitional comments** like "TODO: Remove in v2.0" -- **Never enforce backward compatibility** - Make breaking changes freely -- **Never add @Deprecated annotations** - Delete unnecessary code immediately -- **Clean APIs aggressively** - Remove unused methods, classes, and patterns -- **Focus on final API design** - Design for post-1.0 stability - -## Custom Commands - -This project includes custom commands for common workflows: - -### verifyCuiLoggingGuidelines -Comprehensive logging standards audit: -1. Analyze CUI logging standards from the `cui-llm-rules` repository (standards/logging directory) -2. Scan for logging violations in api-sheriff-library module -3. Check LogRecord compliance -4. Validate documentation in `doc/LogMessages.adoc` -5. Run logging-related tests -6. Generate compliance report - -### fixOpenRewriteMarkers -Fix all OpenRewrite TODO markers in a module: -1. Locate all markers with grep -2. Analyze and fix each marker (production vs test code) -3. Remove markers after fixing -4. Verify fixes with pre-commit build -5. Final validation with full test suite - -### verifyAndCommit -Execute comprehensive quality verification and commit workflow for a specific module: -1. Quality verification build (pre-commit profile) -2. Final verification build (full integration) -3. Error resolution loop -4. Artifact cleanup verification -5. Git commit - -## Slash Commands - -The project includes custom slash commands in `.claude/commands/`: - -- `/verify-project [push]` - Comprehensive project verification -- `/verify-integration-tests` - Integration tests with Quarkus/Keycloak log analysis -- `/verify-micro-benchmark` - JMH micro-benchmark verification -- `/verify-integration-benchmark` - WRK-based integration benchmark verification -- `/verify-all [push]` - End-to-end verification of all commands in sequence - -All commands read execution duration from `doc/commands.md` and update it if changed >10%. - -## Documentation Standards - -- **Format**: AsciiDoc with `.adoc` extension -- **Key documents**: - - `README.adoc` - Project overview - - `doc/Build.adoc` - Build instructions - - `doc/Requirements.adoc` - Functional requirements - - `doc/Specification.adoc` - Technical specifications - - `doc/LogMessages.adoc` - Logging reference -- **Cross-references**: Use `xref:` syntax (not `<<>>`) -- **Blank lines**: Required before all lists -- **Header**: Include TOC and section numbering -- **Source highlighting**: Use `:source-highlighter: highlight.js` - -### Javadoc Standards -- Every public and protected class/interface must be documented -- Include clear purpose statement in class documentation -- Document all public methods with parameters, returns, and exceptions -- Include `@since` tag with version information -- Document thread-safety considerations -- Include usage examples for complex classes and methods -- Every package must have package-info.java -- Use `{@link}` for references to classes, methods, and fields - -## CDI and Quarkus Standards - -- Use constructor injection (mandatory over field injection) -- Single constructor rule: No `@Inject` needed for single constructors -- Use `final` fields for injected dependencies -- Use `@ApplicationScoped` for stateless services -- Use `@QuarkusTest` for CDI context testing -- Use `@QuarkusIntegrationTest` for packaged app testing -- HTTPS required for all integration tests - -## Security Considerations - -As a security-focused API Gateway: -- All changes must consider security implications -- Never expose sensitive data in logs -- Follow OWASP security guidelines -- Validate all inputs and outputs -- Use secure defaults for all configurations - -## General Process Rules - -1. **Use `.plan/temp/` for ALL temporary files** - Covered by `Write(.plan/**)` permission (avoids permission prompts) -2. **If in doubt, ask the user** - Never make assumptions -3. **Always research topics** - Use available tools (WebSearch, WebFetch, etc.) to find recent best practices -4. **Never guess or be creative** - If you cannot find best practices, ask the user -5. **Do not proliferate documents** - Always use context-relevant documents, never create without user approval -6. **Never add dependencies without approval** - Always ask before adding any dependency - -## Important Files - -Key reference files for development: -- `doc/LogMessages.adoc` - Complete logging reference -- `doc/Build.adoc` - Build and deployment instructions -- `doc/Requirements.adoc` - Functional requirements -- `doc/Specification.adoc` - Technical specifications -- `.editorconfig` - Code formatting configuration -- `lombok.config` - Lombok configuration From 82b750141fbdb7f6d3eaf04bb9f8f787ae992b4b Mon Sep 17 00:00:00 2001 From: Oliver Wolff <23139298+cuioss@users.noreply.github.com> Date: Tue, 3 Mar 2026 17:20:55 +0100 Subject: [PATCH 05/24] chore: Recreate CLAUDE.md as self-contained project guide Replace the stub+agents.md split with a single comprehensive CLAUDE.md covering build commands, code standards, pre-1.0 rules, logging, testing, OpenRewrite markers, security, and git workflow. Co-Authored-By: Claude Opus 4.6 --- CLAUDE.md | 277 ++++++++++++++++++++---------------------------------- 1 file changed, 103 insertions(+), 174 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 17c38623..b9d505e4 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,198 +1,127 @@ -# Claude Code Configuration +# CLAUDE.md -All AI development guidelines for this project are located in: **`agents.md`** +This file provides guidance to Claude Code when working with this repository. -This file contains: -- Dev environment tips and build commands -- Testing instructions and pre-commit validation -- Code style and logging standards -- Framework-specific standards (Quarkus, CDI) -- OpenRewrite marker handling -- Custom commands +## Project Overview -Please refer to `agents.md` for complete guidance when working on this API Sheriff project. +API Sheriff is a security-focused API Gateway with a lightweight approach, currently in pre-1.0 development. Built with Maven, Java 21+, and Quarkus 3.32.1. Follows CUI (CUIoss) standards. -- Use `.plan/temp/` for ALL temporary files (covered by `Write(.plan/**)` permission - avoids permission prompts) +## Project Structure -## Git Workflow - -All cuioss repositories have branch protection on `main`. Direct pushes to `main` are never allowed. Always use this workflow: +Multi-module Maven project: +- `api-sheriff-library/` โ€” Core library +- `api-sheriff-quarkus-parent/` โ€” Quarkus framework integration (runtime, deployment, integration-tests) +- `benchmarking/` โ€” Performance benchmarking (benchmark-core for JMH micro, benchmark-integration-wrk for WRK HTTP load testing) +- `bom/` โ€” Bill of Materials (`api-sheriff-bom`) -1. Create a feature branch: `git checkout -b ` -2. Commit changes: `git add && git commit -m ""` -3. Push the branch: `git push -u origin ` -4. Create a PR: `gh pr create --repo cuioss/API-Sheriff --head --base main --title "" --body "<body>"` -5. Wait for CI + Gemini review (waits until checks complete): `gh pr checks --watch` -6. **Handle Gemini review comments** โ€” fetch with `gh api repos/cuioss/API-Sheriff/pulls/<pr-number>/comments` and for each: - - If clearly valid and fixable: fix it, commit, push, then reply explaining the fix and resolve the comment - - If disagree or out of scope: reply explaining why, then resolve the comment - - If uncertain (not 100% confident): **ask the user** before acting - - Every comment MUST get a reply (reason for fix or reason for not fixing) and MUST be resolved -7. Do **NOT** enable auto-merge unless explicitly instructed. Wait for user approval. -8. Return to main: `git checkout main && git pull` +## Build Commands -## Custom Commands +```bash +# Full build with tests +./mvnw clean install -### verifyCuiLoggingGuidelines +# Build without tests +./mvnw clean install -DskipTests -Verify that the codebase complies with CUI logging standards by: +# Single module +./mvnw clean install -pl <module-name> -1. **Analyze CUI logging standards** from the `cui-llm-rules` repository (standards/logging directory) -2. **Scan for logging violations** in the api-sheriff-library module: - - Direct string usage in INFO/WARN/ERROR logging calls - - Missing LogRecord definitions for structured messages - - Incorrect parameter substitution patterns (should use '%s', not '{}' or '%d') - - Wrong exception parameter ordering (exception should come first) -3. **Check LogRecord compliance**: - - All INFO/WARN/ERROR logs must use LogRecord constants - - Proper identifier ranges: INFO (001-099), WARN (100-199), ERROR (200-299) - - DSL-Style Constants Pattern with static imports -4. **Validate documentation** in `doc/LogMessages.adoc` matches LogRecord definitions -5. **Run logging-related tests** to verify LogAsserts work with LogRecord format -6. **Generate compliance report** with: - - Compliance percentage - - List of violations found - - Recommendations for fixes - - Testing verification results +# Single test +./mvnw test -Dtest=ClassName#methodName -**Usage:** When user says "verifyCuiLoggingGuidelines", execute this comprehensive logging standards audit. +# Integration tests +./mvnw clean verify -Pintegration-tests -pl api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests -am -### fixOpenRewriteMarkers <module-path> +# Micro benchmarks +./mvnw clean verify -pl benchmarking/benchmark-core -Pbenchmark -Fix all OpenRewrite TODO markers in a module following CUI standards: +# Integration benchmarks (WRK) +./mvnw clean verify -pl benchmarking/benchmark-integration-wrk -Pbenchmark +``` -**CRITICAL UNDERSTANDING**: Markers like `/*~~(TODO: INFO needs LogRecord)~~>*/` indicate **ACTUAL BUGS**, not just style issues. +### Pre-Commit Process -**Execution Steps**: +**CRITICAL** โ€” run before every commit: -1. **Locate All Markers**: +1. Quality verification (fix ALL errors/warnings): ```bash - grep -r "~~(TODO:" <module-path>/src --include="*.java" + ./mvnw -Ppre-commit clean verify -DskipTests ``` - - Count markers: `grep -r "~~(TODO:" <module-path>/src --include="*.java" | wc -l` - - Group by type: INFO needs LogRecord, WARN needs LogRecord, placeholder mismatches, etc. - -2. **Analyze and Fix Each Marker**: - - **Production Code (src/main/java)**: - - **Placeholder Mismatches**: Fix bugs like `LOGGER.info("value: %s", x, y)` (2 params, 1 placeholder) - - Add missing `%s` placeholders or remove extra parameters - - **Wrong Format Specifiers**: Change `%.2f`, `{:.2f}`, `{}`, `%d` โ†’ **ALWAYS use `%s`** - - **Missing LogRecords**: Create LogRecord constants for INFO/WARN/ERROR messages - - **Generic Exceptions**: Replace `Exception` with specific types (IOException, IllegalStateException) - - **RuntimeException**: Replace with specific exception types - - **Test Code (src/test/java)**: - - **Diagnostic Logging** (performance tests, concurrency tests): - - Add class-level suppression comment: - ```java - // cui-rewrite:disable CuiLogRecordPatternRecipe - // This is a test/utility class that outputs diagnostic information for analysis - ``` - - **NEVER create LogRecords for test diagnostic output** - - **Placeholder Mismatches**: Fix bugs even in tests (change to %s) - - **RuntimeException Throws**: Replace with AssertionError for test failures - - **Generic Exception Catches**: Replace with specific types + InterruptedException/BrokenBarrierException - -3. **Remove Markers After Fixing**: - - **macOS (BSD sed)**: +2. Full verification (must pass completely): ```bash - find <module-path>/src -name "*.java" -exec sed -i '' 's|/\*~~(TODO: INFO needs LogRecord)~~>\*/||g; s|/\*~~(TODO: WARN needs LogRecord)~~>\*/||g; s|/\*~~(TODO: ERROR needs LogRecord)~~>\*/||g' {} + + ./mvnw clean install ``` - **Linux (GNU sed)**: - ```bash - find <module-path>/src -name "*.java" -exec sed -i 's|/\*~~(TODO: INFO needs LogRecord)~~>\*/||g; s|/\*~~(TODO: WARN needs LogRecord)~~>\*/||g; s|/\*~~(TODO: ERROR needs LogRecord)~~>\*/||g' {} + - ``` +## Pre-1.0 Rules (HIGHEST PRIORITY) - - Verify removal: `grep -r "~~(TODO:" <module-path>/src --include="*.java" | wc -l` (should be 0) +- **NEVER deprecate code** โ€” remove it directly +- **NEVER add @Deprecated** โ€” delete unnecessary code immediately +- **NEVER enforce backward compatibility** โ€” make breaking changes freely +- **Clean APIs aggressively** โ€” remove unused methods, classes, patterns -4. **Verify Fixes**: - ```bash - cd <module-path> && ../mvnw -Ppre-commit clean verify - ``` - - All tests must pass - - No compilation errors - - Markers may reappear if bugs not truly fixed - - If markers reappear, repeat steps 2-4 - -5. **Final Validation**: - - Run full test suite: `cd <module-path> && ../mvnw clean install` - - Confirm zero markers: `grep -r "~~(TODO:" <module-path>/src --include="*.java"` - - Verify test count matches previous successful run (no tests accidentally broken) - -**Common Bugs to Watch For**: -- `LOGGER.info("value %s", x, y)` โ†’ Missing placeholder for `y` -- `LOGGER.info("avg %.2f ms", avg)` โ†’ Use `%s` not `%.2f` -- `LOGGER.info("result {}", value)` โ†’ Use `%s` not `{}` -- `catch (Exception e)` โ†’ Use specific exception types -- `catch (RuntimeException e)` โ†’ Use IllegalArgumentException | IllegalStateException -- Test logging creating LogRecords โ†’ Use suppression comment instead - -**Critical Rules**: -- **NEVER remove markers without fixing bugs** -- **NEVER create LogRecords for test diagnostic logging** -- **ALWAYS use `%s` for ALL string substitutions** (never `%.2f`, `{}`, `%d`) -- **ALWAYS fix placeholder/parameter count mismatches** -- **ALWAYS use specific exception types** (never Exception/RuntimeException) - -**Usage:** When user says "fixOpenRewriteMarkers api-sheriff-library", execute this complete marker fixing workflow. - -### verifyAndCommit <module-name> - -Execute comprehensive quality verification and commit workflow for a specific module: - -1. **Quality Verification Build** (pre-commit profile): - ```bash - ./mvnw -Ppre-commit clean verify -pl <module-name> - ``` - - Runs code quality checks (checkstyle, spotbugs, PMD) - - Performs static analysis - - Validates code formatting and style compliance - - **NO SHORTCUTS** - Fix ALL errors and warnings before proceeding +## Code Standards -2. **Final Verification Build** (full integration): - ```bash - ./mvnw clean install -pl <module-name> - ``` - - Runs complete build with all tests - - Validates full integration and functionality - - Ensures no regressions introduced - - This will take nearly 8 Minutes. Always wait for it to complete. 10 minutes on the outside - - **NO SHORTCUTS** - Fix ALL test failures and build errors - -3. **Error Resolution Loop**: - - If ANY errors or warnings occur in either build, STOP and fix them - - Re-run the failed build command until it passes completely - - DO NOT proceed to next step until current step is 100% clean - - Apply fixes systematically and verify each fix - -4. **Artifact Cleanup Verification**: - ```bash - find <module-name>/src/main/java -name "*.class" -type f - find <module-name>/src/test/java -name "*.class" -type f - find <module-name>/src -name "*.jar" -type f - find <module-name>/src -name "*.war" -type f - find <module-name>/src -name "target" -type d - ``` - - Verify NO class files exist in source directories - - Verify NO jar/war files exist in source directories - - Verify NO target directories exist in source directories - - Ensure NO build artifacts contaminate source code - - Clean up any artifacts found before proceeding - - **FAIL BUILD** if any artifacts are found in src/ directories - -5. **Git Commit**: - - Only proceed to commit when ALL steps pass completely - - Create descriptive commit message explaining the changes - - Include Co-Authored-By: Claude footer - -**Usage:** When user says "verifyAndCommit api-sheriff-library", execute this complete verification and commit workflow for the api-sheriff-library module. - -**Critical Rules:** -- **NEVER skip error fixes** - Every warning and error must be resolved -- **NEVER use shortcuts** - Run complete verification cycles -- **NEVER commit with failing builds** - Only commit when everything passes -- **NEVER commit with source artifacts** - Source directories must be clean of .class files -- **ALWAYS fix issues systematically** - Address root causes, not symptoms +- Java 21+ features encouraged (records, sealed classes, pattern matching, text blocks) +- Lombok: `@Builder`, `@Value`, `@NonNull`, `@ToString`, `@EqualsAndHashCode` +- Prefer immutable objects, final fields, empty collections over null, Optional for nullable returns +- Indentation: 4 spaces, LF line endings, UTF-8 + +### Logging + +- Logger: `de.cuioss.tools.logging.CuiLogger` (private static final LOGGER) +- Format: always `%s` for substitution (NEVER `{}`, `%.2f`, `%d`) +- Structured: `de.cuioss.tools.logging.LogRecord` for INFO/WARN/ERROR +- Ranges: INFO (001-099), WARN (100-199), ERROR (200-299) +- Exception parameter always comes first +- Document in `doc/LogMessages.adoc` + +### Testing + +- JUnit 5 exclusively, AAA pattern (Arrange-Act-Assert) +- Minimum 80% coverage +- CUI Test Generator for test data (`@GeneratorsSource` preferred) +- **Forbidden**: Mockito, PowerMock, Hamcrest + +### Javadoc + +- Every public/protected class and method documented +- Include `@since` tags, thread-safety notes, usage examples +- Every package must have `package-info.java` + +## OpenRewrite Markers + +Markers like `/*~~(TODO: INFO needs LogRecord)~~>*/` indicate **actual bugs**: +- Fix placeholder/parameter mismatches, wrong format specifiers +- Create LogRecord constants for production INFO/WARN/ERROR logs +- Replace generic Exception/RuntimeException with specific types +- For test diagnostic logging: add `// cui-rewrite:disable CuiLogRecordPatternRecipe` suppression +- **Never commit code with markers present** + +## Security + +As a security-focused API Gateway: +- All changes must consider security implications +- Never expose sensitive data in logs +- Follow OWASP guidelines, validate all inputs/outputs +- Use secure defaults + +## Dependency Management + +- **Parent POM**: `de.cuioss:cui-java-parent:1.4.4` +- **CRITICAL**: Never add dependencies without explicit user approval + +## Git Workflow + +All cuioss repositories have branch protection on `main`. Always: + +1. Create feature branch: `git checkout -b <branch-name>` +2. Commit and push: `git push -u origin <branch-name>` +3. Create PR: `gh pr create --repo cuioss/API-Sheriff --head <branch-name> --base main --title "<title>" --body "<body>"` +4. Wait for CI + Gemini review: `gh pr checks --watch` +5. **Handle Gemini review comments** โ€” fetch with `gh api repos/cuioss/API-Sheriff/pulls/<pr-number>/comments`: + - Valid and fixable: fix, commit, push, reply explaining, resolve + - Disagree/out of scope: reply explaining why, resolve + - Uncertain: **ask the user** + - Every comment MUST get a reply and MUST be resolved +6. Do **NOT** enable auto-merge unless explicitly instructed +7. Return to main: `git checkout main && git pull` From 8a9d0752cd1b95b8c5774632aa23be5777193398 Mon Sep 17 00:00:00 2001 From: Oliver Wolff <23139298+cuioss@users.noreply.github.com> Date: Tue, 3 Mar 2026 17:28:12 +0100 Subject: [PATCH 06/24] chore: Remove benchmark-core module The module contained only a trivial stub benchmark (single getStatus() call) with no meaningful JMH tests. Remove it entirely along with all references in CI workflows, Python script, CLAUDE.md, and JMH dependency management. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --- .github/workflows/benchmark.yml | 15 +- .github/workflows/claude.yml | 2 +- CLAUDE.md | 5 +- benchmarking/benchmark-core/pom.xml | 291 ------------------ .../api/benchmark/BenchmarkOptionsHelper.java | 201 ------------ .../api/benchmark/BenchmarkRunner.java | 88 ------ benchmarking/pom.xml | 14 - benchmarking/scripts/benchmark-pages.py | 8 +- 8 files changed, 4 insertions(+), 620 deletions(-) delete mode 100644 benchmarking/benchmark-core/pom.xml delete mode 100644 benchmarking/benchmark-core/src/main/java/de/cuioss/sheriff/api/benchmark/BenchmarkOptionsHelper.java delete mode 100644 benchmarking/benchmark-core/src/main/java/de/cuioss/sheriff/api/benchmark/BenchmarkRunner.java diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 6d2ef666..35bfc0c1 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -19,7 +19,7 @@ concurrency: jobs: benchmark: - name: Run JMH Benchmarks + name: Run Integration Benchmarks runs-on: ubuntu-latest # Only run on merged PRs, not just closed ones if: github.event_name != 'pull_request' || github.event.pull_request.merged == true @@ -77,7 +77,6 @@ jobs: ref: main path: previous-pages sparse-checkout: | - api-sheriff/benchmarks/micro/history api-sheriff/benchmarks/integration/history continue-on-error: true @@ -87,17 +86,6 @@ jobs: --previous-pages-dir previous-pages/api-sheriff/benchmarks \ --output-dir "${GITHUB_WORKSPACE}/benchmark-history" - - name: Run Micro Benchmarks - run: | - # Run micro benchmarks using configuration from pom.xml - # Pass history directory as system property for trend calculation - ./mvnw --no-transfer-progress clean verify -pl benchmarking/benchmark-core -Pbenchmark \ - -Dbenchmark.history.dir="${GITHUB_WORKSPACE}/benchmark-history/micro" - - # Verify artifacts were generated - echo "Micro benchmark artifacts generated:" - ls -la benchmarking/benchmark-core/target/benchmark-results/ - - name: Run Integration Benchmarks with WRK run: | # Run WRK-based integration benchmarks with native image @@ -112,7 +100,6 @@ jobs: - name: Assemble benchmark artifacts for deployment run: | python3 benchmarking/scripts/benchmark-pages.py assemble \ - --micro-results benchmarking/benchmark-core/target/benchmark-results/gh-pages-ready \ --integration-results benchmarking/benchmark-integration-wrk/target/benchmark-results/gh-pages-ready \ --previous-pages-dir previous-pages/api-sheriff/benchmarks \ --output-dir gh-pages \ diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index eb402e12..54b5e2ef 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -49,4 +49,4 @@ jobs: additional_permissions: | actions: read - allowed_tools: "Bash(./mvnw*),Bash(./mvnw -Ppre-commit clean verify -DskipTests),Bash(./mvnw clean verify),Bash(./mvnw clean install),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl bom),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl api-sheriff-library),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl api-sheriff-quarkus-parent),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl api-sheriff-quarkus-parent/api-sheriff-quarkus),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl api-sheriff-quarkus-parent/api-sheriff-quarkus-deployment),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl benchmarking),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl benchmarking/benchmark-core),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl benchmarking/benchmark-integration-wrk),Bash(./mvnw clean install -pl bom),Bash(./mvnw clean install -pl api-sheriff-library),Bash(./mvnw clean install -pl api-sheriff-quarkus-parent),Bash(./mvnw clean install -pl api-sheriff-quarkus-parent/api-sheriff-quarkus),Bash(./mvnw clean install -pl api-sheriff-quarkus-parent/api-sheriff-quarkus-deployment),Bash(./mvnw clean install -pl api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests),Bash(./mvnw clean install -pl benchmarking),Bash(./mvnw clean install -pl benchmarking/benchmark-core),Bash(./mvnw clean install -pl benchmarking/benchmark-integration-wrk),Bash(git*),Bash(find*),Bash(gh*),Bash(java*)" + allowed_tools: "Bash(./mvnw*),Bash(./mvnw -Ppre-commit clean verify -DskipTests),Bash(./mvnw clean verify),Bash(./mvnw clean install),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl bom),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl api-sheriff-library),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl api-sheriff-quarkus-parent),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl api-sheriff-quarkus-parent/api-sheriff-quarkus),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl api-sheriff-quarkus-parent/api-sheriff-quarkus-deployment),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl benchmarking),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl benchmarking/benchmark-integration-wrk),Bash(./mvnw clean install -pl bom),Bash(./mvnw clean install -pl api-sheriff-library),Bash(./mvnw clean install -pl api-sheriff-quarkus-parent),Bash(./mvnw clean install -pl api-sheriff-quarkus-parent/api-sheriff-quarkus),Bash(./mvnw clean install -pl api-sheriff-quarkus-parent/api-sheriff-quarkus-deployment),Bash(./mvnw clean install -pl api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests),Bash(./mvnw clean install -pl benchmarking),Bash(./mvnw clean install -pl benchmarking/benchmark-integration-wrk),Bash(git*),Bash(find*),Bash(gh*),Bash(java*)" diff --git a/CLAUDE.md b/CLAUDE.md index b9d505e4..77ec039e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -11,7 +11,7 @@ API Sheriff is a security-focused API Gateway with a lightweight approach, curre Multi-module Maven project: - `api-sheriff-library/` โ€” Core library - `api-sheriff-quarkus-parent/` โ€” Quarkus framework integration (runtime, deployment, integration-tests) -- `benchmarking/` โ€” Performance benchmarking (benchmark-core for JMH micro, benchmark-integration-wrk for WRK HTTP load testing) +- `benchmarking/` โ€” Performance benchmarking (benchmark-integration-wrk for WRK HTTP load testing) - `bom/` โ€” Bill of Materials (`api-sheriff-bom`) ## Build Commands @@ -32,9 +32,6 @@ Multi-module Maven project: # Integration tests ./mvnw clean verify -Pintegration-tests -pl api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests -am -# Micro benchmarks -./mvnw clean verify -pl benchmarking/benchmark-core -Pbenchmark - # Integration benchmarks (WRK) ./mvnw clean verify -pl benchmarking/benchmark-integration-wrk -Pbenchmark ``` diff --git a/benchmarking/benchmark-core/pom.xml b/benchmarking/benchmark-core/pom.xml deleted file mode 100644 index 2907ad21..00000000 --- a/benchmarking/benchmark-core/pom.xml +++ /dev/null @@ -1,291 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project xmlns="http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> - <modelVersion>4.0.0</modelVersion> - <parent> - <groupId>de.cuioss.sheriff.api</groupId> - <artifactId>benchmarking</artifactId> - <version>1.0.0-SNAPSHOT</version> - <relativePath>../pom.xml</relativePath> - </parent> - - <artifactId>benchmark-core</artifactId> - <packaging>jar</packaging> - <name>API Sheriff Benchmark Core</name> - <description>Benchmarking module for API Sheriff functionality</description> - - <properties> - <maven.jar.plugin.automatic.module.name>de.cuioss.sheriff.api.benchmark.core</maven.jar.plugin.automatic.module.name> - <version.benchmarking-common>0.4.1</version.benchmarking-common> - <version.mockwebserver3>5.0.0-alpha.12</version.mockwebserver3> - - <!-- Default benchmark runner --> - <benchmark.runner>de.cuioss.sheriff.api.benchmark.BenchmarkRunner</benchmark.runner> - - <!-- JMH Configuration Properties - Optimized for fast execution (<10 minutes) --> - <jmh.include>de\.cuioss\.sheriff\.api\.benchmark\..*</jmh.include> - <jmh.result.format>JSON</jmh.result.format> - <jmh.result.filePrefix>target/benchmark-results/micro-result</jmh.result.filePrefix> - <jmh.iterations>5</jmh.iterations> - <jmh.warmupIterations>3</jmh.warmupIterations> - <jmh.forks>1</jmh.forks> - <!-- Reduced from 200 to 100 threads to avoid contention and improve P99 latency --> - <jmh.threads>100</jmh.threads> - <jmh.time>4s</jmh.time> - <jmh.warmupTime>1s</jmh.warmupTime> - <!-- Benchmark history directory for trend analysis (passed from CI) --> - <benchmark.history.dir /> - </properties> - - <dependencyManagement> - <dependencies> - <dependency> - <groupId>de.cuioss.sheriff.api</groupId> - <artifactId>api-sheriff-bom</artifactId> - <version>${project.version}</version> - <type>pom</type> - <scope>import</scope> - </dependency> - <dependency> - <groupId>de.cuioss.sheriff.api</groupId> - <artifactId>api-sheriff-library</artifactId> - <version>${project.version}</version> - <classifier>generators</classifier> - </dependency> - <dependency> - <groupId>de.cuioss.sheriff.oauth</groupId> - <artifactId>benchmarking-common</artifactId> - <version>${version.benchmarking-common}</version> - </dependency> - <dependency> - <groupId>com.squareup.okhttp3</groupId> - <artifactId>mockwebserver3</artifactId> - <version>${version.mockwebserver3}</version> - </dependency> - <dependency> - <groupId>com.squareup.okhttp3</groupId> - <artifactId>okhttp</artifactId> - <version>${version.mockwebserver3}</version> - </dependency> - </dependencies> - </dependencyManagement> - - <dependencies> - <!-- Internal module dependencies --> - <dependency> - <groupId>de.cuioss.sheriff.api</groupId> - <artifactId>api-sheriff-library</artifactId> - </dependency> - <dependency> - <groupId>de.cuioss.sheriff.oauth</groupId> - <artifactId>benchmarking-common</artifactId> - </dependency> - - <!-- Test dependencies from library module --> - <dependency> - <groupId>de.cuioss.sheriff.api</groupId> - <artifactId>api-sheriff-library</artifactId> - <version>${project.version}</version> - <classifier>generators</classifier> - <scope>compile</scope> - </dependency> - - <!-- Mock Web Server for HTTP testing --> - <dependency> - <groupId>com.squareup.okhttp3</groupId> - <artifactId>mockwebserver3</artifactId> - <scope>compile</scope> - </dependency> - <dependency> - <groupId>com.squareup.okhttp3</groupId> - <artifactId>okhttp</artifactId> - <scope>compile</scope> - </dependency> - - <!-- Keycloak test integration --> - <dependency> - <groupId>de.cuioss.test</groupId> - <artifactId>cui-test-keycloak-integration</artifactId> - <scope>compile</scope> - <exclusions> - <exclusion> - <groupId>junit</groupId> - <artifactId>junit</artifactId> - </exclusion> - </exclusions> - </dependency> - - <!-- Rest Assured for API testing --> - <dependency> - <groupId>io.rest-assured</groupId> - <artifactId>rest-assured</artifactId> - <scope>compile</scope> - </dependency> - - <!-- Test utilities --> - <dependency> - <groupId>de.cuioss.test</groupId> - <artifactId>cui-test-generator</artifactId> - <scope>compile</scope> - </dependency> - - <!-- JMH dependencies --> - <dependency> - <groupId>org.openjdk.jmh</groupId> - <artifactId>jmh-core</artifactId> - </dependency> - <dependency> - <groupId>org.openjdk.jmh</groupId> - <artifactId>jmh-generator-annprocess</artifactId> - <scope>provided</scope> - </dependency> - <dependency> - <groupId>org.junit.jupiter</groupId> - <artifactId>junit-jupiter</artifactId> - <scope>test</scope> - </dependency> - - <!-- Other dependencies --> - <dependency> - <groupId>org.projectlombok</groupId> - <artifactId>lombok</artifactId> - </dependency> - - <!-- JJWT dependencies --> - <dependency> - <groupId>io.jsonwebtoken</groupId> - <artifactId>jjwt-api</artifactId> - <scope>compile</scope> - </dependency> - <dependency> - <groupId>io.jsonwebtoken</groupId> - <artifactId>jjwt-impl</artifactId> - <scope>compile</scope> - </dependency> - <dependency> - <groupId>io.jsonwebtoken</groupId> - <artifactId>jjwt-jackson</artifactId> - <scope>compile</scope> - </dependency> - - <!-- Implementation of jakarta.json-api --> - <dependency> - <groupId>org.eclipse.parsson</groupId> - <artifactId>parsson</artifactId> - <scope>compile</scope> - </dependency> - - <!-- HdrHistogram for accurate latency recording --> - <dependency> - <groupId>org.hdrhistogram</groupId> - <artifactId>HdrHistogram</artifactId> - <scope>compile</scope> - </dependency> - - <!-- Gson for JSON serialization --> - <dependency> - <groupId>com.google.code.gson</groupId> - <artifactId>gson</artifactId> - <scope>compile</scope> - </dependency> - - <!-- Awaitility for better async testing --> - <dependency> - <groupId>org.awaitility</groupId> - <artifactId>awaitility</artifactId> - <scope>test</scope> - </dependency> - </dependencies> - - <build> - <plugins> - <!-- Skip unit tests by default --> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-surefire-plugin</artifactId> - <configuration> - <skipTests>${skipTests}</skipTests> - </configuration> - </plugin> - - <!-- Enable annotation processing for JMH --> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-compiler-plugin</artifactId> - <configuration> - <annotationProcessorPaths> - <path> - <groupId>org.openjdk.jmh</groupId> - <artifactId>jmh-generator-annprocess</artifactId> - <version>${version.jmh}</version> - </path> - </annotationProcessorPaths> - <release>21</release> - </configuration> - </plugin> - - <!-- Execute benchmark tests when skip.benchmark is false --> - <plugin> - <groupId>org.codehaus.mojo</groupId> - <artifactId>exec-maven-plugin</artifactId> - <executions> - <execution> - <id>run-benchmarks</id> - <phase>verify</phase> - <goals> - <goal>exec</goal> - </goals> - <configuration> - <skip>${skip.benchmark}</skip> - <executable>java</executable> - <arguments> - <argument>-classpath</argument> - <argument>${project.build.outputDirectory}${path.separator}${project.build.directory}/dependency/*</argument> - <argument>-Djmh.include=${jmh.include}</argument> - <argument>-Djmh.result.format=${jmh.result.format}</argument> - <argument>-Djmh.result.filePrefix=${jmh.result.filePrefix}</argument> - <argument>-Djmh.iterations=${jmh.iterations}</argument> - <argument>-Djmh.warmupIterations=${jmh.warmupIterations}</argument> - <argument>-Djmh.forks=${jmh.forks}</argument> - <argument>-Djmh.threads=${jmh.threads}</argument> - <argument>-Djmh.time=${jmh.time}</argument> - <argument>-Djmh.warmupTime=${jmh.warmupTime}</argument> - <argument>-Dbenchmark.history.dir=${benchmark.history.dir}</argument> - <argument>-Djava.util.logging.config.file=benchmark-logging.properties</argument> - <argument>-XX:+UnlockDiagnosticVMOptions</argument> - <argument>-XX:+DebugNonSafepoints</argument> - <argument>${benchmark.runner}</argument> - </arguments> - </configuration> - </execution> - </executions> - </plugin> - - <!-- Build classpath for benchmark execution --> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-dependency-plugin</artifactId> - <!-- Configuration inherited from parent pluginManagement --> - </plugin> - </plugins> - </build> - - <profiles> - <profile> - <id>benchmark</id> - <properties> - <skip.benchmark>false</skip.benchmark> - <benchmark.results.dir>target/benchmark-results</benchmark.results.dir> - </properties> - </profile> - <profile> - <id>benchmark-jfr</id> - <properties> - <skip.benchmark>false</skip.benchmark> - <benchmark.runner>de.cuioss.sheriff.api.benchmark.JfrBenchmarkRunner</benchmark.runner> - <benchmark.results.dir>target/benchmark-jfr-results</benchmark.results.dir> - </properties> - </profile> - </profiles> -</project> \ No newline at end of file diff --git a/benchmarking/benchmark-core/src/main/java/de/cuioss/sheriff/api/benchmark/BenchmarkOptionsHelper.java b/benchmarking/benchmark-core/src/main/java/de/cuioss/sheriff/api/benchmark/BenchmarkOptionsHelper.java deleted file mode 100644 index fe756509..00000000 --- a/benchmarking/benchmark-core/src/main/java/de/cuioss/sheriff/api/benchmark/BenchmarkOptionsHelper.java +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright 2025 the original author or authors. - * <p> - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * <p> - * https://www.apache.org/licenses/LICENSE-2.0 - * <p> - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.cuioss.sheriff.api.benchmark; - -import org.openjdk.jmh.results.format.ResultFormatType; -import org.openjdk.jmh.runner.options.TimeValue; - -import java.io.File; -import java.util.concurrent.TimeUnit; - -/** - * Shared utility class for building JMH benchmark options. - * Consolidates common option parsing logic for benchmark runners. - * - * @author API Sheriff Team - */ -public final class BenchmarkOptionsHelper { - - private BenchmarkOptionsHelper() { - // Utility class - } - - /** - * Gets the result format from system property or defaults to JSON. - * - * @return the result format type - */ - public static ResultFormatType getResultFormat() { - String format = System.getProperty("jmh.result.format", "JSON"); - try { - return ResultFormatType.valueOf(format.toUpperCase()); - } catch (IllegalArgumentException e) { - return ResultFormatType.JSON; - } - } - - /** - * Gets the result file path from system property or returns the default. - * Ensures parent directory exists. - * - * @param defaultFileName the default file name to use if property not set - * @return the result file path - */ - public static String getResultFile(String defaultFileName) { - String filePrefix = System.getProperty("jmh.result.filePrefix"); - if (filePrefix != null && !filePrefix.isEmpty()) { - String resultFile = filePrefix + ".json"; - // Ensure parent directory exists - File file = new File(resultFile); - File parentDir = file.getParentFile(); - if (parentDir != null && !parentDir.exists()) { - parentDir.mkdirs(); - } - return resultFile; - } - return defaultFileName; - } - - /** - * Gets the measurement time from system property or uses the provided default. - * - * @param defaultTime the default time value (e.g., "2s", "5s") - * @return the parsed time value - */ - public static TimeValue getMeasurementTime(String defaultTime) { - String time = System.getProperty("jmh.time", defaultTime); - return parseTimeValue(time); - } - - /** - * Gets the warmup time from system property or uses the provided default. - * - * @param defaultTime the default time value (e.g., "2s", "3s") - * @return the parsed time value - */ - public static TimeValue getWarmupTime(String defaultTime) { - String time = System.getProperty("jmh.warmupTime", defaultTime); - return parseTimeValue(time); - } - - /** - * Gets the thread count from system property or uses the provided default. - * Supports "MAX" to use all available processors. - * - * @param defaultCount the default thread count - * @return the thread count - */ - public static int getThreadCount(int defaultCount) { - String threads = System.getProperty("jmh.threads"); - if (threads != null) { - if ("MAX".equalsIgnoreCase(threads)) { - return Runtime.getRuntime().availableProcessors(); - } - try { - return Integer.parseInt(threads); - } catch (NumberFormatException e) { - // Fall through to default - } - } - return defaultCount; - } - - /** - * Gets the number of forks from system property or uses the provided default. - * - * @param defaultForks the default number of forks - * @return the number of forks - */ - public static int getForks(int defaultForks) { - return Integer.parseInt(System.getProperty("jmh.forks", String.valueOf(defaultForks))); - } - - /** - * Gets the warmup iterations from system property or uses the provided default. - * - * @param defaultIterations the default number of warmup iterations - * @return the number of warmup iterations - */ - public static int getWarmupIterations(int defaultIterations) { - return Integer.parseInt(System.getProperty("jmh.warmupIterations", String.valueOf(defaultIterations))); - } - - /** - * Gets the measurement iterations from system property or uses the provided default. - * - * @param defaultIterations the default number of measurement iterations - * @return the number of measurement iterations - */ - public static int getMeasurementIterations(int defaultIterations) { - return Integer.parseInt(System.getProperty("jmh.measurementIterations", String.valueOf(defaultIterations))); - } - - /** - * Parse a time value string (e.g., "2s", "100ms", "1m"). - * - * @param timeStr the time string to parse - * @return the parsed TimeValue - */ - private static TimeValue parseTimeValue(String timeStr) { - if (timeStr == null || timeStr.isEmpty()) { - return TimeValue.seconds(1); - } - - timeStr = timeStr.trim().toLowerCase(); - - // Extract numeric part and unit - StringBuilder numPart = new StringBuilder(); - StringBuilder unitPart = new StringBuilder(); - boolean foundUnit = false; - - for (char c : timeStr.toCharArray()) { - if (Character.isDigit(c) || c == '.') { - if (!foundUnit) { - numPart.append(c); - } - } else { - foundUnit = true; - unitPart.append(c); - } - } - - try { - long value = Long.parseLong(numPart.toString()); - String unit = unitPart.toString(); - - switch (unit) { - case "ms": - case "milliseconds": - case "millis": - return TimeValue.milliseconds(value); - case "s": - case "sec": - case "seconds": - return TimeValue.seconds(value); - case "m": - case "min": - case "minutes": - return TimeValue.minutes(value); - default: - // Default to seconds if no unit or unknown unit - return TimeValue.seconds(value); - } - } catch (NumberFormatException e) { - // Default fallback - return TimeValue.seconds(1); - } - } -} \ No newline at end of file diff --git a/benchmarking/benchmark-core/src/main/java/de/cuioss/sheriff/api/benchmark/BenchmarkRunner.java b/benchmarking/benchmark-core/src/main/java/de/cuioss/sheriff/api/benchmark/BenchmarkRunner.java deleted file mode 100644 index 84cb8019..00000000 --- a/benchmarking/benchmark-core/src/main/java/de/cuioss/sheriff/api/benchmark/BenchmarkRunner.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2025 the original author or authors. - * <p> - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * <p> - * https://www.apache.org/licenses/LICENSE-2.0 - * <p> - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.cuioss.sheriff.api.benchmark; - -import java.util.concurrent.TimeUnit; - -import org.openjdk.jmh.annotations.Benchmark; -import org.openjdk.jmh.annotations.BenchmarkMode; -import org.openjdk.jmh.annotations.Fork; -import org.openjdk.jmh.annotations.Level; -import org.openjdk.jmh.annotations.Measurement; -import org.openjdk.jmh.annotations.Mode; -import org.openjdk.jmh.annotations.OutputTimeUnit; -import org.openjdk.jmh.annotations.Scope; -import org.openjdk.jmh.annotations.Setup; -import org.openjdk.jmh.annotations.State; -import org.openjdk.jmh.annotations.Warmup; -import org.openjdk.jmh.runner.Runner; -import org.openjdk.jmh.runner.RunnerException; -import org.openjdk.jmh.runner.options.Options; -import org.openjdk.jmh.runner.options.OptionsBuilder; - -import de.cuioss.sheriff.api.ApiSheriff; - -/** - * JMH benchmark suite for API Sheriff library performance testing. - * - * @author API Sheriff Team - */ -@State(Scope.Benchmark) -@BenchmarkMode(Mode.Throughput) -@OutputTimeUnit(TimeUnit.SECONDS) -@Fork(value = 1, jvmArgs = {"-Xmx2G", "-server"}) -@Warmup(iterations = 3, time = 2, timeUnit = TimeUnit.SECONDS) -@Measurement(iterations = 5, time = 2, timeUnit = TimeUnit.SECONDS) -public class BenchmarkRunner { - - private ApiSheriff apiSheriff; - - @Setup(Level.Trial) - public void setup() { - apiSheriff = new ApiSheriff(); - } - - @Benchmark - public String benchmarkGetStatus() { - return apiSheriff.getStatus(); - } - - public static void main(String[] args) throws RunnerException { - // Configure JMH options using helper for system property configuration - Options opt = new OptionsBuilder() - .include(System.getProperty("jmh.include", BenchmarkRunner.class.getSimpleName())) - .forks(BenchmarkOptionsHelper.getForks(1)) - .warmupIterations(BenchmarkOptionsHelper.getWarmupIterations(5)) - .measurementIterations(BenchmarkOptionsHelper.getMeasurementIterations(5)) - .measurementTime(BenchmarkOptionsHelper.getMeasurementTime("2s")) - .warmupTime(BenchmarkOptionsHelper.getWarmupTime("2s")) - .threads(BenchmarkOptionsHelper.getThreadCount(8)) - .resultFormat(BenchmarkOptionsHelper.getResultFormat()) - .result(BenchmarkOptionsHelper.getResultFile(getBenchmarkResultsDir() + "/micro-benchmark-result.json")) - .build(); - - new Runner(opt).run(); - } - - /** - * Gets the benchmark results directory from system property or defaults to target/benchmark-results. - * - * @return the benchmark results directory path - */ - private static String getBenchmarkResultsDir() { - return System.getProperty("benchmark.results.dir", "target/benchmark-results"); - } -} \ No newline at end of file diff --git a/benchmarking/pom.xml b/benchmarking/pom.xml index b47101ba..bbc1881d 100644 --- a/benchmarking/pom.xml +++ b/benchmarking/pom.xml @@ -16,14 +16,11 @@ <description>Parent module for all benchmarking related modules including library and integration benchmarks</description> <modules> - <module>benchmark-core</module> <module>benchmark-integration-wrk</module> </modules> <properties> <maven.jar.plugin.automatic.module.name>de.cuioss.sheriff.api.benchmarking</maven.jar.plugin.automatic.module.name> - <!-- JMH version for benchmarking --> - <version.jmh>1.37</version.jmh> <!-- External dependency versions --> <version.gson>2.13.2</version.gson> <version.hdrhistogram>2.2.2</version.hdrhistogram> @@ -38,17 +35,6 @@ <dependencyManagement> <dependencies> - <dependency> - <groupId>org.openjdk.jmh</groupId> - <artifactId>jmh-core</artifactId> - <version>${version.jmh}</version> - </dependency> - <dependency> - <groupId>org.openjdk.jmh</groupId> - <artifactId>jmh-generator-annprocess</artifactId> - <version>${version.jmh}</version> - <scope>provided</scope> - </dependency> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> diff --git a/benchmarking/scripts/benchmark-pages.py b/benchmarking/scripts/benchmark-pages.py index c5ff3da7..b2f7846f 100644 --- a/benchmarking/scripts/benchmark-pages.py +++ b/benchmarking/scripts/benchmark-pages.py @@ -15,7 +15,6 @@ # After all Maven benchmark runs: python3 benchmarking/scripts/benchmark-pages.py assemble \ - --micro-results benchmarking/benchmark-core/target/benchmark-results/gh-pages-ready \ --integration-results benchmarking/benchmark-integration-wrk/target/benchmark-results/gh-pages-ready \ --previous-pages-dir previous-pages/api-sheriff/benchmarks \ --output-dir gh-pages \ @@ -31,11 +30,6 @@ # Badge files produced by each benchmark type and their names in the root badges/ directory. _BADGE_MAPPING = { - "micro": { - "performance-badge.json": "performance-badge.json", - "trend-badge.json": "trend-badge.json", - "last-run-badge.json": "last-run-badge.json", - }, "integration": { "integration-performance-badge.json": "integration-performance-badge.json", "integration-trend-badge.json": "integration-trend-badge.json", @@ -43,7 +37,7 @@ }, } -_BENCHMARK_TYPES = ("micro", "integration") +_BENCHMARK_TYPES = ("integration",) _DEFAULT_MAX_HISTORY = 10 From eb01ab279692c137bcad903980fb29eebc7e80fb Mon Sep 17 00:00:00 2001 From: Oliver Wolff <23139298+cuioss@users.noreply.github.com> Date: Tue, 3 Mar 2026 19:24:29 +0100 Subject: [PATCH 07/24] chore: Simplify module structure from 8 to 3 modules API Sheriff is a standalone Quarkus app, not a reusable extension. The extension pattern (runtime/deployment split, BOM, separate library) was unnecessary overhead inherited from the OAuthSheriff template. Changes: - Merge api-sheriff-library + api-sheriff-quarkus into unified api-sheriff/ - Replace @BuildStep processor with @RegisterForReflection annotations - Delete bom/, deployment module, ApiSheriffRecorder, ApiSheriffProcessor - Promote integration-tests from nested to root-level module - Absorb dependency/plugin management from BOM + quarkus-parent into root POM - Update Docker, CI/CD, scripts, and docs for new structure Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --- .github/project.yml | 2 +- .github/workflows/benchmark.yml | 8 - .github/workflows/claude.yml | 2 +- .github/workflows/integration-tests.yml | 4 +- CLAUDE.md | 7 +- README.adoc | 34 +- .../docker-compose.yml | 8 +- .../pom.xml | 72 ++-- .../scripts/benchmark-with-monitoring.sh | 10 +- .../scripts/build-native-if-needed.sh | 4 +- .../scripts/start-integration-container.sh | 4 +- .../scripts/stop-integration-container.sh | 0 .../scripts/verify-environment.sh | 0 .../main/docker/Dockerfile.native.distroless | 12 +- .../src/main/docker/Dockerfile.native.jfr | 10 +- .../certificates/generate-certificates.sh | 0 .../certificates/generate-truststore.sh | 0 .../certificates/localhost-truststore.p12 | Bin .../main/docker/certificates/localhost.crt | 0 .../main/docker/certificates/localhost.key | 0 .../src/main/docker/health-check.sh | 0 .../main/docker/keycloak/benchmark-realm.json | 0 .../docker/keycloak/integration-realm.json | 0 .../api/integration/TestApplication.java | 10 +- .../sheriff/api/integration/TestResource.java | 26 +- .../src/main/resources/application.properties | 0 .../src/main/resources/test-jwks.json | 0 .../src/main/resources/test-public-key.pem | 0 .../integration/ApiSheriffIntegrationIT.java | 36 +- .../api/integration/BaseIntegrationTest.java | 12 +- .../test/resources/keys/test_public_key.pem | 0 api-sheriff-library/README.adoc | 155 -------- .../sheriff/api/test/TestDataGenerator.java | 26 -- api-sheriff-quarkus-parent/README.adoc | 273 -------------- .../package-lock.json | 12 - .../package.json | 12 - .../api-sheriff-quarkus-deployment/pom.xml | 229 ------------ .../deployment/ApiSheriffProcessor.java | 113 ------ .../api-sheriff-quarkus/pom.xml | 203 ----------- .../api/quarkus/ApiSheriffRecorder.java | 0 api-sheriff-quarkus-parent/pom.xml | 333 ------------------ {api-sheriff-library => api-sheriff}/pom.xml | 169 ++++++--- .../de/cuioss/sheriff/api/ApiSheriff.java | 18 +- .../de/cuioss/sheriff/api/package-info.java | 16 +- .../api/quarkus/ApiSheriffProducer.java | 18 +- .../sheriff/api/quarkus/package-info.java | 13 +- .../de/cuioss/sheriff/api/ApiSheriffTest.java | 12 +- .../sheriff/api/test/TestDataGenerator.java | 41 +++ .../benchmark-integration-wrk/pom.xml | 8 +- .../wrk/benchmark/WrkResultPostProcessor.java | 10 +- .../benchmark/WrkResultPostProcessorTest.java | 11 +- benchmarking/pom.xml | 7 - bom/pom.xml | 83 ----- pom.xml | 297 +++++++++++++++- 54 files changed, 644 insertions(+), 1676 deletions(-) rename {api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests => api-sheriff-integration-tests}/docker-compose.yml (92%) rename {api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests => api-sheriff-integration-tests}/pom.xml (91%) rename {api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests => api-sheriff-integration-tests}/scripts/benchmark-with-monitoring.sh (97%) rename {api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests => api-sheriff-integration-tests}/scripts/build-native-if-needed.sh (89%) rename {api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests => api-sheriff-integration-tests}/scripts/start-integration-container.sh (96%) rename {api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests => api-sheriff-integration-tests}/scripts/stop-integration-container.sh (100%) rename {api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests => api-sheriff-integration-tests}/scripts/verify-environment.sh (100%) rename {api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests => api-sheriff-integration-tests}/src/main/docker/Dockerfile.native.distroless (58%) rename {api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests => api-sheriff-integration-tests}/src/main/docker/Dockerfile.native.jfr (64%) rename {api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests => api-sheriff-integration-tests}/src/main/docker/certificates/generate-certificates.sh (100%) rename {api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests => api-sheriff-integration-tests}/src/main/docker/certificates/generate-truststore.sh (100%) rename {api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests => api-sheriff-integration-tests}/src/main/docker/certificates/localhost-truststore.p12 (100%) rename {api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests => api-sheriff-integration-tests}/src/main/docker/certificates/localhost.crt (100%) rename {api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests => api-sheriff-integration-tests}/src/main/docker/certificates/localhost.key (100%) rename {api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests => api-sheriff-integration-tests}/src/main/docker/health-check.sh (100%) rename {api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests => api-sheriff-integration-tests}/src/main/docker/keycloak/benchmark-realm.json (100%) rename {api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests => api-sheriff-integration-tests}/src/main/docker/keycloak/integration-realm.json (100%) rename {api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests => api-sheriff-integration-tests}/src/main/java/de/cuioss/sheriff/api/integration/TestApplication.java (90%) rename {api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests => api-sheriff-integration-tests}/src/main/java/de/cuioss/sheriff/api/integration/TestResource.java (82%) rename {api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests => api-sheriff-integration-tests}/src/main/resources/application.properties (100%) rename {api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests => api-sheriff-integration-tests}/src/main/resources/test-jwks.json (100%) rename {api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests => api-sheriff-integration-tests}/src/main/resources/test-public-key.pem (100%) rename {api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests => api-sheriff-integration-tests}/src/test/java/de/cuioss/sheriff/api/integration/ApiSheriffIntegrationIT.java (80%) rename {api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests => api-sheriff-integration-tests}/src/test/java/de/cuioss/sheriff/api/integration/BaseIntegrationTest.java (83%) rename {api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests => api-sheriff-integration-tests}/src/test/resources/keys/test_public_key.pem (100%) delete mode 100644 api-sheriff-library/README.adoc delete mode 100644 api-sheriff-library/src/test/java/de/cuioss/sheriff/api/test/TestDataGenerator.java delete mode 100644 api-sheriff-quarkus-parent/README.adoc delete mode 100644 api-sheriff-quarkus-parent/api-sheriff-quarkus-deployment/package-lock.json delete mode 100644 api-sheriff-quarkus-parent/api-sheriff-quarkus-deployment/package.json delete mode 100644 api-sheriff-quarkus-parent/api-sheriff-quarkus-deployment/pom.xml delete mode 100644 api-sheriff-quarkus-parent/api-sheriff-quarkus-deployment/src/main/java/de/cuioss/sheriff/api/quarkus/deployment/ApiSheriffProcessor.java delete mode 100644 api-sheriff-quarkus-parent/api-sheriff-quarkus/pom.xml delete mode 100644 api-sheriff-quarkus-parent/api-sheriff-quarkus/src/main/java/de/cuioss/sheriff/api/quarkus/ApiSheriffRecorder.java delete mode 100644 api-sheriff-quarkus-parent/pom.xml rename {api-sheriff-library => api-sheriff}/pom.xml (62%) rename {api-sheriff-library => api-sheriff}/src/main/java/de/cuioss/sheriff/api/ApiSheriff.java (75%) rename {api-sheriff-library => api-sheriff}/src/main/java/de/cuioss/sheriff/api/package-info.java (80%) rename {api-sheriff-quarkus-parent/api-sheriff-quarkus => api-sheriff}/src/main/java/de/cuioss/sheriff/api/quarkus/ApiSheriffProducer.java (77%) rename api-sheriff-library/src/main/java/module-info.java => api-sheriff/src/main/java/de/cuioss/sheriff/api/quarkus/package-info.java (79%) rename {api-sheriff-library => api-sheriff}/src/test/java/de/cuioss/sheriff/api/ApiSheriffTest.java (89%) create mode 100644 api-sheriff/src/test/java/de/cuioss/sheriff/api/test/TestDataGenerator.java delete mode 100644 bom/pom.xml diff --git a/.github/project.yml b/.github/project.yml index 3c4a6e9b..f8d7e9e4 100644 --- a/.github/project.yml +++ b/.github/project.yml @@ -12,7 +12,7 @@ maven-build: enable-snapshot-deploy: true maven-profiles-snapshot: 'release-snapshot,javadoc' maven-profiles-release: 'release,javadoc' - npm-cache: true + npm-cache: false sonar: project-key: cuioss_API-Sheriff diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 35bfc0c1..634991c8 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -57,14 +57,6 @@ jobs: distribution: 'temurin' cache: maven - - name: Cache npm packages - uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3 - with: - path: ~/.npm - key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json', '**/package.json') }} - restore-keys: | - ${{ runner.os }}-npm- - - name: Build api-sheriff run: | # Build all modules first to ensure artifacts are available for benchmarking diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index 54b5e2ef..1dd2fc3e 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -49,4 +49,4 @@ jobs: additional_permissions: | actions: read - allowed_tools: "Bash(./mvnw*),Bash(./mvnw -Ppre-commit clean verify -DskipTests),Bash(./mvnw clean verify),Bash(./mvnw clean install),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl bom),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl api-sheriff-library),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl api-sheriff-quarkus-parent),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl api-sheriff-quarkus-parent/api-sheriff-quarkus),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl api-sheriff-quarkus-parent/api-sheriff-quarkus-deployment),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl benchmarking),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl benchmarking/benchmark-integration-wrk),Bash(./mvnw clean install -pl bom),Bash(./mvnw clean install -pl api-sheriff-library),Bash(./mvnw clean install -pl api-sheriff-quarkus-parent),Bash(./mvnw clean install -pl api-sheriff-quarkus-parent/api-sheriff-quarkus),Bash(./mvnw clean install -pl api-sheriff-quarkus-parent/api-sheriff-quarkus-deployment),Bash(./mvnw clean install -pl api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests),Bash(./mvnw clean install -pl benchmarking),Bash(./mvnw clean install -pl benchmarking/benchmark-integration-wrk),Bash(git*),Bash(find*),Bash(gh*),Bash(java*)" + allowed_tools: "Bash(./mvnw*),Bash(./mvnw -Ppre-commit clean verify -DskipTests),Bash(./mvnw clean verify),Bash(./mvnw clean install),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl api-sheriff),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl api-sheriff-integration-tests),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl benchmarking),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl benchmarking/benchmark-integration-wrk),Bash(./mvnw clean install -pl api-sheriff),Bash(./mvnw clean install -pl api-sheriff-integration-tests),Bash(./mvnw clean install -pl benchmarking),Bash(./mvnw clean install -pl benchmarking/benchmark-integration-wrk),Bash(git*),Bash(find*),Bash(gh*),Bash(java*)" diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index d7ddbb7b..1cf52279 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -20,9 +20,9 @@ jobs: with: report-name: api-sheriff-integration-tests maven-args-input: | - verify -Pintegration-tests -pl api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests -am + verify -Pintegration-tests -pl api-sheriff-integration-tests -am reports-folder: | - api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/target/failsafe-reports + api-sheriff-integration-tests/target/failsafe-reports secrets: RELEASE_APP_ID: ${{ secrets.RELEASE_APP_ID }} RELEASE_APP_PRIVATE_KEY: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} diff --git a/CLAUDE.md b/CLAUDE.md index 77ec039e..c255c587 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -9,10 +9,9 @@ API Sheriff is a security-focused API Gateway with a lightweight approach, curre ## Project Structure Multi-module Maven project: -- `api-sheriff-library/` โ€” Core library -- `api-sheriff-quarkus-parent/` โ€” Quarkus framework integration (runtime, deployment, integration-tests) +- `api-sheriff/` โ€” Unified Quarkus application (core library + CDI producers) +- `api-sheriff-integration-tests/` โ€” Integration tests with native container testing - `benchmarking/` โ€” Performance benchmarking (benchmark-integration-wrk for WRK HTTP load testing) -- `bom/` โ€” Bill of Materials (`api-sheriff-bom`) ## Build Commands @@ -30,7 +29,7 @@ Multi-module Maven project: ./mvnw test -Dtest=ClassName#methodName # Integration tests -./mvnw clean verify -Pintegration-tests -pl api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests -am +./mvnw clean verify -Pintegration-tests -pl api-sheriff-integration-tests -am # Integration benchmarks (WRK) ./mvnw clean verify -pl benchmarking/benchmark-integration-wrk -Pbenchmark diff --git a/README.adoc b/README.adoc index 6424dbc8..b570a823 100644 --- a/README.adoc +++ b/README.adoc @@ -41,7 +41,7 @@ https://cuioss.github.io/api-sheriff/about.html[Generated Documentation on githu [.discrete] == What is it? -A template project demonstrating a multi-module Maven structure with Quarkus integration and comprehensive benchmarking. +A security-focused API Gateway with a lightweight approach, built with Quarkus. toc::[] @@ -51,41 +51,23 @@ toc::[] ---- <dependency> <groupId>de.cuioss.sheriff.api</groupId> - <artifactId>api-sheriff-library</artifactId> + <artifactId>api-sheriff</artifactId> </dependency> ---- -== Additional Modules +== Modules -The project includes several additional modules that extend the core functionality: +=== API Sheriff -=== Quarkus Integration +The unified Quarkus application module containing the core library and CDI producers. -The Quarkus Extension provides seamless integration into Quarkus applications. It includes: +=== Integration Tests -* CDI producers for easy dependency injection -* Configuration support via Quarkus properties -* Native image support for GraalVM compilation - -[source,xml] ----- -<dependency> - <groupId>de.cuioss.sheriff.api</groupId> - <artifactId>api-sheriff-quarkus</artifactId> -</dependency> ----- +End-to-end integration tests with native container testing and HTTPS support. === Performance Benchmarking -The project includes two complementary benchmarking modules: - -==== Micro-Benchmarks - -The Benchmark Library provides in-memory performance measurements using JMH (Java Microbenchmark Harness). - -==== Integration Benchmarks - -The Quarkus Integration Benchmarks provides end-to-end performance testing using containerized environments. +Integration benchmarks using WRK HTTP load testing with containerized environments. xref:benchmarking/doc/performance-scoring.adoc[Understand Performance Metrics] diff --git a/api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/docker-compose.yml b/api-sheriff-integration-tests/docker-compose.yml similarity index 92% rename from api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/docker-compose.yml rename to api-sheriff-integration-tests/docker-compose.yml index 5f6d3c5c..39efd236 100644 --- a/api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/docker-compose.yml +++ b/api-sheriff-integration-tests/docker-compose.yml @@ -39,8 +39,8 @@ services: # For JFR: DOCKERFILE=Dockerfile.native.jfr DOCKER_IMAGE_TAG=jfr image: "api-sheriff-integration-tests:${DOCKER_IMAGE_TAG:-distroless}" build: - context: ../.. - dockerfile: api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/main/docker/${DOCKERFILE:-Dockerfile.native.distroless} + context: .. + dockerfile: api-sheriff-integration-tests/src/main/docker/${DOCKERFILE:-Dockerfile.native.distroless} cache_from: - quay.io/quarkus/quarkus-distroless-image:2.0 - registry.access.redhat.com/ubi8/ubi-minimal:8.10 @@ -61,8 +61,8 @@ services: volumes: # Read-only certificate mount (production pattern) - ./src/main/docker/certificates:/app/certificates:ro - # JFR output volume - mount directly to benchmark target directory - - ../quarkus-integration-jmh/target/benchmark-results/jfr-recordings:/tmp/jfr-output:rw + # JFR output volume for profiling recordings + - ./target/jfr-recordings:/tmp/jfr-output:rw # OWASP Security hardening (production-grade) security_opt: diff --git a/api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/pom.xml b/api-sheriff-integration-tests/pom.xml similarity index 91% rename from api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/pom.xml rename to api-sheriff-integration-tests/pom.xml index 64bce7f3..cb005c06 100644 --- a/api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/pom.xml +++ b/api-sheriff-integration-tests/pom.xml @@ -5,18 +5,18 @@ <modelVersion>4.0.0</modelVersion> <parent> <groupId>de.cuioss.sheriff.api</groupId> - <artifactId>api-sheriff-quarkus-parent</artifactId> + <artifactId>api-sheriff-parent</artifactId> <version>1.0.0-SNAPSHOT</version> <relativePath>../pom.xml</relativePath> </parent> - <artifactId>api-sheriff-quarkus-integration-tests</artifactId> + <artifactId>api-sheriff-integration-tests</artifactId> <packaging>jar</packaging> - <name>API Sheriff Quarkus Integration Tests</name> - <description>Integration tests for the API Sheriff Quarkus extension including native container testing with HTTPS support</description> + <name>API Sheriff Integration Tests</name> + <description>Integration tests for API Sheriff including native container testing with HTTPS support</description> <properties> - <maven.jar.plugin.automatic.module.name>de.cuioss.sheriff.api.quarkus.integration.tests</maven.jar.plugin.automatic.module.name> + <maven.jar.plugin.automatic.module.name>de.cuioss.sheriff.api.integration.tests</maven.jar.plugin.automatic.module.name> <!-- Configure test execution - surefire skip, failsafe disabled by default --> <skipITs>true</skipITs> @@ -32,18 +32,28 @@ </properties> <dependencies> - <!-- API Sheriff Extension Under Test --> + <!-- API Sheriff Under Test --> <dependency> <groupId>de.cuioss.sheriff.api</groupId> - <artifactId>api-sheriff-quarkus</artifactId> + <artifactId>api-sheriff</artifactId> </dependency> - - <!-- API Sheriff Deployment Module for Quarkus Extension --> + + <!-- Quarkus dependencies (previously inherited from quarkus-parent) --> <dependency> - <groupId>de.cuioss.sheriff.api</groupId> - <artifactId>api-sheriff-quarkus-deployment</artifactId> - <version>${project.version}</version> - <scope>test</scope> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-core</artifactId> + </dependency> + <dependency> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-arc</artifactId> + </dependency> + <dependency> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-micrometer</artifactId> + </dependency> + <dependency> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-security</artifactId> </dependency> <!-- Quarkus Extensions for REST and Health --> @@ -64,16 +74,32 @@ <artifactId>quarkus-micrometer-registry-prometheus</artifactId> </dependency> + <!-- Other dependencies --> + <dependency> + <groupId>org.projectlombok</groupId> + <artifactId>lombok</artifactId> + </dependency> <!-- API Sheriff Test Utilities for test material --> <dependency> <groupId>de.cuioss.sheriff.api</groupId> - <artifactId>api-sheriff-library</artifactId> + <artifactId>api-sheriff</artifactId> <version>${project.version}</version> <classifier>generators</classifier> <scope>test</scope> </dependency> + <!-- Test dependencies --> + <dependency> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-junit5</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>de.cuioss.test</groupId> + <artifactId>cui-test-juli-logger</artifactId> + <scope>test</scope> + </dependency> <dependency> <groupId>io.rest-assured</groupId> <artifactId>rest-assured</artifactId> @@ -100,7 +126,7 @@ <build> <plugins> - + <!-- Execute Docker cleanup before Maven clean --> <plugin> <groupId>org.codehaus.mojo</groupId> @@ -137,14 +163,14 @@ <properties> <!-- Enable integration tests --> <skipITs>false</skipITs> - + <!-- Container-based native build with optimized rebuild detection --> <quarkus.native.container-build>true</quarkus.native.container-build> <quarkus.native.enabled>true</quarkus.native.enabled> </properties> <build> <plugins> - + <!-- Quarkus plugin (build only on-demand via script) --> <plugin> <groupId>io.quarkus</groupId> @@ -157,7 +183,7 @@ </execution> </executions> </plugin> - + <!-- Skip Unit Tests (Surefire) --> <plugin> <groupId>org.apache.maven.plugins</groupId> @@ -260,14 +286,14 @@ </plugins> </build> </profile> - + <!-- Profile for JFR profiling with UBI-based images --> <profile> <id>jfr</id> <properties> <!-- Enable integration tests --> <skipITs>false</skipITs> - + <!-- JFR profile builds native executable with JFR support --> <quarkus.native.enabled>true</quarkus.native.enabled> <!-- Native build with JFR monitoring enabled --> @@ -276,14 +302,14 @@ </properties> <build> <plugins> - + <!-- Quarkus plugin with JFR support (native build) --> <plugin> <groupId>io.quarkus</groupId> <artifactId>quarkus-maven-plugin</artifactId> <!-- Use parent configuration for native build --> </plugin> - + <!-- Skip Unit Tests (Surefire) --> <plugin> <groupId>org.apache.maven.plugins</groupId> @@ -375,4 +401,4 @@ </build> </profile> </profiles> -</project> \ No newline at end of file +</project> diff --git a/api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/scripts/benchmark-with-monitoring.sh b/api-sheriff-integration-tests/scripts/benchmark-with-monitoring.sh similarity index 97% rename from api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/scripts/benchmark-with-monitoring.sh rename to api-sheriff-integration-tests/scripts/benchmark-with-monitoring.sh index 439fad9e..51ee3eea 100755 --- a/api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/scripts/benchmark-with-monitoring.sh +++ b/api-sheriff-integration-tests/scripts/benchmark-with-monitoring.sh @@ -5,8 +5,8 @@ set -e SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -PROJECT_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)" -RESULTS_DIR="$PROJECT_ROOT/api-sheriff-quarkus-parent/quarkus-integration-jmh/target/monitoring-results" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" +RESULTS_DIR="$PROJECT_ROOT/api-sheriff-integration-tests/target/monitoring-results" TIMESTAMP=$(date +%Y%m%d-%H%M%S) echo "๐Ÿ” API Sheriff Validation Benchmark with Comprehensive Monitoring" @@ -360,11 +360,11 @@ trap cleanup INT TERM echo "๐Ÿ”จ Step 1: Building integration tests (~6 seconds)..." cd "$PROJECT_ROOT" -$MAVEN_CMD clean install -pl api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests -q +$MAVEN_CMD clean install -pl api-sheriff-integration-tests -q echo "๐Ÿ”จ Step 2: Force clean rebuild of native executable and container (~90 seconds)..." # Ensure clean rebuild includes updated application.properties -$MAVEN_CMD clean package -pl api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests -Pintegration-tests -q +$MAVEN_CMD clean package -pl api-sheriff-integration-tests -Pintegration-tests -q # Force Docker to rebuild container with updated configuration docker system prune -f --volumes >/dev/null 2>&1 || true @@ -375,7 +375,7 @@ echo "" # Start benchmark with JFR recording START_TIME=$(date +%s) -$MAVEN_CMD verify -pl api-sheriff-quarkus-parent/quarkus-integration-jmh -Pbenchmark > "$BENCHMARK_LOG" 2>&1 & +$MAVEN_CMD verify -pl benchmarking/benchmark-integration-wrk -Pbenchmark > "$BENCHMARK_LOG" 2>&1 & BENCHMARK_PID=$! # Wait for containers to start diff --git a/api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/scripts/build-native-if-needed.sh b/api-sheriff-integration-tests/scripts/build-native-if-needed.sh similarity index 89% rename from api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/scripts/build-native-if-needed.sh rename to api-sheriff-integration-tests/scripts/build-native-if-needed.sh index 72425e71..0a258083 100755 --- a/api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/scripts/build-native-if-needed.sh +++ b/api-sheriff-integration-tests/scripts/build-native-if-needed.sh @@ -15,9 +15,9 @@ if [[ -z "$RUNNER_FILE" ]]; then # Build native executable using Quarkus Maven plugin # Find the root directory with mvnw - ROOT_DIR=$(cd "${PROJECT_DIR}/../.." && pwd) + ROOT_DIR=$(cd "${PROJECT_DIR}/.." && pwd) cd "${ROOT_DIR}" - ./mvnw --no-transfer-progress -Pintegration-tests quarkus:build -pl api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests + ./mvnw --no-transfer-progress -Pintegration-tests quarkus:build -pl api-sheriff-integration-tests # Verify it was created RUNNER_FILE=$(find "${PROJECT_DIR}/target" -name "*-runner" -type f 2>/dev/null | head -n 1) diff --git a/api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/scripts/start-integration-container.sh b/api-sheriff-integration-tests/scripts/start-integration-container.sh similarity index 96% rename from api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/scripts/start-integration-container.sh rename to api-sheriff-integration-tests/scripts/start-integration-container.sh index 6b80fe38..d932b7c1 100755 --- a/api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/scripts/start-integration-container.sh +++ b/api-sheriff-integration-tests/scripts/start-integration-container.sh @@ -5,7 +5,7 @@ set -e SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" PROJECT_DIR="$(dirname "$SCRIPT_DIR")" -ROOT_DIR="$(dirname "$(dirname "$PROJECT_DIR")")" +ROOT_DIR="$(dirname "$PROJECT_DIR")" echo "๐Ÿš€ Starting API Sheriff Integration Tests with Docker Compose" echo "Project directory: ${PROJECT_DIR}" @@ -50,7 +50,7 @@ else echo "Expected: target/*-runner file and api-sheriff-integration-tests image" echo "Available images:" docker images | grep api-sheriff || echo " No api-sheriff images found" - echo "Run: mvnw verify -Pintegration-tests -pl api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests" + echo "Run: mvnw verify -Pintegration-tests -pl api-sheriff-integration-tests" exit 1 fi diff --git a/api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/scripts/stop-integration-container.sh b/api-sheriff-integration-tests/scripts/stop-integration-container.sh similarity index 100% rename from api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/scripts/stop-integration-container.sh rename to api-sheriff-integration-tests/scripts/stop-integration-container.sh diff --git a/api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/scripts/verify-environment.sh b/api-sheriff-integration-tests/scripts/verify-environment.sh similarity index 100% rename from api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/scripts/verify-environment.sh rename to api-sheriff-integration-tests/scripts/verify-environment.sh diff --git a/api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/main/docker/Dockerfile.native.distroless b/api-sheriff-integration-tests/src/main/docker/Dockerfile.native.distroless similarity index 58% rename from api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/main/docker/Dockerfile.native.distroless rename to api-sheriff-integration-tests/src/main/docker/Dockerfile.native.distroless index eb9780e7..07d7b838 100644 --- a/api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/main/docker/Dockerfile.native.distroless +++ b/api-sheriff-integration-tests/src/main/docker/Dockerfile.native.distroless @@ -13,13 +13,13 @@ LABEL performance.jfr.enabled="false" WORKDIR /app # Copy pre-built native executable from Maven target directory -COPY --chmod=0755 api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/target/*-runner /app/application +COPY --chmod=0755 api-sheriff-integration-tests/target/*-runner /app/application -# Copy certificates and health check script -COPY --chmod=0755 api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/main/docker/health-check.sh /app/health-check.sh -COPY --chmod=0644 api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/main/docker/certificates/localhost.crt /app/certificates/localhost.crt -COPY --chmod=0600 api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/main/docker/certificates/localhost.key /app/certificates/localhost.key -COPY --chmod=0644 api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/main/docker/certificates/localhost-truststore.p12 /app/certificates/localhost-truststore.p12 +# Copy certificates and health check script +COPY --chmod=0755 api-sheriff-integration-tests/src/main/docker/health-check.sh /app/health-check.sh +COPY --chmod=0644 api-sheriff-integration-tests/src/main/docker/certificates/localhost.crt /app/certificates/localhost.crt +COPY --chmod=0600 api-sheriff-integration-tests/src/main/docker/certificates/localhost.key /app/certificates/localhost.key +COPY --chmod=0644 api-sheriff-integration-tests/src/main/docker/certificates/localhost-truststore.p12 /app/certificates/localhost-truststore.p12 EXPOSE 8443 HEALTHCHECK --interval=15s --timeout=5s --retries=3 --start-period=10s CMD ["/app/health-check.sh"] diff --git a/api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/main/docker/Dockerfile.native.jfr b/api-sheriff-integration-tests/src/main/docker/Dockerfile.native.jfr similarity index 64% rename from api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/main/docker/Dockerfile.native.jfr rename to api-sheriff-integration-tests/src/main/docker/Dockerfile.native.jfr index 33a56f5f..a559f910 100644 --- a/api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/main/docker/Dockerfile.native.jfr +++ b/api-sheriff-integration-tests/src/main/docker/Dockerfile.native.jfr @@ -12,13 +12,13 @@ LABEL performance.jfr.enabled="true" WORKDIR /app # Copy pre-built native executable from Maven target directory -COPY --chmod=0755 api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/target/*-runner /app/application +COPY --chmod=0755 api-sheriff-integration-tests/target/*-runner /app/application # Copy certificates and health check script -COPY --chmod=0755 api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/main/docker/health-check.sh /app/health-check.sh -COPY --chmod=0644 api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/main/docker/certificates/localhost.crt /app/certificates/localhost.crt -COPY --chmod=0600 api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/main/docker/certificates/localhost.key /app/certificates/localhost.key -COPY --chmod=0644 api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/main/docker/certificates/localhost-truststore.p12 /app/certificates/localhost-truststore.p12 +COPY --chmod=0755 api-sheriff-integration-tests/src/main/docker/health-check.sh /app/health-check.sh +COPY --chmod=0644 api-sheriff-integration-tests/src/main/docker/certificates/localhost.crt /app/certificates/localhost.crt +COPY --chmod=0600 api-sheriff-integration-tests/src/main/docker/certificates/localhost.key /app/certificates/localhost.key +COPY --chmod=0644 api-sheriff-integration-tests/src/main/docker/certificates/localhost-truststore.p12 /app/certificates/localhost-truststore.p12 # Create JFR output directory with proper permissions RUN mkdir -p /tmp/jfr-output && chmod 777 /tmp/jfr-output diff --git a/api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/main/docker/certificates/generate-certificates.sh b/api-sheriff-integration-tests/src/main/docker/certificates/generate-certificates.sh similarity index 100% rename from api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/main/docker/certificates/generate-certificates.sh rename to api-sheriff-integration-tests/src/main/docker/certificates/generate-certificates.sh diff --git a/api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/main/docker/certificates/generate-truststore.sh b/api-sheriff-integration-tests/src/main/docker/certificates/generate-truststore.sh similarity index 100% rename from api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/main/docker/certificates/generate-truststore.sh rename to api-sheriff-integration-tests/src/main/docker/certificates/generate-truststore.sh diff --git a/api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/main/docker/certificates/localhost-truststore.p12 b/api-sheriff-integration-tests/src/main/docker/certificates/localhost-truststore.p12 similarity index 100% rename from api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/main/docker/certificates/localhost-truststore.p12 rename to api-sheriff-integration-tests/src/main/docker/certificates/localhost-truststore.p12 diff --git a/api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/main/docker/certificates/localhost.crt b/api-sheriff-integration-tests/src/main/docker/certificates/localhost.crt similarity index 100% rename from api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/main/docker/certificates/localhost.crt rename to api-sheriff-integration-tests/src/main/docker/certificates/localhost.crt diff --git a/api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/main/docker/certificates/localhost.key b/api-sheriff-integration-tests/src/main/docker/certificates/localhost.key similarity index 100% rename from api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/main/docker/certificates/localhost.key rename to api-sheriff-integration-tests/src/main/docker/certificates/localhost.key diff --git a/api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/main/docker/health-check.sh b/api-sheriff-integration-tests/src/main/docker/health-check.sh similarity index 100% rename from api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/main/docker/health-check.sh rename to api-sheriff-integration-tests/src/main/docker/health-check.sh diff --git a/api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/main/docker/keycloak/benchmark-realm.json b/api-sheriff-integration-tests/src/main/docker/keycloak/benchmark-realm.json similarity index 100% rename from api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/main/docker/keycloak/benchmark-realm.json rename to api-sheriff-integration-tests/src/main/docker/keycloak/benchmark-realm.json diff --git a/api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/main/docker/keycloak/integration-realm.json b/api-sheriff-integration-tests/src/main/docker/keycloak/integration-realm.json similarity index 100% rename from api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/main/docker/keycloak/integration-realm.json rename to api-sheriff-integration-tests/src/main/docker/keycloak/integration-realm.json diff --git a/api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/main/java/de/cuioss/sheriff/api/integration/TestApplication.java b/api-sheriff-integration-tests/src/main/java/de/cuioss/sheriff/api/integration/TestApplication.java similarity index 90% rename from api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/main/java/de/cuioss/sheriff/api/integration/TestApplication.java rename to api-sheriff-integration-tests/src/main/java/de/cuioss/sheriff/api/integration/TestApplication.java index 9bf1a2f2..5709c446 100644 --- a/api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/main/java/de/cuioss/sheriff/api/integration/TestApplication.java +++ b/api-sheriff-integration-tests/src/main/java/de/cuioss/sheriff/api/integration/TestApplication.java @@ -1,12 +1,12 @@ /* - * Copyright 2025 the original author or authors. - * <p> + * Copyright ยฉ 2025 CUI-OpenSource-Software (info@cuioss.de) + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * <p> - * https://www.apache.org/licenses/LICENSE-2.0 - * <p> + * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. diff --git a/api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/main/java/de/cuioss/sheriff/api/integration/TestResource.java b/api-sheriff-integration-tests/src/main/java/de/cuioss/sheriff/api/integration/TestResource.java similarity index 82% rename from api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/main/java/de/cuioss/sheriff/api/integration/TestResource.java rename to api-sheriff-integration-tests/src/main/java/de/cuioss/sheriff/api/integration/TestResource.java index 92a58ec3..02944354 100644 --- a/api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/main/java/de/cuioss/sheriff/api/integration/TestResource.java +++ b/api-sheriff-integration-tests/src/main/java/de/cuioss/sheriff/api/integration/TestResource.java @@ -1,12 +1,12 @@ /* - * Copyright 2025 the original author or authors. - * <p> + * Copyright ยฉ 2025 CUI-OpenSource-Software (info@cuioss.de) + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * <p> - * https://www.apache.org/licenses/LICENSE-2.0 - * <p> + * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -53,20 +53,20 @@ public Response health() { // Verify that ApiSheriff is properly injected and configured if (apiSheriff == null) { return Response.status(Response.Status.SERVICE_UNAVAILABLE) - .entity("{\"status\":\"DOWN\",\"reason\":\"ApiSheriff not available\"}") - .build(); + .entity("{\"status\":\"DOWN\",\"reason\":\"ApiSheriff not available\"}") + .build(); } // Get status to verify it's working String status = apiSheriff.getStatus(); - + return Response.ok("{\"status\":\"UP\",\"apiSheriff\":\"" + status + "\"}") - .build(); + .build(); - } catch (Exception e) { + } /*~~(TODO: Catch specific not Exception. Suppress: // cui-rewrite:disable InvalidExceptionUsageRecipe)~~>*/catch (Exception e) { return Response.status(Response.Status.INTERNAL_SERVER_ERROR) - .entity("{\"status\":\"DOWN\",\"error\":\"" + e.getMessage() + "\"}") - .build(); + .entity("{\"status\":\"DOWN\",\"error\":\"" + e.getMessage() + "\"}") + .build(); } } @@ -80,6 +80,6 @@ public Response health() { @Produces(MediaType.APPLICATION_JSON) public Response info() { return Response.ok("{\"message\":\"API Sheriff Integration Test\",\"version\":\"1.0.0-SNAPSHOT\"}") - .build(); + .build(); } } \ No newline at end of file diff --git a/api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/main/resources/application.properties b/api-sheriff-integration-tests/src/main/resources/application.properties similarity index 100% rename from api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/main/resources/application.properties rename to api-sheriff-integration-tests/src/main/resources/application.properties diff --git a/api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/main/resources/test-jwks.json b/api-sheriff-integration-tests/src/main/resources/test-jwks.json similarity index 100% rename from api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/main/resources/test-jwks.json rename to api-sheriff-integration-tests/src/main/resources/test-jwks.json diff --git a/api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/main/resources/test-public-key.pem b/api-sheriff-integration-tests/src/main/resources/test-public-key.pem similarity index 100% rename from api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/main/resources/test-public-key.pem rename to api-sheriff-integration-tests/src/main/resources/test-public-key.pem diff --git a/api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/test/java/de/cuioss/sheriff/api/integration/ApiSheriffIntegrationIT.java b/api-sheriff-integration-tests/src/test/java/de/cuioss/sheriff/api/integration/ApiSheriffIntegrationIT.java similarity index 80% rename from api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/test/java/de/cuioss/sheriff/api/integration/ApiSheriffIntegrationIT.java rename to api-sheriff-integration-tests/src/test/java/de/cuioss/sheriff/api/integration/ApiSheriffIntegrationIT.java index ffde8f57..6f4f546a 100644 --- a/api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/test/java/de/cuioss/sheriff/api/integration/ApiSheriffIntegrationIT.java +++ b/api-sheriff-integration-tests/src/test/java/de/cuioss/sheriff/api/integration/ApiSheriffIntegrationIT.java @@ -1,12 +1,12 @@ /* - * Copyright 2025 the original author or authors. - * <p> + * Copyright ยฉ 2025 CUI-OpenSource-Software (info@cuioss.de) + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * <p> - * https://www.apache.org/licenses/LICENSE-2.0 - * <p> + * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -28,18 +28,18 @@ * * @author API Sheriff Team */ -public class ApiSheriffIntegrationIT extends BaseIntegrationTest { +class ApiSheriffIntegrationIT extends BaseIntegrationTest { /** * Test that the health endpoint returns a successful response, * indicating that API Sheriff is properly configured. */ @Test - public void testApiSheriffHealthEndpoint() { + void apiSheriffHealthEndpoint() { given() - .when() + .when() .get("/test/health") - .then() + .then() .statusCode(200) .contentType("application/json") .body("status", is("UP")) @@ -50,11 +50,11 @@ public void testApiSheriffHealthEndpoint() { * Test that the info endpoint returns expected information. */ @Test - public void testInfoEndpoint() { + void infoEndpoint() { given() - .when() + .when() .get("/test/info") - .then() + .then() .statusCode(200) .contentType("application/json") .body("message", containsString("API Sheriff Integration Test")) @@ -65,11 +65,11 @@ public void testInfoEndpoint() { * Test that the Quarkus health check endpoint is available. */ @Test - public void testQuarkusHealthEndpoint() { + void quarkusHealthEndpoint() { given() - .when() + .when() .get("/q/health") - .then() + .then() .statusCode(200) .contentType("application/json"); } @@ -78,11 +78,11 @@ public void testQuarkusHealthEndpoint() { * Test that metrics endpoint is available (from Micrometer integration). */ @Test - public void testMetricsEndpoint() { + void metricsEndpoint() { given() - .when() + .when() .get("/q/metrics") - .then() + .then() .statusCode(200); } } \ No newline at end of file diff --git a/api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/test/java/de/cuioss/sheriff/api/integration/BaseIntegrationTest.java b/api-sheriff-integration-tests/src/test/java/de/cuioss/sheriff/api/integration/BaseIntegrationTest.java similarity index 83% rename from api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/test/java/de/cuioss/sheriff/api/integration/BaseIntegrationTest.java rename to api-sheriff-integration-tests/src/test/java/de/cuioss/sheriff/api/integration/BaseIntegrationTest.java index 474c3be6..f123a698 100644 --- a/api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/test/java/de/cuioss/sheriff/api/integration/BaseIntegrationTest.java +++ b/api-sheriff-integration-tests/src/test/java/de/cuioss/sheriff/api/integration/BaseIntegrationTest.java @@ -1,12 +1,12 @@ /* - * Copyright 2025 the original author or authors. - * <p> + * Copyright ยฉ 2025 CUI-OpenSource-Software (info@cuioss.de) + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * <p> - * https://www.apache.org/licenses/LICENSE-2.0 - * <p> + * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -39,6 +39,6 @@ static void setUpBaseIntegrationTest() { String testPort = System.getProperty("test.https.port", DEFAULT_TEST_PORT); RestAssured.port = Integer.parseInt(testPort); - System.out.println("Integration tests configured for HTTPS port: " + testPort); + /*~~(TODO: Use CuiLogger. Suppress: // cui-rewrite:disable CuiLoggerStandardsRecipe)~~>*/System.out.println("Integration tests configured for HTTPS port: " + testPort); } } \ No newline at end of file diff --git a/api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/test/resources/keys/test_public_key.pem b/api-sheriff-integration-tests/src/test/resources/keys/test_public_key.pem similarity index 100% rename from api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/src/test/resources/keys/test_public_key.pem rename to api-sheriff-integration-tests/src/test/resources/keys/test_public_key.pem diff --git a/api-sheriff-library/README.adoc b/api-sheriff-library/README.adoc deleted file mode 100644 index 40cd2dac..00000000 --- a/api-sheriff-library/README.adoc +++ /dev/null @@ -1,155 +0,0 @@ -= API Sheriff Library - -The core library module providing lightweight, high-performance API gateway functionality with comprehensive security features and rate limiting capabilities. - -== Overview - -The API Sheriff Library is the foundational component of the API Sheriff project, providing essential security and rate limiting functionality for API gateways. It's designed to be framework-agnostic and can be integrated into any Java application. - -== Key Components - -=== ApiSheriff -The main gateway class that coordinates all security measures and API gateway features. - -[source,java] ----- -ApiGatewayConfig config = ApiGatewayConfig.builder() - .rateLimit(100) - .timeWindow(Duration.ofMinutes(1)) - .requestTimeout(Duration.ofSeconds(30)) - .corsEnabled(true) - .build(); - -ApiSheriff sheriff = new ApiSheriff(config); - -if (sheriff.isRequestAllowed("client-123", "/api/users")) { - // Process request -} ----- - -=== ApiGatewayConfig -Flexible configuration system using the builder pattern with comprehensive validation. - -[source,java] ----- -ApiGatewayConfig config = ApiGatewayConfig.builder() - .rateLimit(1000) - .timeWindow(Duration.ofMinutes(5)) - .requestTimeout(Duration.ofSeconds(60)) - .corsEnabled(false) - .customProperty("feature.auth", true) - .build(); ----- - -=== RateLimiter -Thread-safe rate limiter implementation using a sliding window approach for accurate rate limiting. - -[source,java] ----- -RateLimiter rateLimiter = new RateLimiter(100, Duration.ofMinutes(1).toMillis()); - -if (rateLimiter.isRequestAllowed("client-id")) { - // Process request -} - -// Check remaining requests -int remaining = rateLimiter.getRemainingRequests("client-id"); ----- - -== Features - -* **Thread-Safe**: All components are designed for concurrent access -* **High Performance**: Optimized for minimal latency and high throughput -* **Configurable**: Extensive configuration options with sensible defaults -* **Monitoring**: Built-in logging and metrics support -* **Validation**: Comprehensive input validation with meaningful error messages -* **Multi-tenant**: Per-client rate limiting and state management - -== Usage Patterns - -=== Basic Rate Limiting -[source,java] ----- -ApiSheriff sheriff = new ApiSheriff( - ApiGatewayConfig.builder() - .rateLimit(50) - .timeWindow(Duration.ofMinutes(1)) - .build() -); - -boolean allowed = sheriff.isRequestAllowed("client-123", "/api/endpoint"); ----- - -=== Configuration Validation -[source,java] ----- -Optional<String> validationError = sheriff.validateConfiguration(); -if (validationError.isPresent()) { - log.error("Configuration invalid: {}", validationError.get()); -} ----- - -=== Client State Management -[source,java] ----- -// Reset specific client -sheriff.resetClientState("problematic-client"); - -// Get rate limiter statistics -RateLimiter rateLimiter = sheriff.getRateLimiter(); -int trackedClients = rateLimiter.getTrackedClientCount(); ----- - -== Maven Coordinates - -[source,xml] ----- -<dependency> - <groupId>de.cuioss.sheriff.api</groupId> - <artifactId>api-sheriff-library</artifactId> - <version>${api-sheriff.version}</version> -</dependency> ----- - -== Dependencies - -The library has minimal dependencies: - -* **Lombok**: For code generation and boilerplate reduction -* **CUI Tools**: For logging and utility functions -* **Jakarta JSON API**: For JSON processing (provided scope) - -== Thread Safety - -All public APIs are thread-safe and can be safely called from multiple threads concurrently. The implementation uses: - -* `ConcurrentHashMap` for client state management -* `AtomicInteger` for counters -* `synchronized` blocks for critical sections -* Immutable configuration objects - -== Performance Characteristics - -* **Memory**: Minimal memory footprint with efficient data structures -* **Latency**: Sub-millisecond request validation in most cases -* **Throughput**: Supports thousands of requests per second per instance -* **Scaling**: Linear scaling with client count and request volume - -== Testing - -The library includes comprehensive unit tests and performance benchmarks: - -* Unit tests with >90% code coverage -* Parameterized tests for edge cases -* Concurrent access testing -* Performance benchmarks with JMH - -== Integration - -The library can be integrated into various environments: - -* Standalone Java applications -* Spring Boot applications -* Quarkus applications (see api-sheriff-quarkus module) -* Jakarta EE applications -* Any framework supporting standard Java libraries \ No newline at end of file diff --git a/api-sheriff-library/src/test/java/de/cuioss/sheriff/api/test/TestDataGenerator.java b/api-sheriff-library/src/test/java/de/cuioss/sheriff/api/test/TestDataGenerator.java deleted file mode 100644 index 7a5d717e..00000000 --- a/api-sheriff-library/src/test/java/de/cuioss/sheriff/api/test/TestDataGenerator.java +++ /dev/null @@ -1,26 +0,0 @@ -package de.cuioss.sheriff.api.test; - -import lombok.experimental.UtilityClass; - -/** - * Test data generator for API Sheriff tests - */ -@UtilityClass -public class TestDataGenerator { - - /** - * Generates a test API key - * @return test API key - */ - public static String generateApiKey() { - return "test-api-key-" + System.currentTimeMillis(); - } - - /** - * Generates a test endpoint URL - * @return test endpoint URL - */ - public static String generateEndpoint() { - return "https://api.example.com/v1/test-" + System.currentTimeMillis(); - } -} \ No newline at end of file diff --git a/api-sheriff-quarkus-parent/README.adoc b/api-sheriff-quarkus-parent/README.adoc deleted file mode 100644 index 1eca5b8b..00000000 --- a/api-sheriff-quarkus-parent/README.adoc +++ /dev/null @@ -1,273 +0,0 @@ -= API Sheriff Quarkus Extension - -Native Quarkus extension providing seamless integration of API Sheriff functionality into Quarkus applications with CDI support, configuration binding, and native image compatibility. - -== Overview - -The API Sheriff Quarkus Extension provides first-class integration between API Sheriff and Quarkus, leveraging Quarkus's dependency injection, configuration management, and build-time optimizations for optimal performance and ease of use. - -== Modules - -=== api-sheriff-quarkus -Runtime components including CDI producers and configuration binding. - -=== api-sheriff-quarkus-deployment -Build-time components for Quarkus native image compilation and dependency injection setup. - -=== api-sheriff-quarkus-integration-tests -Comprehensive integration tests for the Quarkus extension. - -== Features - -* **CDI Integration**: Automatic bean registration and dependency injection -* **Configuration Binding**: Native Quarkus configuration property support -* **Native Image Support**: Full GraalVM native image compatibility -* **Build-time Optimization**: Quarkus build-time processing for optimal performance -* **Health Checks**: Built-in health check support -* **Metrics Integration**: MicroProfile Metrics support -* **Hot Reload**: Development mode with hot reload support - -== Quick Start - -=== 1. Add Dependency - -[source,xml] ----- -<dependency> - <groupId>de.cuioss.sheriff.api</groupId> - <artifactId>api-sheriff-quarkus</artifactId> - <version>${api-sheriff.version}</version> -</dependency> ----- - -=== 2. Configure Application - -Add to your `application.properties`: - -[source,properties] ----- -# Rate limiting configuration -api-sheriff.rate-limit=200 -api-sheriff.time-window=60 -api-sheriff.request-timeout=30 -api-sheriff.cors-enabled=true ----- - -=== 3. Inject and Use - -[source,java] ----- -@RestController -@ApplicationScoped -public class ApiGatewayResource { - - @Inject - ApiSheriff apiSheriff; - - @GET - @Path("/check/{clientId}") - public Response checkRequest(@PathParam("clientId") String clientId, - @QueryParam("endpoint") String endpoint) { - - if (apiSheriff.isRequestAllowed(clientId, endpoint)) { - return Response.ok("Request allowed").build(); - } else { - return Response.status(429).entity("Rate limit exceeded").build(); - } - } -} ----- - -== Configuration Properties - -All configuration properties are prefixed with `api-sheriff.`: - -[cols="1,1,2,1"] -|=== -|Property |Type |Description |Default - -|`rate-limit` -|Integer -|Maximum requests per client within time window -|100 - -|`time-window` -|Long -|Time window in seconds for rate limiting -|60 - -|`request-timeout` -|Long -|Request timeout in seconds -|30 - -|`cors-enabled` -|Boolean -|Enable CORS support -|false -|=== - -=== Environment Variables - -Configuration can also be provided via environment variables: - -[source,bash] ----- -API_SHERIFF_RATE_LIMIT=500 -API_SHERIFF_TIME_WINDOW=120 -API_SHERIFF_REQUEST_TIMEOUT=45 -API_SHERIFF_CORS_ENABLED=true ----- - -== Advanced Usage - -=== Custom Configuration - -[source,java] ----- -@ApplicationScoped -public class CustomApiSheriffProducer { - - @Produces - @Alternative - @Priority(1000) - public ApiGatewayConfig customConfig() { - return ApiGatewayConfig.builder() - .rateLimit(1000) - .timeWindow(Duration.ofMinutes(5)) - .customProperty("tenant.isolation", true) - .build(); - } -} ----- - -=== Integration with REST Endpoints - -[source,java] ----- -@ApplicationScoped -public class RateLimitingFilter implements ContainerRequestFilter { - - @Inject - ApiSheriff apiSheriff; - - @Override - public void filter(ContainerRequestContext context) throws IOException { - String clientId = extractClientId(context); - String endpoint = context.getUriInfo().getPath(); - - if (!apiSheriff.isRequestAllowed(clientId, endpoint)) { - context.abortWith( - Response.status(429) - .entity("Rate limit exceeded") - .build() - ); - } - } -} ----- - -=== Health Checks - -[source,java] ----- -@ApplicationScoped -public class ApiSheriffHealthCheck implements HealthCheck { - - @Inject - ApiSheriff apiSheriff; - - @Override - public HealthCheckResponse call() { - Optional<String> validationError = apiSheriff.validateConfiguration(); - - if (validationError.isEmpty()) { - return HealthCheckResponse.up("api-sheriff"); - } else { - return HealthCheckResponse.down("api-sheriff") - .withData("error", validationError.get()); - } - } -} ----- - -== Development Mode - -The extension supports Quarkus development mode with hot reload: - -[source,bash] ----- -./mvnw quarkus:dev ----- - -Configuration changes in `application.properties` will be automatically reloaded. - -== Native Image - -The extension is fully compatible with GraalVM native image compilation: - -[source,bash] ----- -./mvnw clean package -Pnative ----- - -All necessary reflection and resource configurations are automatically handled by the build processor. - -== Testing - -=== Unit Testing - -[source,java] ----- -@QuarkusTest -class ApiSheriffExtensionTest { - - @Inject - ApiSheriff apiSheriff; - - @Test - void shouldInjectApiSheriff() { - assertNotNull(apiSheriff); - assertTrue(apiSheriff.isRequestAllowed("test-client", "/api/test")); - } -} ----- - -=== Integration Testing - -[source,java] ----- -@QuarkusTest -class ApiGatewayIntegrationTest { - - @Test - void shouldRespectRateLimit() { - given() - .pathParam("clientId", "test-client") - .queryParam("endpoint", "/api/test") - .when() - .get("/check/{clientId}") - .then() - .statusCode(200); - } -} ----- - -== Performance - -The Quarkus extension is optimized for: - -* **Startup Time**: Build-time dependency injection setup -* **Memory Usage**: Minimal runtime overhead -* **Native Image**: Full GraalVM native image support -* **Hot Reload**: Fast development cycle iteration - -== Migration from Core Library - -If migrating from the core library to the Quarkus extension: - -1. Replace `api-sheriff-library` dependency with `api-sheriff-quarkus` -2. Remove manual `ApiSheriff` instantiation -3. Add `@Inject ApiSheriff` to your components -4. Move configuration to `application.properties` -5. Optional: Add health checks and metrics integration \ No newline at end of file diff --git a/api-sheriff-quarkus-parent/api-sheriff-quarkus-deployment/package-lock.json b/api-sheriff-quarkus-parent/api-sheriff-quarkus-deployment/package-lock.json deleted file mode 100644 index 8d382aea..00000000 --- a/api-sheriff-quarkus-parent/api-sheriff-quarkus-deployment/package-lock.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "name": "api-sheriff-quarkus-deployment", - "version": "1.0.0-SNAPSHOT", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "api-sheriff-quarkus-deployment", - "version": "1.0.0-SNAPSHOT" - } - } -} diff --git a/api-sheriff-quarkus-parent/api-sheriff-quarkus-deployment/package.json b/api-sheriff-quarkus-parent/api-sheriff-quarkus-deployment/package.json deleted file mode 100644 index b978044a..00000000 --- a/api-sheriff-quarkus-parent/api-sheriff-quarkus-deployment/package.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "name": "api-sheriff-quarkus-deployment", - "version": "1.0.0-SNAPSHOT", - "description": "Deployment module for Quarkus integration for API Sheriff", - "private": true, - "scripts": { - "test:ci-strict": "echo 'No JavaScript tests to run'", - "format:check": "echo 'No JavaScript formatting to check'", - "validate:css": "echo 'No CSS to validate'", - "lint": "echo 'No JavaScript to lint'" - } -} \ No newline at end of file diff --git a/api-sheriff-quarkus-parent/api-sheriff-quarkus-deployment/pom.xml b/api-sheriff-quarkus-parent/api-sheriff-quarkus-deployment/pom.xml deleted file mode 100644 index ec7b9b8f..00000000 --- a/api-sheriff-quarkus-parent/api-sheriff-quarkus-deployment/pom.xml +++ /dev/null @@ -1,229 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project xmlns="http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> - <modelVersion>4.0.0</modelVersion> - <parent> - <groupId>de.cuioss.sheriff.api</groupId> - <artifactId>api-sheriff-quarkus-parent</artifactId> - <version>1.0.0-SNAPSHOT</version> - <relativePath>../pom.xml</relativePath> - </parent> - - <artifactId>api-sheriff-quarkus-deployment</artifactId> - <packaging>jar</packaging> - <name>API Sheriff Quarkus Integration - Deployment</name> - <description>Deployment module for Quarkus integration for API Sheriff</description> - - <properties> - <maven.jar.plugin.automatic.module.name>de.cuioss.sheriff.api.quarkus.deployment</maven.jar.plugin.automatic.module.name> - - <!-- Sonar configuration for JavaScript coverage --> - <sonar.javascript.lcov.reportPaths>target/coverage/lcov.info</sonar.javascript.lcov.reportPaths> - <sonar.coverage.exclusions>**/*.test.js,**/test/**/*,**/mocks/**/*</sonar.coverage.exclusions> - <sonar.javascript.file.suffixes>.js</sonar.javascript.file.suffixes> - <sonar.javascript.coverage.overall_condition.branch>55</sonar.javascript.coverage.overall_condition.branch> - <sonar.javascript.coverage.new_condition.branch>55</sonar.javascript.coverage.new_condition.branch> - - <!-- JaCoCo configuration for Java code coverage --> - <sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths> - </properties> - - <dependencies> - <!-- Runtime module dependency --> - <dependency> - <groupId>de.cuioss.sheriff.api</groupId> - <artifactId>api-sheriff-quarkus</artifactId> - </dependency> - - <!-- Quarkus deployment dependencies --> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-core-deployment</artifactId> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-arc-deployment</artifactId> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-micrometer-deployment</artifactId> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-security-deployment</artifactId> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-smallrye-health-deployment</artifactId> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-vertx-http-deployment</artifactId> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-scheduler-deployment</artifactId> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-config-yaml-deployment</artifactId> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-hibernate-validator-deployment</artifactId> - </dependency> - <!-- DevUI integration --> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-devui-deployment-spi</artifactId> - </dependency> - - <!-- Test dependencies --> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-junit5-internal</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.jboss.logmanager</groupId> - <artifactId>jboss-logmanager</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.junit.jupiter</groupId> - <artifactId>junit-jupiter</artifactId> - <scope>test</scope> - </dependency> - </dependencies> - - <build> - <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-compiler-plugin</artifactId> - <configuration> - <annotationProcessorPaths> - <path> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-extension-processor</artifactId> - </path> - </annotationProcessorPaths> - <!-- Use release instead of source/target to properly handle modules --> - <release>21</release> - </configuration> - </plugin> - <plugin> - <groupId>com.github.eirslett</groupId> - <artifactId>frontend-maven-plugin</artifactId> - <configuration> - <nodeVersion>${frontend.node.version}</nodeVersion> - <npmVersion>${frontend.npm.version}</npmVersion> - <installDirectory>target</installDirectory> - </configuration> - <executions> - <execution> - <id>install-node-and-npm</id> - <goals> - <goal>install-node-and-npm</goal> - </goals> - </execution> - <execution> - <id>npm-install</id> - <goals> - <goal>npm</goal> - </goals> - <configuration> - <arguments>install</arguments> - </configuration> - </execution> - <execution> - <id>npm-test</id> - <goals> - <goal>npm</goal> - </goals> - <phase>test</phase> - <configuration> - <arguments>run test:ci-strict</arguments> - </configuration> - </execution> - <execution> - <id>npm-format-check</id> - <goals> - <goal>npm</goal> - </goals> - <phase>compile</phase> - <configuration> - <arguments>run format:check</arguments> - </configuration> - </execution> - <execution> - <id>npm-css-validate</id> - <goals> - <goal>npm</goal> - </goals> - <phase>compile</phase> - <configuration> - <arguments>run validate:css</arguments> - </configuration> - </execution> - <execution> - <id>npm-lint</id> - <goals> - <goal>npm</goal> - </goals> - <phase>compile</phase> - <configuration> - <arguments>run lint</arguments> - </configuration> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-surefire-plugin</artifactId> - <configuration> - <!-- Override argLine to include JaCoCo agent --> - <argLine>@{argLine} -XX:+IgnoreUnrecognizedVMOptions -Djava.awt.headless=true</argLine> - </configuration> - </plugin> - <!-- Add JaCoCo for code coverage with Sonar --> - <plugin> - <groupId>org.jacoco</groupId> - <artifactId>jacoco-maven-plugin</artifactId> - <executions> - <execution> - <id>prepare-agent</id> - <goals> - <goal>prepare-agent</goal> - </goals> - <configuration> - <!-- Configure JaCoCo to work with deployment tests --> - <includes> - <include>de/cuioss/sheriff/api/quarkus/deployment/**</include> - </includes> - <!-- Ensure JaCoCo agent is properly attached to tests --> - <append>true</append> - <!-- Ensure destination file is set --> - <destFile>${project.build.directory}/jacoco.exec</destFile> - </configuration> - </execution> - <execution> - <id>report</id> - <phase>test</phase> - <goals> - <goal>report</goal> - </goals> - <configuration> - <outputDirectory>${project.build.directory}/site/jacoco</outputDirectory> - <formats> - <format>XML</format> - <format>HTML</format> - </formats> - </configuration> - </execution> - </executions> - </plugin> - </plugins> - </build> -</project> \ No newline at end of file diff --git a/api-sheriff-quarkus-parent/api-sheriff-quarkus-deployment/src/main/java/de/cuioss/sheriff/api/quarkus/deployment/ApiSheriffProcessor.java b/api-sheriff-quarkus-parent/api-sheriff-quarkus-deployment/src/main/java/de/cuioss/sheriff/api/quarkus/deployment/ApiSheriffProcessor.java deleted file mode 100644 index 65d9eaa3..00000000 --- a/api-sheriff-quarkus-parent/api-sheriff-quarkus-deployment/src/main/java/de/cuioss/sheriff/api/quarkus/deployment/ApiSheriffProcessor.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright 2025 the original author or authors. - * <p> - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * <p> - * https://www.apache.org/licenses/LICENSE-2.0 - * <p> - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.cuioss.sheriff.api.quarkus.deployment; - -import io.quarkus.arc.deployment.AdditionalBeanBuildItem; -import io.quarkus.arc.deployment.BeanContainerBuildItem; -import io.quarkus.deployment.annotations.BuildProducer; -import io.quarkus.deployment.annotations.BuildStep; -import io.quarkus.deployment.annotations.ExecutionTime; -import io.quarkus.deployment.annotations.Record; -import io.quarkus.deployment.builditem.CombinedIndexBuildItem; -import io.quarkus.deployment.builditem.FeatureBuildItem; -import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem; - -import de.cuioss.sheriff.api.ApiSheriff; -import de.cuioss.sheriff.api.quarkus.ApiSheriffProducer; - -/** - * Quarkus build step processor for API Sheriff extension. - * This class configures the API Sheriff components for Quarkus applications during build time. - * - * <p>The processor handles:</p> - * <ul> - * <li>Feature registration for the API Sheriff extension</li> - * <li>CDI bean registration for automatic dependency injection</li> - * <li>Native image configuration for GraalVM compilation</li> - * <li>Reflection registration for runtime class access</li> - * </ul> - * - * <h2>Build Time Configuration:</h2> - * <p>This processor runs during Quarkus build time and prepares all necessary - * components for runtime. It ensures that API Sheriff classes are properly - * registered with CDI and configured for native image compilation.</p> - * - * <h2>Native Image Support:</h2> - * <p>The processor automatically registers classes that require reflection - * access during native image execution, ensuring that the API Sheriff - * functionality works correctly in both JVM and native modes.</p> - * - * @author API Sheriff Team - */ -public class ApiSheriffProcessor { - - private static final String FEATURE = "api-sheriff"; - - /** - * Registers the API Sheriff feature with Quarkus. - * This build step creates a feature item that identifies the API Sheriff - * extension in the Quarkus runtime. - * - * @return FeatureBuildItem for API Sheriff - */ - @BuildStep - FeatureBuildItem feature() { - return new FeatureBuildItem(FEATURE); - } - - /** - * Registers API Sheriff classes as CDI beans. - * This build step ensures that all API Sheriff components are available - * for dependency injection in the Quarkus application. - * - * @param additionalBeans producer for additional CDI beans - */ - @BuildStep - void addBeans(BuildProducer<AdditionalBeanBuildItem> additionalBeans) { - // Register only the producer class - it will handle bean creation - additionalBeans.produce(AdditionalBeanBuildItem.unremovableOf(ApiSheriffProducer.class)); - } - - /** - * Registers classes for reflection in native image. - * This build step ensures that API Sheriff classes that require reflection - * access are properly registered for GraalVM native image compilation. - * - * @param reflectiveClass producer for reflective class registration - * @param combinedIndex the combined index of all classes - */ - @BuildStep - void addReflectiveClasses(BuildProducer<ReflectiveClassBuildItem> reflectiveClass, - CombinedIndexBuildItem combinedIndex) { - - // Register main API Sheriff classes for reflection - reflectiveClass.produce(ReflectiveClassBuildItem.builder(ApiSheriff.class) - .constructors() - .methods() - .fields() - .build()); - - - // Register the producer class for CDI proxy generation - reflectiveClass.produce(ReflectiveClassBuildItem.builder(ApiSheriffProducer.class) - .constructors() - .methods() - .fields() - .build()); - } - - -} \ No newline at end of file diff --git a/api-sheriff-quarkus-parent/api-sheriff-quarkus/pom.xml b/api-sheriff-quarkus-parent/api-sheriff-quarkus/pom.xml deleted file mode 100644 index d62316bb..00000000 --- a/api-sheriff-quarkus-parent/api-sheriff-quarkus/pom.xml +++ /dev/null @@ -1,203 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project xmlns="http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> - <modelVersion>4.0.0</modelVersion> - <parent> - <groupId>de.cuioss.sheriff.api</groupId> - <artifactId>api-sheriff-quarkus-parent</artifactId> - <version>1.0.0-SNAPSHOT</version> - <relativePath>../pom.xml</relativePath> - </parent> - - <artifactId>api-sheriff-quarkus</artifactId> - <packaging>jar</packaging> - <name>API Sheriff Quarkus Integration - Runtime</name> - <description>Runtime module for Quarkus integration for API Sheriff, providing configuration, producers, - and integration from SecurityEvents to Micrometer - </description> - - <properties> - <maven.jar.plugin.automatic.module.name>de.cuioss.sheriff.api.quarkus</maven.jar.plugin.automatic.module.name> - </properties> - - <dependencies> - <!-- Test dependencies --> - <dependency> - <groupId>io.rest-assured</groupId> - <artifactId>rest-assured</artifactId> - <scope>test</scope> - </dependency> - - <!-- Other test dependencies --> - <dependency> - <groupId>org.jboss.logmanager</groupId> - <artifactId>jboss-logmanager</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.jboss.weld</groupId> - <artifactId>weld-junit5</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.junit.jupiter</groupId> - <artifactId>junit-jupiter</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>de.cuioss.sheriff.api</groupId> - <artifactId>api-sheriff-library</artifactId> - <version>${project.version}</version> - <classifier>generators</classifier> - <scope>test</scope> - </dependency> - - <!-- Runtime-specific dependencies can be added here --> - <!-- All common dependencies are inherited from parent --> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-scheduler</artifactId> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-config-yaml</artifactId> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-hibernate-validator</artifactId> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-smallrye-health</artifactId> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-vertx-http</artifactId> - <optional>true</optional> - </dependency> - <dependency> - <groupId>jakarta.servlet</groupId> - <artifactId>jakarta.servlet-api</artifactId> - <scope>provided</scope> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-resteasy</artifactId> - <optional>true</optional> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-jacoco</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.awaitility</groupId> - <artifactId>awaitility</artifactId> - <scope>test</scope> - </dependency> - <!-- JJWT dependencies. Reduced to testing --> - <dependency> - <groupId>io.jsonwebtoken</groupId> - <artifactId>jjwt-api</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>io.jsonwebtoken</groupId> - <artifactId>jjwt-impl</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>io.jsonwebtoken</groupId> - <artifactId>jjwt-jackson</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>de.cuioss.test</groupId> - <artifactId>cui-test-generator</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.easymock</groupId> - <artifactId>easymock</artifactId> - <version>${version.easymock}</version> - <scope>test</scope> - </dependency> - </dependencies> - - <build> - <plugins> - <plugin> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-maven-plugin</artifactId> - <!-- Use inherited configuration from pluginManagement --> - </plugin> - <plugin> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-extension-maven-plugin</artifactId> - <version>${version.quarkus}</version> - <executions> - <execution> - <phase>compile</phase> - <goals> - <goal>extension-descriptor</goal> - </goals> - <configuration> - <deployment>${project.groupId}:api-sheriff-quarkus-deployment:${project.version}</deployment> - </configuration> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-compiler-plugin</artifactId> - <configuration> - <annotationProcessorPaths> - <path> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-extension-processor</artifactId> - </path> - </annotationProcessorPaths> - <!-- Use release instead of source/target to properly handle modules --> - <release>21</release> - </configuration> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-surefire-plugin</artifactId> - <configuration> - <argLine>@{argLine} -XX:+IgnoreUnrecognizedVMOptions -Djava.awt.headless=true</argLine> - <systemPropertyVariables> - <quarkus.jacoco.reuse-data-file>true</quarkus.jacoco.reuse-data-file> - </systemPropertyVariables> - </configuration> - </plugin> - <!-- JaCoCo Plugin for test coverage --> - <plugin> - <groupId>org.jacoco</groupId> - <artifactId>jacoco-maven-plugin</artifactId> - <executions> - <execution> - <id>default-prepare-agent</id> - <goals> - <goal>prepare-agent</goal> - </goals> - </execution> - <execution> - <id>default-report</id> - <phase>test</phase> - <goals> - <goal>report</goal> - </goals> - <configuration> - <formats> - <format>XML</format> - <format>HTML</format> - </formats> - </configuration> - </execution> - </executions> - </plugin> - </plugins> - </build> -</project> \ No newline at end of file diff --git a/api-sheriff-quarkus-parent/api-sheriff-quarkus/src/main/java/de/cuioss/sheriff/api/quarkus/ApiSheriffRecorder.java b/api-sheriff-quarkus-parent/api-sheriff-quarkus/src/main/java/de/cuioss/sheriff/api/quarkus/ApiSheriffRecorder.java deleted file mode 100644 index e69de29b..00000000 diff --git a/api-sheriff-quarkus-parent/pom.xml b/api-sheriff-quarkus-parent/pom.xml deleted file mode 100644 index ec5a38f5..00000000 --- a/api-sheriff-quarkus-parent/pom.xml +++ /dev/null @@ -1,333 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project xmlns="http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> - <modelVersion>4.0.0</modelVersion> - <parent> - <groupId>de.cuioss.sheriff.api</groupId> - <artifactId>api-sheriff-parent</artifactId> - <version>1.0.0-SNAPSHOT</version> - <relativePath>../pom.xml</relativePath> - </parent> - - <artifactId>api-sheriff-quarkus-parent</artifactId> - <packaging>pom</packaging> - <name>API Sheriff Quarkus Integration Parent</name> - <description>Parent module for Quarkus integration for API Sheriff, providing configuration, producers, and integration from SecurityEvents to Micrometer</description> - - <modules> - <module>api-sheriff-quarkus</module> - <module>api-sheriff-quarkus-deployment</module> - <module>api-sheriff-quarkus-integration-tests</module> - </modules> - - <properties> - <!-- - Logging configuration: - - Use JBoss LogManager for tests (java.util.logging.manager=org.jboss.logmanager.LogManager) - - Configure logging.properties in each module's test resources - - Suppress JVM warnings with -XX:+IgnoreUnrecognizedVMOptions - --> - <version.weld-junit5>5.0.3.Final</version.weld-junit5> - <version.easymock>5.6.0</version.easymock> - <!-- Default empty argLine for JaCoCo compatibility - JaCoCo will override this when active --> - <argLine /> - </properties> - - <dependencyManagement> - <dependencies> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-bom</artifactId> - <version>${version.quarkus}</version> - <type>pom</type> - <scope>import</scope> - </dependency> - <dependency> - <groupId>de.cuioss.sheriff.api</groupId> - <artifactId>api-sheriff-bom</artifactId> - <version>${project.version}</version> - <type>pom</type> - <scope>import</scope> - </dependency> - <!-- Override JUnit Platform versions to match Jupiter (cui-java-parent provides - version.junit.jupiter, but the Quarkus BOM pins older Platform versions) --> - <dependency> - <groupId>org.junit.platform</groupId> - <artifactId>junit-platform-commons</artifactId> - <version>${version.junit.jupiter}</version> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.junit.platform</groupId> - <artifactId>junit-platform-engine</artifactId> - <version>${version.junit.jupiter}</version> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.junit.platform</groupId> - <artifactId>junit-platform-launcher</artifactId> - <version>${version.junit.jupiter}</version> - <scope>test</scope> - </dependency> - <!-- Additional dependencies --> - <dependency> - <groupId>org.jboss.weld</groupId> - <artifactId>weld-junit5</artifactId> - <version>${version.weld-junit5}</version> - <scope>test</scope> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-extension-processor</artifactId> - <version>${version.quarkus}</version> - </dependency> - </dependencies> - </dependencyManagement> - - <dependencies> - <!-- Internal module dependencies --> - <dependency> - <groupId>de.cuioss.sheriff.api</groupId> - <artifactId>api-sheriff-library</artifactId> - </dependency> - - <!-- Quarkus dependencies --> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-core</artifactId> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-arc</artifactId> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-micrometer</artifactId> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-security</artifactId> - </dependency> - - <!-- Other dependencies --> - <dependency> - <groupId>org.projectlombok</groupId> - <artifactId>lombok</artifactId> - </dependency> - - <!-- Test dependencies --> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-junit5</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>de.cuioss.test</groupId> - <artifactId>cui-test-juli-logger</artifactId> - <scope>test</scope> - </dependency> - </dependencies> - - <build> - <pluginManagement> - <plugins> - <plugin> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-maven-plugin</artifactId> - <version>${version.quarkus}</version> - <extensions>true</extensions> - <executions> - <execution> - <goals> - <goal>build</goal> - <goal>generate-code</goal> - <goal>generate-code-tests</goal> - </goals> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-compiler-plugin</artifactId> - <configuration> - <!-- Use release instead of source/target to properly handle modules --> - <release>21</release> - </configuration> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-surefire-plugin</artifactId> - <configuration> - <systemPropertyVariables> - <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager> - <java.util.logging.config.file>${project.build.testOutputDirectory}/logging.properties</java.util.logging.config.file> - <maven.home>${maven.home}</maven.home> - <quarkus.test.arg-line>@{argLine}</quarkus.test.arg-line> - </systemPropertyVariables> - <useModulePath>false</useModulePath> - <useFile>false</useFile> - <trimStackTrace>false</trimStackTrace> - <enableAssertions>true</enableAssertions> - <!-- JaCoCo-compatible argLine (will be empty if JaCoCo not active) --> - <argLine>@{argLine} -XX:+IgnoreUnrecognizedVMOptions -Djava.awt.headless=true</argLine> - <!-- Stability configurations --> - <forkedProcessTimeoutInSeconds>0</forkedProcessTimeoutInSeconds> - <forkedProcessExitTimeoutInSeconds>60</forkedProcessExitTimeoutInSeconds> - <!-- Fix for class loading issues --> - <useSystemClassLoader>false</useSystemClassLoader> - <reuseForks>false</reuseForks> - </configuration> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-failsafe-plugin</artifactId> - <configuration> - <systemPropertyVariables> - <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager> - <java.util.logging.config.file>${project.build.testOutputDirectory}/logging.properties</java.util.logging.config.file> - <maven.home>${maven.home}</maven.home> - <quarkus.test.arg-line>@{argLine}</quarkus.test.arg-line> - </systemPropertyVariables> - <useModulePath>false</useModulePath> - <useFile>false</useFile> - <trimStackTrace>false</trimStackTrace> - <enableAssertions>true</enableAssertions> - <argLine>@{argLine} -XX:+IgnoreUnrecognizedVMOptions -Djava.awt.headless=true</argLine> - <!-- Fix for class loading issues --> - <useSystemClassLoader>false</useSystemClassLoader> - <reuseForks>false</reuseForks> - <!-- Standardized IT naming patterns --> - <includes> - <include>**/*IT.java</include> - <include>**/*IntegrationTest.java</include> - </includes> - </configuration> - <executions> - <execution> - <goals> - <goal>integration-test</goal> - <goal>verify</goal> - </goals> - </execution> - </executions> - </plugin> - </plugins> - </pluginManagement> - <!-- No plugins in parent - all configurations inherited from pluginManagement --> - </build> - - <profiles> - <profile> - <id>coverage</id> - <build> - <pluginManagement> - <plugins> - <plugin> - <groupId>org.jacoco</groupId> - <artifactId>jacoco-maven-plugin</artifactId> - <executions> - <execution> - <id>prepare-agent</id> - <goals> - <goal>prepare-agent</goal> - </goals> - <configuration> - <append>true</append> - <destFile>${project.build.directory}/jacoco.exec</destFile> - </configuration> - </execution> - <execution> - <id>prepare-agent-integration</id> - <goals> - <goal>prepare-agent-integration</goal> - </goals> - <configuration> - <destFile>${project.build.directory}/jacoco-it.exec</destFile> - <append>true</append> - </configuration> - </execution> - <execution> - <id>report</id> - <phase>test</phase> - <goals> - <goal>report</goal> - </goals> - <configuration> - <outputDirectory>${project.build.directory}/site/jacoco</outputDirectory> - <formats> - <format>XML</format> - <format>HTML</format> - </formats> - </configuration> - </execution> - <execution> - <id>report-integration</id> - <phase>post-integration-test</phase> - <goals> - <goal>report-integration</goal> - </goals> - <configuration> - <outputDirectory>${project.build.directory}/site/jacoco-it</outputDirectory> - <formats> - <format>XML</format> - <format>HTML</format> - </formats> - </configuration> - </execution> - <execution> - <id>merge-results</id> - <phase>verify</phase> - <goals> - <goal>merge</goal> - </goals> - <configuration> - <fileSets> - <fileSet> - <directory>${project.build.directory}</directory> - <includes> - <include>*.exec</include> - </includes> - </fileSet> - </fileSets> - <destFile>${project.build.directory}/jacoco-merged.exec</destFile> - </configuration> - </execution> - <execution> - <id>report-merged</id> - <phase>verify</phase> - <goals> - <goal>report</goal> - </goals> - <configuration> - <dataFile>${project.build.directory}/jacoco-merged.exec</dataFile> - <outputDirectory>${project.build.directory}/site/jacoco-merged</outputDirectory> - <formats> - <format>XML</format> - <format>HTML</format> - </formats> - </configuration> - </execution> - </executions> - </plugin> - </plugins> - </pluginManagement> - <plugins> - <plugin> - <groupId>org.jacoco</groupId> - <artifactId>jacoco-maven-plugin</artifactId> - </plugin> - </plugins> - </build> - <properties> - <!-- Multiple XML report paths for Sonar to pick up coverage from all modules --> - <sonar.coverage.jacoco.xmlReportPaths> - ${project.build.directory}/site/jacoco/jacoco.xml, - api-sheriff-quarkus/target/site/jacoco/jacoco.xml, - api-sheriff-quarkus-deployment/target/site/jacoco/jacoco.xml, - ../target/site/jacoco/jacoco.xml - </sonar.coverage.jacoco.xmlReportPaths> - </properties> - </profile> - </profiles> -</project> \ No newline at end of file diff --git a/api-sheriff-library/pom.xml b/api-sheriff/pom.xml similarity index 62% rename from api-sheriff-library/pom.xml rename to api-sheriff/pom.xml index 9453dfa6..7ba267b1 100644 --- a/api-sheriff-library/pom.xml +++ b/api-sheriff/pom.xml @@ -10,28 +10,17 @@ <relativePath>../pom.xml</relativePath> </parent> - <artifactId>api-sheriff-library</artifactId> + <artifactId>api-sheriff</artifactId> <packaging>jar</packaging> - <name>API Sheriff Library</name> - <description>Core library for API Sheriff gateway with security features</description> + <name>API Sheriff</name> + <description>Unified Quarkus application module for API Sheriff gateway with security features</description> <properties> <maven.jar.plugin.automatic.module.name>de.cuioss.sheriff.api</maven.jar.plugin.automatic.module.name> </properties> - <dependencyManagement> - <dependencies> - <dependency> - <groupId>de.cuioss.sheriff.api</groupId> - <artifactId>api-sheriff-bom</artifactId> - <version>${project.version}</version> - <type>pom</type> - <scope>import</scope> - </dependency> - </dependencies> - </dependencyManagement> - <dependencies> + <!-- Core library dependencies --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> @@ -46,13 +35,77 @@ <scope>provided</scope> </dependency> - <!-- Unit testing --> + <!-- Quarkus dependencies --> + <dependency> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-core</artifactId> + </dependency> + <dependency> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-arc</artifactId> + </dependency> + <dependency> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-micrometer</artifactId> + </dependency> + <dependency> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-security</artifactId> + </dependency> + <dependency> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-scheduler</artifactId> + </dependency> + <dependency> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-config-yaml</artifactId> + </dependency> + <dependency> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-hibernate-validator</artifactId> + </dependency> + <dependency> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-smallrye-health</artifactId> + </dependency> + <dependency> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-vertx-http</artifactId> + <optional>true</optional> + </dependency> + <dependency> + <groupId>jakarta.servlet</groupId> + <artifactId>jakarta.servlet-api</artifactId> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-resteasy</artifactId> + <optional>true</optional> + </dependency> + + <!-- Test dependencies --> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter</artifactId> <scope>test</scope> </dependency> - <!-- JJWT dependencies. Reduced to testing --> + <dependency> + <groupId>org.junit.jupiter</groupId> + <artifactId>junit-jupiter-params</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-junit5</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-jacoco</artifactId> + <scope>test</scope> + </dependency> + <!-- JJWT dependencies --> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-api</artifactId> @@ -68,27 +121,31 @@ <artifactId>jjwt-jackson</artifactId> <scope>test</scope> </dependency> - <!-- Test --> + <!-- CUI test dependencies --> <dependency> <groupId>de.cuioss.test</groupId> <artifactId>cui-test-mockwebserver-junit5</artifactId> <scope>test</scope> </dependency> - <!-- Implementation of jakarta.json-api--> - <!-- The concrete is up to the integration--> <dependency> - <groupId>org.eclipse.parsson</groupId> - <artifactId>parsson</artifactId> + <groupId>de.cuioss.test</groupId> + <artifactId>cui-test-value-objects</artifactId> <scope>test</scope> </dependency> <dependency> - <groupId>org.junit.jupiter</groupId> - <artifactId>junit-jupiter-params</artifactId> + <groupId>de.cuioss.test</groupId> + <artifactId>cui-test-generator</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>de.cuioss.test</groupId> - <artifactId>cui-test-value-objects</artifactId> + <artifactId>cui-test-juli-logger</artifactId> + <scope>test</scope> + </dependency> + <!-- Jakarta JSON implementation for tests --> + <dependency> + <groupId>org.eclipse.parsson</groupId> + <artifactId>parsson</artifactId> <scope>test</scope> </dependency> <dependency> @@ -96,42 +153,47 @@ <artifactId>rest-assured</artifactId> <scope>test</scope> </dependency> + <!-- SLF4J bridges for test containers --> <dependency> - <groupId>jakarta.servlet</groupId> - <artifactId>jakarta.servlet-api</artifactId> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-jdk14</artifactId> <scope>test</scope> </dependency> <dependency> - <groupId>de.cuioss.test</groupId> - <artifactId>cui-test-generator</artifactId> + <groupId>org.slf4j</groupId> + <artifactId>jcl-over-slf4j</artifactId> <scope>test</scope> </dependency> <dependency> - <groupId>de.cuioss.test</groupId> - <artifactId>cui-test-juli-logger</artifactId> + <groupId>org.awaitility</groupId> + <artifactId>awaitility</artifactId> <scope>test</scope> </dependency> - <!-- Simple implementation that is actually a bridge to juli logging. Used for test-containers slf4j --> + <!-- Weld/CDI testing --> <dependency> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-jdk14</artifactId> + <groupId>org.jboss.weld</groupId> + <artifactId>weld-junit5</artifactId> <scope>test</scope> </dependency> - <!-- Bridge jakarta-commons logging to slf4j --> <dependency> - <groupId>org.slf4j</groupId> - <artifactId>jcl-over-slf4j</artifactId> + <groupId>org.jboss.logmanager</groupId> + <artifactId>jboss-logmanager</artifactId> <scope>test</scope> </dependency> <dependency> - <groupId>org.awaitility</groupId> - <artifactId>awaitility</artifactId> + <groupId>org.easymock</groupId> + <artifactId>easymock</artifactId> + <version>${version.easymock}</version> <scope>test</scope> </dependency> </dependencies> <build> <plugins> + <plugin> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-maven-plugin</artifactId> + </plugin> <!-- Create test-jar artifact with test utilities --> <plugin> <groupId>org.apache.maven.plugins</groupId> @@ -196,7 +258,32 @@ </execution> </executions> </plugin> + <!-- JaCoCo Plugin for test coverage --> + <plugin> + <groupId>org.jacoco</groupId> + <artifactId>jacoco-maven-plugin</artifactId> + <executions> + <execution> + <id>default-prepare-agent</id> + <goals> + <goal>prepare-agent</goal> + </goals> + </execution> + <execution> + <id>default-report</id> + <phase>test</phase> + <goals> + <goal>report</goal> + </goals> + <configuration> + <formats> + <format>XML</format> + <format>HTML</format> + </formats> + </configuration> + </execution> + </executions> + </plugin> </plugins> </build> - -</project> \ No newline at end of file +</project> diff --git a/api-sheriff-library/src/main/java/de/cuioss/sheriff/api/ApiSheriff.java b/api-sheriff/src/main/java/de/cuioss/sheriff/api/ApiSheriff.java similarity index 75% rename from api-sheriff-library/src/main/java/de/cuioss/sheriff/api/ApiSheriff.java rename to api-sheriff/src/main/java/de/cuioss/sheriff/api/ApiSheriff.java index d07a2cb1..da94d12f 100644 --- a/api-sheriff-library/src/main/java/de/cuioss/sheriff/api/ApiSheriff.java +++ b/api-sheriff/src/main/java/de/cuioss/sheriff/api/ApiSheriff.java @@ -1,12 +1,12 @@ /* - * Copyright 2025 the original author or authors. - * <p> + * Copyright ยฉ 2025 CUI-OpenSource-Software (info@cuioss.de) + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * <p> - * https://www.apache.org/licenses/LICENSE-2.0 - * <p> + * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -16,6 +16,7 @@ package de.cuioss.sheriff.api; import de.cuioss.tools.logging.CuiLogger; +import io.quarkus.runtime.annotations.RegisterForReflection; /** * Main API Sheriff class. @@ -23,15 +24,16 @@ * * @author API Sheriff Team */ +@RegisterForReflection public class ApiSheriff { - private static final CuiLogger log = new CuiLogger(ApiSheriff.class); + private static final CuiLogger LOGGER = new CuiLogger(ApiSheriff.class); /** * Creates a new ApiSheriff instance. */ public ApiSheriff() { - log.debug("ApiSheriff initialized"); + LOGGER.debug("ApiSheriff initialized"); } /** @@ -42,4 +44,4 @@ public ApiSheriff() { public String getStatus() { return "API Sheriff is operational"; } -} \ No newline at end of file +} diff --git a/api-sheriff-library/src/main/java/de/cuioss/sheriff/api/package-info.java b/api-sheriff/src/main/java/de/cuioss/sheriff/api/package-info.java similarity index 80% rename from api-sheriff-library/src/main/java/de/cuioss/sheriff/api/package-info.java rename to api-sheriff/src/main/java/de/cuioss/sheriff/api/package-info.java index 27b5a4f1..3bd1d8b9 100644 --- a/api-sheriff-library/src/main/java/de/cuioss/sheriff/api/package-info.java +++ b/api-sheriff/src/main/java/de/cuioss/sheriff/api/package-info.java @@ -1,12 +1,12 @@ /* - * Copyright 2025 the original author or authors. - * <p> + * Copyright ยฉ 2025 CUI-OpenSource-Software (info@cuioss.de) + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * <p> - * https://www.apache.org/licenses/LICENSE-2.0 - * <p> + * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -15,9 +15,9 @@ */ /** * Main package for the API Sheriff library. - * + * * This package contains the core functionality of the API Sheriff project. - * + * * @author API Sheriff Team */ -package de.cuioss.sheriff.api; \ No newline at end of file +package de.cuioss.sheriff.api; diff --git a/api-sheriff-quarkus-parent/api-sheriff-quarkus/src/main/java/de/cuioss/sheriff/api/quarkus/ApiSheriffProducer.java b/api-sheriff/src/main/java/de/cuioss/sheriff/api/quarkus/ApiSheriffProducer.java similarity index 77% rename from api-sheriff-quarkus-parent/api-sheriff-quarkus/src/main/java/de/cuioss/sheriff/api/quarkus/ApiSheriffProducer.java rename to api-sheriff/src/main/java/de/cuioss/sheriff/api/quarkus/ApiSheriffProducer.java index c71ec965..3105e521 100644 --- a/api-sheriff-quarkus-parent/api-sheriff-quarkus/src/main/java/de/cuioss/sheriff/api/quarkus/ApiSheriffProducer.java +++ b/api-sheriff/src/main/java/de/cuioss/sheriff/api/quarkus/ApiSheriffProducer.java @@ -1,12 +1,12 @@ /* - * Copyright 2025 the original author or authors. - * <p> + * Copyright ยฉ 2025 CUI-OpenSource-Software (info@cuioss.de) + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * <p> - * https://www.apache.org/licenses/LICENSE-2.0 - * <p> + * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -17,6 +17,7 @@ import de.cuioss.sheriff.api.ApiSheriff; import de.cuioss.tools.logging.CuiLogger; +import io.quarkus.runtime.annotations.RegisterForReflection; import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.inject.Produces; @@ -27,9 +28,10 @@ * @author API Sheriff Team */ @ApplicationScoped +@RegisterForReflection public class ApiSheriffProducer { - private static final CuiLogger log = new CuiLogger(ApiSheriffProducer.class); + private static final CuiLogger LOGGER = new CuiLogger(ApiSheriffProducer.class); /** * Produces an application-scoped ApiSheriff instance. @@ -39,7 +41,7 @@ public class ApiSheriffProducer { @Produces @ApplicationScoped public ApiSheriff produceApiSheriff() { - log.debug("Creating ApiSheriff instance"); + LOGGER.debug("Creating ApiSheriff instance"); return new ApiSheriff(); } -} \ No newline at end of file +} diff --git a/api-sheriff-library/src/main/java/module-info.java b/api-sheriff/src/main/java/de/cuioss/sheriff/api/quarkus/package-info.java similarity index 79% rename from api-sheriff-library/src/main/java/module-info.java rename to api-sheriff/src/main/java/de/cuioss/sheriff/api/quarkus/package-info.java index cdf9b1ac..48653699 100644 --- a/api-sheriff-library/src/main/java/module-info.java +++ b/api-sheriff/src/main/java/de/cuioss/sheriff/api/quarkus/package-info.java @@ -13,10 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -module de.cuioss.sheriff.api { - exports de.cuioss.sheriff.api; - - requires static lombok; - requires de.cuioss.java.tools; - requires java.logging; -} \ No newline at end of file +/** + * Quarkus CDI integration for the API Sheriff library. + * + * @author API Sheriff Team + */ +package de.cuioss.sheriff.api.quarkus; diff --git a/api-sheriff-library/src/test/java/de/cuioss/sheriff/api/ApiSheriffTest.java b/api-sheriff/src/test/java/de/cuioss/sheriff/api/ApiSheriffTest.java similarity index 89% rename from api-sheriff-library/src/test/java/de/cuioss/sheriff/api/ApiSheriffTest.java rename to api-sheriff/src/test/java/de/cuioss/sheriff/api/ApiSheriffTest.java index 3c65feb0..1a647fa7 100644 --- a/api-sheriff-library/src/test/java/de/cuioss/sheriff/api/ApiSheriffTest.java +++ b/api-sheriff/src/test/java/de/cuioss/sheriff/api/ApiSheriffTest.java @@ -1,12 +1,12 @@ /* - * Copyright 2025 the original author or authors. - * <p> + * Copyright ยฉ 2025 CUI-OpenSource-Software (info@cuioss.de) + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * <p> - * https://www.apache.org/licenses/LICENSE-2.0 - * <p> + * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -36,4 +36,4 @@ void shouldReturnStatus() { ApiSheriff sheriff = new ApiSheriff(); assertEquals("API Sheriff is operational", sheriff.getStatus()); } -} \ No newline at end of file +} diff --git a/api-sheriff/src/test/java/de/cuioss/sheriff/api/test/TestDataGenerator.java b/api-sheriff/src/test/java/de/cuioss/sheriff/api/test/TestDataGenerator.java new file mode 100644 index 00000000..756673ae --- /dev/null +++ b/api-sheriff/src/test/java/de/cuioss/sheriff/api/test/TestDataGenerator.java @@ -0,0 +1,41 @@ +/* + * Copyright ยฉ 2025 CUI-OpenSource-Software (info@cuioss.de) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.cuioss.sheriff.api.test; + +import lombok.experimental.UtilityClass; + +/** + * Test data generator for API Sheriff tests + */ +@UtilityClass +public class TestDataGenerator { + + /** + * Generates a test API key + * @return test API key + */ + public static String generateApiKey() { + return "test-api-key-" + System.currentTimeMillis(); + } + + /** + * Generates a test endpoint URL + * @return test endpoint URL + */ + public static String generateEndpoint() { + return "https://api.example.com/v1/test-" + System.currentTimeMillis(); + } +} diff --git a/benchmarking/benchmark-integration-wrk/pom.xml b/benchmarking/benchmark-integration-wrk/pom.xml index 2bdb4710..edf01c4a 100644 --- a/benchmarking/benchmark-integration-wrk/pom.xml +++ b/benchmarking/benchmark-integration-wrk/pom.xml @@ -20,10 +20,10 @@ <skip.container.lifecycle>false</skip.container.lifecycle> <!-- Scripts location --> - <integration.scripts.dir>${project.basedir}/../../api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests/scripts</integration.scripts.dir> + <integration.scripts.dir>${project.basedir}/../../api-sheriff-integration-tests/scripts</integration.scripts.dir> <!-- Docker compose directory for WRK benchmarks --> - <integration.compose.dir>${project.basedir}/../../api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests</integration.compose.dir> + <integration.compose.dir>${project.basedir}/../../api-sheriff-integration-tests</integration.compose.dir> <!-- Integration test service URLs (host access via published ports) --> <integration.service.url>https://localhost:10443</integration.service.url> @@ -148,7 +148,7 @@ <argument>-Pintegration-tests</argument> <argument>-DskipTests</argument> </arguments> - <workingDirectory>${project.basedir}/../../api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests</workingDirectory> + <workingDirectory>${project.basedir}/../../api-sheriff-integration-tests</workingDirectory> </configuration> </execution> @@ -218,7 +218,7 @@ <arguments> <argument>clean</argument> </arguments> - <workingDirectory>${project.basedir}/../../api-sheriff-quarkus-parent/api-sheriff-quarkus-integration-tests</workingDirectory> + <workingDirectory>${project.basedir}/../../api-sheriff-integration-tests</workingDirectory> </configuration> </execution> </executions> diff --git a/benchmarking/benchmark-integration-wrk/src/main/java/de/cuioss/sheriff/api/wrk/benchmark/WrkResultPostProcessor.java b/benchmarking/benchmark-integration-wrk/src/main/java/de/cuioss/sheriff/api/wrk/benchmark/WrkResultPostProcessor.java index c46853ca..bcee859d 100644 --- a/benchmarking/benchmark-integration-wrk/src/main/java/de/cuioss/sheriff/api/wrk/benchmark/WrkResultPostProcessor.java +++ b/benchmarking/benchmark-integration-wrk/src/main/java/de/cuioss/sheriff/api/wrk/benchmark/WrkResultPostProcessor.java @@ -1,12 +1,12 @@ /* - * Copyright 2025 the original author or authors. - * <p> + * Copyright ยฉ 2025 CUI-OpenSource-Software (info@cuioss.de) + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * <p> - * https://www.apache.org/licenses/LICENSE-2.0 - * <p> + * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. diff --git a/benchmarking/benchmark-integration-wrk/src/test/java/de/cuioss/sheriff/api/wrk/benchmark/WrkResultPostProcessorTest.java b/benchmarking/benchmark-integration-wrk/src/test/java/de/cuioss/sheriff/api/wrk/benchmark/WrkResultPostProcessorTest.java index 21803047..b96b7a98 100644 --- a/benchmarking/benchmark-integration-wrk/src/test/java/de/cuioss/sheriff/api/wrk/benchmark/WrkResultPostProcessorTest.java +++ b/benchmarking/benchmark-integration-wrk/src/test/java/de/cuioss/sheriff/api/wrk/benchmark/WrkResultPostProcessorTest.java @@ -1,12 +1,12 @@ /* - * Copyright 2025 the original author or authors. - * <p> + * Copyright ยฉ 2025 CUI-OpenSource-Software (info@cuioss.de) + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * <p> - * https://www.apache.org/licenses/LICENSE-2.0 - * <p> + * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -24,7 +24,6 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.StandardCopyOption; import static de.cuioss.sheriff.api.wrk.benchmark.WrkResultPostProcessor.*; import static org.junit.jupiter.api.Assertions.*; diff --git a/benchmarking/pom.xml b/benchmarking/pom.xml index bbc1881d..cba83ae9 100644 --- a/benchmarking/pom.xml +++ b/benchmarking/pom.xml @@ -50,13 +50,6 @@ <artifactId>commons-io</artifactId> <version>${version.commons-io}</version> </dependency> - <dependency> - <groupId>de.cuioss.sheriff.api</groupId> - <artifactId>api-sheriff-bom</artifactId> - <version>${project.version}</version> - <type>pom</type> - <scope>import</scope> - </dependency> </dependencies> </dependencyManagement> <build> diff --git a/bom/pom.xml b/bom/pom.xml deleted file mode 100644 index 91dcd57f..00000000 --- a/bom/pom.xml +++ /dev/null @@ -1,83 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project xmlns="http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> - <modelVersion>4.0.0</modelVersion> - <parent> - <groupId>de.cuioss.sheriff.api</groupId> - <artifactId>api-sheriff-parent</artifactId> - <version>1.0.0-SNAPSHOT</version> - <relativePath>../pom.xml</relativePath> - </parent> - - <artifactId>api-sheriff-bom</artifactId> - <packaging>pom</packaging> - <name>API Sheriff BOM</name> - <description>Bill of Materials (BOM) for API Sheriff modules</description> - <properties> - <version.jjwt>0.13.0</version.jjwt> - </properties> - - <dependencyManagement> - <dependencies> - <dependency> - <groupId>de.cuioss</groupId> - <artifactId>java-ee-orthogonal</artifactId> - <version>${version.cui.parent}</version> - <type>pom</type> - <scope>import</scope> - </dependency> - <dependency> - <groupId>de.cuioss</groupId> - <artifactId>java-ee-10-bom</artifactId> - <version>${version.cui.parent}</version> - <type>pom</type> - <scope>import</scope> - </dependency> - <!-- JJWT dependencies --> - <dependency> - <groupId>io.jsonwebtoken</groupId> - <artifactId>jjwt-api</artifactId> - <version>${version.jjwt}</version> - <scope>test</scope> - </dependency> - <dependency> - <groupId>io.jsonwebtoken</groupId> - <artifactId>jjwt-impl</artifactId> - <scope>test</scope> - <version>${version.jjwt}</version> - </dependency> - <dependency> - <groupId>io.jsonwebtoken</groupId> - <artifactId>jjwt-jackson</artifactId> - <version>${version.jjwt}</version> - <scope>test</scope> - </dependency> - - <!-- Internal modules --> - <dependency> - <groupId>de.cuioss.sheriff.api</groupId> - <artifactId>api-sheriff-library</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>de.cuioss.sheriff.api</groupId> - <artifactId>api-sheriff-library</artifactId> - <version>${project.version}</version> - <type>test-jar</type> - <classifier>generators</classifier> - <scope>test</scope> - </dependency> - <dependency> - <groupId>de.cuioss.sheriff.api</groupId> - <artifactId>benchmarking</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>de.cuioss.sheriff.api</groupId> - <artifactId>api-sheriff-quarkus</artifactId> - <version>${project.version}</version> - </dependency> - </dependencies> - </dependencyManagement> -</project> \ No newline at end of file diff --git a/pom.xml b/pom.xml index 6b47dfda..c14f7e59 100644 --- a/pom.xml +++ b/pom.xml @@ -21,9 +21,8 @@ <url>https://github.com/cuioss/api-sheriff/</url> <modules> - <module>bom</module> - <module>api-sheriff-library</module> - <module>api-sheriff-quarkus-parent</module> + <module>api-sheriff</module> + <module>api-sheriff-integration-tests</module> <module>benchmarking</module> </modules> <scm> @@ -44,8 +43,294 @@ <properties> <maven.compiler.release>21</maven.compiler.release> <version.quarkus>3.32.1</version.quarkus> - <frontend.node.version>v22.22.0</frontend.node.version> - <frontend.npm.version>10.9.2</frontend.npm.version> + <version.jjwt>0.13.0</version.jjwt> + <version.weld-junit5>5.0.3.Final</version.weld-junit5> + <version.easymock>5.6.0</version.easymock> + <!-- Default empty argLine for JaCoCo compatibility - JaCoCo will override this when active --> + <argLine /> </properties> -</project> \ No newline at end of file + <dependencyManagement> + <dependencies> + <dependency> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-bom</artifactId> + <version>${version.quarkus}</version> + <type>pom</type> + <scope>import</scope> + </dependency> + <dependency> + <groupId>de.cuioss</groupId> + <artifactId>java-ee-orthogonal</artifactId> + <version>${version.cui.parent}</version> + <type>pom</type> + <scope>import</scope> + </dependency> + <dependency> + <groupId>de.cuioss</groupId> + <artifactId>java-ee-10-bom</artifactId> + <version>${version.cui.parent}</version> + <type>pom</type> + <scope>import</scope> + </dependency> + <!-- JJWT dependencies --> + <dependency> + <groupId>io.jsonwebtoken</groupId> + <artifactId>jjwt-api</artifactId> + <version>${version.jjwt}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>io.jsonwebtoken</groupId> + <artifactId>jjwt-impl</artifactId> + <version>${version.jjwt}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>io.jsonwebtoken</groupId> + <artifactId>jjwt-jackson</artifactId> + <version>${version.jjwt}</version> + <scope>test</scope> + </dependency> + <!-- Internal modules --> + <dependency> + <groupId>de.cuioss.sheriff.api</groupId> + <artifactId>api-sheriff</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>de.cuioss.sheriff.api</groupId> + <artifactId>api-sheriff</artifactId> + <version>${project.version}</version> + <type>test-jar</type> + <classifier>generators</classifier> + <scope>test</scope> + </dependency> + <!-- Override JUnit Platform versions to match Jupiter (cui-java-parent provides + version.junit.jupiter, but the Quarkus BOM pins older Platform versions) --> + <dependency> + <groupId>org.junit.platform</groupId> + <artifactId>junit-platform-commons</artifactId> + <version>${version.junit.jupiter}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.junit.platform</groupId> + <artifactId>junit-platform-engine</artifactId> + <version>${version.junit.jupiter}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.junit.platform</groupId> + <artifactId>junit-platform-launcher</artifactId> + <version>${version.junit.jupiter}</version> + <scope>test</scope> + </dependency> + <!-- Additional dependencies --> + <dependency> + <groupId>org.jboss.weld</groupId> + <artifactId>weld-junit5</artifactId> + <version>${version.weld-junit5}</version> + <scope>test</scope> + </dependency> + </dependencies> + </dependencyManagement> + + <build> + <pluginManagement> + <plugins> + <plugin> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-maven-plugin</artifactId> + <version>${version.quarkus}</version> + <extensions>true</extensions> + <executions> + <execution> + <goals> + <goal>build</goal> + <goal>generate-code</goal> + <goal>generate-code-tests</goal> + </goals> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <configuration> + <release>21</release> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <configuration> + <systemPropertyVariables> + <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager> + <java.util.logging.config.file>${project.build.testOutputDirectory}/logging.properties</java.util.logging.config.file> + <maven.home>${maven.home}</maven.home> + <quarkus.test.arg-line>@{argLine}</quarkus.test.arg-line> + </systemPropertyVariables> + <useModulePath>false</useModulePath> + <useFile>false</useFile> + <trimStackTrace>false</trimStackTrace> + <enableAssertions>true</enableAssertions> + <!-- JaCoCo-compatible argLine (will be empty if JaCoCo not active) --> + <argLine>@{argLine} -XX:+IgnoreUnrecognizedVMOptions -Djava.awt.headless=true</argLine> + <!-- Stability configurations --> + <forkedProcessTimeoutInSeconds>0</forkedProcessTimeoutInSeconds> + <forkedProcessExitTimeoutInSeconds>60</forkedProcessExitTimeoutInSeconds> + <!-- Fix for class loading issues --> + <useSystemClassLoader>false</useSystemClassLoader> + <reuseForks>false</reuseForks> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-failsafe-plugin</artifactId> + <configuration> + <systemPropertyVariables> + <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager> + <java.util.logging.config.file>${project.build.testOutputDirectory}/logging.properties</java.util.logging.config.file> + <maven.home>${maven.home}</maven.home> + <quarkus.test.arg-line>@{argLine}</quarkus.test.arg-line> + </systemPropertyVariables> + <useModulePath>false</useModulePath> + <useFile>false</useFile> + <trimStackTrace>false</trimStackTrace> + <enableAssertions>true</enableAssertions> + <argLine>@{argLine} -XX:+IgnoreUnrecognizedVMOptions -Djava.awt.headless=true</argLine> + <!-- Fix for class loading issues --> + <useSystemClassLoader>false</useSystemClassLoader> + <reuseForks>false</reuseForks> + <!-- Standardized IT naming patterns --> + <includes> + <include>**/*IT.java</include> + <include>**/*IntegrationTest.java</include> + </includes> + </configuration> + <executions> + <execution> + <goals> + <goal>integration-test</goal> + <goal>verify</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </pluginManagement> + </build> + + <profiles> + <profile> + <id>coverage</id> + <build> + <pluginManagement> + <plugins> + <plugin> + <groupId>org.jacoco</groupId> + <artifactId>jacoco-maven-plugin</artifactId> + <executions> + <execution> + <id>prepare-agent</id> + <goals> + <goal>prepare-agent</goal> + </goals> + <configuration> + <append>true</append> + <destFile>${project.build.directory}/jacoco.exec</destFile> + </configuration> + </execution> + <execution> + <id>prepare-agent-integration</id> + <goals> + <goal>prepare-agent-integration</goal> + </goals> + <configuration> + <destFile>${project.build.directory}/jacoco-it.exec</destFile> + <append>true</append> + </configuration> + </execution> + <execution> + <id>report</id> + <phase>test</phase> + <goals> + <goal>report</goal> + </goals> + <configuration> + <outputDirectory>${project.build.directory}/site/jacoco</outputDirectory> + <formats> + <format>XML</format> + <format>HTML</format> + </formats> + </configuration> + </execution> + <execution> + <id>report-integration</id> + <phase>post-integration-test</phase> + <goals> + <goal>report-integration</goal> + </goals> + <configuration> + <outputDirectory>${project.build.directory}/site/jacoco-it</outputDirectory> + <formats> + <format>XML</format> + <format>HTML</format> + </formats> + </configuration> + </execution> + <execution> + <id>merge-results</id> + <phase>verify</phase> + <goals> + <goal>merge</goal> + </goals> + <configuration> + <fileSets> + <fileSet> + <directory>${project.build.directory}</directory> + <includes> + <include>*.exec</include> + </includes> + </fileSet> + </fileSets> + <destFile>${project.build.directory}/jacoco-merged.exec</destFile> + </configuration> + </execution> + <execution> + <id>report-merged</id> + <phase>verify</phase> + <goals> + <goal>report</goal> + </goals> + <configuration> + <dataFile>${project.build.directory}/jacoco-merged.exec</dataFile> + <outputDirectory>${project.build.directory}/site/jacoco-merged</outputDirectory> + <formats> + <format>XML</format> + <format>HTML</format> + </formats> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </pluginManagement> + <plugins> + <plugin> + <groupId>org.jacoco</groupId> + <artifactId>jacoco-maven-plugin</artifactId> + </plugin> + </plugins> + </build> + <properties> + <sonar.coverage.jacoco.xmlReportPaths> + ${project.build.directory}/site/jacoco/jacoco.xml, + api-sheriff/target/site/jacoco/jacoco.xml, + ../target/site/jacoco/jacoco.xml + </sonar.coverage.jacoco.xmlReportPaths> + </properties> + </profile> + </profiles> +</project> From 601ebef559d0b5e3c340e27b94d6753807c8cd4b Mon Sep 17 00:00:00 2001 From: Oliver Wolff <23139298+cuioss@users.noreply.github.com> Date: Wed, 4 Mar 2026 07:51:06 +0100 Subject: [PATCH 08/24] chore: Collapse benchmarking into single benchmark-integration module Remove unnecessary parent POM nesting (benchmarking/benchmark-integration-wrk) and promote to a single top-level benchmark-integration module. Replace performance-scoring.adoc with a link to the OAuthSheriff original. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --- .github/workflows/benchmark.yml | 10 +- .github/workflows/claude.yml | 2 +- CLAUDE.md | 4 +- README.adoc | 4 +- .../scripts/benchmark-with-monitoring.sh | 2 +- .../sheriff/api/integration/TestResource.java | 2 +- .../api/integration/BaseIntegrationTest.java | 1 + benchmark-integration/README.adoc | 21 ++ .../doc/performance-scoring.adoc | 5 + .../pom.xml | 75 ++++- .../scripts/benchmark-pages.py | 6 +- .../wrk/benchmark/WrkResultPostProcessor.java | 0 .../benchmark/WrkResultPostProcessorTest.java | 0 .../src/test/resources/wrk-health-results.txt | 0 .../src/test/resources/wrk-jwt-results.txt | 0 benchmarking/README.adoc | 307 ------------------ benchmarking/doc/performance-scoring.adoc | 107 ------ benchmarking/pom.xml | 97 ------ pom.xml | 2 +- 19 files changed, 107 insertions(+), 538 deletions(-) create mode 100644 benchmark-integration/README.adoc create mode 100644 benchmark-integration/doc/performance-scoring.adoc rename {benchmarking/benchmark-integration-wrk => benchmark-integration}/pom.xml (76%) rename {benchmarking => benchmark-integration}/scripts/benchmark-pages.py (97%) rename {benchmarking/benchmark-integration-wrk => benchmark-integration}/src/main/java/de/cuioss/sheriff/api/wrk/benchmark/WrkResultPostProcessor.java (100%) rename {benchmarking/benchmark-integration-wrk => benchmark-integration}/src/test/java/de/cuioss/sheriff/api/wrk/benchmark/WrkResultPostProcessorTest.java (100%) rename {benchmarking/benchmark-integration-wrk => benchmark-integration}/src/test/resources/wrk-health-results.txt (100%) rename {benchmarking/benchmark-integration-wrk => benchmark-integration}/src/test/resources/wrk-jwt-results.txt (100%) delete mode 100644 benchmarking/README.adoc delete mode 100644 benchmarking/doc/performance-scoring.adoc delete mode 100644 benchmarking/pom.xml diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 634991c8..586e9293 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -74,7 +74,7 @@ jobs: - name: Prepare Historical Data for Benchmarks run: | - python3 benchmarking/scripts/benchmark-pages.py prepare-history \ + python3 benchmark-integration/scripts/benchmark-pages.py prepare-history \ --previous-pages-dir previous-pages/api-sheriff/benchmarks \ --output-dir "${GITHUB_WORKSPACE}/benchmark-history" @@ -82,17 +82,17 @@ jobs: run: | # Run WRK-based integration benchmarks with native image echo "Running WRK integration benchmarks with native Quarkus..." - ./mvnw --no-transfer-progress clean verify -pl benchmarking/benchmark-integration-wrk -Pbenchmark \ + ./mvnw --no-transfer-progress clean verify -pl benchmark-integration -Pbenchmark \ -Dbenchmark.history.dir="${GITHUB_WORKSPACE}/benchmark-history/integration" # Verify artifacts were generated echo "Integration benchmark artifacts generated:" - ls -la benchmarking/benchmark-integration-wrk/target/benchmark-results/ + ls -la benchmark-integration/target/benchmark-results/ - name: Assemble benchmark artifacts for deployment run: | - python3 benchmarking/scripts/benchmark-pages.py assemble \ - --integration-results benchmarking/benchmark-integration-wrk/target/benchmark-results/gh-pages-ready \ + python3 benchmark-integration/scripts/benchmark-pages.py assemble \ + --integration-results benchmark-integration/target/benchmark-results/gh-pages-ready \ --previous-pages-dir previous-pages/api-sheriff/benchmarks \ --output-dir gh-pages \ --commit-sha "${{ github.sha }}" diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index 1dd2fc3e..80c0c62e 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -49,4 +49,4 @@ jobs: additional_permissions: | actions: read - allowed_tools: "Bash(./mvnw*),Bash(./mvnw -Ppre-commit clean verify -DskipTests),Bash(./mvnw clean verify),Bash(./mvnw clean install),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl api-sheriff),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl api-sheriff-integration-tests),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl benchmarking),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl benchmarking/benchmark-integration-wrk),Bash(./mvnw clean install -pl api-sheriff),Bash(./mvnw clean install -pl api-sheriff-integration-tests),Bash(./mvnw clean install -pl benchmarking),Bash(./mvnw clean install -pl benchmarking/benchmark-integration-wrk),Bash(git*),Bash(find*),Bash(gh*),Bash(java*)" + allowed_tools: "Bash(./mvnw*),Bash(./mvnw -Ppre-commit clean verify -DskipTests),Bash(./mvnw clean verify),Bash(./mvnw clean install),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl api-sheriff),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl api-sheriff-integration-tests),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl benchmark-integration),Bash(./mvnw clean install -pl api-sheriff),Bash(./mvnw clean install -pl api-sheriff-integration-tests),Bash(./mvnw clean install -pl benchmark-integration),Bash(git*),Bash(find*),Bash(gh*),Bash(java*)" diff --git a/CLAUDE.md b/CLAUDE.md index c255c587..01be6aec 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -11,7 +11,7 @@ API Sheriff is a security-focused API Gateway with a lightweight approach, curre Multi-module Maven project: - `api-sheriff/` โ€” Unified Quarkus application (core library + CDI producers) - `api-sheriff-integration-tests/` โ€” Integration tests with native container testing -- `benchmarking/` โ€” Performance benchmarking (benchmark-integration-wrk for WRK HTTP load testing) +- `benchmark-integration/` โ€” WRK HTTP load testing benchmarks ## Build Commands @@ -32,7 +32,7 @@ Multi-module Maven project: ./mvnw clean verify -Pintegration-tests -pl api-sheriff-integration-tests -am # Integration benchmarks (WRK) -./mvnw clean verify -pl benchmarking/benchmark-integration-wrk -Pbenchmark +./mvnw clean verify -pl benchmark-integration -Pbenchmark ``` ### Pre-Commit Process diff --git a/README.adoc b/README.adoc index b570a823..3c368c32 100644 --- a/README.adoc +++ b/README.adoc @@ -34,7 +34,7 @@ image:https://img.shields.io/endpoint?url=https://cuioss.github.io/api-sheriff/b image:https://img.shields.io/endpoint?url=https://cuioss.github.io/api-sheriff/benchmarks/badges/integration-performance-badge.json[Integration Performance,link=https://cuioss.github.io/api-sheriff/benchmarks/integration-index.html] image:https://img.shields.io/endpoint?url=https://cuioss.github.io/api-sheriff/benchmarks/badges/integration-trend-badge.json[Integration Trend,link=https://cuioss.github.io/api-sheriff/benchmarks/integration-performance-trends.html] -xref:benchmarking/doc/performance-scoring.adoc[Understand Performance Metrics] +xref:benchmark-integration/doc/performance-scoring.adoc[Understand Performance Metrics] https://cuioss.github.io/api-sheriff/about.html[Generated Documentation on github-pages] @@ -69,7 +69,7 @@ End-to-end integration tests with native container testing and HTTPS support. Integration benchmarks using WRK HTTP load testing with containerized environments. -xref:benchmarking/doc/performance-scoring.adoc[Understand Performance Metrics] +xref:benchmark-integration/doc/performance-scoring.adoc[Understand Performance Metrics] == External Resources diff --git a/api-sheriff-integration-tests/scripts/benchmark-with-monitoring.sh b/api-sheriff-integration-tests/scripts/benchmark-with-monitoring.sh index 51ee3eea..249037cb 100755 --- a/api-sheriff-integration-tests/scripts/benchmark-with-monitoring.sh +++ b/api-sheriff-integration-tests/scripts/benchmark-with-monitoring.sh @@ -375,7 +375,7 @@ echo "" # Start benchmark with JFR recording START_TIME=$(date +%s) -$MAVEN_CMD verify -pl benchmarking/benchmark-integration-wrk -Pbenchmark > "$BENCHMARK_LOG" 2>&1 & +$MAVEN_CMD verify -pl benchmark-integration -Pbenchmark > "$BENCHMARK_LOG" 2>&1 & BENCHMARK_PID=$! # Wait for containers to start diff --git a/api-sheriff-integration-tests/src/main/java/de/cuioss/sheriff/api/integration/TestResource.java b/api-sheriff-integration-tests/src/main/java/de/cuioss/sheriff/api/integration/TestResource.java index 02944354..89f80161 100644 --- a/api-sheriff-integration-tests/src/main/java/de/cuioss/sheriff/api/integration/TestResource.java +++ b/api-sheriff-integration-tests/src/main/java/de/cuioss/sheriff/api/integration/TestResource.java @@ -63,7 +63,7 @@ public Response health() { return Response.ok("{\"status\":\"UP\",\"apiSheriff\":\"" + status + "\"}") .build(); - } /*~~(TODO: Catch specific not Exception. Suppress: // cui-rewrite:disable InvalidExceptionUsageRecipe)~~>*/catch (Exception e) { + } /*~~(TODO: Catch specific not Exception. Suppress: // cui-rewrite:disable InvalidExceptionUsageRecipe)~~>*/ catch (Exception e) { return Response.status(Response.Status.INTERNAL_SERVER_ERROR) .entity("{\"status\":\"DOWN\",\"error\":\"" + e.getMessage() + "\"}") .build(); diff --git a/api-sheriff-integration-tests/src/test/java/de/cuioss/sheriff/api/integration/BaseIntegrationTest.java b/api-sheriff-integration-tests/src/test/java/de/cuioss/sheriff/api/integration/BaseIntegrationTest.java index f123a698..768b850b 100644 --- a/api-sheriff-integration-tests/src/test/java/de/cuioss/sheriff/api/integration/BaseIntegrationTest.java +++ b/api-sheriff-integration-tests/src/test/java/de/cuioss/sheriff/api/integration/BaseIntegrationTest.java @@ -39,6 +39,7 @@ static void setUpBaseIntegrationTest() { String testPort = System.getProperty("test.https.port", DEFAULT_TEST_PORT); RestAssured.port = Integer.parseInt(testPort); + /*~~(TODO: Use CuiLogger. Suppress: // cui-rewrite:disable CuiLoggerStandardsRecipe)~~>*/ /*~~(TODO: Use CuiLogger. Suppress: // cui-rewrite:disable CuiLoggerStandardsRecipe)~~>*/System.out.println("Integration tests configured for HTTPS port: " + testPort); } } \ No newline at end of file diff --git a/benchmark-integration/README.adoc b/benchmark-integration/README.adoc new file mode 100644 index 00000000..11fa1a09 --- /dev/null +++ b/benchmark-integration/README.adoc @@ -0,0 +1,21 @@ += API Sheriff Integration Benchmarks + +WRK-based HTTP benchmarks for API Sheriff endpoints with integration test infrastructure. + +== Running Benchmarks + +[source,bash] +---- +./mvnw clean verify -pl benchmark-integration -Pbenchmark +---- + +For quick runs (shorter duration, assumes containers already running): + +[source,bash] +---- +./mvnw clean verify -pl benchmark-integration -Pbenchmark -Pquick +---- + +== Performance Scoring + +See the https://github.com/cuioss/OAuthSheriff/blob/main/benchmarking/doc/performance-scoring.adoc[JWT Performance Scoring System] documentation in the OAuthSheriff repository. diff --git a/benchmark-integration/doc/performance-scoring.adoc b/benchmark-integration/doc/performance-scoring.adoc new file mode 100644 index 00000000..5ac6c41b --- /dev/null +++ b/benchmark-integration/doc/performance-scoring.adoc @@ -0,0 +1,5 @@ += JWT Performance Scoring System + +This document is maintained in the OAuthSheriff repository. + +See: https://github.com/cuioss/OAuthSheriff/blob/main/benchmarking/doc/performance-scoring.adoc diff --git a/benchmarking/benchmark-integration-wrk/pom.xml b/benchmark-integration/pom.xml similarity index 76% rename from benchmarking/benchmark-integration-wrk/pom.xml rename to benchmark-integration/pom.xml index edf01c4a..709e0f12 100644 --- a/benchmarking/benchmark-integration-wrk/pom.xml +++ b/benchmark-integration/pom.xml @@ -4,15 +4,17 @@ <parent> <groupId>de.cuioss.sheriff.api</groupId> - <artifactId>benchmarking</artifactId> + <artifactId>api-sheriff-parent</artifactId> <version>1.0.0-SNAPSHOT</version> + <relativePath>../pom.xml</relativePath> </parent> - <artifactId>benchmark-integration-wrk</artifactId> - <name>API Sheriff WRK-based Integration Benchmarks</name> + <artifactId>benchmark-integration</artifactId> + <name>API Sheriff Integration Benchmarks</name> <description>WRK-based HTTP benchmarks for API Sheriff endpoints with integration test infrastructure</description> <properties> + <maven.jar.plugin.automatic.module.name>de.cuioss.sheriff.api.benchmark.integration</maven.jar.plugin.automatic.module.name> <!-- Skip benchmarks by default (enable with -Pbenchmark) --> <skip.benchmark>true</skip.benchmark> @@ -20,10 +22,10 @@ <skip.container.lifecycle>false</skip.container.lifecycle> <!-- Scripts location --> - <integration.scripts.dir>${project.basedir}/../../api-sheriff-integration-tests/scripts</integration.scripts.dir> + <integration.scripts.dir>${project.basedir}/../api-sheriff-integration-tests/scripts</integration.scripts.dir> <!-- Docker compose directory for WRK benchmarks --> - <integration.compose.dir>${project.basedir}/../../api-sheriff-integration-tests</integration.compose.dir> + <integration.compose.dir>${project.basedir}/../api-sheriff-integration-tests</integration.compose.dir> <!-- Integration test service URLs (host access via published ports) --> <integration.service.url>https://localhost:10443</integration.service.url> @@ -44,8 +46,14 @@ <benchmark.history.dir>${wrk.results.dir}/history</benchmark.history.dir> <wrk.jwt.token_count>100</wrk.jwt.token_count> - <!-- benchmarking-common version --> + <!-- External dependency versions --> <version.benchmarking-common>0.4.1</version.benchmarking-common> + <version.gson>2.13.2</version.gson> + <version.hdrhistogram>2.2.2</version.hdrhistogram> + <version.commons-io>2.21.0</version.commons-io> + + <!-- Sonar configuration: Skip analysis for benchmarking modules --> + <sonar.skip>true</sonar.skip> </properties> <dependencyManagement> @@ -55,6 +63,21 @@ <artifactId>benchmarking-common</artifactId> <version>${version.benchmarking-common}</version> </dependency> + <dependency> + <groupId>com.google.code.gson</groupId> + <artifactId>gson</artifactId> + <version>${version.gson}</version> + </dependency> + <dependency> + <groupId>org.hdrhistogram</groupId> + <artifactId>HdrHistogram</artifactId> + <version>${version.hdrhistogram}</version> + </dependency> + <dependency> + <groupId>commons-io</groupId> + <artifactId>commons-io</artifactId> + <version>${version.commons-io}</version> + </dependency> </dependencies> </dependencyManagement> @@ -93,6 +116,37 @@ </dependencies> <build> + <pluginManagement> + <plugins> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>exec-maven-plugin</artifactId> + <configuration> + <skip>${skip.benchmark}</skip> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-dependency-plugin</artifactId> + <executions> + <execution> + <id>copy-dependencies</id> + <phase>package</phase> + <goals> + <goal>copy-dependencies</goal> + </goals> + <configuration> + <outputDirectory>${project.build.directory}/dependency</outputDirectory> + <overWriteReleases>false</overWriteReleases> + <overWriteSnapshots>false</overWriteSnapshots> + <overWriteIfNewer>true</overWriteIfNewer> + <includeScope>runtime</includeScope> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </pluginManagement> <plugins> <!-- Configure surefire for unit tests --> <plugin> @@ -114,7 +168,6 @@ <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> - <!-- Configuration inherited from parent pluginManagement --> </plugin> </plugins> </build> @@ -140,7 +193,7 @@ </goals> <configuration> <skip>${skip.container.lifecycle}</skip> - <executable>../../mvnw</executable> + <executable>../mvnw</executable> <arguments> <argument>compile</argument> <argument>exec:exec@build-native-if-needed</argument> @@ -148,7 +201,7 @@ <argument>-Pintegration-tests</argument> <argument>-DskipTests</argument> </arguments> - <workingDirectory>${project.basedir}/../../api-sheriff-integration-tests</workingDirectory> + <workingDirectory>${project.basedir}/../api-sheriff-integration-tests</workingDirectory> </configuration> </execution> @@ -214,11 +267,11 @@ </goals> <configuration> <skip>${skip.container.lifecycle}</skip> - <executable>../../mvnw</executable> + <executable>../mvnw</executable> <arguments> <argument>clean</argument> </arguments> - <workingDirectory>${project.basedir}/../../api-sheriff-integration-tests</workingDirectory> + <workingDirectory>${project.basedir}/../api-sheriff-integration-tests</workingDirectory> </configuration> </execution> </executions> diff --git a/benchmarking/scripts/benchmark-pages.py b/benchmark-integration/scripts/benchmark-pages.py similarity index 97% rename from benchmarking/scripts/benchmark-pages.py rename to benchmark-integration/scripts/benchmark-pages.py index b2f7846f..cef22a3e 100644 --- a/benchmarking/scripts/benchmark-pages.py +++ b/benchmark-integration/scripts/benchmark-pages.py @@ -9,13 +9,13 @@ Usage in CI: # Before Maven benchmark runs: - python3 benchmarking/scripts/benchmark-pages.py prepare-history \ + python3 benchmark-integration/scripts/benchmark-pages.py prepare-history \ --previous-pages-dir previous-pages/api-sheriff/benchmarks \ --output-dir "$GITHUB_WORKSPACE/benchmark-history" # After all Maven benchmark runs: - python3 benchmarking/scripts/benchmark-pages.py assemble \ - --integration-results benchmarking/benchmark-integration-wrk/target/benchmark-results/gh-pages-ready \ + python3 benchmark-integration/scripts/benchmark-pages.py assemble \ + --integration-results benchmark-integration/target/benchmark-results/gh-pages-ready \ --previous-pages-dir previous-pages/api-sheriff/benchmarks \ --output-dir gh-pages \ --commit-sha "$COMMIT_SHA" diff --git a/benchmarking/benchmark-integration-wrk/src/main/java/de/cuioss/sheriff/api/wrk/benchmark/WrkResultPostProcessor.java b/benchmark-integration/src/main/java/de/cuioss/sheriff/api/wrk/benchmark/WrkResultPostProcessor.java similarity index 100% rename from benchmarking/benchmark-integration-wrk/src/main/java/de/cuioss/sheriff/api/wrk/benchmark/WrkResultPostProcessor.java rename to benchmark-integration/src/main/java/de/cuioss/sheriff/api/wrk/benchmark/WrkResultPostProcessor.java diff --git a/benchmarking/benchmark-integration-wrk/src/test/java/de/cuioss/sheriff/api/wrk/benchmark/WrkResultPostProcessorTest.java b/benchmark-integration/src/test/java/de/cuioss/sheriff/api/wrk/benchmark/WrkResultPostProcessorTest.java similarity index 100% rename from benchmarking/benchmark-integration-wrk/src/test/java/de/cuioss/sheriff/api/wrk/benchmark/WrkResultPostProcessorTest.java rename to benchmark-integration/src/test/java/de/cuioss/sheriff/api/wrk/benchmark/WrkResultPostProcessorTest.java diff --git a/benchmarking/benchmark-integration-wrk/src/test/resources/wrk-health-results.txt b/benchmark-integration/src/test/resources/wrk-health-results.txt similarity index 100% rename from benchmarking/benchmark-integration-wrk/src/test/resources/wrk-health-results.txt rename to benchmark-integration/src/test/resources/wrk-health-results.txt diff --git a/benchmarking/benchmark-integration-wrk/src/test/resources/wrk-jwt-results.txt b/benchmark-integration/src/test/resources/wrk-jwt-results.txt similarity index 100% rename from benchmarking/benchmark-integration-wrk/src/test/resources/wrk-jwt-results.txt rename to benchmark-integration/src/test/resources/wrk-jwt-results.txt diff --git a/benchmarking/README.adoc b/benchmarking/README.adoc deleted file mode 100644 index 0c64077f..00000000 --- a/benchmarking/README.adoc +++ /dev/null @@ -1,307 +0,0 @@ -= API Sheriff Benchmarking - -Comprehensive performance testing and benchmarking suite for API Sheriff components, including both standalone library benchmarks and integration benchmarks for various frameworks. - -== Overview - -The benchmarking module provides thorough performance testing capabilities to ensure API Sheriff meets performance requirements across different deployment scenarios. It includes both micro-benchmarks for individual components and integration benchmarks for real-world usage patterns. - -== Modules - -=== benchmark-library -Standalone JMH benchmarks for the core API Sheriff library components, focusing on: -now verify that the - -=== benchmark-integration-quarkus -Integration benchmarks testing API Sheriff within Quarkus applications, including: - -* CDI injection overhead -* Configuration property loading performance -* Native image performance characteristics -* Real-world usage pattern simulation - -== Benchmark Categories - -=== Core Library Benchmarks - -==== Rate Limiting Performance -- Single-threaded request processing -- Multi-threaded concurrent access -- Rate limit exceeded scenarios -- Client state management operations - -==== Configuration Benchmarks -- Configuration validation performance -- Custom property access -- Builder pattern overhead - -==== Memory Benchmarks -- Object allocation patterns -- Garbage collection impact -- Memory usage scaling with client count - -=== Integration Benchmarks - -==== CDI Performance -- Injection overhead comparison -- Proxy call performance -- Bean lookup costs - -==== Quarkus Specific -- Application startup impact -- Configuration loading performance -- Native image execution characteristics - -== Running Benchmarks - -=== Prerequisites - -[source,bash] ----- -# Ensure you have sufficient system resources -# Recommended: 8GB+ RAM, dedicated CPU cores -export MAVEN_OPTS="-Xmx4G -XX:+UseG1GC" ----- - -=== Library Benchmarks - -Run micro benchmarks using the benchmark profile: - -[source,bash] ----- -./mvnw clean verify -Pbenchmark -pl benchmarking/benchmark-library ----- - -With custom JMH options via system properties: - -[source,bash] ----- -./mvnw clean verify -Pbenchmark -pl benchmarking/benchmark-library \ - -Djmh.warmupIterations=5 \ - -Djmh.measurementIterations=10 \ - -Djmh.forks=1 \ - -Djmh.threads=4 \ - -Djmh.time=2s ----- - -For JFR profiling: - -[source,bash] ----- -./mvnw clean verify -Pbenchmark-jfr -pl benchmarking/benchmark-library ----- - -=== Integration Benchmarks - -Run integration benchmarks with native Quarkus: - -[source,bash] ----- -./mvnw clean verify -Pbenchmark-testing -pl benchmarking/benchmark-integration-quarkus ----- - -For JFR profiling with native image: - -[source,bash] ----- -./mvnw clean verify -Pbenchmark-jfr -pl benchmarking/benchmark-integration-quarkus ----- - -== Benchmark Configuration - -=== JMH Parameters - -Common JMH configuration options: - -[cols="1,2,1"] -|=== -|Parameter |Description |Default - -|Warmup Iterations -|Number of warmup iterations -|3 - -|Measurement Iterations -|Number of measurement iterations -|5 - -|Forks -|Number of benchmark forks -|1 - -|Threads -|Number of benchmark threads -|1 - -|Mode -|Benchmark mode (Throughput/AverageTime) -|Throughput -|=== - -=== Parameterized Tests - -Benchmarks support various parameters: - -==== Rate Limiting Parameters -- `rateLimit`: 100, 1000, 10000 requests -- `timeWindow`: 1, 5, 10 seconds -- `clientCount`: 1, 10, 100 concurrent clients - -==== Load Parameters -- `concurrentThreads`: 1, 4, 8, 16 threads -- `requestBurst`: 10, 100, 1000 requests per burst -- `endpointVariation`: Different endpoint patterns - -== Benchmark Results Interpretation - -=== Throughput Benchmarks - -[source] ----- -Benchmark Mode Cnt Score Error Units -BenchmarkRunner.benchmarkSingleThreaded thrpt 5 2834.567 ยฑ 45.123 ops/s -BenchmarkRunner.benchmarkConcurrent thrpt 5 8234.123 ยฑ 89.456 ops/s ----- - -**Score**: Operations per second (higher is better) -**Error**: Statistical margin of error -**Units**: Operations per time unit - -=== Memory Benchmarks - -[source] ----- -Benchmark Mode Cnt Score Error Units -BenchmarkRunner.memoryAllocation avgt 5 12.345 ยฑ 0.123 ns/op - -Secondary metrics: -ยทGC.alloc.rate avgt 5 234.567 ยฑ 5.678 MB/sec -ยทGC.count avgt 5 2.000 ยฑ 0.000 counts ----- - -== Performance Targets - -=== Core Library Targets -- **Throughput**: >5,000 ops/sec single-threaded -- **Latency**: <1ms average request processing -- **Memory**: <100MB heap for 10,000 concurrent clients -- **Scaling**: Linear scaling up to 16 threads - -=== Integration Targets -- **CDI Overhead**: <5% performance impact -- **Startup Time**: <2 seconds additional startup -- **Native Image**: >90% of JVM performance -- **Configuration**: <10ms configuration loading - -== Continuous Benchmarking - -=== CI Integration - -[source,yaml] ----- -# .github/workflows/benchmarks.yml -name: Performance Benchmarks -on: - pull_request: - branches: [ main ] - schedule: - - cron: '0 2 * * *' # Daily at 2 AM - -jobs: - benchmark: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - name: Run Benchmarks - run: | - cd benchmarking - ./mvnw clean test -Pbenchmark ----- - -=== Performance Regression Detection - -Benchmarks include performance regression detection: - -[source,java] ----- -// Fail if performance drops below threshold -@Measurement(iterations = 5, time = 2) -@BenchmarkMode(Mode.Throughput) -@Fork(value = 1, jvmArgs = {"-Xmx2G"}) -public void benchmarkWithThreshold() { - // Test implementation - // CI will fail if throughput < baseline - 10% -} ----- - -== Custom Benchmarks - -=== Adding New Benchmarks - -[source,java] ----- -@Benchmark -@BenchmarkMode(Mode.AverageTime) -@OutputTimeUnit(TimeUnit.MICROSECONDS) -public long benchmarkCustomScenario() { - // Your benchmark implementation - return apiSheriff.customOperation(); -} ----- - -=== Benchmark Best Practices - -1. **Warm-up**: Always include adequate warm-up iterations -2. **Isolation**: Use separate JVM forks for reliable results -3. **Realistic Data**: Use representative test data -4. **Multiple Metrics**: Measure both throughput and latency -5. **Memory Profiling**: Include GC and allocation metrics -6. **Repeatability**: Ensure consistent test conditions - -== Analysis and Reporting - -=== Performance Reports - -Benchmarks generate comprehensive performance reports: - -- JSON results for automated analysis -- HTML reports with charts and graphs -- CSV data for spreadsheet analysis -- Performance trend tracking - -=== Profiling Integration - -Support for various profilers: - -[source,bash] ----- -# JProfiler integration -java -jar benchmarks.jar -prof jprofiler - -# Async profiler -java -jar benchmarks.jar -prof async - -# GC profiling -java -jar benchmarks.jar -prof gc ----- - -== Troubleshooting - -=== Common Issues - -**Out of Memory Errors** -[source,bash] ----- -export MAVEN_OPTS="-Xmx4G" -# Or reduce benchmark parameters ----- - -**Inconsistent Results** -- Ensure system is idle during benchmarks -- Use dedicated benchmark environment -- Increase measurement iterations - -**Native Image Issues** -- Verify GraalVM version compatibility -- Check reflection configuration -- Review native image build logs \ No newline at end of file diff --git a/benchmarking/doc/performance-scoring.adoc b/benchmarking/doc/performance-scoring.adoc deleted file mode 100644 index 6dd0497a..00000000 --- a/benchmarking/doc/performance-scoring.adoc +++ /dev/null @@ -1,107 +0,0 @@ -= JWT Performance Scoring System -:source-highlighter: highlight.js - -== Overview - -A weighted performance score combining throughput, latency, and error resilience into a single metric. - -== Formula - -[source,text] ----- -Performance Score = (Throughput ร— 0.57) + (Latency_Inverted ร— 0.40) + (Error_Resilience ร— 0.03) - -Where: -- Throughput = Operations/second (concurrent load) -- Latency_Inverted = 1,000,000 รท Average_Time_Microseconds -- Error_Resilience = Operations/second (0% error scenario) ----- - -== Metrics - -=== Throughput (57% weight) - -* Measures: Token validations per second under concurrent load -* Configuration: `@BenchmarkMode(Mode.Throughput)` with `@Threads(Threads.MAX)` -* Target: >10,000 ops/sec (good), >50,000 ops/sec (excellent) - -=== Latency (40% weight) - -* Measures: Average single-threaded validation time -* Configuration: `@BenchmarkMode(Mode.AverageTime)` with `@Threads(1)` -* Target: <100ฮผs (good), <50ฮผs (excellent) - -=== Error Resilience (3% weight) - -* Measures: Performance stability with invalid tokens -* Validates error handling doesn't degrade performance - -== Score Interpretation - -[cols="1,1,2", options="header"] -|=== -|Score Range |Level |Description - -|> 40,000 -|Exceptional -|High-scale production ready - -|30,000-40,000 -|Excellent -|Most production scenarios - -|20,000-30,000 -|Good -|Typical applications - -|10,000-20,000 -|Moderate -|Low-medium load - -|< 10,000 -|Needs Improvement -|Optimization required -|=== - -== Example Calculation - -[source,text] ----- -Throughput: 45,000 ops/sec -Average Time: 80 microseconds -Error Resilience: 40,000 ops/sec - -Latency_Inverted = 1,000,000 รท 80 = 12,500 ops/sec -Score = (45,000 ร— 0.57) + (12,500 ร— 0.40) + (40,000 ร— 0.03) - = 25,650 + 5,000 + 1,200 = 31,850 ----- - -== Badge Format - -[source,text] ----- -Performance Score: 32000 (45k ops/s, 0.15ms) - โ†‘ โ†‘ โ†‘ - | | โ””โ”€ Average validation time - | โ””โ”€ Throughput (rounded) - โ””โ”€ Weighted score ----- - -== Usage - -* **Regression Detection**: Track performance over releases -* **Optimization Tracking**: Measure improvement impact -* **Capacity Planning**: Understand performance characteristics - -== Limitations - -* Environment dependent (hardware, JVM settings) -* Based on synthetic test tokens -* Single library performance only - -== Best Practices - -1. Focus on trends over absolute values -2. Use consistent test environments -3. Run multiple iterations for accuracy -4. Consider context when interpreting results \ No newline at end of file diff --git a/benchmarking/pom.xml b/benchmarking/pom.xml deleted file mode 100644 index cba83ae9..00000000 --- a/benchmarking/pom.xml +++ /dev/null @@ -1,97 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project xmlns="http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> - <modelVersion>4.0.0</modelVersion> - <parent> - <groupId>de.cuioss.sheriff.api</groupId> - <artifactId>api-sheriff-parent</artifactId> - <version>1.0.0-SNAPSHOT</version> - <relativePath>../pom.xml</relativePath> - </parent> - - <artifactId>benchmarking</artifactId> - <packaging>pom</packaging> - <name>API Sheriff Benchmarking Parent</name> - <description>Parent module for all benchmarking related modules including library and integration benchmarks</description> - - <modules> - <module>benchmark-integration-wrk</module> - </modules> - - <properties> - <maven.jar.plugin.automatic.module.name>de.cuioss.sheriff.api.benchmarking</maven.jar.plugin.automatic.module.name> - <!-- External dependency versions --> - <version.gson>2.13.2</version.gson> - <version.hdrhistogram>2.2.2</version.hdrhistogram> - <version.commons-io>2.21.0</version.commons-io> - <!-- Skip benchmarks by default --> - <skip.benchmark>true</skip.benchmark> - - <!-- Sonar configuration: Skip analysis for benchmarking modules --> - <!-- Benchmarking code is for performance testing, not production code --> - <sonar.skip>true</sonar.skip> - </properties> - - <dependencyManagement> - <dependencies> - <dependency> - <groupId>com.google.code.gson</groupId> - <artifactId>gson</artifactId> - <version>${version.gson}</version> - </dependency> - <dependency> - <groupId>org.hdrhistogram</groupId> - <artifactId>HdrHistogram</artifactId> - <version>${version.hdrhistogram}</version> - </dependency> - <dependency> - <groupId>commons-io</groupId> - <artifactId>commons-io</artifactId> - <version>${version.commons-io}</version> - </dependency> - </dependencies> - </dependencyManagement> - <build> - <pluginManagement> - <plugins> - <plugin> - <groupId>org.codehaus.mojo</groupId> - <artifactId>exec-maven-plugin</artifactId> - <configuration> - <skip>${skip.benchmark}</skip> - </configuration> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-dependency-plugin</artifactId> - <executions> - <execution> - <id>copy-dependencies</id> - <phase>package</phase> - <goals> - <goal>copy-dependencies</goal> - </goals> - <configuration> - <outputDirectory>${project.build.directory}/dependency</outputDirectory> - <overWriteReleases>false</overWriteReleases> - <overWriteSnapshots>false</overWriteSnapshots> - <overWriteIfNewer>true</overWriteIfNewer> - <includeScope>runtime</includeScope> - </configuration> - </execution> - </executions> - </plugin> - </plugins> - </pluginManagement> - </build> - - <profiles> - <profile> - <id>benchmark</id> - <properties> - <skip.benchmark>false</skip.benchmark> - </properties> - </profile> - </profiles> -</project> diff --git a/pom.xml b/pom.xml index c14f7e59..4667d727 100644 --- a/pom.xml +++ b/pom.xml @@ -23,7 +23,7 @@ <modules> <module>api-sheriff</module> <module>api-sheriff-integration-tests</module> - <module>benchmarking</module> + <module>benchmark-integration</module> </modules> <scm> <url>https://github.com/cuioss/api-sheriff/</url> From 1f7a3058dd559e8ecf5e17dcf1a910a699191e74 Mon Sep 17 00:00:00 2001 From: Oliver Wolff <23139298+cuioss@users.noreply.github.com> Date: Wed, 4 Mar 2026 11:00:27 +0100 Subject: [PATCH 09/24] chore: Make api-sheriff the deployable Quarkus application MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move application code (QuarkusMain, REST resource) from api-sheriff-integration-tests into api-sheriff module, making it the standalone deployable application that produces the native executable. - Move TestApplication โ†’ ApiSheriffApplication in api-sheriff - Move TestResource โ†’ GatewayResource (@Path("/api")) in gateway package - Add application.properties with production defaults to api-sheriff - Add native profile, Jandex plugin, resteasy-jackson and prometheus deps - Simplify integration-tests to pure test coordinator (no compile Quarkus deps) - Update Dockerfiles to COPY runner from api-sheriff/target - Switch distroless Dockerfile to ubi9-quarkus-micro-image - Move all test-specific config to docker-compose environment variables - Update build/start scripts to target api-sheriff module - Fix OpenRewrite markers in GatewayResource and BaseIntegrationTest Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --- CLAUDE.md | 4 +- README.adoc | 4 +- .../docker-compose.yml | 40 +++++- api-sheriff-integration-tests/pom.xml | 119 +++++------------- .../scripts/benchmark-with-monitoring.sh | 4 +- .../scripts/build-native-if-needed.sh | 21 ++-- .../scripts/start-integration-container.sh | 19 +-- .../main/docker/Dockerfile.native.distroless | 15 ++- .../src/main/docker/Dockerfile.native.jfr | 10 +- .../src/main/resources/application.properties | 111 +--------------- .../api/integration/BaseIntegrationTest.java | 4 +- api-sheriff/pom.xml | 23 +++- .../de/cuioss/sheriff/api/ApiSheriff.java | 2 +- .../sheriff/api/ApiSheriffApplication.java | 11 +- .../sheriff/api/gateway/GatewayResource.java | 48 ++++--- .../sheriff/api/gateway/package-info.java | 25 ++++ .../api/quarkus/ApiSheriffProducer.java | 7 +- .../src/main/resources/application.properties | 34 +++++ benchmark-integration/pom.xml | 8 +- 19 files changed, 228 insertions(+), 281 deletions(-) rename api-sheriff-integration-tests/src/main/java/de/cuioss/sheriff/api/integration/TestApplication.java => api-sheriff/src/main/java/de/cuioss/sheriff/api/ApiSheriffApplication.java (79%) rename api-sheriff-integration-tests/src/main/java/de/cuioss/sheriff/api/integration/TestResource.java => api-sheriff/src/main/java/de/cuioss/sheriff/api/gateway/GatewayResource.java (55%) create mode 100644 api-sheriff/src/main/java/de/cuioss/sheriff/api/gateway/package-info.java create mode 100644 api-sheriff/src/main/resources/application.properties diff --git a/CLAUDE.md b/CLAUDE.md index 01be6aec..21f5b499 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -9,8 +9,8 @@ API Sheriff is a security-focused API Gateway with a lightweight approach, curre ## Project Structure Multi-module Maven project: -- `api-sheriff/` โ€” Unified Quarkus application (core library + CDI producers) -- `api-sheriff-integration-tests/` โ€” Integration tests with native container testing +- `api-sheriff/` โ€” Deployable Quarkus application (core library, CDI producers, REST endpoints, native executable) +- `api-sheriff-integration-tests/` โ€” Integration test coordinator (Docker infrastructure, IT suites, scripts) - `benchmark-integration/` โ€” WRK HTTP load testing benchmarks ## Build Commands diff --git a/README.adoc b/README.adoc index 3c368c32..de23a2f2 100644 --- a/README.adoc +++ b/README.adoc @@ -59,11 +59,11 @@ toc::[] === API Sheriff -The unified Quarkus application module containing the core library and CDI producers. +The deployable Quarkus application module โ€” core library, CDI producers, REST endpoints, and native executable target. === Integration Tests -End-to-end integration tests with native container testing and HTTPS support. +Integration test coordinator โ€” Docker infrastructure, native container builds, and IT suites with HTTPS support. === Performance Benchmarking diff --git a/api-sheriff-integration-tests/docker-compose.yml b/api-sheriff-integration-tests/docker-compose.yml index 39efd236..0ae4e12c 100644 --- a/api-sheriff-integration-tests/docker-compose.yml +++ b/api-sheriff-integration-tests/docker-compose.yml @@ -1,4 +1,4 @@ -# JWT Integration Tests - Production-Grade Configuration +# API Sheriff Integration Tests - Production-Grade Configuration # Purpose: Test with production-equivalent settings to catch issues early services: @@ -33,16 +33,16 @@ services: networks: - jwt-integration - api-sheriff-integration-tests: + api-sheriff: # Use separate Dockerfiles for different variants # For distroless: DOCKERFILE=Dockerfile.native.distroless DOCKER_IMAGE_TAG=distroless # For JFR: DOCKERFILE=Dockerfile.native.jfr DOCKER_IMAGE_TAG=jfr - image: "api-sheriff-integration-tests:${DOCKER_IMAGE_TAG:-distroless}" + image: "api-sheriff:${DOCKER_IMAGE_TAG:-distroless}" build: context: .. dockerfile: api-sheriff-integration-tests/src/main/docker/${DOCKERFILE:-Dockerfile.native.distroless} cache_from: - - quay.io/quarkus/quarkus-distroless-image:2.0 + - quay.io/quarkus/ubi9-quarkus-micro-image:2.0 - registry.access.redhat.com/ubi8/ubi-minimal:8.10 - quay.io/quarkus/ubi-quarkus-mandrel-builder-image:jdk-21 @@ -54,6 +54,38 @@ services: # JFR configuration handled by image variant (distroless vs JFR-enabled) - JAVA_OPTS_APPEND=-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager -Djdk.tls.rejectClientInitiatedRenegotiation=true -Djavax.net.ssl.sessionCacheSize=20480 -Djavax.net.ssl.sessionTimeout=300 -Djsse.enableSNIExtension=true -Djdk.tls.maxHandshakeMessageSize=65536 -Djdk.tls.maxCertificateChainLength=10 -Djdk.tls.useExtendedMasterSecret=true - QUARKUS_LOG_LEVEL=INFO + # Certificate paths (runtime override) + - QUARKUS_HTTP_SSL_CERTIFICATE_FILES=/app/certificates/localhost.crt + - QUARKUS_HTTP_SSL_CERTIFICATE_KEY_FILES=/app/certificates/localhost.key + - QUARKUS_TLS_DEFAULT_TRUST__STORE_P12_PATH=/app/certificates/localhost-truststore.p12 + - QUARKUS_TLS_DEFAULT_TRUST__STORE_P12_PASSWORD=localhost-trust + # JWT Issuer Configuration โ€” default issuer (static key, disabled for Docker tests) + - API_SHERIFF_ISSUERS_DEFAULT_ISSUER__IDENTIFIER=https://test-auth.example.com + - API_SHERIFF_ISSUERS_DEFAULT_ENABLED=false + - API_SHERIFF_ISSUERS_DEFAULT_JWKS_FILE__PATH=classpath:test-jwks.json + # JWT Issuer Configuration โ€” Keycloak issuer (well-known discovery) + - API_SHERIFF_ISSUERS_KEYCLOAK_ENABLED=true + - API_SHERIFF_ISSUERS_KEYCLOAK_ISSUER__IDENTIFIER=https://keycloak:8443/realms/benchmark + - API_SHERIFF_ISSUERS_KEYCLOAK_JWKS_HTTP_WELL__KNOWN__URL=https://keycloak:8443/realms/benchmark/.well-known/openid-configuration + - API_SHERIFF_ISSUERS_KEYCLOAK_EXPECTED__CLIENT__ID=benchmark-client + - API_SHERIFF_ISSUERS_KEYCLOAK_KEYCLOAK_MAPPERS_DEFAULT__ROLES_ENABLED=false + - API_SHERIFF_ISSUERS_KEYCLOAK_KEYCLOAK_MAPPERS_DEFAULT__GROUPS_ENABLED=false + - API_SHERIFF_ISSUERS_KEYCLOAK_CLAIM__SUB__OPTIONAL=true + # JWT Issuer Configuration โ€” Integration issuer (direct JWKS URL) + - API_SHERIFF_ISSUERS_INTEGRATION_ENABLED=true + - API_SHERIFF_ISSUERS_INTEGRATION_ISSUER__IDENTIFIER=https://keycloak:8443/realms/integration + - API_SHERIFF_ISSUERS_INTEGRATION_JWKS_HTTP_URL=https://keycloak:8443/realms/integration/protocol/openid-connect/certs + - API_SHERIFF_ISSUERS_INTEGRATION_EXPECTED__CLIENT__ID=integration-client + - API_SHERIFF_ISSUERS_INTEGRATION_KEYCLOAK_MAPPERS_DEFAULT__ROLES_ENABLED=false + - API_SHERIFF_ISSUERS_INTEGRATION_KEYCLOAK_MAPPERS_DEFAULT__GROUPS_ENABLED=false + - API_SHERIFF_ISSUERS_INTEGRATION_CLAIM__SUB__OPTIONAL=false + # Health check overrides for testing + - API_SHERIFF_HEALTH_JWKS_CACHE__SECONDS=30 + - API_SHERIFF_HEALTH_JWKS_TIMEOUT__SECONDS=5 + # Test overrides โ€” faster metrics, no caching + - API_SHERIFF_METRICS_COLLECTION_INTERVAL=2s + - API_SHERIFF_CACHE_ACCESS__TOKEN_MAX__SIZE=0 + - API_SHERIFF_CACHE_ACCESS__TOKEN_EVICTION__INTERVAL__SECONDS=10 depends_on: - keycloak diff --git a/api-sheriff-integration-tests/pom.xml b/api-sheriff-integration-tests/pom.xml index cb005c06..c2281d35 100644 --- a/api-sheriff-integration-tests/pom.xml +++ b/api-sheriff-integration-tests/pom.xml @@ -13,17 +13,13 @@ <artifactId>api-sheriff-integration-tests</artifactId> <packaging>jar</packaging> <name>API Sheriff Integration Tests</name> - <description>Integration tests for API Sheriff including native container testing with HTTPS support</description> + <description>Integration test coordinator for API Sheriff โ€” builds native containers and runs IT suites</description> <properties> <maven.jar.plugin.automatic.module.name>de.cuioss.sheriff.api.integration.tests</maven.jar.plugin.automatic.module.name> - <!-- Configure test execution - surefire skip, failsafe disabled by default --> + <!-- Configure test execution - failsafe disabled by default --> <skipITs>true</skipITs> - <!-- Native image build for integration tests - disabled by default --> - <quarkus.native.container-build>false</quarkus.native.container-build> - <quarkus.native.enabled>false</quarkus.native.enabled> - <!-- HTTPS configuration for testing (Docker external port) --> <test.https.port>10443</test.https.port> @@ -32,54 +28,12 @@ </properties> <dependencies> - <!-- API Sheriff Under Test --> + <!-- API Sheriff application (reactor dependency) --> <dependency> <groupId>de.cuioss.sheriff.api</groupId> <artifactId>api-sheriff</artifactId> </dependency> - <!-- Quarkus dependencies (previously inherited from quarkus-parent) --> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-core</artifactId> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-arc</artifactId> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-micrometer</artifactId> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-security</artifactId> - </dependency> - - <!-- Quarkus Extensions for REST and Health --> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-resteasy</artifactId> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-resteasy-jackson</artifactId> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-smallrye-health</artifactId> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-micrometer-registry-prometheus</artifactId> - </dependency> - - <!-- Other dependencies --> - <dependency> - <groupId>org.projectlombok</groupId> - <artifactId>lombok</artifactId> - </dependency> - <!-- API Sheriff Test Utilities for test material --> <dependency> <groupId>de.cuioss.sheriff.api</groupId> @@ -126,6 +80,17 @@ <build> <plugins> + <!-- Disable Quarkus build for this module (app is api-sheriff) --> + <plugin> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-maven-plugin</artifactId> + <executions> + <execution> + <id>default</id> + <phase>none</phase> + </execution> + </executions> + </plugin> <!-- Execute Docker cleanup before Maven clean --> <plugin> @@ -157,33 +122,14 @@ </build> <profiles> - <!-- Profile for running integration tests with distroless native image (no JFR) --> + <!-- Profile for running integration tests with native image --> <profile> <id>integration-tests</id> <properties> - <!-- Enable integration tests --> <skipITs>false</skipITs> - - <!-- Container-based native build with optimized rebuild detection --> - <quarkus.native.container-build>true</quarkus.native.container-build> - <quarkus.native.enabled>true</quarkus.native.enabled> </properties> <build> <plugins> - - <!-- Quarkus plugin (build only on-demand via script) --> - <plugin> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-maven-plugin</artifactId> - <executions> - <!-- Override parent's default execution to prevent automatic native build --> - <execution> - <id>default</id> - <phase>none</phase> - </execution> - </executions> - </plugin> - <!-- Skip Unit Tests (Surefire) --> <plugin> <groupId>org.apache.maven.plugins</groupId> @@ -210,7 +156,6 @@ <systemPropertyVariables> <test.https.port>${test.https.port}</test.https.port> <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager> - <quarkus.native.enabled>false</quarkus.native.enabled> </systemPropertyVariables> <skipITs>${skipITs}</skipITs> </configuration> @@ -223,7 +168,7 @@ <groupId>org.codehaus.mojo</groupId> <artifactId>exec-maven-plugin</artifactId> <executions> - <!-- Build native executable if needed --> + <!-- Build native executable if needed (targets api-sheriff module) --> <execution> <id>build-native-if-needed</id> <phase>pre-integration-test</phase> @@ -248,7 +193,7 @@ <arguments> <argument>compose</argument> <argument>build</argument> - <argument>api-sheriff-integration-tests</argument> + <argument>api-sheriff</argument> </arguments> <environmentVariables> <DOCKERFILE>Dockerfile.native.distroless</DOCKERFILE> @@ -291,25 +236,10 @@ <profile> <id>jfr</id> <properties> - <!-- Enable integration tests --> <skipITs>false</skipITs> - - <!-- JFR profile builds native executable with JFR support --> - <quarkus.native.enabled>true</quarkus.native.enabled> - <!-- Native build with JFR monitoring enabled --> - <quarkus.native.monitoring>jfr</quarkus.native.monitoring> - <quarkus.jfr.enabled>true</quarkus.jfr.enabled> </properties> <build> <plugins> - - <!-- Quarkus plugin with JFR support (native build) --> - <plugin> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-maven-plugin</artifactId> - <!-- Use parent configuration for native build --> - </plugin> - <!-- Skip Unit Tests (Surefire) --> <plugin> <groupId>org.apache.maven.plugins</groupId> @@ -336,7 +266,6 @@ <systemPropertyVariables> <test.https.port>${test.https.port}</test.https.port> <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager> - <quarkus.native.enabled>false</quarkus.native.enabled> </systemPropertyVariables> <skipITs>${skipITs}</skipITs> </configuration> @@ -349,6 +278,18 @@ <groupId>org.codehaus.mojo</groupId> <artifactId>exec-maven-plugin</artifactId> <executions> + <!-- Build native executable if needed (targets api-sheriff module) --> + <execution> + <id>build-native-if-needed</id> + <phase>pre-integration-test</phase> + <goals> + <goal>exec</goal> + </goals> + <configuration> + <executable>./scripts/build-native-if-needed.sh</executable> + <workingDirectory>${project.basedir}</workingDirectory> + </configuration> + </execution> <!-- Build Docker image with native JFR support --> <execution> <id>docker-build-jfr</id> @@ -362,7 +303,7 @@ <arguments> <argument>compose</argument> <argument>build</argument> - <argument>api-sheriff-integration-tests</argument> + <argument>api-sheriff</argument> </arguments> <environmentVariables> <DOCKERFILE>Dockerfile.native.jfr</DOCKERFILE> diff --git a/api-sheriff-integration-tests/scripts/benchmark-with-monitoring.sh b/api-sheriff-integration-tests/scripts/benchmark-with-monitoring.sh index 249037cb..57289ac5 100755 --- a/api-sheriff-integration-tests/scripts/benchmark-with-monitoring.sh +++ b/api-sheriff-integration-tests/scripts/benchmark-with-monitoring.sh @@ -360,11 +360,11 @@ trap cleanup INT TERM echo "๐Ÿ”จ Step 1: Building integration tests (~6 seconds)..." cd "$PROJECT_ROOT" -$MAVEN_CMD clean install -pl api-sheriff-integration-tests -q +$MAVEN_CMD clean install -pl api-sheriff -q echo "๐Ÿ”จ Step 2: Force clean rebuild of native executable and container (~90 seconds)..." # Ensure clean rebuild includes updated application.properties -$MAVEN_CMD clean package -pl api-sheriff-integration-tests -Pintegration-tests -q +$MAVEN_CMD clean package -pl api-sheriff -Pnative -q # Force Docker to rebuild container with updated configuration docker system prune -f --volumes >/dev/null 2>&1 || true diff --git a/api-sheriff-integration-tests/scripts/build-native-if-needed.sh b/api-sheriff-integration-tests/scripts/build-native-if-needed.sh index 0a258083..d3d55d5d 100755 --- a/api-sheriff-integration-tests/scripts/build-native-if-needed.sh +++ b/api-sheriff-integration-tests/scripts/build-native-if-needed.sh @@ -2,25 +2,26 @@ set -e # Script to build native executable if it doesn't exist +# Targets the api-sheriff module (the deployable application) SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_DIR="$(dirname "$SCRIPT_DIR")" +ROOT_DIR="$(cd "${PROJECT_DIR}/.." && pwd)" +APP_TARGET_DIR="${ROOT_DIR}/api-sheriff/target" -# Check if native executable exists -RUNNER_FILE=$(find "${PROJECT_DIR}/target" -name "*-runner" -type f 2>/dev/null | head -n 1) +# Check if native executable exists in api-sheriff target +RUNNER_FILE=$(find "${APP_TARGET_DIR}" -name "*-runner" -type f 2>/dev/null | head -n 1) if [[ -z "$RUNNER_FILE" ]]; then echo "๐Ÿ”จ Native executable not found, building it now..." echo "This will take approximately 2 minutes..." - - # Build native executable using Quarkus Maven plugin - # Find the root directory with mvnw - ROOT_DIR=$(cd "${PROJECT_DIR}/.." && pwd) + + # Build native executable using Quarkus Maven plugin on api-sheriff module cd "${ROOT_DIR}" - ./mvnw --no-transfer-progress -Pintegration-tests quarkus:build -pl api-sheriff-integration-tests - + ./mvnw --no-transfer-progress -Pnative quarkus:build -pl api-sheriff + # Verify it was created - RUNNER_FILE=$(find "${PROJECT_DIR}/target" -name "*-runner" -type f 2>/dev/null | head -n 1) + RUNNER_FILE=$(find "${APP_TARGET_DIR}" -name "*-runner" -type f 2>/dev/null | head -n 1) if [[ -z "$RUNNER_FILE" ]]; then echo "โŒ Failed to build native executable" exit 1 @@ -28,4 +29,4 @@ if [[ -z "$RUNNER_FILE" ]]; then echo "โœ… Native executable built: $(basename "$RUNNER_FILE")" else echo "โœ… Native executable already exists: $(basename "$RUNNER_FILE")" -fi \ No newline at end of file +fi diff --git a/api-sheriff-integration-tests/scripts/start-integration-container.sh b/api-sheriff-integration-tests/scripts/start-integration-container.sh index d932b7c1..be2af58b 100755 --- a/api-sheriff-integration-tests/scripts/start-integration-container.sh +++ b/api-sheriff-integration-tests/scripts/start-integration-container.sh @@ -1,11 +1,12 @@ #!/bin/bash -# Start JWT Integration Tests using Docker Compose +# Start API Sheriff Integration Tests using Docker Compose set -e SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" PROJECT_DIR="$(dirname "$SCRIPT_DIR")" ROOT_DIR="$(dirname "$PROJECT_DIR")" +APP_TARGET_DIR="${ROOT_DIR}/api-sheriff/target" echo "๐Ÿš€ Starting API Sheriff Integration Tests with Docker Compose" echo "Project directory: ${PROJECT_DIR}" @@ -14,10 +15,10 @@ echo "Root directory: ${ROOT_DIR}" cd "${PROJECT_DIR}" # Check build approach - Native executable + Docker copy vs Docker build -RUNNER_FILE=$(find target/ -name "*-runner" -type f 2>/dev/null | head -n 1) +RUNNER_FILE=$(find "${APP_TARGET_DIR}" -name "*-runner" -type f 2>/dev/null | head -n 1) # Detect image type - prefer JFR if available, fallback to distroless -JFR_IMAGE=$(docker images --format "{{.Repository}}:{{.Tag}}" | grep "^api-sheriff-integration-tests:jfr$" || true) -DISTROLESS_IMAGE=$(docker images --format "{{.Repository}}:{{.Tag}}" | grep "^api-sheriff-integration-tests:distroless$" || true) +JFR_IMAGE=$(docker images --format "{{.Repository}}:{{.Tag}}" | grep "^api-sheriff:jfr$" || true) +DISTROLESS_IMAGE=$(docker images --format "{{.Repository}}:{{.Tag}}" | grep "^api-sheriff:distroless$" || true) if [[ -n "$JFR_IMAGE" ]]; then AVAILABLE_IMAGE="$JFR_IMAGE" @@ -47,10 +48,10 @@ elif [[ "$IMAGE_EXISTS" == "true" ]]; then MODE="native (Docker-built) - $IMAGE_TYPE" else echo "โŒ Neither native executable nor Docker image found" - echo "Expected: target/*-runner file and api-sheriff-integration-tests image" + echo "Expected: api-sheriff/target/*-runner file and api-sheriff image" echo "Available images:" docker images | grep api-sheriff || echo " No api-sheriff images found" - echo "Run: mvnw verify -Pintegration-tests -pl api-sheriff-integration-tests" + echo "Run: mvnw verify -Pintegration-tests -pl api-sheriff-integration-tests -am" exit 1 fi @@ -88,7 +89,7 @@ for i in {1..30}; do fi if [ $i -eq 30 ]; then echo "โŒ Quarkus service failed to start within 30 seconds" - echo "Check logs with: docker compose logs api-sheriff-integration-tests" + echo "Check logs with: docker compose logs api-sheriff" exit 1 fi echo "โณ Waiting for Quarkus... (attempt $i/30)" @@ -96,13 +97,13 @@ for i in {1..30}; do done # Extract native startup time from logs -NATIVE_STARTUP=$(docker compose logs api-sheriff-integration-tests 2>/dev/null | grep "started in" | sed -n 's/.*started in \([0-9.]*\)s.*/\1/p' | tail -1) +NATIVE_STARTUP=$(docker compose logs api-sheriff 2>/dev/null | grep "started in" | sed -n 's/.*started in \([0-9.]*\)s.*/\1/p' | tail -1) if [ ! -z "$NATIVE_STARTUP" ]; then echo "โšก Native app startup: ${NATIVE_STARTUP}s (application only)" fi # Show actual image size -IMAGE_SIZE=$(docker images --format "table {{.Repository}}:{{.Tag}}\t{{.Size}}" | grep api-sheriff-integration-tests | awk '{print $2}' | head -1) +IMAGE_SIZE=$(docker images --format "table {{.Repository}}:{{.Tag}}\t{{.Size}}" | grep "api-sheriff:" | grep -v integration | awk '{print $2}' | head -1) if [ ! -z "$IMAGE_SIZE" ]; then echo "๐Ÿ“ฆ Image size: ${IMAGE_SIZE} (native image)" fi diff --git a/api-sheriff-integration-tests/src/main/docker/Dockerfile.native.distroless b/api-sheriff-integration-tests/src/main/docker/Dockerfile.native.distroless index 07d7b838..b1ab5a97 100644 --- a/api-sheriff-integration-tests/src/main/docker/Dockerfile.native.distroless +++ b/api-sheriff-integration-tests/src/main/docker/Dockerfile.native.distroless @@ -1,21 +1,20 @@ # Simple Dockerfile for copying pre-built native executable # This approach is much faster as it avoids rebuilding the native image in Docker -FROM quay.io/quarkus/quarkus-distroless-image:2.0 +FROM quay.io/quarkus/ubi9-quarkus-micro-image:2.0 -LABEL org.opencontainers.image.title="API Sheriff Integration Tests - Distroless" +LABEL org.opencontainers.image.title="API Sheriff - Native" LABEL org.opencontainers.image.description="Security-hardened Quarkus native application" LABEL org.opencontainers.image.vendor="CUI" LABEL org.opencontainers.image.version="1.0.0-SNAPSHOT" LABEL security.scan.required="true" -LABEL security.distroless="true" LABEL performance.jfr.enabled="false" WORKDIR /app -# Copy pre-built native executable from Maven target directory -COPY --chmod=0755 api-sheriff-integration-tests/target/*-runner /app/application +# Copy pre-built native executable from api-sheriff module target directory +COPY --chmod=0755 api-sheriff/target/*-runner /app/application -# Copy certificates and health check script +# Copy certificates and health check script from integration-tests infrastructure COPY --chmod=0755 api-sheriff-integration-tests/src/main/docker/health-check.sh /app/health-check.sh COPY --chmod=0644 api-sheriff-integration-tests/src/main/docker/certificates/localhost.crt /app/certificates/localhost.crt COPY --chmod=0600 api-sheriff-integration-tests/src/main/docker/certificates/localhost.key /app/certificates/localhost.key @@ -23,7 +22,7 @@ COPY --chmod=0644 api-sheriff-integration-tests/src/main/docker/certificates/loc EXPOSE 8443 HEALTHCHECK --interval=15s --timeout=5s --retries=3 --start-period=10s CMD ["/app/health-check.sh"] -USER nonroot +USER 1001 # Optimized entrypoint for production ENTRYPOINT ["/app/application", \ @@ -31,4 +30,4 @@ ENTRYPOINT ["/app/application", \ "-Djavax.net.ssl.trustStorePassword=localhost-trust", \ "-Djavax.net.ssl.trustStoreType=PKCS12", \ "-Djdk.tls.rejectClientInitiatedRenegotiation=true", \ - "-Djavax.net.ssl.sessionCacheSize=20480"] \ No newline at end of file + "-Djavax.net.ssl.sessionCacheSize=20480"] diff --git a/api-sheriff-integration-tests/src/main/docker/Dockerfile.native.jfr b/api-sheriff-integration-tests/src/main/docker/Dockerfile.native.jfr index a559f910..dae7ea26 100644 --- a/api-sheriff-integration-tests/src/main/docker/Dockerfile.native.jfr +++ b/api-sheriff-integration-tests/src/main/docker/Dockerfile.native.jfr @@ -2,7 +2,7 @@ # This approach is much faster as it avoids rebuilding the native image in Docker FROM quay.io/quarkus/ubi9-quarkus-micro-image:2.0 -LABEL org.opencontainers.image.title="API Sheriff Integration Tests - JFR" +LABEL org.opencontainers.image.title="API Sheriff - JFR" LABEL org.opencontainers.image.description="Quarkus native application with JFR profiling support" LABEL org.opencontainers.image.vendor="CUI" LABEL org.opencontainers.image.version="1.0.0-SNAPSHOT" @@ -11,10 +11,10 @@ LABEL performance.jfr.enabled="true" WORKDIR /app -# Copy pre-built native executable from Maven target directory -COPY --chmod=0755 api-sheriff-integration-tests/target/*-runner /app/application +# Copy pre-built native executable from api-sheriff module target directory +COPY --chmod=0755 api-sheriff/target/*-runner /app/application -# Copy certificates and health check script +# Copy certificates and health check script from integration-tests infrastructure COPY --chmod=0755 api-sheriff-integration-tests/src/main/docker/health-check.sh /app/health-check.sh COPY --chmod=0644 api-sheriff-integration-tests/src/main/docker/certificates/localhost.crt /app/certificates/localhost.crt COPY --chmod=0600 api-sheriff-integration-tests/src/main/docker/certificates/localhost.key /app/certificates/localhost.key @@ -33,4 +33,4 @@ ENTRYPOINT ["/app/application", \ "-Djavax.net.ssl.trustStorePassword=localhost-trust", \ "-Djavax.net.ssl.trustStoreType=PKCS12", \ "-XX:+FlightRecorder", \ - "-XX:StartFlightRecording=filename=/tmp/jfr-output/api-sheriff-profile.jfr,dumponexit=true,duration=240s,settings=profile"] \ No newline at end of file + "-XX:StartFlightRecording=filename=/tmp/jfr-output/api-sheriff-profile.jfr,dumponexit=true,duration=240s,settings=profile"] diff --git a/api-sheriff-integration-tests/src/main/resources/application.properties b/api-sheriff-integration-tests/src/main/resources/application.properties index 80731a05..927e29a3 100644 --- a/api-sheriff-integration-tests/src/main/resources/application.properties +++ b/api-sheriff-integration-tests/src/main/resources/application.properties @@ -1,108 +1,3 @@ -# JWT Integration Test Application Configuration - -# Application metadata -quarkus.application.name=api-sheriff-integration-tests -quarkus.application.version=1.0.0-SNAPSHOT - -# HTTPS Configuration for native image integration tests (using PEM certificates) -quarkus.http.ssl.certificate.files=/app/certificates/localhost.crt -quarkus.http.ssl.certificate.key-files=/app/certificates/localhost.key -quarkus.http.port=8080 -quarkus.http.ssl-port=8443 -# HTTPS Configuration - redirect HTTP requests to HTTPS for security -quarkus.http.insecure-requests=redirect - -# JWT Configuration for Integration Testing -# Default issuer for static key testing (disabled for Docker integration tests) -api.sheriff.issuers.default.issuer-identifier=https://test-auth.example.com -api.sheriff.issuers.default.enabled=false -api.sheriff.issuers.default.jwks.file-path=classpath:test-jwks.json - -# Keycloak issuer for well-known discovery testing (uses default mappers) -api.sheriff.issuers.keycloak.enabled=true -# IMPORTANT: issuer-identifier must match what Keycloak puts in tokens (Docker internal URL) -api.sheriff.issuers.keycloak.issuer-identifier=https://keycloak:8443/realms/benchmark -# JWKS URLs use internal Docker hostname for container-to-container communication -api.sheriff.issuers.keycloak.jwks.http.well-known-url=https://keycloak:8443/realms/benchmark/.well-known/openid-configuration -api.sheriff.issuers.keycloak.expected-client-id=benchmark-client -# Disable default mappers since benchmark realm uses protocol mappers directly -api.sheriff.issuers.keycloak.keycloak.mappers.default-roles.enabled=false -api.sheriff.issuers.keycloak.keycloak.mappers.default-groups.enabled=false -# Make subject claim optional for benchmark realm (Keycloak access tokens don't include 'sub' by default) -api.sheriff.issuers.keycloak.claim-sub-optional=true - -# Integration issuer for direct JWKS URL testing (uses protocol mappers) -api.sheriff.issuers.integration.enabled=true -# IMPORTANT: issuer-identifier must match what Keycloak puts in tokens (Docker internal URL) -api.sheriff.issuers.integration.issuer-identifier=https://keycloak:8443/realms/integration -# JWKS URLs use Docker service name for container-to-container communication -api.sheriff.issuers.integration.jwks.http.url=https://keycloak:8443/realms/integration/protocol/openid-connect/certs -api.sheriff.issuers.integration.expected-client-id=integration-client -# This issuer uses traditional protocol mappers (no default mappers needed) -# Disable default mappers since protocol mappers are configured in realm -api.sheriff.issuers.integration.keycloak.mappers.default-roles.enabled=false -api.sheriff.issuers.integration.keycloak.mappers.default-groups.enabled=false -# Subject claim is required since protocol mapper provides it -api.sheriff.issuers.integration.claim-sub-optional=false - - -# Health Checks -api.sheriff.health.enabled=true -api.sheriff.health.jwks.cache-seconds=30 -api.sheriff.health.jwks.timeout-seconds=5 - -# Security Provider Configuration -# Use default JCA providers for RSA operations - -# TLS Configuration for HTTPS endpoints with proper certificate validation -# Uses modern Quarkus TLS Registry for native image compatibility (research-based) -quarkus.ssl.native=true -quarkus.tls.default.trust-store.p12.path=/app/certificates/localhost-truststore.p12 -quarkus.tls.default.trust-store.p12.password=localhost-trust - -# Metrics Configuration -# Set faster collection interval for integration tests (2s instead of default 10s) -api.sheriff.metrics.collection.interval=2s - -# Cache Configuration for testing -# DISABLED for benchmark accuracy - set to 0 to force full validation on every request -api.sheriff.cache.access-token.max-size=0 -api.sheriff.cache.access-token.eviction-interval-seconds=10 - -# Logging -quarkus.log.level=INFO -quarkus.log.category."de.cuioss.sheriff".level=INFO - -# Development settings -quarkus.live-reload.instrumentation=false - -# Native Image Configuration -# Enable HTTPS protocol for JWT well-known discovery and JWKS endpoints -# TESTING: INFO logging level impact on performance (was DEBUG) -quarkus.native.additional-build-args=--enable-url-protocols=https,--enable-http,--enable-https,-O2 - -# JFR Configuration for Native Images (2024-2025 best practices) -quarkus.native.monitoring=jfr - -# TLS Performance Optimization -# Enable TLS 1.3 with 1.2 fallback for better handshake performance -quarkus.tls.protocols=TLSv1.3,TLSv1.2 -# Optimize cipher suites for performance (TLS 1.3 prioritized) -quarkus.tls.cipher-suites=TLS_AES_256_GCM_SHA384,TLS_CHACHA20_POLY1305_SHA256,TLS_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 -# Enable ALPN for HTTP/2 support -quarkus.tls.alpn=true -# Include certificates in native image -quarkus.native.resources.includes=**/*.p12,**/*.crt,**/*.key -# Container memory limit removed for build - will be applied at runtime via Docker -# Build requires unrestricted memory, runtime testing uses Docker --memory=64m - -# REST Configuration (default: /) - -# Virtual Threads Configuration (VERIFIED: 24-30% improvement) -quarkus.virtual-threads.name-prefix=jwt-validation -quarkus.virtual-threads.shutdown-timeout=10s - -# REMOVED UNVERIFIED OPTIMIZATIONS FOR TESTING: -# - JFR monitoring: --enable-monitoring=jfr (needs verification) -# - Compiler optimization: -O2 (needs verification) -# - Memory runtime options: -m=256m (needs verification) +# Integration Test Configuration +# Runtime configuration is provided via docker-compose.yml environment variables. +# This file is kept for classpath resource references only. diff --git a/api-sheriff-integration-tests/src/test/java/de/cuioss/sheriff/api/integration/BaseIntegrationTest.java b/api-sheriff-integration-tests/src/test/java/de/cuioss/sheriff/api/integration/BaseIntegrationTest.java index 768b850b..60312ff3 100644 --- a/api-sheriff-integration-tests/src/test/java/de/cuioss/sheriff/api/integration/BaseIntegrationTest.java +++ b/api-sheriff-integration-tests/src/test/java/de/cuioss/sheriff/api/integration/BaseIntegrationTest.java @@ -39,7 +39,7 @@ static void setUpBaseIntegrationTest() { String testPort = System.getProperty("test.https.port", DEFAULT_TEST_PORT); RestAssured.port = Integer.parseInt(testPort); - /*~~(TODO: Use CuiLogger. Suppress: // cui-rewrite:disable CuiLoggerStandardsRecipe)~~>*/ - /*~~(TODO: Use CuiLogger. Suppress: // cui-rewrite:disable CuiLoggerStandardsRecipe)~~>*/System.out.println("Integration tests configured for HTTPS port: " + testPort); + // cui-rewrite:disable CuiLoggerStandardsRecipe + System.out.println("Integration tests configured for HTTPS port: " + testPort); } } \ No newline at end of file diff --git a/api-sheriff/pom.xml b/api-sheriff/pom.xml index 7ba267b1..8f12859e 100644 --- a/api-sheriff/pom.xml +++ b/api-sheriff/pom.xml @@ -81,7 +81,14 @@ <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-resteasy</artifactId> - <optional>true</optional> + </dependency> + <dependency> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-resteasy-jackson</artifactId> + </dependency> + <dependency> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-micrometer-registry-prometheus</artifactId> </dependency> <!-- Test dependencies --> @@ -194,6 +201,10 @@ <groupId>io.quarkus</groupId> <artifactId>quarkus-maven-plugin</artifactId> </plugin> + <plugin> + <groupId>io.smallrye</groupId> + <artifactId>jandex-maven-plugin</artifactId> + </plugin> <!-- Create test-jar artifact with test utilities --> <plugin> <groupId>org.apache.maven.plugins</groupId> @@ -286,4 +297,14 @@ </plugin> </plugins> </build> + + <profiles> + <profile> + <id>native</id> + <properties> + <quarkus.native.container-build>true</quarkus.native.container-build> + <quarkus.native.enabled>true</quarkus.native.enabled> + </properties> + </profile> + </profiles> </project> diff --git a/api-sheriff/src/main/java/de/cuioss/sheriff/api/ApiSheriff.java b/api-sheriff/src/main/java/de/cuioss/sheriff/api/ApiSheriff.java index da94d12f..32ae830a 100644 --- a/api-sheriff/src/main/java/de/cuioss/sheriff/api/ApiSheriff.java +++ b/api-sheriff/src/main/java/de/cuioss/sheriff/api/ApiSheriff.java @@ -15,8 +15,8 @@ */ package de.cuioss.sheriff.api; -import de.cuioss.tools.logging.CuiLogger; import io.quarkus.runtime.annotations.RegisterForReflection; +import de.cuioss.tools.logging.CuiLogger; /** * Main API Sheriff class. diff --git a/api-sheriff-integration-tests/src/main/java/de/cuioss/sheriff/api/integration/TestApplication.java b/api-sheriff/src/main/java/de/cuioss/sheriff/api/ApiSheriffApplication.java similarity index 79% rename from api-sheriff-integration-tests/src/main/java/de/cuioss/sheriff/api/integration/TestApplication.java rename to api-sheriff/src/main/java/de/cuioss/sheriff/api/ApiSheriffApplication.java index 5709c446..9885bc3a 100644 --- a/api-sheriff-integration-tests/src/main/java/de/cuioss/sheriff/api/integration/TestApplication.java +++ b/api-sheriff/src/main/java/de/cuioss/sheriff/api/ApiSheriffApplication.java @@ -13,26 +13,27 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.cuioss.sheriff.api.integration; +package de.cuioss.sheriff.api; import io.quarkus.runtime.Quarkus; import io.quarkus.runtime.QuarkusApplication; import io.quarkus.runtime.annotations.QuarkusMain; /** - * Test application for API Sheriff integration testing. + * Main entry point for the API Sheriff gateway application. * <p> - * This application provides endpoints for testing API Sheriff functionality, + * This application provides the security-focused API Gateway with REST endpoints, * health checks, and metrics in a containerized environment. * * @author API Sheriff Team + * @since 1.0 */ @QuarkusMain -public class TestApplication implements QuarkusApplication { +public class ApiSheriffApplication implements QuarkusApplication { @Override public int run(String... args) throws Exception { Quarkus.waitForExit(); return 0; } -} \ No newline at end of file +} diff --git a/api-sheriff-integration-tests/src/main/java/de/cuioss/sheriff/api/integration/TestResource.java b/api-sheriff/src/main/java/de/cuioss/sheriff/api/gateway/GatewayResource.java similarity index 55% rename from api-sheriff-integration-tests/src/main/java/de/cuioss/sheriff/api/integration/TestResource.java rename to api-sheriff/src/main/java/de/cuioss/sheriff/api/gateway/GatewayResource.java index 89f80161..d76f1034 100644 --- a/api-sheriff-integration-tests/src/main/java/de/cuioss/sheriff/api/integration/TestResource.java +++ b/api-sheriff/src/main/java/de/cuioss/sheriff/api/gateway/GatewayResource.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.cuioss.sheriff.api.integration; +package de.cuioss.sheriff.api.gateway; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; @@ -27,59 +27,53 @@ import de.cuioss.sheriff.api.ApiSheriff; /** - * REST resource for testing API Sheriff integration in Quarkus applications. + * REST resource for the API Sheriff gateway providing health and info endpoints. * * @author API Sheriff Team + * @since 1.0 */ -@Path("/test") +@Path("/api") @ApplicationScoped @RegisterForReflection @Produces(MediaType.APPLICATION_JSON) -public class TestResource { +public class GatewayResource { @Inject ApiSheriff apiSheriff; /** * Health check endpoint to verify that API Sheriff is properly configured. - * + * * @return Response indicating the health status of API Sheriff */ @GET @Path("/health") @Produces(MediaType.APPLICATION_JSON) public Response health() { - try { - // Verify that ApiSheriff is properly injected and configured - if (apiSheriff == null) { - return Response.status(Response.Status.SERVICE_UNAVAILABLE) - .entity("{\"status\":\"DOWN\",\"reason\":\"ApiSheriff not available\"}") - .build(); - } - - // Get status to verify it's working - String status = apiSheriff.getStatus(); - - return Response.ok("{\"status\":\"UP\",\"apiSheriff\":\"" + status + "\"}") - .build(); - - } /*~~(TODO: Catch specific not Exception. Suppress: // cui-rewrite:disable InvalidExceptionUsageRecipe)~~>*/ catch (Exception e) { - return Response.status(Response.Status.INTERNAL_SERVER_ERROR) - .entity("{\"status\":\"DOWN\",\"error\":\"" + e.getMessage() + "\"}") + // Verify that ApiSheriff is properly injected and configured + if (apiSheriff == null) { + return Response.status(Response.Status.SERVICE_UNAVAILABLE) + .entity("{\"status\":\"DOWN\",\"reason\":\"ApiSheriff not available\"}") .build(); } + + // Get status to verify it's working + String status = apiSheriff.getStatus(); + + return Response.ok("{\"status\":\"UP\",\"apiSheriff\":\"" + status + "\"}") + .build(); } /** - * Test endpoint for basic API Sheriff functionality. - * - * @return Response with test information + * Info endpoint for basic API Sheriff status. + * + * @return Response with application information */ @GET @Path("/info") @Produces(MediaType.APPLICATION_JSON) public Response info() { - return Response.ok("{\"message\":\"API Sheriff Integration Test\",\"version\":\"1.0.0-SNAPSHOT\"}") + return Response.ok("{\"message\":\"API Sheriff Gateway\",\"version\":\"1.0.0-SNAPSHOT\"}") .build(); } -} \ No newline at end of file +} diff --git a/api-sheriff/src/main/java/de/cuioss/sheriff/api/gateway/package-info.java b/api-sheriff/src/main/java/de/cuioss/sheriff/api/gateway/package-info.java new file mode 100644 index 00000000..899e71e4 --- /dev/null +++ b/api-sheriff/src/main/java/de/cuioss/sheriff/api/gateway/package-info.java @@ -0,0 +1,25 @@ +/* + * Copyright ยฉ 2025 CUI-OpenSource-Software (info@cuioss.de) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Gateway REST endpoints for the API Sheriff application. + * <p> + * This package contains the JAX-RS resources that serve as the external API + * for the API Sheriff gateway, including health and info endpoints. + * + * @since 1.0 + */ +package de.cuioss.sheriff.api.gateway; diff --git a/api-sheriff/src/main/java/de/cuioss/sheriff/api/quarkus/ApiSheriffProducer.java b/api-sheriff/src/main/java/de/cuioss/sheriff/api/quarkus/ApiSheriffProducer.java index 3105e521..82942a03 100644 --- a/api-sheriff/src/main/java/de/cuioss/sheriff/api/quarkus/ApiSheriffProducer.java +++ b/api-sheriff/src/main/java/de/cuioss/sheriff/api/quarkus/ApiSheriffProducer.java @@ -15,12 +15,13 @@ */ package de.cuioss.sheriff.api.quarkus; -import de.cuioss.sheriff.api.ApiSheriff; -import de.cuioss.tools.logging.CuiLogger; -import io.quarkus.runtime.annotations.RegisterForReflection; import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.inject.Produces; +import io.quarkus.runtime.annotations.RegisterForReflection; +import de.cuioss.sheriff.api.ApiSheriff; +import de.cuioss.tools.logging.CuiLogger; + /** * CDI producer for API Sheriff components. * This class provides CDI integration for the API Sheriff library in Quarkus applications. diff --git a/api-sheriff/src/main/resources/application.properties b/api-sheriff/src/main/resources/application.properties new file mode 100644 index 00000000..80715903 --- /dev/null +++ b/api-sheriff/src/main/resources/application.properties @@ -0,0 +1,34 @@ +# API Sheriff Application Configuration + +# Application metadata +quarkus.application.name=api-sheriff + +# HTTP/HTTPS Configuration +quarkus.http.port=8080 +quarkus.http.ssl-port=8443 +quarkus.http.insecure-requests=redirect + +# TLS Configuration +quarkus.ssl.native=true +quarkus.tls.protocols=TLSv1.3,TLSv1.2 +quarkus.tls.cipher-suites=TLS_AES_256_GCM_SHA384,TLS_CHACHA20_POLY1305_SHA256,TLS_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 +quarkus.tls.alpn=true + +# Native Image Configuration +quarkus.native.additional-build-args=--enable-url-protocols=https,--enable-http,--enable-https,-O2 +quarkus.native.resources.includes=**/*.p12,**/*.crt,**/*.key +quarkus.native.monitoring=jfr + +# Virtual Threads Configuration +quarkus.virtual-threads.name-prefix=jwt-validation +quarkus.virtual-threads.shutdown-timeout=10s + +# Logging +quarkus.log.level=INFO +quarkus.log.category."de.cuioss.sheriff".level=INFO + +# Development settings +quarkus.live-reload.instrumentation=false + +# Health Checks +api.sheriff.health.enabled=true diff --git a/benchmark-integration/pom.xml b/benchmark-integration/pom.xml index 709e0f12..5061e975 100644 --- a/benchmark-integration/pom.xml +++ b/benchmark-integration/pom.xml @@ -184,7 +184,7 @@ <groupId>org.codehaus.mojo</groupId> <artifactId>exec-maven-plugin</artifactId> <executions> - <!-- Build integration tests (using smart native build script) --> + <!-- Build native executable and Docker image via integration-tests module --> <execution> <id>maven-build-integration-tests</id> <phase>pre-integration-test</phase> @@ -258,7 +258,7 @@ </configuration> </execution> - <!-- Clean integration tests to force container rebuild --> + <!-- Clean api-sheriff and integration-tests to force container rebuild --> <execution> <id>clean-integration-tests-for-rebuild</id> <phase>clean</phase> @@ -270,8 +270,10 @@ <executable>../mvnw</executable> <arguments> <argument>clean</argument> + <argument>-pl</argument> + <argument>api-sheriff,api-sheriff-integration-tests</argument> </arguments> - <workingDirectory>${project.basedir}/../api-sheriff-integration-tests</workingDirectory> + <workingDirectory>${project.basedir}/..</workingDirectory> </configuration> </execution> </executions> From e05ce57760d10eca38e37b9829c9d8c159d59ce7 Mon Sep 17 00:00:00 2001 From: Oliver Wolff <23139298+cuioss@users.noreply.github.com> Date: Wed, 4 Mar 2026 12:11:10 +0100 Subject: [PATCH 10/24] chore: Add production Dockerfile, fix integration tests, add benchmark tests - Add api-sheriff/src/main/docker/Dockerfile.native for production deployments without baked-in certificates - Fix ApiSheriffIntegrationIT paths from /test/ to /api/ and update response assertion to match GatewayResource output - Add GatewayEndpointBenchmarkTest for /api/health and /api/info WRK output parsing validation - Fix ../mvnw path bug in benchmark-integration pom.xml - Add deployment section to README.adoc and docker build commands to CLAUDE.md Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --- CLAUDE.md | 6 + README.adoc | 28 +++ .../integration/ApiSheriffIntegrationIT.java | 6 +- api-sheriff/src/main/docker/Dockerfile.native | 19 ++ benchmark-integration/pom.xml | 2 +- .../GatewayEndpointBenchmarkTest.java | 163 ++++++++++++++++++ 6 files changed, 220 insertions(+), 4 deletions(-) create mode 100644 api-sheriff/src/main/docker/Dockerfile.native create mode 100644 benchmark-integration/src/test/java/de/cuioss/sheriff/api/wrk/benchmark/GatewayEndpointBenchmarkTest.java diff --git a/CLAUDE.md b/CLAUDE.md index 21f5b499..31304c38 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -33,6 +33,12 @@ Multi-module Maven project: # Integration benchmarks (WRK) ./mvnw clean verify -pl benchmark-integration -Pbenchmark + +# Build native executable +./mvnw clean install -Pnative -pl api-sheriff -am -DskipTests + +# Build production Docker image +docker build -f api-sheriff/src/main/docker/Dockerfile.native -t api-sheriff:latest api-sheriff/ ``` ### Pre-Commit Process diff --git a/README.adoc b/README.adoc index de23a2f2..24c5e0ab 100644 --- a/README.adoc +++ b/README.adoc @@ -71,6 +71,34 @@ Integration benchmarks using WRK HTTP load testing with containerized environmen xref:benchmark-integration/doc/performance-scoring.adoc[Understand Performance Metrics] +== Deployment + +=== Production Docker Image + +Build the native executable and production Docker image: + +[source,bash] +---- +# Build native executable +./mvnw clean install -Pnative -pl api-sheriff -am -DskipTests + +# Build production Docker image +docker build -f api-sheriff/src/main/docker/Dockerfile.native -t api-sheriff:latest api-sheriff/ +---- + +Run with TLS certificates mounted at runtime: + +[source,bash] +---- +docker run -p 8443:8443 \ + -v /path/to/certs:/certs:ro \ + -e QUARKUS_HTTP_SSL_CERTIFICATE_FILES=/certs/server.crt \ + -e QUARKUS_HTTP_SSL_CERTIFICATE_KEY_FILES=/certs/server.key \ + api-sheriff:latest +---- + +* Port `8443` โ€” All endpoints (`/api/health`, `/api/info`, `/q/health`, `/q/metrics`) + == External Resources * https://cuioss.github.io/api-sheriff/about.html[Generated Documentation on GitHub Pages] \ No newline at end of file diff --git a/api-sheriff-integration-tests/src/test/java/de/cuioss/sheriff/api/integration/ApiSheriffIntegrationIT.java b/api-sheriff-integration-tests/src/test/java/de/cuioss/sheriff/api/integration/ApiSheriffIntegrationIT.java index 6f4f546a..e5ee2dd7 100644 --- a/api-sheriff-integration-tests/src/test/java/de/cuioss/sheriff/api/integration/ApiSheriffIntegrationIT.java +++ b/api-sheriff-integration-tests/src/test/java/de/cuioss/sheriff/api/integration/ApiSheriffIntegrationIT.java @@ -38,7 +38,7 @@ class ApiSheriffIntegrationIT extends BaseIntegrationTest { void apiSheriffHealthEndpoint() { given() .when() - .get("/test/health") + .get("/api/health") .then() .statusCode(200) .contentType("application/json") @@ -53,11 +53,11 @@ void apiSheriffHealthEndpoint() { void infoEndpoint() { given() .when() - .get("/test/info") + .get("/api/info") .then() .statusCode(200) .contentType("application/json") - .body("message", containsString("API Sheriff Integration Test")) + .body("message", containsString("API Sheriff Gateway")) .body("version", containsString("1.0.0-SNAPSHOT")); } diff --git a/api-sheriff/src/main/docker/Dockerfile.native b/api-sheriff/src/main/docker/Dockerfile.native new file mode 100644 index 00000000..9c999afa --- /dev/null +++ b/api-sheriff/src/main/docker/Dockerfile.native @@ -0,0 +1,19 @@ +# Production Dockerfile for API Sheriff native executable +# No baked-in certificates โ€” mount TLS certs at runtime via volumes or secrets +FROM quay.io/quarkus/ubi9-quarkus-micro-image:2.0 + +LABEL org.opencontainers.image.title="API Sheriff" +LABEL org.opencontainers.image.description="Security-focused API Gateway โ€” Quarkus native executable" +LABEL org.opencontainers.image.vendor="CUIoss" +LABEL org.opencontainers.image.licenses="Apache-2.0" +LABEL org.opencontainers.image.source="https://github.com/cuioss/API-Sheriff" +LABEL org.opencontainers.image.base.name="quay.io/quarkus/ubi9-quarkus-micro-image:2.0" + +WORKDIR /work/ +COPY --chown=1001:root --chmod=0755 target/*-runner /work/application +RUN chown 1001 /work && chmod "g+rwX" /work && chown 1001:root /work + +EXPOSE 8443 +USER 1001 + +ENTRYPOINT ["./application", "-Dquarkus.http.host=0.0.0.0"] diff --git a/benchmark-integration/pom.xml b/benchmark-integration/pom.xml index 5061e975..ba5b3fbf 100644 --- a/benchmark-integration/pom.xml +++ b/benchmark-integration/pom.xml @@ -267,7 +267,7 @@ </goals> <configuration> <skip>${skip.container.lifecycle}</skip> - <executable>../mvnw</executable> + <executable>./mvnw</executable> <arguments> <argument>clean</argument> <argument>-pl</argument> diff --git a/benchmark-integration/src/test/java/de/cuioss/sheriff/api/wrk/benchmark/GatewayEndpointBenchmarkTest.java b/benchmark-integration/src/test/java/de/cuioss/sheriff/api/wrk/benchmark/GatewayEndpointBenchmarkTest.java new file mode 100644 index 00000000..3db9df1d --- /dev/null +++ b/benchmark-integration/src/test/java/de/cuioss/sheriff/api/wrk/benchmark/GatewayEndpointBenchmarkTest.java @@ -0,0 +1,163 @@ +/* + * Copyright ยฉ 2025 CUI-OpenSource-Software (info@cuioss.de) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.cuioss.sheriff.api.wrk.benchmark; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import java.nio.file.Files; +import java.nio.file.Path; + +import static de.cuioss.sheriff.api.wrk.benchmark.WrkResultPostProcessor.BENCHMARK_NAME_HEALTH; +import static de.cuioss.sheriff.api.wrk.benchmark.WrkResultPostProcessor.WRK_HEALTH_OUTPUT_FILE; +import static org.junit.jupiter.api.Assertions.*; + + +/** + * Tests WRK output parsing for the {@code /api/health} and {@code /api/info} + * gateway endpoints. Uses synthetic WRK output to validate the parsing pipeline + * without requiring running containers. + * + * @author API Sheriff Team + * @since 1.0 + */ +class GatewayEndpointBenchmarkTest { + + @TempDir + Path tempDir; + + private WrkResultPostProcessor processor; + + @BeforeEach + void setUp() { + processor = new WrkResultPostProcessor(); + } + + @Test + void parseGatewayHealthBenchmark() throws Exception { + // Arrange โ€” synthetic WRK output for /api/health gateway endpoint + String wrkOutput = """ + === BENCHMARK METADATA === + benchmark_name: healthCheck + start_time: 1700000000 + start_time_iso: 2023-11-14T22:13:20Z + === WRK OUTPUT === + + Running 30s test @ https://localhost:10443/api/health + 4 threads and 50 connections + Thread Stats Avg Stdev Max +/- Stdev + Latency 650.00us 300.00us 8.00ms 92.00% + Req/Sec 7.50k 800.00 12.00k 70.00% + Latency Distribution + 50% 600.00us + 75% 0.85ms + 90% 1.10ms + 99% 2.50ms + 450000 requests in 30.00s, 120.00MB read + Requests/sec: 15000.00 + Transfer/sec: 4.00MB + + === BENCHMARK COMPLETE === + end_time: 1700000030 + end_time_iso: 2023-11-14T22:13:50Z + duration_seconds: 30 + """; + + Path wrkDir = tempDir.resolve("wrk"); + Files.createDirectories(wrkDir); + Files.writeString(wrkDir.resolve(WRK_HEALTH_OUTPUT_FILE), wrkOutput); + + // Act + Path outputDir = tempDir.resolve("output"); + processor.process(tempDir, outputDir); + + // Assert โ€” verify JSON structure and percentile ordering + Path jsonFile = outputDir.resolve("gh-pages-ready/data/benchmark-data.json"); + assertTrue(Files.exists(jsonFile), "Benchmark data JSON should be created"); + + JsonObject json = JsonParser.parseString(Files.readString(jsonFile)).getAsJsonObject(); + JsonObject benchmark = json.getAsJsonArray("benchmarks").get(0).getAsJsonObject(); + + assertEquals(BENCHMARK_NAME_HEALTH, benchmark.get("name").getAsString()); + assertTrue(benchmark.has("score"), "Benchmark should have score"); + assertTrue(benchmark.has("scoreUnit"), "Benchmark should have scoreUnit"); + + JsonObject percentiles = benchmark.getAsJsonObject("percentiles"); + assertTrue(percentiles.get("50.0").getAsDouble() <= percentiles.get("75.0").getAsDouble(), + "P50 should be <= P75"); + assertTrue(percentiles.get("75.0").getAsDouble() <= percentiles.get("90.0").getAsDouble(), + "P75 should be <= P90"); + assertTrue(percentiles.get("90.0").getAsDouble() <= percentiles.get("99.0").getAsDouble(), + "P90 should be <= P99"); + } + + @Test + void parseGatewayInfoBenchmark() throws Exception { + // Arrange โ€” synthetic WRK output for /api/info endpoint using health output file + String wrkOutput = """ + === BENCHMARK METADATA === + benchmark_name: healthCheck + start_time: 1700000000 + start_time_iso: 2023-11-14T22:13:20Z + === WRK OUTPUT === + + Running 30s test @ https://localhost:10443/api/info + 4 threads and 50 connections + Thread Stats Avg Stdev Max +/- Stdev + Latency 700.00us 350.00us 9.00ms 91.00% + Req/Sec 7.00k 750.00 11.00k 72.00% + Latency Distribution + 50% 650.00us + 75% 0.90ms + 90% 1.20ms + 99% 2.80ms + 420000 requests in 30.00s, 110.00MB read + Requests/sec: 14000.00 + Transfer/sec: 3.67MB + + === BENCHMARK COMPLETE === + end_time: 1700000030 + end_time_iso: 2023-11-14T22:13:50Z + duration_seconds: 30 + """; + + Path wrkDir = tempDir.resolve("wrk"); + Files.createDirectories(wrkDir); + Files.writeString(wrkDir.resolve(WRK_HEALTH_OUTPUT_FILE), wrkOutput); + + // Act + Path outputDir = tempDir.resolve("output"); + processor.process(tempDir, outputDir); + + // Assert โ€” verify parsing succeeds with different latency values + Path jsonFile = outputDir.resolve("gh-pages-ready/data/benchmark-data.json"); + assertTrue(Files.exists(jsonFile), "Benchmark data JSON should be created"); + + JsonObject json = JsonParser.parseString(Files.readString(jsonFile)).getAsJsonObject(); + JsonObject benchmark = json.getAsJsonArray("benchmarks").get(0).getAsJsonObject(); + + assertFalse(benchmark.get("score").getAsString().isEmpty(), "Score should not be empty"); + + JsonObject percentiles = benchmark.getAsJsonObject("percentiles"); + double p50 = percentiles.get("50.0").getAsDouble(); + double p99 = percentiles.get("99.0").getAsDouble(); + assertTrue(p50 > 0, "P50 should be positive"); + assertTrue(p50 <= p99, "P50 should be <= P99"); + } +} From d30630c4399cb28908a88dc8f8370856b777275b Mon Sep 17 00:00:00 2001 From: Oliver Wolff <23139298+cuioss@users.noreply.github.com> Date: Wed, 4 Mar 2026 12:17:15 +0100 Subject: [PATCH 11/24] chore: Remove invalid and dead properties from application.properties - Remove quarkus.virtual-threads.shutdown-timeout (non-existent property, caused duration parse error) - Remove api.sheriff.health.enabled (not wired to any @ConfigProperty) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --- api-sheriff/src/main/resources/application.properties | 4 ---- 1 file changed, 4 deletions(-) diff --git a/api-sheriff/src/main/resources/application.properties b/api-sheriff/src/main/resources/application.properties index 80715903..6ba0e014 100644 --- a/api-sheriff/src/main/resources/application.properties +++ b/api-sheriff/src/main/resources/application.properties @@ -21,7 +21,6 @@ quarkus.native.monitoring=jfr # Virtual Threads Configuration quarkus.virtual-threads.name-prefix=jwt-validation -quarkus.virtual-threads.shutdown-timeout=10s # Logging quarkus.log.level=INFO @@ -29,6 +28,3 @@ quarkus.log.category."de.cuioss.sheriff".level=INFO # Development settings quarkus.live-reload.instrumentation=false - -# Health Checks -api.sheriff.health.enabled=true From 2b22392fd5e963d26b615afd80798730018eb62b Mon Sep 17 00:00:00 2001 From: Oliver Wolff <23139298+cuioss@users.noreply.github.com> Date: Wed, 4 Mar 2026 13:07:22 +0100 Subject: [PATCH 12/24] chore: Consolidate Dockerfiles into api-sheriff module Test what we deliver: production Dockerfiles now live in api-sheriff/src/main/docker/ and integration tests use them directly. Test-specific configuration (TLS truststore, certificates) is injected at docker-compose level instead of being baked into separate Dockerfiles. - Dockerfile.native: distroless production image (digest-pinned, nonroot, no shell, no baked-in certs) - Dockerfile.native.jfr: UBI micro with JFR profiling support - Delete redundant test Dockerfiles from integration-tests module - docker-compose: use production images with command: for truststore flags and volume mounts for certificates - Fix Dockerfile reference in pom.xml and start script Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --- .../docker-compose.yml | 33 +++++++++-------- api-sheriff-integration-tests/pom.xml | 2 +- .../scripts/start-integration-container.sh | 2 +- .../main/docker/Dockerfile.native.distroless | 33 ----------------- .../src/main/docker/Dockerfile.native.jfr | 36 ------------------- api-sheriff/src/main/docker/Dockerfile.native | 20 +++++++---- .../src/main/docker/Dockerfile.native.jfr | 35 ++++++++++++++++++ 7 files changed, 66 insertions(+), 95 deletions(-) delete mode 100644 api-sheriff-integration-tests/src/main/docker/Dockerfile.native.distroless delete mode 100644 api-sheriff-integration-tests/src/main/docker/Dockerfile.native.jfr create mode 100644 api-sheriff/src/main/docker/Dockerfile.native.jfr diff --git a/api-sheriff-integration-tests/docker-compose.yml b/api-sheriff-integration-tests/docker-compose.yml index 0ae4e12c..2f187f26 100644 --- a/api-sheriff-integration-tests/docker-compose.yml +++ b/api-sheriff-integration-tests/docker-compose.yml @@ -34,25 +34,29 @@ services: - jwt-integration api-sheriff: - # Use separate Dockerfiles for different variants - # For distroless: DOCKERFILE=Dockerfile.native.distroless DOCKER_IMAGE_TAG=distroless - # For JFR: DOCKERFILE=Dockerfile.native.jfr DOCKER_IMAGE_TAG=jfr + # Production Dockerfiles from api-sheriff module โ€” test instrumentation at compose level + # For distroless: DOCKERFILE=Dockerfile.native DOCKER_IMAGE_TAG=distroless (default) + # For JFR: DOCKERFILE=Dockerfile.native.jfr DOCKER_IMAGE_TAG=jfr image: "api-sheriff:${DOCKER_IMAGE_TAG:-distroless}" build: - context: .. - dockerfile: api-sheriff-integration-tests/src/main/docker/${DOCKERFILE:-Dockerfile.native.distroless} + context: ../api-sheriff + dockerfile: src/main/docker/${DOCKERFILE:-Dockerfile.native} cache_from: + - quay.io/quarkus/quarkus-distroless-image:2.0 - quay.io/quarkus/ubi9-quarkus-micro-image:2.0 - - registry.access.redhat.com/ubi8/ubi-minimal:8.10 - - quay.io/quarkus/ubi-quarkus-mandrel-builder-image:jdk-21 ports: - "10443:8443" # External test port for integration tests + # Test-specific TLS truststore flags (not baked into production image) + command: + - "-Djavax.net.ssl.trustStore=/app/certificates/localhost-truststore.p12" + - "-Djavax.net.ssl.trustStorePassword=localhost-trust" + - "-Djavax.net.ssl.trustStoreType=PKCS12" + - "-Djdk.tls.rejectClientInitiatedRenegotiation=true" + - "-Djavax.net.ssl.sessionCacheSize=20480" + environment: - # JVM SSL Session Cache Optimization for TLS Performance - # JFR configuration handled by image variant (distroless vs JFR-enabled) - - JAVA_OPTS_APPEND=-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager -Djdk.tls.rejectClientInitiatedRenegotiation=true -Djavax.net.ssl.sessionCacheSize=20480 -Djavax.net.ssl.sessionTimeout=300 -Djsse.enableSNIExtension=true -Djdk.tls.maxHandshakeMessageSize=65536 -Djdk.tls.maxCertificateChainLength=10 -Djdk.tls.useExtendedMasterSecret=true - QUARKUS_LOG_LEVEL=INFO # Certificate paths (runtime override) - QUARKUS_HTTP_SSL_CERTIFICATE_FILES=/app/certificates/localhost.crt @@ -119,13 +123,8 @@ services: memory: 256M cpus: '1.0' - # Health check using internal script (optimized for fast native startup) - healthcheck: - test: ["CMD", "/app/health-check.sh"] - interval: 15s - timeout: 5s - retries: 3 - start_period: 10s + # Health check: startup script handles readiness via external curl probe + # No Docker HEALTHCHECK โ€” distroless has no shell; JFR variant has its own # Network isolation (production pattern) networks: diff --git a/api-sheriff-integration-tests/pom.xml b/api-sheriff-integration-tests/pom.xml index c2281d35..1a53bc08 100644 --- a/api-sheriff-integration-tests/pom.xml +++ b/api-sheriff-integration-tests/pom.xml @@ -196,7 +196,7 @@ <argument>api-sheriff</argument> </arguments> <environmentVariables> - <DOCKERFILE>Dockerfile.native.distroless</DOCKERFILE> + <DOCKERFILE>Dockerfile.native</DOCKERFILE> <DOCKER_IMAGE_TAG>distroless</DOCKER_IMAGE_TAG> <DOCKER_BUILDKIT>1</DOCKER_BUILDKIT> </environmentVariables> diff --git a/api-sheriff-integration-tests/scripts/start-integration-container.sh b/api-sheriff-integration-tests/scripts/start-integration-container.sh index be2af58b..71ae5b49 100755 --- a/api-sheriff-integration-tests/scripts/start-integration-container.sh +++ b/api-sheriff-integration-tests/scripts/start-integration-container.sh @@ -29,7 +29,7 @@ elif [[ -n "$DISTROLESS_IMAGE" ]]; then AVAILABLE_IMAGE="$DISTROLESS_IMAGE" IMAGE_TYPE="distroless" export DOCKER_IMAGE_TAG="distroless" - export DOCKERFILE="Dockerfile.native.distroless" + export DOCKERFILE="Dockerfile.native" else AVAILABLE_IMAGE="" IMAGE_TYPE="none" diff --git a/api-sheriff-integration-tests/src/main/docker/Dockerfile.native.distroless b/api-sheriff-integration-tests/src/main/docker/Dockerfile.native.distroless deleted file mode 100644 index b1ab5a97..00000000 --- a/api-sheriff-integration-tests/src/main/docker/Dockerfile.native.distroless +++ /dev/null @@ -1,33 +0,0 @@ -# Simple Dockerfile for copying pre-built native executable -# This approach is much faster as it avoids rebuilding the native image in Docker -FROM quay.io/quarkus/ubi9-quarkus-micro-image:2.0 - -LABEL org.opencontainers.image.title="API Sheriff - Native" -LABEL org.opencontainers.image.description="Security-hardened Quarkus native application" -LABEL org.opencontainers.image.vendor="CUI" -LABEL org.opencontainers.image.version="1.0.0-SNAPSHOT" -LABEL security.scan.required="true" -LABEL performance.jfr.enabled="false" - -WORKDIR /app - -# Copy pre-built native executable from api-sheriff module target directory -COPY --chmod=0755 api-sheriff/target/*-runner /app/application - -# Copy certificates and health check script from integration-tests infrastructure -COPY --chmod=0755 api-sheriff-integration-tests/src/main/docker/health-check.sh /app/health-check.sh -COPY --chmod=0644 api-sheriff-integration-tests/src/main/docker/certificates/localhost.crt /app/certificates/localhost.crt -COPY --chmod=0600 api-sheriff-integration-tests/src/main/docker/certificates/localhost.key /app/certificates/localhost.key -COPY --chmod=0644 api-sheriff-integration-tests/src/main/docker/certificates/localhost-truststore.p12 /app/certificates/localhost-truststore.p12 - -EXPOSE 8443 -HEALTHCHECK --interval=15s --timeout=5s --retries=3 --start-period=10s CMD ["/app/health-check.sh"] -USER 1001 - -# Optimized entrypoint for production -ENTRYPOINT ["/app/application", \ - "-Djavax.net.ssl.trustStore=/app/certificates/localhost-truststore.p12", \ - "-Djavax.net.ssl.trustStorePassword=localhost-trust", \ - "-Djavax.net.ssl.trustStoreType=PKCS12", \ - "-Djdk.tls.rejectClientInitiatedRenegotiation=true", \ - "-Djavax.net.ssl.sessionCacheSize=20480"] diff --git a/api-sheriff-integration-tests/src/main/docker/Dockerfile.native.jfr b/api-sheriff-integration-tests/src/main/docker/Dockerfile.native.jfr deleted file mode 100644 index dae7ea26..00000000 --- a/api-sheriff-integration-tests/src/main/docker/Dockerfile.native.jfr +++ /dev/null @@ -1,36 +0,0 @@ -# Simple Dockerfile for copying pre-built native executable with JFR support -# This approach is much faster as it avoids rebuilding the native image in Docker -FROM quay.io/quarkus/ubi9-quarkus-micro-image:2.0 - -LABEL org.opencontainers.image.title="API Sheriff - JFR" -LABEL org.opencontainers.image.description="Quarkus native application with JFR profiling support" -LABEL org.opencontainers.image.vendor="CUI" -LABEL org.opencontainers.image.version="1.0.0-SNAPSHOT" -LABEL security.scan.required="true" -LABEL performance.jfr.enabled="true" - -WORKDIR /app - -# Copy pre-built native executable from api-sheriff module target directory -COPY --chmod=0755 api-sheriff/target/*-runner /app/application - -# Copy certificates and health check script from integration-tests infrastructure -COPY --chmod=0755 api-sheriff-integration-tests/src/main/docker/health-check.sh /app/health-check.sh -COPY --chmod=0644 api-sheriff-integration-tests/src/main/docker/certificates/localhost.crt /app/certificates/localhost.crt -COPY --chmod=0600 api-sheriff-integration-tests/src/main/docker/certificates/localhost.key /app/certificates/localhost.key -COPY --chmod=0644 api-sheriff-integration-tests/src/main/docker/certificates/localhost-truststore.p12 /app/certificates/localhost-truststore.p12 - -# Create JFR output directory with proper permissions -RUN mkdir -p /tmp/jfr-output && chmod 777 /tmp/jfr-output - -EXPOSE 8443 -HEALTHCHECK --interval=15s --timeout=8s --retries=3 --start-period=15s CMD ["/app/health-check.sh"] -USER 1001 - -# JFR-enabled entrypoint with profiling optimized for benchmarking -ENTRYPOINT ["/app/application", \ - "-Djavax.net.ssl.trustStore=/app/certificates/localhost-truststore.p12", \ - "-Djavax.net.ssl.trustStorePassword=localhost-trust", \ - "-Djavax.net.ssl.trustStoreType=PKCS12", \ - "-XX:+FlightRecorder", \ - "-XX:StartFlightRecording=filename=/tmp/jfr-output/api-sheriff-profile.jfr,dumponexit=true,duration=240s,settings=profile"] diff --git a/api-sheriff/src/main/docker/Dockerfile.native b/api-sheriff/src/main/docker/Dockerfile.native index 9c999afa..b293ee90 100644 --- a/api-sheriff/src/main/docker/Dockerfile.native +++ b/api-sheriff/src/main/docker/Dockerfile.native @@ -1,19 +1,25 @@ # Production Dockerfile for API Sheriff native executable +# Distroless: no shell, no package manager โ€” minimal attack surface # No baked-in certificates โ€” mount TLS certs at runtime via volumes or secrets -FROM quay.io/quarkus/ubi9-quarkus-micro-image:2.0 +# Health probes handled externally by orchestrator (Kubernetes liveness/readiness) +FROM quay.io/quarkus/quarkus-distroless-image:2.0@sha256:0278fd70d9627df836295570da0fd22034ea664efc12a834a0532cea7556a87b LABEL org.opencontainers.image.title="API Sheriff" LABEL org.opencontainers.image.description="Security-focused API Gateway โ€” Quarkus native executable" +LABEL org.opencontainers.image.version="1.0.0-SNAPSHOT" LABEL org.opencontainers.image.vendor="CUIoss" LABEL org.opencontainers.image.licenses="Apache-2.0" LABEL org.opencontainers.image.source="https://github.com/cuioss/API-Sheriff" -LABEL org.opencontainers.image.base.name="quay.io/quarkus/ubi9-quarkus-micro-image:2.0" +LABEL org.opencontainers.image.base.name="quay.io/quarkus/quarkus-distroless-image:2.0" +LABEL security.scan.required="true" +LABEL security.distroless="true" -WORKDIR /work/ -COPY --chown=1001:root --chmod=0755 target/*-runner /work/application -RUN chown 1001 /work && chmod "g+rwX" /work && chown 1001:root /work +WORKDIR /app + +# Copy pre-built native executable +COPY --chmod=0755 target/*-runner /app/application EXPOSE 8443 -USER 1001 +USER nonroot -ENTRYPOINT ["./application", "-Dquarkus.http.host=0.0.0.0"] +ENTRYPOINT ["/app/application", "-Dquarkus.http.host=0.0.0.0"] diff --git a/api-sheriff/src/main/docker/Dockerfile.native.jfr b/api-sheriff/src/main/docker/Dockerfile.native.jfr new file mode 100644 index 00000000..af7fbf15 --- /dev/null +++ b/api-sheriff/src/main/docker/Dockerfile.native.jfr @@ -0,0 +1,35 @@ +# JFR-enabled Dockerfile for API Sheriff native executable +# UBI micro base (has shell, needed for HEALTHCHECK and JFR output) +# No baked-in certificates โ€” mount TLS certs at runtime via volumes or secrets +FROM quay.io/quarkus/ubi9-quarkus-micro-image:2.0@sha256:7d6c45257b2c8a27b05ac544a1a713abc2d36371f01675fb4497fbb385ae2046 + +LABEL org.opencontainers.image.title="API Sheriff - JFR" +LABEL org.opencontainers.image.description="Security-focused API Gateway โ€” Quarkus native executable with JFR profiling" +LABEL org.opencontainers.image.version="1.0.0-SNAPSHOT" +LABEL org.opencontainers.image.vendor="CUIoss" +LABEL org.opencontainers.image.licenses="Apache-2.0" +LABEL org.opencontainers.image.source="https://github.com/cuioss/API-Sheriff" +LABEL org.opencontainers.image.base.name="quay.io/quarkus/ubi9-quarkus-micro-image:2.0" +LABEL security.scan.required="true" +LABEL performance.jfr.enabled="true" + +WORKDIR /app + +# Copy pre-built native executable +COPY --chown=1001:root --chmod=0755 target/*-runner /app/application + +# Create JFR output directory with proper permissions +RUN mkdir -p /tmp/jfr-output && chmod 777 /tmp/jfr-output + +EXPOSE 8443 + +# Port probe health check using bash /dev/tcp (available in UBI micro) +HEALTHCHECK --interval=15s --timeout=5s --start-period=15s --retries=3 \ + CMD echo -n '' > /dev/tcp/127.0.0.1/8443 2>/dev/null || exit 1 + +USER 1001 + +# JFR-enabled entrypoint with profiling optimized for benchmarking +ENTRYPOINT ["/app/application", "-Dquarkus.http.host=0.0.0.0", \ + "-XX:+FlightRecorder", \ + "-XX:StartFlightRecording=filename=/tmp/jfr-output/api-sheriff-profile.jfr,dumponexit=true,duration=240s,settings=profile"] From 319fbc47072f653e319f5cc854bc618d14a866e6 Mon Sep 17 00:00:00 2001 From: Oliver Wolff <23139298+cuioss@users.noreply.github.com> Date: Wed, 4 Mar 2026 16:32:02 +0100 Subject: [PATCH 13/24] chore: Add container log capture for integration tests and benchmarks Align with OAuthSheriff pattern: Quarkus app logs via file logging to mounted volume, Keycloak logs via docker logs dump before container shutdown. Both log files land in target/ for CI artifact collection. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --- .../docker-compose.yml | 4 ++ api-sheriff-integration-tests/pom.xml | 38 +++++++++++ .../scripts/dump-keycloak-logs.sh | 67 +++++++++++++++++++ .../scripts/start-integration-container.sh | 5 ++ .../src/main/resources/application.properties | 9 +++ benchmark-integration/pom.xml | 16 +++++ 6 files changed, 139 insertions(+) create mode 100755 api-sheriff-integration-tests/scripts/dump-keycloak-logs.sh diff --git a/api-sheriff-integration-tests/docker-compose.yml b/api-sheriff-integration-tests/docker-compose.yml index 2f187f26..6a25f95e 100644 --- a/api-sheriff-integration-tests/docker-compose.yml +++ b/api-sheriff-integration-tests/docker-compose.yml @@ -58,6 +58,8 @@ services: environment: - QUARKUS_LOG_LEVEL=INFO + # File logging to mounted target directory + - LOG_FILE_PATH=/logs/quarkus.log # Certificate paths (runtime override) - QUARKUS_HTTP_SSL_CERTIFICATE_FILES=/app/certificates/localhost.crt - QUARKUS_HTTP_SSL_CERTIFICATE_KEY_FILES=/app/certificates/localhost.key @@ -97,6 +99,8 @@ services: volumes: # Read-only certificate mount (production pattern) - ./src/main/docker/certificates:/app/certificates:ro + # Mount target directory for log files (defaults to ./target) + - ${LOG_TARGET_DIR:-./target}:/logs:rw # JFR output volume for profiling recordings - ./target/jfr-recordings:/tmp/jfr-output:rw diff --git a/api-sheriff-integration-tests/pom.xml b/api-sheriff-integration-tests/pom.xml index 1a53bc08..de1feee9 100644 --- a/api-sheriff-integration-tests/pom.xml +++ b/api-sheriff-integration-tests/pom.xml @@ -212,6 +212,25 @@ <configuration> <executable>./scripts/start-integration-container.sh</executable> <workingDirectory>${project.basedir}</workingDirectory> + <environmentVariables> + <!-- Pass target directory for Quarkus file logging --> + <LOG_TARGET_DIR>${project.build.directory}</LOG_TARGET_DIR> + </environmentVariables> + </configuration> + </execution> + <!-- Dump Keycloak container logs before stopping containers --> + <execution> + <id>dump-keycloak-logs</id> + <phase>post-integration-test</phase> + <goals> + <goal>exec</goal> + </goals> + <configuration> + <executable>./scripts/dump-keycloak-logs.sh</executable> + <arguments> + <argument>target</argument> + </arguments> + <workingDirectory>${project.basedir}</workingDirectory> </configuration> </execution> <!-- Stop application after integration tests --> @@ -322,6 +341,25 @@ <configuration> <executable>./scripts/start-integration-container.sh</executable> <workingDirectory>${project.basedir}</workingDirectory> + <environmentVariables> + <!-- Pass target directory for Quarkus file logging --> + <LOG_TARGET_DIR>${project.build.directory}</LOG_TARGET_DIR> + </environmentVariables> + </configuration> + </execution> + <!-- Dump Keycloak container logs before stopping containers --> + <execution> + <id>dump-keycloak-logs</id> + <phase>post-integration-test</phase> + <goals> + <goal>exec</goal> + </goals> + <configuration> + <executable>./scripts/dump-keycloak-logs.sh</executable> + <arguments> + <argument>target</argument> + </arguments> + <workingDirectory>${project.basedir}</workingDirectory> </configuration> </execution> <!-- Stop application after integration tests --> diff --git a/api-sheriff-integration-tests/scripts/dump-keycloak-logs.sh b/api-sheriff-integration-tests/scripts/dump-keycloak-logs.sh new file mode 100755 index 00000000..5fd00ffe --- /dev/null +++ b/api-sheriff-integration-tests/scripts/dump-keycloak-logs.sh @@ -0,0 +1,67 @@ +#!/bin/bash + +# Keycloak Container Log Dumping Script +# Usage: ./dump-keycloak-logs.sh <target-directory> +# Example: ./dump-keycloak-logs.sh target +# +# Note: Quarkus logs are written directly to target/quarkus.log via file logging + +set -euo pipefail + +# Configuration +KEYCLOAK_CONTAINER_NAME="api-sheriff-integration-tests-keycloak-1" +TIMESTAMP=$(date +"%Y-%m-%d_%H-%M-%S") +KEYCLOAK_LOG_FILENAME="keycloak-logs-${TIMESTAMP}.txt" + +# Parameter validation +if [ $# -ne 1 ]; then + echo "โŒ Error: Target directory parameter required" + echo "Usage: $0 <target-directory>" + echo "Example: $0 target" + exit 1 +fi + +TARGET_DIR="$1" + +# Create target directory if it doesn't exist +if [ ! -d "$TARGET_DIR" ]; then + echo "๐Ÿ“ Creating target directory: $TARGET_DIR" + mkdir -p "$TARGET_DIR" +fi + +# Resolve absolute path for clarity +TARGET_ABS_PATH=$(cd "$TARGET_DIR" && pwd) +KEYCLOAK_LOG_FILE_PATH="${TARGET_ABS_PATH}/${KEYCLOAK_LOG_FILENAME}" + +echo "๐Ÿš€ Dumping Keycloak container logs..." +echo "๐Ÿ“ฆ Keycloak container: $KEYCLOAK_CONTAINER_NAME" +echo "๐Ÿ“ Output file: $KEYCLOAK_LOG_FILE_PATH" + +# Check if container exists and is running +if ! docker ps --format "{{.Names}}" | grep -q "^${KEYCLOAK_CONTAINER_NAME}$"; then + if docker ps -a --format "{{.Names}}" | grep -q "^${KEYCLOAK_CONTAINER_NAME}$"; then + echo "โš ๏ธ Warning: Container $KEYCLOAK_CONTAINER_NAME exists but is not running" + echo "๐Ÿ“‹ Attempting to dump logs from stopped container..." + else + echo "โŒ Error: Container $KEYCLOAK_CONTAINER_NAME not found" + echo "๐Ÿ” Available containers:" + docker ps -a --format "table {{.Names}}\t{{.Status}}" + exit 1 + fi +else + echo "โœ… Container is running" +fi + +# Dump logs +echo "๐Ÿ“ฅ Dumping Keycloak logs..." +if docker logs "$KEYCLOAK_CONTAINER_NAME" > "$KEYCLOAK_LOG_FILE_PATH" 2>&1; then + LOG_SIZE=$(wc -l < "$KEYCLOAK_LOG_FILE_PATH") + FILE_SIZE=$(du -h "$KEYCLOAK_LOG_FILE_PATH" | cut -f1) + echo "โœ… Successfully dumped $LOG_SIZE lines ($FILE_SIZE)" + echo "๐Ÿ“ Full path: $KEYCLOAK_LOG_FILE_PATH" + echo "๐ŸŽ‰ Keycloak logs successfully dumped!" + exit 0 +else + echo "โŒ Failed to dump logs from container: $KEYCLOAK_CONTAINER_NAME" + exit 1 +fi diff --git a/api-sheriff-integration-tests/scripts/start-integration-container.sh b/api-sheriff-integration-tests/scripts/start-integration-container.sh index 71ae5b49..a17a0ee5 100755 --- a/api-sheriff-integration-tests/scripts/start-integration-container.sh +++ b/api-sheriff-integration-tests/scripts/start-integration-container.sh @@ -56,6 +56,11 @@ else fi +# Set LOG_TARGET_DIR to project's target directory for Quarkus file logging +export LOG_TARGET_DIR="${LOG_TARGET_DIR:-${PROJECT_DIR}/target}" +mkdir -p "${LOG_TARGET_DIR}" +echo "๐Ÿ“ Quarkus logs will be written to: ${LOG_TARGET_DIR}/quarkus.log" + # Start with Docker Compose (includes Keycloak) echo "๐Ÿณ Starting Docker containers (Quarkus $MODE + Keycloak)..." (cd "${PROJECT_DIR}" && docker compose -f "$COMPOSE_FILE" up -d) diff --git a/api-sheriff/src/main/resources/application.properties b/api-sheriff/src/main/resources/application.properties index 6ba0e014..cac2ebc4 100644 --- a/api-sheriff/src/main/resources/application.properties +++ b/api-sheriff/src/main/resources/application.properties @@ -26,5 +26,14 @@ quarkus.virtual-threads.name-prefix=jwt-validation quarkus.log.level=INFO quarkus.log.category."de.cuioss.sheriff".level=INFO +# File logging (enabled in Docker via LOG_FILE_PATH env var) +quarkus.log.file.enable=true +quarkus.log.file.path=${LOG_FILE_PATH:/quarkus.log} +quarkus.log.file.level=INFO +quarkus.log.file.format=%d{yyyy-MM-dd HH:mm:ss,SSS z} %-5p [%c{3.}] (%t) %s%e%n +quarkus.log.file.rotation.max-file-size=100M +quarkus.log.file.rotation.max-backup-index=5 +%dev.quarkus.log.file.enable=false + # Development settings quarkus.live-reload.instrumentation=false diff --git a/benchmark-integration/pom.xml b/benchmark-integration/pom.xml index ba5b3fbf..a4e798a1 100644 --- a/benchmark-integration/pom.xml +++ b/benchmark-integration/pom.xml @@ -239,6 +239,22 @@ </configuration> </execution> + <!-- Dump Keycloak container logs before stopping containers --> + <execution> + <id>dump-keycloak-logs</id> + <phase>post-integration-test</phase> + <goals> + <goal>exec</goal> + </goals> + <configuration> + <skip>${skip.container.lifecycle}</skip> + <executable>${integration.scripts.dir}/dump-keycloak-logs.sh</executable> + <arguments> + <argument>${wrk.results.dir}</argument> + </arguments> + <workingDirectory>${project.basedir}</workingDirectory> + </configuration> + </execution> <!-- Stop integration test containers --> <execution> <id>stop-integration-containers</id> From 311616d2f4ff88f0981a8cc3c6e3c824e1c2102c Mon Sep 17 00:00:00 2001 From: Oliver Wolff <23139298+cuioss@users.noreply.github.com> Date: Wed, 4 Mar 2026 17:00:31 +0100 Subject: [PATCH 14/24] chore: Remove 17 unused dependencies from POMs Remove jjwt (3), easymock, weld-junit5, quarkus-config-yaml, quarkus-hibernate-validator, quarkus-security, quarkus-scheduler, quarkus-vertx-http, jakarta.servlet-api, jakarta.json-api, junit-jupiter-params, parsson, rest-assured, slf4j bridges, awaitility, jboss-logmanager from api-sheriff. Remove dev-ui-tests from integration-tests. Remove version properties and BOM entries from parent. None were imported in any Java source file. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --- api-sheriff-integration-tests/pom.xml | 7 -- api-sheriff/pom.xml | 102 +------------------------- pom.xml | 29 -------- 3 files changed, 3 insertions(+), 135 deletions(-) diff --git a/api-sheriff-integration-tests/pom.xml b/api-sheriff-integration-tests/pom.xml index de1feee9..6f9b46fc 100644 --- a/api-sheriff-integration-tests/pom.xml +++ b/api-sheriff-integration-tests/pom.xml @@ -69,13 +69,6 @@ <artifactId>awaitility</artifactId> <scope>test</scope> </dependency> - - <!-- Dev UI Testing Dependencies --> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-vertx-http-dev-ui-tests</artifactId> - <scope>test</scope> - </dependency> </dependencies> <build> diff --git a/api-sheriff/pom.xml b/api-sheriff/pom.xml index 8f12859e..aeaa4453 100644 --- a/api-sheriff/pom.xml +++ b/api-sheriff/pom.xml @@ -29,11 +29,6 @@ <groupId>de.cuioss</groupId> <artifactId>cui-java-tools</artifactId> </dependency> - <dependency> - <groupId>jakarta.json</groupId> - <artifactId>jakarta.json-api</artifactId> - <scope>provided</scope> - </dependency> <!-- Quarkus dependencies --> <dependency> @@ -46,23 +41,11 @@ </dependency> <dependency> <groupId>io.quarkus</groupId> - <artifactId>quarkus-micrometer</artifactId> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-security</artifactId> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-scheduler</artifactId> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-config-yaml</artifactId> + <artifactId>quarkus-resteasy</artifactId> </dependency> <dependency> <groupId>io.quarkus</groupId> - <artifactId>quarkus-hibernate-validator</artifactId> + <artifactId>quarkus-resteasy-jackson</artifactId> </dependency> <dependency> <groupId>io.quarkus</groupId> @@ -70,21 +53,7 @@ </dependency> <dependency> <groupId>io.quarkus</groupId> - <artifactId>quarkus-vertx-http</artifactId> - <optional>true</optional> - </dependency> - <dependency> - <groupId>jakarta.servlet</groupId> - <artifactId>jakarta.servlet-api</artifactId> - <scope>provided</scope> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-resteasy</artifactId> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-resteasy-jackson</artifactId> + <artifactId>quarkus-micrometer</artifactId> </dependency> <dependency> <groupId>io.quarkus</groupId> @@ -97,11 +66,6 @@ <artifactId>junit-jupiter</artifactId> <scope>test</scope> </dependency> - <dependency> - <groupId>org.junit.jupiter</groupId> - <artifactId>junit-jupiter-params</artifactId> - <scope>test</scope> - </dependency> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-junit5</artifactId> @@ -112,22 +76,6 @@ <artifactId>quarkus-jacoco</artifactId> <scope>test</scope> </dependency> - <!-- JJWT dependencies --> - <dependency> - <groupId>io.jsonwebtoken</groupId> - <artifactId>jjwt-api</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>io.jsonwebtoken</groupId> - <artifactId>jjwt-impl</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>io.jsonwebtoken</groupId> - <artifactId>jjwt-jackson</artifactId> - <scope>test</scope> - </dependency> <!-- CUI test dependencies --> <dependency> <groupId>de.cuioss.test</groupId> @@ -149,50 +97,6 @@ <artifactId>cui-test-juli-logger</artifactId> <scope>test</scope> </dependency> - <!-- Jakarta JSON implementation for tests --> - <dependency> - <groupId>org.eclipse.parsson</groupId> - <artifactId>parsson</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>io.rest-assured</groupId> - <artifactId>rest-assured</artifactId> - <scope>test</scope> - </dependency> - <!-- SLF4J bridges for test containers --> - <dependency> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-jdk14</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.slf4j</groupId> - <artifactId>jcl-over-slf4j</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.awaitility</groupId> - <artifactId>awaitility</artifactId> - <scope>test</scope> - </dependency> - <!-- Weld/CDI testing --> - <dependency> - <groupId>org.jboss.weld</groupId> - <artifactId>weld-junit5</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.jboss.logmanager</groupId> - <artifactId>jboss-logmanager</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.easymock</groupId> - <artifactId>easymock</artifactId> - <version>${version.easymock}</version> - <scope>test</scope> - </dependency> </dependencies> <build> diff --git a/pom.xml b/pom.xml index 4667d727..3b6d64a4 100644 --- a/pom.xml +++ b/pom.xml @@ -43,9 +43,6 @@ <properties> <maven.compiler.release>21</maven.compiler.release> <version.quarkus>3.32.1</version.quarkus> - <version.jjwt>0.13.0</version.jjwt> - <version.weld-junit5>5.0.3.Final</version.weld-junit5> - <version.easymock>5.6.0</version.easymock> <!-- Default empty argLine for JaCoCo compatibility - JaCoCo will override this when active --> <argLine /> </properties> @@ -73,25 +70,6 @@ <type>pom</type> <scope>import</scope> </dependency> - <!-- JJWT dependencies --> - <dependency> - <groupId>io.jsonwebtoken</groupId> - <artifactId>jjwt-api</artifactId> - <version>${version.jjwt}</version> - <scope>test</scope> - </dependency> - <dependency> - <groupId>io.jsonwebtoken</groupId> - <artifactId>jjwt-impl</artifactId> - <version>${version.jjwt}</version> - <scope>test</scope> - </dependency> - <dependency> - <groupId>io.jsonwebtoken</groupId> - <artifactId>jjwt-jackson</artifactId> - <version>${version.jjwt}</version> - <scope>test</scope> - </dependency> <!-- Internal modules --> <dependency> <groupId>de.cuioss.sheriff.api</groupId> @@ -126,13 +104,6 @@ <version>${version.junit.jupiter}</version> <scope>test</scope> </dependency> - <!-- Additional dependencies --> - <dependency> - <groupId>org.jboss.weld</groupId> - <artifactId>weld-junit5</artifactId> - <version>${version.weld-junit5}</version> - <scope>test</scope> - </dependency> </dependencies> </dependencyManagement> From 21f4ca21552491f97e93144d524f776fb39fb1e4 Mon Sep 17 00:00:00 2001 From: Oliver Wolff <23139298+cuioss@users.noreply.github.com> Date: Wed, 4 Mar 2026 17:17:15 +0100 Subject: [PATCH 15/24] chore: Extract oauth-sheriff version to root POM, remove transitive deps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move benchmarking-common version to root-level version.oauth-sheriff property. Remove gson, HdrHistogram, and commons-io โ€” all transitive from benchmarking-common. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --- benchmark-integration/pom.xml | 40 ++--------------------------------- pom.xml | 1 + 2 files changed, 3 insertions(+), 38 deletions(-) diff --git a/benchmark-integration/pom.xml b/benchmark-integration/pom.xml index a4e798a1..952b1147 100644 --- a/benchmark-integration/pom.xml +++ b/benchmark-integration/pom.xml @@ -46,52 +46,16 @@ <benchmark.history.dir>${wrk.results.dir}/history</benchmark.history.dir> <wrk.jwt.token_count>100</wrk.jwt.token_count> - <!-- External dependency versions --> - <version.benchmarking-common>0.4.1</version.benchmarking-common> - <version.gson>2.13.2</version.gson> - <version.hdrhistogram>2.2.2</version.hdrhistogram> - <version.commons-io>2.21.0</version.commons-io> - <!-- Sonar configuration: Skip analysis for benchmarking modules --> <sonar.skip>true</sonar.skip> </properties> - <dependencyManagement> - <dependencies> - <dependency> - <groupId>de.cuioss.sheriff.oauth</groupId> - <artifactId>benchmarking-common</artifactId> - <version>${version.benchmarking-common}</version> - </dependency> - <dependency> - <groupId>com.google.code.gson</groupId> - <artifactId>gson</artifactId> - <version>${version.gson}</version> - </dependency> - <dependency> - <groupId>org.hdrhistogram</groupId> - <artifactId>HdrHistogram</artifactId> - <version>${version.hdrhistogram}</version> - </dependency> - <dependency> - <groupId>commons-io</groupId> - <artifactId>commons-io</artifactId> - <version>${version.commons-io}</version> - </dependency> - </dependencies> - </dependencyManagement> - <dependencies> - <!-- Core benchmark common utilities --> + <!-- Core benchmark common utilities (gson, HdrHistogram, commons-io are transitive) --> <dependency> <groupId>de.cuioss.sheriff.oauth</groupId> <artifactId>benchmarking-common</artifactId> - </dependency> - - <!-- Gson for JSON processing --> - <dependency> - <groupId>com.google.code.gson</groupId> - <artifactId>gson</artifactId> + <version>${version.oauth-sheriff}</version> </dependency> <!-- CUI Java Tools for logging --> diff --git a/pom.xml b/pom.xml index 3b6d64a4..150d088d 100644 --- a/pom.xml +++ b/pom.xml @@ -43,6 +43,7 @@ <properties> <maven.compiler.release>21</maven.compiler.release> <version.quarkus>3.32.1</version.quarkus> + <version.oauth-sheriff>0.4.1</version.oauth-sheriff> <!-- Default empty argLine for JaCoCo compatibility - JaCoCo will override this when active --> <argLine /> </properties> From 50ec7ce66dabac92184b936287358f33e6e15a2a Mon Sep 17 00:00:00 2001 From: Oliver Wolff <23139298+cuioss@users.noreply.github.com> Date: Wed, 4 Mar 2026 18:09:21 +0100 Subject: [PATCH 16/24] feat: Implement WRK benchmark execution pipeline Wire complete WRK benchmark pipeline following OAuthSheriff's proven pattern: Dockerfile.wrk, Lua scripts, shell runners, Prometheus monitoring, and Maven exec-plugin integration to invoke WrkResultPostProcessor. New files: - Dockerfile.wrk (Alpine + wrk + Lua scripts) - Lua scripts for /q/health/live and /api/health - Shell scripts: pre-flight health check + 2 benchmark runners - prometheus.yml for metrics scraping Modified: - docker-compose.yml: add Prometheus and WRK services - pom.xml: add 4 exec-maven-plugin executions in benchmark profile Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --- .../docker-compose.yml | 23 +++++ api-sheriff-integration-tests/prometheus.yml | 12 +++ benchmark-integration/Dockerfile.wrk | 5 + benchmark-integration/pom.xml | 93 +++++++++++++++++++ .../wrk-scripts/api_health_benchmark.sh | 34 +++++++ .../wrk-scripts/api_health_check.lua | 27 ++++++ .../wrk-scripts/health_live_benchmark.sh | 34 +++++++ .../wrk-scripts/health_live_check.lua | 27 ++++++ .../wrk-scripts/pre-benchmark-health-check.sh | 38 ++++++++ 9 files changed, 293 insertions(+) create mode 100644 api-sheriff-integration-tests/prometheus.yml create mode 100644 benchmark-integration/Dockerfile.wrk create mode 100755 benchmark-integration/src/main/resources/wrk-scripts/api_health_benchmark.sh create mode 100644 benchmark-integration/src/main/resources/wrk-scripts/api_health_check.lua create mode 100755 benchmark-integration/src/main/resources/wrk-scripts/health_live_benchmark.sh create mode 100644 benchmark-integration/src/main/resources/wrk-scripts/health_live_check.lua create mode 100755 benchmark-integration/src/main/resources/wrk-scripts/pre-benchmark-health-check.sh diff --git a/api-sheriff-integration-tests/docker-compose.yml b/api-sheriff-integration-tests/docker-compose.yml index 6a25f95e..c7c82eba 100644 --- a/api-sheriff-integration-tests/docker-compose.yml +++ b/api-sheriff-integration-tests/docker-compose.yml @@ -137,6 +137,29 @@ services: # Production restart policy restart: unless-stopped + prometheus: + image: prom/prometheus:v3.6.0 + ports: + - "9090:9090" + volumes: + - ./prometheus.yml:/etc/prometheus/prometheus.yml:ro + command: + - '--config.file=/etc/prometheus/prometheus.yml' + - '--storage.tsdb.retention.time=1h' + - '--web.enable-lifecycle' + networks: + - jwt-integration + + wrk: + build: + context: .. + dockerfile: benchmark-integration/Dockerfile.wrk + networks: + - jwt-integration + profiles: + - benchmark + restart: "no" + networks: jwt-integration: driver: bridge diff --git a/api-sheriff-integration-tests/prometheus.yml b/api-sheriff-integration-tests/prometheus.yml new file mode 100644 index 00000000..3e873069 --- /dev/null +++ b/api-sheriff-integration-tests/prometheus.yml @@ -0,0 +1,12 @@ +global: + scrape_interval: 2s + evaluation_interval: 2s + +scrape_configs: + - job_name: 'quarkus-benchmark' + static_configs: + - targets: ['api-sheriff:8443'] + metrics_path: '/q/metrics' + scheme: https + tls_config: + insecure_skip_verify: true diff --git a/benchmark-integration/Dockerfile.wrk b/benchmark-integration/Dockerfile.wrk new file mode 100644 index 00000000..e75cdecc --- /dev/null +++ b/benchmark-integration/Dockerfile.wrk @@ -0,0 +1,5 @@ +FROM alpine:3.22 +RUN apk add --no-cache wrk +COPY benchmark-integration/src/main/resources/wrk-scripts/*.lua /scripts/ +ENTRYPOINT ["wrk"] +CMD ["--help"] diff --git a/benchmark-integration/pom.xml b/benchmark-integration/pom.xml index 952b1147..410b443a 100644 --- a/benchmark-integration/pom.xml +++ b/benchmark-integration/pom.xml @@ -203,6 +203,99 @@ </configuration> </execution> + <!-- Pre-benchmark health check --> + <execution> + <id>pre-benchmark-health-check</id> + <phase>integration-test</phase> + <goals> + <goal>exec</goal> + </goals> + <configuration> + <executable>bash</executable> + <arguments> + <argument>${wrk.script.dir}/pre-benchmark-health-check.sh</argument> + </arguments> + <environmentVariables> + <INTEGRATION_SERVICE_URL>${integration.service.url}</INTEGRATION_SERVICE_URL> + <PROMETHEUS_URL>http://localhost:9090</PROMETHEUS_URL> + <KEYCLOAK_URL>https://localhost:1090</KEYCLOAK_URL> + </environmentVariables> + </configuration> + </execution> + + <!-- Run WRK health/live benchmark --> + <execution> + <id>run-wrk-health-live-benchmark</id> + <phase>integration-test</phase> + <goals> + <goal>exec</goal> + </goals> + <configuration> + <executable>bash</executable> + <arguments> + <argument>${wrk.script.dir}/health_live_benchmark.sh</argument> + </arguments> + <outputFile>${wrk.output.dir}/wrk-health-live-results.txt</outputFile> + <timeout>240000</timeout> + <environmentVariables> + <WRK_THREADS>${wrk.threads}</WRK_THREADS> + <WRK_CONNECTIONS>${wrk.connections}</WRK_CONNECTIONS> + <WRK_DURATION>${wrk.duration}</WRK_DURATION> + <WRK_TIMEOUT>${wrk.timeout}</WRK_TIMEOUT> + <COMPOSE_DIR>${integration.compose.dir}</COMPOSE_DIR> + </environmentVariables> + </configuration> + </execution> + + <!-- Run WRK api/health benchmark --> + <execution> + <id>run-wrk-api-health-benchmark</id> + <phase>integration-test</phase> + <goals> + <goal>exec</goal> + </goals> + <configuration> + <executable>bash</executable> + <arguments> + <argument>${wrk.script.dir}/api_health_benchmark.sh</argument> + </arguments> + <outputFile>${wrk.output.dir}/wrk-api-health-results.txt</outputFile> + <timeout>240000</timeout> + <environmentVariables> + <WRK_THREADS>${wrk.threads}</WRK_THREADS> + <WRK_CONNECTIONS>${wrk.connections}</WRK_CONNECTIONS> + <WRK_DURATION>${wrk.duration}</WRK_DURATION> + <WRK_TIMEOUT>${wrk.timeout}</WRK_TIMEOUT> + <COMPOSE_DIR>${integration.compose.dir}</COMPOSE_DIR> + </environmentVariables> + </configuration> + </execution> + + <!-- Process WRK results and generate reports --> + <execution> + <id>process-wrk-results</id> + <phase>post-integration-test</phase> + <goals> + <goal>java</goal> + </goals> + <configuration> + <mainClass>de.cuioss.sheriff.api.wrk.benchmark.WrkResultPostProcessor</mainClass> + <arguments> + <argument>${wrk.results.dir}</argument> + </arguments> + <systemProperties> + <systemProperty> + <key>quarkus.metrics.url</key> + <value>${quarkus.metrics.url}</value> + </systemProperty> + <systemProperty> + <key>prometheus.url</key> + <value>http://localhost:9090</value> + </systemProperty> + </systemProperties> + </configuration> + </execution> + <!-- Dump Keycloak container logs before stopping containers --> <execution> <id>dump-keycloak-logs</id> diff --git a/benchmark-integration/src/main/resources/wrk-scripts/api_health_benchmark.sh b/benchmark-integration/src/main/resources/wrk-scripts/api_health_benchmark.sh new file mode 100755 index 00000000..70361340 --- /dev/null +++ b/benchmark-integration/src/main/resources/wrk-scripts/api_health_benchmark.sh @@ -0,0 +1,34 @@ +#!/bin/bash +# Benchmark runner for /api/health endpoint +set -e + +WRK_THREADS="${WRK_THREADS:-5}" +WRK_CONNECTIONS="${WRK_CONNECTIONS:-50}" +WRK_DURATION="${WRK_DURATION:-60s}" +WRK_TIMEOUT="${WRK_TIMEOUT:-2s}" +COMPOSE_DIR="${COMPOSE_DIR:?COMPOSE_DIR must be set}" + +BENCHMARK_NAME="gatewayHealth" +TARGET_URL="https://api-sheriff:8443/api/health" + +echo "=== BENCHMARK METADATA ===" +echo "benchmark_name: ${BENCHMARK_NAME}" +echo "target_url: ${TARGET_URL}" +echo "threads: ${WRK_THREADS}" +echo "connections: ${WRK_CONNECTIONS}" +echo "duration: ${WRK_DURATION}" +echo "start_time: $(date +%s)" +echo "=== WRK OUTPUT ===" + +cd "${COMPOSE_DIR}" +docker compose run --rm wrk \ + -t"${WRK_THREADS}" \ + -c"${WRK_CONNECTIONS}" \ + -d"${WRK_DURATION}" \ + --timeout "${WRK_TIMEOUT}" \ + --latency \ + -s /scripts/api_health_check.lua \ + "${TARGET_URL}" + +echo "end_time: $(date +%s)" +echo "=== BENCHMARK COMPLETE ===" diff --git a/benchmark-integration/src/main/resources/wrk-scripts/api_health_check.lua b/benchmark-integration/src/main/resources/wrk-scripts/api_health_check.lua new file mode 100644 index 00000000..2993d4a9 --- /dev/null +++ b/benchmark-integration/src/main/resources/wrk-scripts/api_health_check.lua @@ -0,0 +1,27 @@ +-- api_health_check.lua +-- WRK Lua script for benchmarking /api/health endpoint +-- Sends GET requests with JSON Accept header and validates 200 response + +local error_count = 0 +local success_count = 0 +local non_200_count = 0 + +wrk.method = "GET" +wrk.headers["Accept"] = "application/json" + +function response(status, headers, body) + if status == 200 then + success_count = success_count + 1 + else + non_200_count = non_200_count + 1 + end +end + +function done(summary, latency, requests) + io.write("--- Lua Script Summary ---\n") + io.write(string.format("Successful requests (200): %d\n", success_count)) + io.write(string.format("Non-200 responses: %d\n", non_200_count)) + io.write(string.format("Socket errors: connect=%d, read=%d, write=%d, timeout=%d\n", + summary.errors.connect, summary.errors.read, + summary.errors.write, summary.errors.timeout)) +end diff --git a/benchmark-integration/src/main/resources/wrk-scripts/health_live_benchmark.sh b/benchmark-integration/src/main/resources/wrk-scripts/health_live_benchmark.sh new file mode 100755 index 00000000..77eb36be --- /dev/null +++ b/benchmark-integration/src/main/resources/wrk-scripts/health_live_benchmark.sh @@ -0,0 +1,34 @@ +#!/bin/bash +# Benchmark runner for /q/health/live endpoint +set -e + +WRK_THREADS="${WRK_THREADS:-5}" +WRK_CONNECTIONS="${WRK_CONNECTIONS:-50}" +WRK_DURATION="${WRK_DURATION:-60s}" +WRK_TIMEOUT="${WRK_TIMEOUT:-2s}" +COMPOSE_DIR="${COMPOSE_DIR:?COMPOSE_DIR must be set}" + +BENCHMARK_NAME="healthLiveCheck" +TARGET_URL="https://api-sheriff:8443/q/health/live" + +echo "=== BENCHMARK METADATA ===" +echo "benchmark_name: ${BENCHMARK_NAME}" +echo "target_url: ${TARGET_URL}" +echo "threads: ${WRK_THREADS}" +echo "connections: ${WRK_CONNECTIONS}" +echo "duration: ${WRK_DURATION}" +echo "start_time: $(date +%s)" +echo "=== WRK OUTPUT ===" + +cd "${COMPOSE_DIR}" +docker compose run --rm wrk \ + -t"${WRK_THREADS}" \ + -c"${WRK_CONNECTIONS}" \ + -d"${WRK_DURATION}" \ + --timeout "${WRK_TIMEOUT}" \ + --latency \ + -s /scripts/health_live_check.lua \ + "${TARGET_URL}" + +echo "end_time: $(date +%s)" +echo "=== BENCHMARK COMPLETE ===" diff --git a/benchmark-integration/src/main/resources/wrk-scripts/health_live_check.lua b/benchmark-integration/src/main/resources/wrk-scripts/health_live_check.lua new file mode 100644 index 00000000..200c92c2 --- /dev/null +++ b/benchmark-integration/src/main/resources/wrk-scripts/health_live_check.lua @@ -0,0 +1,27 @@ +-- health_live_check.lua +-- WRK Lua script for benchmarking /q/health/live endpoint +-- Sends GET requests with JSON Accept header and tracks errors + +local error_count = 0 +local success_count = 0 +local non_200_count = 0 + +wrk.method = "GET" +wrk.headers["Accept"] = "application/json" + +function response(status, headers, body) + if status == 200 then + success_count = success_count + 1 + else + non_200_count = non_200_count + 1 + end +end + +function done(summary, latency, requests) + io.write("--- Lua Script Summary ---\n") + io.write(string.format("Successful requests (200): %d\n", success_count)) + io.write(string.format("Non-200 responses: %d\n", non_200_count)) + io.write(string.format("Socket errors: connect=%d, read=%d, write=%d, timeout=%d\n", + summary.errors.connect, summary.errors.read, + summary.errors.write, summary.errors.timeout)) +end diff --git a/benchmark-integration/src/main/resources/wrk-scripts/pre-benchmark-health-check.sh b/benchmark-integration/src/main/resources/wrk-scripts/pre-benchmark-health-check.sh new file mode 100755 index 00000000..09332814 --- /dev/null +++ b/benchmark-integration/src/main/resources/wrk-scripts/pre-benchmark-health-check.sh @@ -0,0 +1,38 @@ +#!/bin/bash +# Pre-flight check: verify Quarkus, Prometheus, and Keycloak are reachable before benchmarks start +set -e + +INTEGRATION_SERVICE_URL="${INTEGRATION_SERVICE_URL:?INTEGRATION_SERVICE_URL must be set}" +PROMETHEUS_URL="${PROMETHEUS_URL:?PROMETHEUS_URL must be set}" +KEYCLOAK_URL="${KEYCLOAK_URL:?KEYCLOAK_URL must be set}" + +MAX_RETRIES=30 +RETRY_INTERVAL=2 + +check_service() { + local name="$1" + local url="$2" + local retries=0 + + echo "Checking ${name} at ${url}..." + while [ $retries -lt $MAX_RETRIES ]; do + if curl -k -s -o /dev/null -w "%{http_code}" "$url" | grep -q "200"; then + echo "${name} is ready." + return 0 + fi + retries=$((retries + 1)) + echo "Waiting for ${name}... (attempt ${retries}/${MAX_RETRIES})" + sleep $RETRY_INTERVAL + done + + echo "ERROR: ${name} at ${url} did not become ready within $((MAX_RETRIES * RETRY_INTERVAL))s" + return 1 +} + +echo "=== Pre-Benchmark Health Check ===" + +check_service "Quarkus (health/live)" "${INTEGRATION_SERVICE_URL}/q/health/live" +check_service "Prometheus" "${PROMETHEUS_URL}/-/ready" +check_service "Keycloak" "${KEYCLOAK_URL}/health/ready" + +echo "=== All services are ready. Proceeding with benchmarks. ===" From bcb07f416f12e528c9e6186e719759c3390445ba Mon Sep 17 00:00:00 2001 From: Oliver Wolff <23139298+cuioss@users.noreply.github.com> Date: Wed, 4 Mar 2026 18:41:51 +0100 Subject: [PATCH 17/24] chore: Remove OAuthSheriff copy-paste artifacts from WrkResultPostProcessor Remove 8 unused constants referencing JWT validation endpoints that don't exist in API Sheriff. Replace test resource files with actual API Sheriff benchmark data (healthLiveCheck, gatewayHealth) and update all tests to match the real benchmark names and URLs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --- .../wrk/benchmark/WrkResultPostProcessor.java | 8 ---- .../GatewayEndpointBenchmarkTest.java | 27 +++++++------- .../benchmark/WrkResultPostProcessorTest.java | 37 +++++++++---------- ...results.txt => wrk-api-health-results.txt} | 9 +---- .../src/test/resources/wrk-health-results.txt | 9 +---- 5 files changed, 35 insertions(+), 55 deletions(-) rename benchmark-integration/src/test/resources/{wrk-jwt-results.txt => wrk-api-health-results.txt} (69%) diff --git a/benchmark-integration/src/main/java/de/cuioss/sheriff/api/wrk/benchmark/WrkResultPostProcessor.java b/benchmark-integration/src/main/java/de/cuioss/sheriff/api/wrk/benchmark/WrkResultPostProcessor.java index bcee859d..2eca8917 100644 --- a/benchmark-integration/src/main/java/de/cuioss/sheriff/api/wrk/benchmark/WrkResultPostProcessor.java +++ b/benchmark-integration/src/main/java/de/cuioss/sheriff/api/wrk/benchmark/WrkResultPostProcessor.java @@ -49,14 +49,6 @@ public class WrkResultPostProcessor { // File naming constants public static final String WRK_OUTPUT_FILE_SUFFIX = "-results.txt"; - public static final String WRK_HEALTH_OUTPUT_FILE = "wrk-health-results.txt"; - public static final String WRK_JWT_OUTPUT_FILE = "wrk-jwt-results.txt"; - public static final String BENCHMARK_NAME_HEALTH = "healthCheck"; - public static final String BENCHMARK_NAME_JWT = "jwtValidation"; - public static final String PROMETHEUS_METRICS_DIR = "prometheus"; - public static final String GH_PAGES_DATA_DIR = "gh-pages-ready/data"; - public static final String HEALTH_METRICS_FILE = BENCHMARK_NAME_HEALTH + "-metrics.json"; - public static final String JWT_METRICS_FILE = BENCHMARK_NAME_JWT + "-metrics.json"; private final WrkBenchmarkConverter converter = new WrkBenchmarkConverter(); private final ReportGenerator reportGenerator = new ReportGenerator(); diff --git a/benchmark-integration/src/test/java/de/cuioss/sheriff/api/wrk/benchmark/GatewayEndpointBenchmarkTest.java b/benchmark-integration/src/test/java/de/cuioss/sheriff/api/wrk/benchmark/GatewayEndpointBenchmarkTest.java index 3db9df1d..122d3e98 100644 --- a/benchmark-integration/src/test/java/de/cuioss/sheriff/api/wrk/benchmark/GatewayEndpointBenchmarkTest.java +++ b/benchmark-integration/src/test/java/de/cuioss/sheriff/api/wrk/benchmark/GatewayEndpointBenchmarkTest.java @@ -24,13 +24,11 @@ import java.nio.file.Files; import java.nio.file.Path; -import static de.cuioss.sheriff.api.wrk.benchmark.WrkResultPostProcessor.BENCHMARK_NAME_HEALTH; -import static de.cuioss.sheriff.api.wrk.benchmark.WrkResultPostProcessor.WRK_HEALTH_OUTPUT_FILE; import static org.junit.jupiter.api.Assertions.*; /** - * Tests WRK output parsing for the {@code /api/health} and {@code /api/info} + * Tests WRK output parsing for the {@code /q/health/live} and {@code /api/health} * gateway endpoints. Uses synthetic WRK output to validate the parsing pipeline * without requiring running containers. * @@ -50,16 +48,16 @@ void setUp() { } @Test - void parseGatewayHealthBenchmark() throws Exception { - // Arrange โ€” synthetic WRK output for /api/health gateway endpoint + void parseHealthLiveBenchmark() throws Exception { + // Arrange โ€” synthetic WRK output for /q/health/live endpoint String wrkOutput = """ === BENCHMARK METADATA === - benchmark_name: healthCheck + benchmark_name: healthLiveCheck start_time: 1700000000 start_time_iso: 2023-11-14T22:13:20Z === WRK OUTPUT === - Running 30s test @ https://localhost:10443/api/health + Running 30s test @ https://api-sheriff:8443/q/health/live 4 threads and 50 connections Thread Stats Avg Stdev Max +/- Stdev Latency 650.00us 300.00us 8.00ms 92.00% @@ -81,7 +79,7 @@ void parseGatewayHealthBenchmark() throws Exception { Path wrkDir = tempDir.resolve("wrk"); Files.createDirectories(wrkDir); - Files.writeString(wrkDir.resolve(WRK_HEALTH_OUTPUT_FILE), wrkOutput); + Files.writeString(wrkDir.resolve("wrk-health-live-results.txt"), wrkOutput); // Act Path outputDir = tempDir.resolve("output"); @@ -94,7 +92,7 @@ void parseGatewayHealthBenchmark() throws Exception { JsonObject json = JsonParser.parseString(Files.readString(jsonFile)).getAsJsonObject(); JsonObject benchmark = json.getAsJsonArray("benchmarks").get(0).getAsJsonObject(); - assertEquals(BENCHMARK_NAME_HEALTH, benchmark.get("name").getAsString()); + assertEquals("healthLiveCheck", benchmark.get("name").getAsString()); assertTrue(benchmark.has("score"), "Benchmark should have score"); assertTrue(benchmark.has("scoreUnit"), "Benchmark should have scoreUnit"); @@ -108,16 +106,16 @@ void parseGatewayHealthBenchmark() throws Exception { } @Test - void parseGatewayInfoBenchmark() throws Exception { - // Arrange โ€” synthetic WRK output for /api/info endpoint using health output file + void parseApiHealthBenchmark() throws Exception { + // Arrange โ€” synthetic WRK output for /api/health endpoint String wrkOutput = """ === BENCHMARK METADATA === - benchmark_name: healthCheck + benchmark_name: gatewayHealth start_time: 1700000000 start_time_iso: 2023-11-14T22:13:20Z === WRK OUTPUT === - Running 30s test @ https://localhost:10443/api/info + Running 30s test @ https://api-sheriff:8443/api/health 4 threads and 50 connections Thread Stats Avg Stdev Max +/- Stdev Latency 700.00us 350.00us 9.00ms 91.00% @@ -139,7 +137,7 @@ void parseGatewayInfoBenchmark() throws Exception { Path wrkDir = tempDir.resolve("wrk"); Files.createDirectories(wrkDir); - Files.writeString(wrkDir.resolve(WRK_HEALTH_OUTPUT_FILE), wrkOutput); + Files.writeString(wrkDir.resolve("wrk-api-health-results.txt"), wrkOutput); // Act Path outputDir = tempDir.resolve("output"); @@ -152,6 +150,7 @@ void parseGatewayInfoBenchmark() throws Exception { JsonObject json = JsonParser.parseString(Files.readString(jsonFile)).getAsJsonObject(); JsonObject benchmark = json.getAsJsonArray("benchmarks").get(0).getAsJsonObject(); + assertEquals("gatewayHealth", benchmark.get("name").getAsString()); assertFalse(benchmark.get("score").getAsString().isEmpty(), "Score should not be empty"); JsonObject percentiles = benchmark.getAsJsonObject("percentiles"); diff --git a/benchmark-integration/src/test/java/de/cuioss/sheriff/api/wrk/benchmark/WrkResultPostProcessorTest.java b/benchmark-integration/src/test/java/de/cuioss/sheriff/api/wrk/benchmark/WrkResultPostProcessorTest.java index b96b7a98..e6bd2353 100644 --- a/benchmark-integration/src/test/java/de/cuioss/sheriff/api/wrk/benchmark/WrkResultPostProcessorTest.java +++ b/benchmark-integration/src/test/java/de/cuioss/sheriff/api/wrk/benchmark/WrkResultPostProcessorTest.java @@ -25,7 +25,6 @@ import java.nio.file.Files; import java.nio.file.Path; -import static de.cuioss.sheriff.api.wrk.benchmark.WrkResultPostProcessor.*; import static org.junit.jupiter.api.Assertions.*; /** @@ -51,9 +50,9 @@ void comprehensiveStructureGeneration() throws Exception { Path wrkDir = tempDir.resolve("wrk"); Files.createDirectories(wrkDir); Path healthSource = Path.of("src/test/resources/wrk-health-results.txt"); - Path jwtSource = Path.of("src/test/resources/wrk-jwt-results.txt"); - Files.copy(healthSource, wrkDir.resolve(WRK_HEALTH_OUTPUT_FILE)); - Files.copy(jwtSource, wrkDir.resolve(WRK_JWT_OUTPUT_FILE)); + Path apiHealthSource = Path.of("src/test/resources/wrk-api-health-results.txt"); + Files.copy(healthSource, wrkDir.resolve("wrk-health-results.txt")); + Files.copy(apiHealthSource, wrkDir.resolve("wrk-api-health-results.txt")); // Process results Path outputDir = tempDir.resolve("output"); @@ -64,11 +63,11 @@ void comprehensiveStructureGeneration() throws Exception { } @Test - void parseWrkHealthOutput() throws Exception { + void parseHealthLiveOutput() throws Exception { Path wrkDir = tempDir.resolve("wrk"); Files.createDirectories(wrkDir); Path sourceFile = Path.of("src/test/resources/wrk-health-results.txt"); - Path targetFile = wrkDir.resolve(WRK_HEALTH_OUTPUT_FILE); + Path targetFile = wrkDir.resolve("wrk-health-results.txt"); Files.copy(sourceFile, targetFile); Path outputDir = tempDir.resolve("output"); @@ -89,7 +88,7 @@ void parseWrkHealthOutput() throws Exception { assertTrue(json.has("benchmarks")); JsonObject healthBenchmark = json.getAsJsonArray("benchmarks").get(0).getAsJsonObject(); - assertEquals(BENCHMARK_NAME_HEALTH, healthBenchmark.get("name").getAsString()); + assertEquals("healthLiveCheck", healthBenchmark.get("name").getAsString()); assertTrue(healthBenchmark.has("mode")); assertTrue(healthBenchmark.has("score")); assertTrue(healthBenchmark.has("scoreUnit")); @@ -111,11 +110,11 @@ void parseWrkHealthOutput() throws Exception { } @Test - void parseWrkJwtOutput() throws Exception { + void parseApiHealthOutput() throws Exception { Path wrkDir = tempDir.resolve("wrk"); Files.createDirectories(wrkDir); - Path sourceFile = Path.of("src/test/resources/wrk-jwt-results.txt"); - Path targetFile = wrkDir.resolve(WRK_JWT_OUTPUT_FILE); + Path sourceFile = Path.of("src/test/resources/wrk-api-health-results.txt"); + Path targetFile = wrkDir.resolve("wrk-api-health-results.txt"); Files.copy(sourceFile, targetFile); Path outputDir = tempDir.resolve("output"); @@ -125,23 +124,23 @@ void parseWrkJwtOutput() throws Exception { String jsonContent = Files.readString(jsonFile); JsonObject json = JsonParser.parseString(jsonContent).getAsJsonObject(); - JsonObject jwtBenchmark = null; + JsonObject apiHealthBenchmark = null; var benchmarks = json.getAsJsonArray("benchmarks"); for (int i = 0; i < benchmarks.size(); i++) { var bench = benchmarks.get(i).getAsJsonObject(); String benchName = bench.get("name").getAsString(); - if (BENCHMARK_NAME_JWT.equals(benchName) || "jwt-validation".equals(benchName)) { - jwtBenchmark = bench; + if ("gatewayHealth".equals(benchName)) { + apiHealthBenchmark = bench; break; } } - assertNotNull(jwtBenchmark, "JWT Validation benchmark should be present"); - assertTrue(jwtBenchmark.has("mode")); - assertTrue(jwtBenchmark.has("score")); - assertTrue(jwtBenchmark.has("scoreUnit")); + assertNotNull(apiHealthBenchmark, "Gateway Health benchmark should be present"); + assertTrue(apiHealthBenchmark.has("mode")); + assertTrue(apiHealthBenchmark.has("score")); + assertTrue(apiHealthBenchmark.has("scoreUnit")); - JsonObject percentiles = jwtBenchmark.getAsJsonObject("percentiles"); + JsonObject percentiles = apiHealthBenchmark.getAsJsonObject("percentiles"); assertTrue(percentiles.has("50.0")); assertTrue(percentiles.has("75.0")); assertTrue(percentiles.has("90.0")); @@ -199,7 +198,7 @@ void parseRealWrkFormatVariations() throws Exception { Path wrkDir = tempDir.resolve("wrk"); Files.createDirectories(wrkDir); - Path testFile = wrkDir.resolve(WRK_HEALTH_OUTPUT_FILE); + Path testFile = wrkDir.resolve("wrk-format-test-results.txt"); Files.writeString(testFile, wrkOutput); Path outputDir = tempDir.resolve("output"); diff --git a/benchmark-integration/src/test/resources/wrk-jwt-results.txt b/benchmark-integration/src/test/resources/wrk-api-health-results.txt similarity index 69% rename from benchmark-integration/src/test/resources/wrk-jwt-results.txt rename to benchmark-integration/src/test/resources/wrk-api-health-results.txt index 1e208227..78bca017 100644 --- a/benchmark-integration/src/test/resources/wrk-jwt-results.txt +++ b/benchmark-integration/src/test/resources/wrk-api-health-results.txt @@ -1,15 +1,10 @@ === BENCHMARK METADATA === -benchmark_name: jwt-validation +benchmark_name: gatewayHealth start_time: 1758797251 start_time_iso: 2025-09-25T12:47:31+02:00 === WRK OUTPUT === -Loaded 100 tokens from environment -Loaded 100 tokens from environment -Loaded 100 tokens from environment -Loaded 100 tokens from environment -Loaded 100 tokens from environment -Running 5s test @ https://localhost:10443/jwt/validate +Running 5s test @ https://api-sheriff:8443/api/health 4 threads and 20 connections Thread Stats Avg Stdev Max +/- Stdev Latency 4.33ms 6.30ms 42.53ms 87.28% diff --git a/benchmark-integration/src/test/resources/wrk-health-results.txt b/benchmark-integration/src/test/resources/wrk-health-results.txt index 2e8969f0..ef074289 100644 --- a/benchmark-integration/src/test/resources/wrk-health-results.txt +++ b/benchmark-integration/src/test/resources/wrk-health-results.txt @@ -1,15 +1,10 @@ === BENCHMARK METADATA === -benchmark_name: healthCheck +benchmark_name: healthLiveCheck start_time: 1758797205 start_time_iso: 2025-09-25T12:46:45+02:00 === WRK OUTPUT === -Loaded 100 tokens from environment -Loaded 100 tokens from environment -Loaded 100 tokens from environment -Loaded 100 tokens from environment -Loaded 100 tokens from environment -Running 5s test @ https://localhost:10443/q/health/live/jwt/validate +Running 5s test @ https://api-sheriff:8443/q/health/live 4 threads and 20 connections Thread Stats Avg Stdev Max +/- Stdev Latency 4.51ms 6.70ms 41.04ms 87.50% From 7bc2003954ac36352037da973cd959be7bb9b7bb Mon Sep 17 00:00:00 2001 From: Oliver Wolff <23139298+cuioss@users.noreply.github.com> Date: Wed, 4 Mar 2026 21:45:58 +0100 Subject: [PATCH 18/24] chore: Clean up docker-compose.yml, remove OAuthSheriff artifacts, add dns:api-sheriff to SAN Remove dead JVM flags (no effect in native image), redundant QUARKUS_LOG_LEVEL, verbose network driver_opts (all defaults). Rename network jwt-integration to api-sheriff. Add dns:api-sheriff to certificate SAN for WRK container connectivity. Regenerate certificates with updated DNAME and SAN. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --- .../docker-compose.yml | 31 +++------- .../certificates/generate-certificates.sh | 10 ++-- .../certificates/generate-truststore.sh | 4 +- .../certificates/localhost-truststore.p12 | Bin 1334 -> 1366 bytes .../main/docker/certificates/localhost.crt | 41 ++++++------- .../main/docker/certificates/localhost.key | 54 +++++++++--------- 6 files changed, 63 insertions(+), 77 deletions(-) diff --git a/api-sheriff-integration-tests/docker-compose.yml b/api-sheriff-integration-tests/docker-compose.yml index c7c82eba..732b48c0 100644 --- a/api-sheriff-integration-tests/docker-compose.yml +++ b/api-sheriff-integration-tests/docker-compose.yml @@ -31,7 +31,7 @@ services: - KC_HOSTNAME=localhost # External hostname for Docker container well-known discovery networks: - - jwt-integration + - api-sheriff api-sheriff: # Production Dockerfiles from api-sheriff module โ€” test instrumentation at compose level @@ -48,16 +48,7 @@ services: ports: - "10443:8443" # External test port for integration tests - # Test-specific TLS truststore flags (not baked into production image) - command: - - "-Djavax.net.ssl.trustStore=/app/certificates/localhost-truststore.p12" - - "-Djavax.net.ssl.trustStorePassword=localhost-trust" - - "-Djavax.net.ssl.trustStoreType=PKCS12" - - "-Djdk.tls.rejectClientInitiatedRenegotiation=true" - - "-Djavax.net.ssl.sessionCacheSize=20480" - environment: - - QUARKUS_LOG_LEVEL=INFO # File logging to mounted target directory - LOG_FILE_PATH=/logs/quarkus.log # Certificate paths (runtime override) @@ -65,11 +56,11 @@ services: - QUARKUS_HTTP_SSL_CERTIFICATE_KEY_FILES=/app/certificates/localhost.key - QUARKUS_TLS_DEFAULT_TRUST__STORE_P12_PATH=/app/certificates/localhost-truststore.p12 - QUARKUS_TLS_DEFAULT_TRUST__STORE_P12_PASSWORD=localhost-trust - # JWT Issuer Configuration โ€” default issuer (static key, disabled for Docker tests) + # Issuer: default (disabled for container tests) - API_SHERIFF_ISSUERS_DEFAULT_ISSUER__IDENTIFIER=https://test-auth.example.com - API_SHERIFF_ISSUERS_DEFAULT_ENABLED=false - API_SHERIFF_ISSUERS_DEFAULT_JWKS_FILE__PATH=classpath:test-jwks.json - # JWT Issuer Configuration โ€” Keycloak issuer (well-known discovery) + # Issuer: Keycloak (well-known discovery) - API_SHERIFF_ISSUERS_KEYCLOAK_ENABLED=true - API_SHERIFF_ISSUERS_KEYCLOAK_ISSUER__IDENTIFIER=https://keycloak:8443/realms/benchmark - API_SHERIFF_ISSUERS_KEYCLOAK_JWKS_HTTP_WELL__KNOWN__URL=https://keycloak:8443/realms/benchmark/.well-known/openid-configuration @@ -77,7 +68,7 @@ services: - API_SHERIFF_ISSUERS_KEYCLOAK_KEYCLOAK_MAPPERS_DEFAULT__ROLES_ENABLED=false - API_SHERIFF_ISSUERS_KEYCLOAK_KEYCLOAK_MAPPERS_DEFAULT__GROUPS_ENABLED=false - API_SHERIFF_ISSUERS_KEYCLOAK_CLAIM__SUB__OPTIONAL=true - # JWT Issuer Configuration โ€” Integration issuer (direct JWKS URL) + # Issuer: integration (direct JWKS URL) - API_SHERIFF_ISSUERS_INTEGRATION_ENABLED=true - API_SHERIFF_ISSUERS_INTEGRATION_ISSUER__IDENTIFIER=https://keycloak:8443/realms/integration - API_SHERIFF_ISSUERS_INTEGRATION_JWKS_HTTP_URL=https://keycloak:8443/realms/integration/protocol/openid-connect/certs @@ -132,7 +123,7 @@ services: # Network isolation (production pattern) networks: - - jwt-integration + - api-sheriff # Production restart policy restart: unless-stopped @@ -148,24 +139,18 @@ services: - '--storage.tsdb.retention.time=1h' - '--web.enable-lifecycle' networks: - - jwt-integration + - api-sheriff wrk: build: context: .. dockerfile: benchmark-integration/Dockerfile.wrk networks: - - jwt-integration + - api-sheriff profiles: - benchmark restart: "no" networks: - jwt-integration: + api-sheriff: driver: bridge - # Control inter-container communication (production setting) - internal: false - driver_opts: - com.docker.network.bridge.enable_icc: "true" - com.docker.network.bridge.enable_ip_masquerade: "true" - com.docker.network.driver.mtu: "1500" diff --git a/api-sheriff-integration-tests/src/main/docker/certificates/generate-certificates.sh b/api-sheriff-integration-tests/src/main/docker/certificates/generate-certificates.sh index 63b23ced..d175565b 100755 --- a/api-sheriff-integration-tests/src/main/docker/certificates/generate-certificates.sh +++ b/api-sheriff-integration-tests/src/main/docker/certificates/generate-certificates.sh @@ -1,17 +1,17 @@ #!/bin/bash -# Script to generate PEM certificates for JWT Quarkus integration testing +# Script to generate PEM certificates for API Sheriff integration testing # Generates passwordless localhost certificates for secure container usage set -e SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" CERT_DIR="${SCRIPT_DIR}" -CERT_DNAME="CN=localhost, OU=Integration Testing, O=CUI-JWT, L=Berlin, ST=Berlin, C=DE" +CERT_DNAME="CN=localhost, OU=Integration Testing, O=API-Sheriff, L=Berlin, ST=Berlin, C=DE" CERT_VALIDITY=730 TEMP_KEYSTORE="${CERT_DIR}/temp-keystore.p12" TEMP_PASSWORD="temp-$(date +%s)" -echo "Generating PEM certificates for JWT integration testing..." +echo "Generating PEM certificates for API Sheriff integration testing..." echo "Certificate directory: ${CERT_DIR}" # Clean up existing certificates @@ -25,7 +25,7 @@ keytool -genkeypair \ -keysize 2048 \ -validity ${CERT_VALIDITY} \ -dname "${CERT_DNAME}" \ - -ext san=dns:localhost,dns:keycloak,ip:127.0.0.1,ip:0.0.0.0 \ + -ext san=dns:localhost,dns:keycloak,dns:api-sheriff,ip:127.0.0.1,ip:0.0.0.0 \ -keystore "${TEMP_KEYSTORE}" \ -storetype PKCS12 \ -storepass "${TEMP_PASSWORD}" \ @@ -64,6 +64,6 @@ echo " - localhost.key: Private key in PEM format (restricted access)" echo "" echo "Certificate valid for ${CERT_VALIDITY} days (2 years)" echo "Subject: ${CERT_DNAME}" -echo "SAN: dns:localhost,dns:keycloak,ip:127.0.0.1,ip:0.0.0.0" +echo "SAN: dns:localhost,dns:keycloak,dns:api-sheriff,ip:127.0.0.1,ip:0.0.0.0" echo "" echo "Security: No passwords required - file permissions provide security" \ No newline at end of file diff --git a/api-sheriff-integration-tests/src/main/docker/certificates/generate-truststore.sh b/api-sheriff-integration-tests/src/main/docker/certificates/generate-truststore.sh index 49059143..64caad56 100755 --- a/api-sheriff-integration-tests/src/main/docker/certificates/generate-truststore.sh +++ b/api-sheriff-integration-tests/src/main/docker/certificates/generate-truststore.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Script to generate Java truststore for JWT Quarkus integration testing +# Script to generate Java truststore for API Sheriff integration testing # Creates truststore with localhost certificate for proper TLS validation set -e @@ -9,7 +9,7 @@ CERT_DIR="${SCRIPT_DIR}" TRUSTSTORE_FILE="${CERT_DIR}/localhost-truststore.p12" TRUSTSTORE_PASSWORD="localhost-trust" -echo "Generating Java truststore for JWT integration testing..." +echo "Generating Java truststore for API Sheriff integration testing..." echo "Certificate directory: ${CERT_DIR}" # Check if certificate exists diff --git a/api-sheriff-integration-tests/src/main/docker/certificates/localhost-truststore.p12 b/api-sheriff-integration-tests/src/main/docker/certificates/localhost-truststore.p12 index 61d2e5e8342d38de7cce6aa9ecbb873400b46d7f..741f870aad0608c04e5ada4b776a13e39373b900 100644 GIT binary patch delta 1309 zcmV+&1>*X)3f2lhFoFeA0s#Xsf&}~q2`Yw2hW8Bt2LYgh1nmTZ1nDq>1m!S-1mOk= zDuzgg_YDCD2B3lj(lCMq&H@1dFoFcfkw7aHo^fT|5e|2~E=fr}*oqn6W_`sFk$)tA zl0`4ge_6Fg74|zIOq&aKfPw^29fX45HD(@!77j<uY^Gh2?ts)O#XU>VBclRy0v}S~ z^a0R{2CZVa7I~MxeU7gfGf~KK#?0$p|L?MC+0$eaESu&yzB(74Ckfo=&jzf9)GgPy z;AkPW1A=>qo9dZ?EtkP>>C6aCtFmr?v6NILyhS^h!XXA8jn`!v3CH#$bo-5q7ebIL zD)WyTfDennc=w1!XE6{MTL*;tY2{40Z6y?*0S1jl5ug?4o1e!hY+hi$fLyt$XHB*b zNISXUhd`d%Fz+JaWs6_LxiOCXg>g%&Q|ABX@KS2pB|h-*w|@!#7ILuwV;o0+Hmk@j z+vS_}B*&`+zORV7)vs7$K$je9=37>)6ya@gePUNQJVUt)N?#(zoQ64;h~}IZ7!O2v ztu`$QM+9s-sD(Ll*7ARdGmbM;<0^L{L4|wqq`G7mHaYkHcm0s{)t4g)PNLki)r9&Q zwicUm-VFri%bdKTIG4W9Gs~`ju*W$k-6CoWU=k_Kx#|J#)_bN@5!Zkw0G=-Ik!{A$ zdf5$EK|iugd*alro|PPOtc^9bQE(zKjnb$gEgCdy)`1g14Qf*+*1>$4P6XwMg0s1= ze<{Pe2B%q@>1a0uU6}Se)uo8^xzM=iXadS0aJ%7&7>e{5OlJ&>GVVHm@z3*>TICRA zM0Z&B^!szOm$XOzf7Tv8pX4Z_oz^07tw*HB$SqYaB1h}A!z(EL^bk|Z+raCUCK;=+ zm%SPeG7RvS^|xk;e#~aWO;-Z?ji;E7J8#-DV++#jV06Uv9c81l^(Asyef3==_;HQm zavw_a)n(RLi^_%Yip_U_Q~#vO3T<|T6PKOxED_5Sx##^V5|8>Eo5rE|*j(+bGKOBF zVM-RiQXy5DyTO)oDSXZk*qr)SVT*uHB3p=E*>%tOGkYo-E5LmSi8>UkLj^rLw!j64 zS*x%5uCQ=M%SdI}^Ywup&G+)#gQeFs)}1o;%m>v-2bT9H1vwmlVSI;3v9M=xXoJg; zZTKN%V4spdc7gryp{a+tG&(uy0zPBvIHLBqy)N(5MAXe&abu1A**V*ySy>xpErpFX z6)~JDvvtcM{B=JB2mA)W6|VhJ0Tr5#`7Hlj9@+Kj!hs948@=yBRh&{ZGM}nrYfy3@ z1vCkqOc(Zrn;isy!)!IeQnwY_H(xGqP~bAagrZwui8Hi;ixF76a2Bt`0>|64X5}Mv ziLN>ppTW-*0Q`d@XCdId**P5KSkB_{^5_J230;NWa>ZKS#Iz;)=$oBQ++EiNdI@zR zzjUzS-`wXqHq7Ci&27{mfsirNnJKvTily5027Jn5yg5XF7(M{D!@%?dnw#dBQ-fk# z{Rv+#wQ9^1o33jH(x!)<-)!3Mq4CN#AAfJQ+&bkzgVb%2?+bvftrsO^rAhG2Jdht4 zQ$DUuGM`4Tisoc8I$h$Zk@_iE^bDBFl7Ik@X<o~<7&JTYE$BgxFikKqFbxI?V1`Hm zWdj5P0R;d&1R(sg!_dpa%CAN5!!RZw)j3O0(<F(3G$E!4WSc@|39AGYtGxT91V4-+ T|F(1f@KZo|&D6wP0s<!xWqNat delta 1277 zcmV<Z1Oofk3bqPBFoFd#0s#Xsf&|<K2`Yw2hW8Bt2LYgh1kD731j#Uh1jR6d1i=Og zDuzgg_YDCD2B3ljvM_=Kt^xr7FoFc9kw7aH%l!%yT+98jY8RYESLjv_eys(wk$)tA zZ{n}ooG#h=lEm0;oQf)8fPw@t2p>VY_wUy0da=l<&4OK7#jzy5c#A0=-LR$(y~=&x zQi(MN(HaP9h5)jEG<X8r5s@yk#{c&F0{}FBews(uQH%C(ug9-Ty7UwIw&BaYjJE?T z^$a~CBW?S9)pK0#2^N{U1m=XFF0^fb!eaqTN!8cB-DUmV%P2`(uPgP2d)U2xWjgW@ z1dej-2|ogJcOCEZsMywlATW}THM+$4-!bt&m&!FA19QJ~ik3<^1-?nDyGn@b+{!@; zM2%TMX%o=N!O(m`&Tn9RKy$VAF@x0IQ2|UB<f%Jkkn2f|%F-K3-`?lCvFOr&ggGG4 z(%>g^wfOB^0B{v7e*QeTUU${$=l9^syYy^NV}$ih8N*-Z8cOi|S?D6&>B<JAWKbb4 zi540+|Dsg6c0$wE)*q}Cs|oHossCu<Cm)JpffU%D*@9j@pqG;VMbm>Tw%d``<UR-b z^Om$jr%TJT$t<_Bu8h91a=4g(!6)BhqplA`P3+40OwRDnu%WsnyBjr*D)Xt81tIb^ zUi-T?hsdbgLXIn$WzjU&XS)+%{QW#HpsJ-SQ2Z_=9=J{=U##%8T==}>D7~`ED@0VW ze_Kq=571?(SMefvw&|#xXBqj+%@?U~WGKpGO8#AAaZ(bdd3|^0Wz_qBGVk79(^YRV z|5AT8L2>0#Z*{s1paC0^n~%1M{f;6T6^vD#V#TZp(R_ZDt2MxX=TeRi7^MQY{xkX6 zX?tT}>BCCF-imY_)NA(7K&qKId8H8({SXP`jf{Ia!D`Nc8UR*Bc{oz5iId_K88YVu ziS7oA@R4JVtOGJ=5qs%>=QDly?@0V@p}xH2;z#^??rxMwzO#%a=w%<8omR?qQAG8U zN)daR_8^3E3*;lpX3piteRC=pJ@uc8`3838nP(^qPB)+;n#Cs*9Gxi5C+{-$>H7zg zpDiFx;841WhVjyZO+&wdo-W}(Ce<S+ACAu}=Eme)N#eOnUvG1N-LmVl(3!De_7TZm zDnoDtJMqwp2+Z6e#a#3jMsoM1j+u$(9#P1s#{dg-ie-!s0Em_QEYw9P92W#y;!!36 z7lY#`f7+aEDKXTTo~L2(qob<^gljMo(sZ(VYlvWBTvD8~{w`o5t5+9iAxn-~K82K5 zgH=W4SOp4f!(qjLo682*dzJ8mZ4@QWz<7p2I5?f`XhfWYV0<BJ$QS>3%B35zO|y?$ z1Rv64$-smA)9_ZJLoDYh9Ox2J-jpn3s1Kb?7T^8gY#_xKv~JVUzNq374>^348D+SK zZoPObuy96_e9<>)_HJ4j*Wh_`4liLETF|2_T1|-V(2Bf&2Kr&^BEOOeS7m;cD{4B( zwT8>#e8#^?gKBNibID;k*Crc0g+i@c22Z4C)IKIu6g^}_*uv+KNk_NM!L><M(TR5u zi%v&ih!V}iFikKqFbxI?V1`HmWdj5P0R;dAASuhee>)7b!T@#j!hY9xkTmwwCU3a8 n7jzd65yBK41jGasB{Vh85uy=6?<r`4=TKCjb~P{l0s<!xs0L{` diff --git a/api-sheriff-integration-tests/src/main/docker/certificates/localhost.crt b/api-sheriff-integration-tests/src/main/docker/certificates/localhost.crt index 689c1407..fe906f4c 100644 --- a/api-sheriff-integration-tests/src/main/docker/certificates/localhost.crt +++ b/api-sheriff-integration-tests/src/main/docker/certificates/localhost.crt @@ -1,22 +1,23 @@ -----BEGIN CERTIFICATE----- -MIIDtjCCAp6gAwIBAgIJAKJe1eKGCr7tMA0GCSqGSIb3DQEBDAUAMHMxCzAJBgNV -BAYTAkRFMQ8wDQYDVQQIEwZCZXJsaW4xDzANBgNVBAcTBkJlcmxpbjEQMA4GA1UE -ChMHQ1VJLUpXVDEcMBoGA1UECxMTSW50ZWdyYXRpb24gVGVzdGluZzESMBAGA1UE -AxMJbG9jYWxob3N0MB4XDTI1MDcwNDExMDM1M1oXDTI3MDcwNDExMDM1M1owczEL -MAkGA1UEBhMCREUxDzANBgNVBAgTBkJlcmxpbjEPMA0GA1UEBxMGQmVybGluMRAw -DgYDVQQKEwdDVUktSldUMRwwGgYDVQQLExNJbnRlZ3JhdGlvbiBUZXN0aW5nMRIw -EAYDVQQDEwlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB -AQDpWdNs0eTnFVFFA34eWjU3NzXPzEn0/GQTjC8jfyf766z5WCArwN7AfxIkBhSa -35JSfPdTB3p0LmWUyhm0843BSHD21ZQyICimDxyWSB5BL2DWwPf2qw2KhiLOn9Yc -SQrR4UakW0CF4OmIT98QLIVbsL7baHthmKn7pqNjvfe9Xhvws29bqdakxECwKLTg -vq6Nk1WobVz+phillM3the8wk83a0yBAYlOTVEebD3IXDhjMsC0Fyug0LmWCuX3w -bPcZdf9zjUbGt8h7k3PQ5OjkKlW5HTyRE20wmsOMZmGgQX+OnF5sT2ES6ebjG1lT -jsW3mfxpJyHb1nJXELedTjb7AgMBAAGjTTBLMB0GA1UdDgQWBBTe7icNOG1nJ8EI -mfDSYgfobZKkijAqBgNVHREEIzAhgglsb2NhbGhvc3SCCGtleWNsb2FrhwR/AAAB -hwQAAAAAMA0GCSqGSIb3DQEBDAUAA4IBAQBCaPx5x4LUhIpbfbd2qGlAgOgCbXRx -iDlaYtJTqD/I/d4CwReMADQgoNI+Ey0Whu890cNwIAU6E2uzXcvu5lof2NpebYyr -20mOCpwTKBNnztHZ+nbFBPDEhCe3uoqfRB1qeEOEtjL7KZwNlBLCK6TYNk6jTte3 -D/hCrEKsCxaQUmywKPF/yIQP+YOxZuCI90v/8Y5Qqj9uS2CwHTiSKTFm4JDPA1f1 -sCD/JsdALv1dtKKkO5pbumupyw0ySb0Z3O9D3Ufkg7D1/27iW2YL6fqcsJT6x8Ox -o4R7BzVGOmvHF6CIS3Rd/dvYkgNQDekOGbq+/Et42+T5tYHpdD3WUHTG +MIIDyzCCArOgAwIBAgIJAIn+s76rgt1zMA0GCSqGSIb3DQEBDAUAMHcxCzAJBgNV +BAYTAkRFMQ8wDQYDVQQIEwZCZXJsaW4xDzANBgNVBAcTBkJlcmxpbjEUMBIGA1UE +ChMLQVBJLVNoZXJpZmYxHDAaBgNVBAsTE0ludGVncmF0aW9uIFRlc3RpbmcxEjAQ +BgNVBAMTCWxvY2FsaG9zdDAeFw0yNjAzMDQyMDI2NTJaFw0yODAzMDMyMDI2NTJa +MHcxCzAJBgNVBAYTAkRFMQ8wDQYDVQQIEwZCZXJsaW4xDzANBgNVBAcTBkJlcmxp +bjEUMBIGA1UEChMLQVBJLVNoZXJpZmYxHDAaBgNVBAsTE0ludGVncmF0aW9uIFRl +c3RpbmcxEjAQBgNVBAMTCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBALsV2R8NOjmWnJAshFzbUUtpG4Ow5da41h7qSRfXLbCe8tOioTod +kLMtYrC6TTJv0tPIflUqPxQ4qyjkQs0IH6C2pWffXc+Fl6ZeRDYl6Dkdt4/Dy/k7 +ybytZ5DjL3r5n13/IOvi+kWqPQYbppnecCyskASS7XPSGIOcgpAuOxb3DmfBsE6D +NXjbSq9ouwpHjzNQjpMhzFjUTGYjLVvPQxdQkUwsiffKzrbgGmUH9ZS1y1Aj5TdP +b8zc3DlOyPNvgDDAGq3BEkXwtH5TUAigeOFI/dOTwai7jGlTBxnxdnY9UnrXZT0L +ecOBTJYbnL/zqYE8YbGxVXnmVDAqducphrECAwEAAaNaMFgwHQYDVR0OBBYEFFu6 +h0rtSLTmhhQiljH84cA102srMDcGA1UdEQQwMC6CCWxvY2FsaG9zdIIIa2V5Y2xv +YWuCC2FwaS1zaGVyaWZmhwR/AAABhwQAAAAAMA0GCSqGSIb3DQEBDAUAA4IBAQBC +Jv4FL8/9UPtyc6yxQOKTTBC+rPzzjYposhGVRQG+j4zLUEYYYP+qW+L54Uj/+iYe +iPvBYutYT5Z3sKnGtvnJR6EVn4Ot0E5m3mPFIIJLKwpyQZ8jv6SJ6zofcB4j+8HP +pbvuv+V6or6t3j4U4SMgd4D/qFZbRh5ksnoyxshnvSpMltAmVhtX1QUO5P/M427c +U3NbrZjw5DijNy5M5/mpPd3UfftvnxbwiakUpk5qs42hmi89moywkYVB5yWdfleA +IavDpmVSvJdzHtNgweNhJ0qKBvuIFCsrJiN7yK+VaC926+RR5QlTxWFVomg8Ln26 +4XirSlJCS1o6EmhmcM4k -----END CERTIFICATE----- diff --git a/api-sheriff-integration-tests/src/main/docker/certificates/localhost.key b/api-sheriff-integration-tests/src/main/docker/certificates/localhost.key index b73c44fe..0f37923e 100644 --- a/api-sheriff-integration-tests/src/main/docker/certificates/localhost.key +++ b/api-sheriff-integration-tests/src/main/docker/certificates/localhost.key @@ -1,32 +1,32 @@ Bag Attributes friendlyName: localhost - localKeyID: 54 69 6D 65 20 31 37 35 31 36 32 37 30 33 33 35 31 31 + localKeyID: 54 69 6D 65 20 31 37 37 32 36 35 36 30 31 32 39 39 35 Key Attributes: <No Attributes> -----BEGIN PRIVATE KEY----- -MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDpWdNs0eTnFVFF -A34eWjU3NzXPzEn0/GQTjC8jfyf766z5WCArwN7AfxIkBhSa35JSfPdTB3p0LmWU -yhm0843BSHD21ZQyICimDxyWSB5BL2DWwPf2qw2KhiLOn9YcSQrR4UakW0CF4OmI -T98QLIVbsL7baHthmKn7pqNjvfe9Xhvws29bqdakxECwKLTgvq6Nk1WobVz+phil -lM3the8wk83a0yBAYlOTVEebD3IXDhjMsC0Fyug0LmWCuX3wbPcZdf9zjUbGt8h7 -k3PQ5OjkKlW5HTyRE20wmsOMZmGgQX+OnF5sT2ES6ebjG1lTjsW3mfxpJyHb1nJX -ELedTjb7AgMBAAECggEAGA1FKIs937+nv8hLYI+Fuqo7Jq701IaLPiSN20fI9ENn -cc/uiPP5QbgXQ5VI3Gm86DmvOGSl74G0wLBQFAGik9CGrDp5au07o1odZTQLwkZC -4f/Dzy30WFnZDpkU9ZdlwRpKMLijHul+yKkK4dzk5f2CvpS3WujkZGbZonc7KM5v -BkNWoGBqxCRS8tzX1s7m+f9AOEj45Jz1f2wdd+JBp/MIg+5SBikGIsNAf7BvlpHn -fbKjcFvs3yaM9svDwCCc2ORuvAoAZ8wW3EXCbQQIn2ShCt72LqfP6utYAx0p84tC -wx5HYllDopetWrZ95lNmht8y2mmdR/FsHRI0/CmZAQKBgQD6mTSu1L9kCzb2IBYd -fDWL4nQs2HZDy8W8z5/pYimASNAgy3KAWAfja1800PJn1LwwShb1vnokyoCY+4qp -LMRp9jjVZHA+9ERv9x24BvboI8HJnkEei+1fLvEeHwCOyY2YHzwkw+J4BUK4QKFY -S6tWLbR/2vtlgSkupnuqad+8ewKBgQDuYXLRhBwWo3CZYhxEQg71/Z3hshgtL8Y+ -L2kEE0+kJN4SvcoiS8HtCZ/UynT9kCS7UCbMEM34FoPXd6e0XZ+lcu1w/Gbganpe -rln3QlBS3C2PzMpD7radAVl+rap0QbffKLHgRV+vQ7ixZ8dUkIllXyh2ZIqRW17G -m7A44hSngQKBgQDoA9LAD59HvA5d4CU5lVdqNPbE0oDkkhR4lG6EwOqVqFRyGIrh -gx+CklWqa84TDeZSezY4vesOhyJ7AWFG8njDdkD2aTB3SObYFx4/1Mri8MApsEiw -RHM4ThjVf3SfvsJG1pxzmZzi7FPyjXwUaLKwbk6QlaluOCBt3ZvfknigYwKBgCOQ -4oKkBVTTWc9otfLxMC4/grjTy4uiXx+UD0UOZImG/qMpMelgCDUHhJNJCZ9zTCeu -U7uKnlBve4hAUAM3HMSgmxCKeAbvnAZYWQ/tEvLp6tpTobH1AcX3F5Uw8AecboSb -G77sWtRZdErzwue5EObRBcZ0RcBeM4vKWsaB5LcBAoGBANNebcFUbwGwSFgVY0Ub -hwOfyoEHgrPDbKIwmLOOY2e6NP2kabo1tdrIaLPVWvw0j+bQFsgeoi6tnnpIKWJP -hLcQtB3iD3mk8mKHbr3APqHmK/l6MTKE0zh2ilKhFIVpUVQZKnZV+ktOFaCBjrhl -d3p5s0u8b+r3Xbt0j7+cgsI8 +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC7FdkfDTo5lpyQ +LIRc21FLaRuDsOXWuNYe6kkX1y2wnvLToqE6HZCzLWKwuk0yb9LTyH5VKj8UOKso +5ELNCB+gtqVn313PhZemXkQ2Jeg5HbePw8v5O8m8rWeQ4y96+Z9d/yDr4vpFqj0G +G6aZ3nAsrJAEku1z0hiDnIKQLjsW9w5nwbBOgzV420qvaLsKR48zUI6TIcxY1Exm +Iy1bz0MXUJFMLIn3ys624BplB/WUtctQI+U3T2/M3Nw5Tsjzb4AwwBqtwRJF8LR+ +U1AIoHjhSP3Tk8Gou4xpUwcZ8XZ2PVJ612U9C3nDgUyWG5y/86mBPGGxsVV55lQw +KnbnKYaxAgMBAAECggEAK8IctmlY3srmREeRTwnCPj3voFICNEKn3HPGlGOxTWAk +IlGl3cq4A1zAel8c+sjSelQpDmDy/5cQm6AmKsA1a5kE36KMVeNkmNZwJG0h36ge +fOsaPKmaEj5J3MbynlQgDTOFHv9IM/6xRso1YcR4Hs7e4Z7/GKnBr5juJeyWSBSr +B0V6rb0pZZbTJ5V5rgQX8luWEgVNXZikkdsbBhfRdgNLzB/dil3fV7PxoxZUkvQl +6cem0HRnoB/nOmIVq8BfaCm+kSCe6JBZMrP62eLSaiJr2sVUyxZatEcGRWe0MGmB +3WxSwxtPzM2A+cNLqgIoubAGsVb4x3Jv5Iqc6HRa9QKBgQDqICCwTHa7inv9dxd7 +jp27KclnDQtnGwe4Lscqe8jtlaZOfXF5FAR7HCdZeNe1gJb+RYc3y6BdWJYz4WjV +yzYrwcUKy0XlGd3CkanndDYkoEVEYtdLYG2zJmZuaiZazLROUAs9p0uALAHfrWod +Lv5W+wE3o0qizt+QvnMTDrC6XQKBgQDMkJosqoLDwrAjFOSkuggUN/aqcUjnf/Eg +JIKDLKqouofZKRylJEQFPmMsf9GL7q6e6lyrrpdikzal95JyGfkwN7L1FRGF/dAn +ns8Ivs6aZbvQ1bN0hIhSNI28aAf407JneXvM8YGVOjPwI17m/g/38D0JaKLcKYSF +oIt9MjAAZQKBgQDRIgOxF4xTt79LyQ6b2ugAYLI8MAXIgvehSX+07j+sIiodIKa0 +3fGmup5XqL8erQ+zcA36BBVqbJA3JZmMp+nqqjrFipATtshFXfJkAoW+r79P9+6S +sT8scRe8d2ttXj+NWKjB2OdzRVwjHneUO/8LWUlcFqu7xIkldUm7czrgLQKBgQCC +R42I6McC+ZjHnuTG7Bt9FO8pOaCenuLn/5iHBgliD/m4mfA+VExlsofirTy9C7N2 +Tffa9wQ+qVbieDtyI4yJ4s88OsDAPxc0RHXCMhLOTgBBTfhOOqG/CO1DklWRaPFz +6PCpYx2N9lVhmIU2Q5PT6dJVjag64s4ddFOh1jav6QKBgBy33Sr6pGcVG9nzES2p +MWCClDkSMAoNnHS5OmLwOkGvldwhyzZ4rL0mVWqjPCpMbUoIXTBjy0OaUJLIQ9Nj +si7ZSa4ChR6Tf7gDF/Ea5IM5mVacs41TSX16aFCmpyW+C6HAdeoJxvslTm0N4Gg6 +ysPybT9r313v2eY81F17lpgL -----END PRIVATE KEY----- From 7053cf3797bb77ec4e0f3f9f78bb83263944e9f4 Mon Sep 17 00:00:00 2001 From: Oliver Wolff <23139298+cuioss@users.noreply.github.com> Date: Wed, 4 Mar 2026 22:19:49 +0100 Subject: [PATCH 19/24] chore: Remove 22 orphaned API_SHERIFF_* env vars from docker-compose.yml All issuer, health, metrics, and cache properties were copied from OAuthSheriff but have no @ConfigProperty or @ConfigMapping backing in the codebase. Quarkus silently ignores them at runtime. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --- .../docker-compose.yml | 27 ------------------- 1 file changed, 27 deletions(-) diff --git a/api-sheriff-integration-tests/docker-compose.yml b/api-sheriff-integration-tests/docker-compose.yml index 732b48c0..895d5d30 100644 --- a/api-sheriff-integration-tests/docker-compose.yml +++ b/api-sheriff-integration-tests/docker-compose.yml @@ -56,33 +56,6 @@ services: - QUARKUS_HTTP_SSL_CERTIFICATE_KEY_FILES=/app/certificates/localhost.key - QUARKUS_TLS_DEFAULT_TRUST__STORE_P12_PATH=/app/certificates/localhost-truststore.p12 - QUARKUS_TLS_DEFAULT_TRUST__STORE_P12_PASSWORD=localhost-trust - # Issuer: default (disabled for container tests) - - API_SHERIFF_ISSUERS_DEFAULT_ISSUER__IDENTIFIER=https://test-auth.example.com - - API_SHERIFF_ISSUERS_DEFAULT_ENABLED=false - - API_SHERIFF_ISSUERS_DEFAULT_JWKS_FILE__PATH=classpath:test-jwks.json - # Issuer: Keycloak (well-known discovery) - - API_SHERIFF_ISSUERS_KEYCLOAK_ENABLED=true - - API_SHERIFF_ISSUERS_KEYCLOAK_ISSUER__IDENTIFIER=https://keycloak:8443/realms/benchmark - - API_SHERIFF_ISSUERS_KEYCLOAK_JWKS_HTTP_WELL__KNOWN__URL=https://keycloak:8443/realms/benchmark/.well-known/openid-configuration - - API_SHERIFF_ISSUERS_KEYCLOAK_EXPECTED__CLIENT__ID=benchmark-client - - API_SHERIFF_ISSUERS_KEYCLOAK_KEYCLOAK_MAPPERS_DEFAULT__ROLES_ENABLED=false - - API_SHERIFF_ISSUERS_KEYCLOAK_KEYCLOAK_MAPPERS_DEFAULT__GROUPS_ENABLED=false - - API_SHERIFF_ISSUERS_KEYCLOAK_CLAIM__SUB__OPTIONAL=true - # Issuer: integration (direct JWKS URL) - - API_SHERIFF_ISSUERS_INTEGRATION_ENABLED=true - - API_SHERIFF_ISSUERS_INTEGRATION_ISSUER__IDENTIFIER=https://keycloak:8443/realms/integration - - API_SHERIFF_ISSUERS_INTEGRATION_JWKS_HTTP_URL=https://keycloak:8443/realms/integration/protocol/openid-connect/certs - - API_SHERIFF_ISSUERS_INTEGRATION_EXPECTED__CLIENT__ID=integration-client - - API_SHERIFF_ISSUERS_INTEGRATION_KEYCLOAK_MAPPERS_DEFAULT__ROLES_ENABLED=false - - API_SHERIFF_ISSUERS_INTEGRATION_KEYCLOAK_MAPPERS_DEFAULT__GROUPS_ENABLED=false - - API_SHERIFF_ISSUERS_INTEGRATION_CLAIM__SUB__OPTIONAL=false - # Health check overrides for testing - - API_SHERIFF_HEALTH_JWKS_CACHE__SECONDS=30 - - API_SHERIFF_HEALTH_JWKS_TIMEOUT__SECONDS=5 - # Test overrides โ€” faster metrics, no caching - - API_SHERIFF_METRICS_COLLECTION_INTERVAL=2s - - API_SHERIFF_CACHE_ACCESS__TOKEN_MAX__SIZE=0 - - API_SHERIFF_CACHE_ACCESS__TOKEN_EVICTION__INTERVAL__SECONDS=10 depends_on: - keycloak From 035bc05875f9911850bcc14c3199a5cc1121637d Mon Sep 17 00:00:00 2001 From: Oliver Wolff <23139298+cuioss@users.noreply.github.com> Date: Thu, 5 Mar 2026 09:25:59 +0100 Subject: [PATCH 20/24] chore: Extract JFR config into docker-compose.jfr.yml override file Move JFR-specific Docker configuration (image tag, dockerfile, volume) out of the base docker-compose.yml into a separate override file, matching the OAuthSheriff pattern. Shell scripts and Maven profiles now use `-f` compose flags instead of environment variable substitution. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --- .../docker-compose.jfr.yml | 13 +++++++++ .../docker-compose.yml | 11 ++----- api-sheriff-integration-tests/pom.xml | 8 ++--- .../scripts/start-integration-container.sh | 10 ++----- .../scripts/stop-integration-container.sh | 29 ++++++++++++------- 5 files changed, 41 insertions(+), 30 deletions(-) create mode 100644 api-sheriff-integration-tests/docker-compose.jfr.yml diff --git a/api-sheriff-integration-tests/docker-compose.jfr.yml b/api-sheriff-integration-tests/docker-compose.jfr.yml new file mode 100644 index 00000000..6a4a29ac --- /dev/null +++ b/api-sheriff-integration-tests/docker-compose.jfr.yml @@ -0,0 +1,13 @@ +# Docker Compose override for JFR profiling +# Usage: docker compose -f docker-compose.yml -f docker-compose.jfr.yml up -d + +services: + api-sheriff: + image: "api-sheriff:jfr" + build: + context: ../api-sheriff + dockerfile: src/main/docker/Dockerfile.native.jfr + volumes: + - ./src/main/docker/certificates:/app/certificates:ro + - ${LOG_TARGET_DIR:-./target}:/logs:rw + - ./target/jfr-recordings:/tmp/jfr-output:rw diff --git a/api-sheriff-integration-tests/docker-compose.yml b/api-sheriff-integration-tests/docker-compose.yml index 895d5d30..a33ebdee 100644 --- a/api-sheriff-integration-tests/docker-compose.yml +++ b/api-sheriff-integration-tests/docker-compose.yml @@ -34,13 +34,10 @@ services: - api-sheriff api-sheriff: - # Production Dockerfiles from api-sheriff module โ€” test instrumentation at compose level - # For distroless: DOCKERFILE=Dockerfile.native DOCKER_IMAGE_TAG=distroless (default) - # For JFR: DOCKERFILE=Dockerfile.native.jfr DOCKER_IMAGE_TAG=jfr - image: "api-sheriff:${DOCKER_IMAGE_TAG:-distroless}" + image: "api-sheriff:distroless" build: context: ../api-sheriff - dockerfile: src/main/docker/${DOCKERFILE:-Dockerfile.native} + dockerfile: src/main/docker/Dockerfile.native cache_from: - quay.io/quarkus/quarkus-distroless-image:2.0 - quay.io/quarkus/ubi9-quarkus-micro-image:2.0 @@ -65,8 +62,6 @@ services: - ./src/main/docker/certificates:/app/certificates:ro # Mount target directory for log files (defaults to ./target) - ${LOG_TARGET_DIR:-./target}:/logs:rw - # JFR output volume for profiling recordings - - ./target/jfr-recordings:/tmp/jfr-output:rw # OWASP Security hardening (production-grade) security_opt: @@ -92,7 +87,7 @@ services: cpus: '1.0' # Health check: startup script handles readiness via external curl probe - # No Docker HEALTHCHECK โ€” distroless has no shell; JFR variant has its own + # No Docker HEALTHCHECK โ€” distroless has no shell # Network isolation (production pattern) networks: diff --git a/api-sheriff-integration-tests/pom.xml b/api-sheriff-integration-tests/pom.xml index 6f9b46fc..2525d5bf 100644 --- a/api-sheriff-integration-tests/pom.xml +++ b/api-sheriff-integration-tests/pom.xml @@ -189,8 +189,6 @@ <argument>api-sheriff</argument> </arguments> <environmentVariables> - <DOCKERFILE>Dockerfile.native</DOCKERFILE> - <DOCKER_IMAGE_TAG>distroless</DOCKER_IMAGE_TAG> <DOCKER_BUILDKIT>1</DOCKER_BUILDKIT> </environmentVariables> </configuration> @@ -314,12 +312,14 @@ <workingDirectory>${project.basedir}</workingDirectory> <arguments> <argument>compose</argument> + <argument>-f</argument> + <argument>docker-compose.yml</argument> + <argument>-f</argument> + <argument>docker-compose.jfr.yml</argument> <argument>build</argument> <argument>api-sheriff</argument> </arguments> <environmentVariables> - <DOCKERFILE>Dockerfile.native.jfr</DOCKERFILE> - <DOCKER_IMAGE_TAG>jfr</DOCKER_IMAGE_TAG> <DOCKER_BUILDKIT>1</DOCKER_BUILDKIT> </environmentVariables> </configuration> diff --git a/api-sheriff-integration-tests/scripts/start-integration-container.sh b/api-sheriff-integration-tests/scripts/start-integration-container.sh index a17a0ee5..59f9d032 100755 --- a/api-sheriff-integration-tests/scripts/start-integration-container.sh +++ b/api-sheriff-integration-tests/scripts/start-integration-container.sh @@ -23,13 +23,11 @@ DISTROLESS_IMAGE=$(docker images --format "{{.Repository}}:{{.Tag}}" | grep "^ap if [[ -n "$JFR_IMAGE" ]]; then AVAILABLE_IMAGE="$JFR_IMAGE" IMAGE_TYPE="jfr" - export DOCKER_IMAGE_TAG="jfr" - export DOCKERFILE="Dockerfile.native.jfr" + COMPOSE_CMD="docker compose -f docker-compose.yml -f docker-compose.jfr.yml" elif [[ -n "$DISTROLESS_IMAGE" ]]; then AVAILABLE_IMAGE="$DISTROLESS_IMAGE" IMAGE_TYPE="distroless" - export DOCKER_IMAGE_TAG="distroless" - export DOCKERFILE="Dockerfile.native" + COMPOSE_CMD="docker compose -f docker-compose.yml" else AVAILABLE_IMAGE="" IMAGE_TYPE="none" @@ -40,11 +38,9 @@ IMAGE_EXISTS=$([ ! -z "$AVAILABLE_IMAGE" ] && echo "true" || echo "false") if [[ -n "$RUNNER_FILE" ]] && [[ "$IMAGE_EXISTS" == "true" ]]; then echo "๐Ÿ“ฆ Using Maven-built native executable: $(basename "$RUNNER_FILE")" echo "๐Ÿณ Docker image: $AVAILABLE_IMAGE ($IMAGE_TYPE mode)" - COMPOSE_FILE="docker-compose.yml" MODE="native (Maven-built + Docker copy) - $IMAGE_TYPE" elif [[ "$IMAGE_EXISTS" == "true" ]]; then echo "๐Ÿ“ฆ Using Docker-built native image: $AVAILABLE_IMAGE ($IMAGE_TYPE mode)" - COMPOSE_FILE="docker-compose.yml" MODE="native (Docker-built) - $IMAGE_TYPE" else echo "โŒ Neither native executable nor Docker image found" @@ -63,7 +59,7 @@ echo "๐Ÿ“ Quarkus logs will be written to: ${LOG_TARGET_DIR}/quarkus.log" # Start with Docker Compose (includes Keycloak) echo "๐Ÿณ Starting Docker containers (Quarkus $MODE + Keycloak)..." -(cd "${PROJECT_DIR}" && docker compose -f "$COMPOSE_FILE" up -d) +(cd "${PROJECT_DIR}" && $COMPOSE_CMD up -d) # Wait for Keycloak to be ready first echo "โณ Waiting for Keycloak to be ready..." diff --git a/api-sheriff-integration-tests/scripts/stop-integration-container.sh b/api-sheriff-integration-tests/scripts/stop-integration-container.sh index fc818a32..e91601b1 100755 --- a/api-sheriff-integration-tests/scripts/stop-integration-container.sh +++ b/api-sheriff-integration-tests/scripts/stop-integration-container.sh @@ -1,35 +1,42 @@ #!/bin/bash -# Stop JWT Integration Tests Docker containers +# Stop API Sheriff Integration Tests Docker containers set -e SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" PROJECT_DIR="$(dirname "$SCRIPT_DIR")" -echo "๐Ÿ›‘ Stopping JWT Integration Tests Docker containers" +echo "๐Ÿ›‘ Stopping API Sheriff Integration Tests Docker containers" cd "${PROJECT_DIR}" -# Use the docker-compose.yml file (only file available) -COMPOSE_FILE="docker-compose.yml" -MODE="native" +# Detect if JFR image is running to use matching compose files +JFR_RUNNING=$(docker ps --format "{{.Image}}" | grep "^api-sheriff:jfr$" || true) + +if [[ -n "$JFR_RUNNING" ]]; then + COMPOSE_CMD="docker compose -f docker-compose.yml -f docker-compose.jfr.yml" + MODE="jfr" +else + COMPOSE_CMD="docker compose -f docker-compose.yml" + MODE="distroless" +fi # Stop and remove containers echo "๐Ÿ“ฆ Stopping Docker containers ($MODE mode)..." -docker compose -f "$COMPOSE_FILE" down +$COMPOSE_CMD down # Optional: Clean up images and volumes if [ "$1" = "--clean" ]; then echo "๐Ÿงน Cleaning up Docker images and volumes..." - docker compose -f "$COMPOSE_FILE" down --volumes --rmi all + $COMPOSE_CMD down --volumes --rmi all fi -echo "โœ… JWT Integration Tests stopped successfully" +echo "โœ… API Sheriff Integration Tests stopped successfully" # Show final status -if docker compose -f "$COMPOSE_FILE" ps | grep -q "Up"; then +if $COMPOSE_CMD ps | grep -q "Up"; then echo "โš ๏ธ Some containers are still running:" - docker compose -f "$COMPOSE_FILE" ps + $COMPOSE_CMD ps else echo "โœ… All containers are stopped" -fi \ No newline at end of file +fi From ca736c1a6b691ad1c91d4b6526bd5d0ba412caa7 Mon Sep 17 00:00:00 2001 From: Oliver Wolff <23139298+cuioss@users.noreply.github.com> Date: Thu, 5 Mar 2026 11:44:04 +0100 Subject: [PATCH 21/24] feat: Enable Quarkus management interface for health/metrics on port 9000 Separate operational endpoints (health, metrics) from application traffic by enabling the Quarkus management interface on a dedicated plain HTTP port. This follows the Keycloak pattern already in the project, eliminates TLS complexity for probes, and allows Prometheus to scrape without insecure_skip_verify. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --- api-sheriff-integration-tests/docker-compose.yml | 4 ++-- api-sheriff-integration-tests/prometheus.yml | 6 ++---- .../scripts/build-native-if-needed.sh | 4 ++-- .../scripts/start-integration-container.sh | 8 ++++---- .../api/integration/ApiSheriffIntegrationIT.java | 6 ++++-- .../api/integration/BaseIntegrationTest.java | 13 +++++++++++++ api-sheriff/src/main/docker/Dockerfile.native | 4 ++-- api-sheriff/src/main/docker/Dockerfile.native.jfr | 2 +- .../src/main/resources/application.properties | 4 ++++ benchmark-integration/pom.xml | 4 +++- .../resources/wrk-scripts/health_live_benchmark.sh | 2 +- .../wrk-scripts/pre-benchmark-health-check.sh | 3 ++- 12 files changed, 40 insertions(+), 20 deletions(-) diff --git a/api-sheriff-integration-tests/docker-compose.yml b/api-sheriff-integration-tests/docker-compose.yml index a33ebdee..b6c0bf35 100644 --- a/api-sheriff-integration-tests/docker-compose.yml +++ b/api-sheriff-integration-tests/docker-compose.yml @@ -44,6 +44,7 @@ services: ports: - "10443:8443" # External test port for integration tests + - "19000:9000" # Management interface (health/metrics, plain HTTP) environment: # File logging to mounted target directory @@ -86,8 +87,7 @@ services: memory: 256M cpus: '1.0' - # Health check: startup script handles readiness via external curl probe - # No Docker HEALTHCHECK โ€” distroless has no shell + # Health check: startup script probes management interface (port 9000, plain HTTP) # Network isolation (production pattern) networks: diff --git a/api-sheriff-integration-tests/prometheus.yml b/api-sheriff-integration-tests/prometheus.yml index 3e873069..44aa3fd2 100644 --- a/api-sheriff-integration-tests/prometheus.yml +++ b/api-sheriff-integration-tests/prometheus.yml @@ -5,8 +5,6 @@ global: scrape_configs: - job_name: 'quarkus-benchmark' static_configs: - - targets: ['api-sheriff:8443'] + - targets: ['api-sheriff:9000'] metrics_path: '/q/metrics' - scheme: https - tls_config: - insecure_skip_verify: true + scheme: http diff --git a/api-sheriff-integration-tests/scripts/build-native-if-needed.sh b/api-sheriff-integration-tests/scripts/build-native-if-needed.sh index d3d55d5d..27e8c04e 100755 --- a/api-sheriff-integration-tests/scripts/build-native-if-needed.sh +++ b/api-sheriff-integration-tests/scripts/build-native-if-needed.sh @@ -16,9 +16,9 @@ if [[ -z "$RUNNER_FILE" ]]; then echo "๐Ÿ”จ Native executable not found, building it now..." echo "This will take approximately 2 minutes..." - # Build native executable using Quarkus Maven plugin on api-sheriff module + # Build native executable with full lifecycle (ensures resources/augmentation) cd "${ROOT_DIR}" - ./mvnw --no-transfer-progress -Pnative quarkus:build -pl api-sheriff + ./mvnw --no-transfer-progress clean package -Pnative -pl api-sheriff -DskipTests # Verify it was created RUNNER_FILE=$(find "${APP_TARGET_DIR}" -name "*-runner" -type f 2>/dev/null | head -n 1) diff --git a/api-sheriff-integration-tests/scripts/start-integration-container.sh b/api-sheriff-integration-tests/scripts/start-integration-container.sh index 59f9d032..3df75b00 100755 --- a/api-sheriff-integration-tests/scripts/start-integration-container.sh +++ b/api-sheriff-integration-tests/scripts/start-integration-container.sh @@ -81,7 +81,7 @@ done echo "โณ Waiting for Quarkus service to be ready..." START_TIME=$(date +%s) for i in {1..30}; do - if curl -k -s https://localhost:10443/q/health/live > /dev/null 2>&1; then + if curl -sf http://localhost:19000/q/health/live > /dev/null 2>&1; then END_TIME=$(date +%s) TOTAL_TIME=$((END_TIME - START_TIME)) echo "โœ… Quarkus service is ready!" @@ -113,12 +113,12 @@ echo "" echo "๐ŸŽ‰ API Sheriff Integration Benchmark Environment is running!" echo "" echo "๐Ÿ“ฑ Application URLs:" -echo " ๐Ÿ” Health Check: https://localhost:10443/q/health" -echo " ๐Ÿ“Š Metrics: https://localhost:10443/q/metrics" +echo " ๐Ÿ” Health Check: http://localhost:19000/q/health" +echo " ๐Ÿ“Š Metrics: http://localhost:19000/q/metrics" echo " ๐Ÿ”‘ Keycloak: https://localhost:1443/auth" echo "" echo "๐Ÿงช Quick test commands:" -echo " curl -k https://localhost:10443/q/health/live" +echo " curl -sf http://localhost:19000/q/health/live" echo " curl -k https://localhost:1090/health/ready" echo "" echo "๐Ÿ›‘ To stop: ./scripts/stop-integration-container.sh" diff --git a/api-sheriff-integration-tests/src/test/java/de/cuioss/sheriff/api/integration/ApiSheriffIntegrationIT.java b/api-sheriff-integration-tests/src/test/java/de/cuioss/sheriff/api/integration/ApiSheriffIntegrationIT.java index e5ee2dd7..f2ece8e8 100644 --- a/api-sheriff-integration-tests/src/test/java/de/cuioss/sheriff/api/integration/ApiSheriffIntegrationIT.java +++ b/api-sheriff-integration-tests/src/test/java/de/cuioss/sheriff/api/integration/ApiSheriffIntegrationIT.java @@ -62,11 +62,12 @@ void infoEndpoint() { } /** - * Test that the Quarkus health check endpoint is available. + * Test that the Quarkus health check endpoint is available on the management interface. */ @Test void quarkusHealthEndpoint() { given() + .baseUri(managementBaseUri()) .when() .get("/q/health") .then() @@ -75,11 +76,12 @@ void quarkusHealthEndpoint() { } /** - * Test that metrics endpoint is available (from Micrometer integration). + * Test that metrics endpoint is available on the management interface. */ @Test void metricsEndpoint() { given() + .baseUri(managementBaseUri()) .when() .get("/q/metrics") .then() diff --git a/api-sheriff-integration-tests/src/test/java/de/cuioss/sheriff/api/integration/BaseIntegrationTest.java b/api-sheriff-integration-tests/src/test/java/de/cuioss/sheriff/api/integration/BaseIntegrationTest.java index 60312ff3..92530ddb 100644 --- a/api-sheriff-integration-tests/src/test/java/de/cuioss/sheriff/api/integration/BaseIntegrationTest.java +++ b/api-sheriff-integration-tests/src/test/java/de/cuioss/sheriff/api/integration/BaseIntegrationTest.java @@ -28,6 +28,7 @@ public abstract class BaseIntegrationTest { private static final String DEFAULT_TEST_PORT = "10443"; + private static final String DEFAULT_MANAGEMENT_PORT = "19000"; @BeforeAll static void setUpBaseIntegrationTest() { @@ -42,4 +43,16 @@ static void setUpBaseIntegrationTest() { // cui-rewrite:disable CuiLoggerStandardsRecipe System.out.println("Integration tests configured for HTTPS port: " + testPort); } + + /** + * Returns the management interface base URI (plain HTTP, port 19000). + * Health and metrics endpoints are served on the management port + * when {@code quarkus.management.enabled=true}. + * + * @return management base URI for health/metrics endpoints + */ + static String managementBaseUri() { + String managementPort = System.getProperty("test.management.port", DEFAULT_MANAGEMENT_PORT); + return "http://localhost:" + managementPort; + } } \ No newline at end of file diff --git a/api-sheriff/src/main/docker/Dockerfile.native b/api-sheriff/src/main/docker/Dockerfile.native index b293ee90..9d913700 100644 --- a/api-sheriff/src/main/docker/Dockerfile.native +++ b/api-sheriff/src/main/docker/Dockerfile.native @@ -1,7 +1,7 @@ # Production Dockerfile for API Sheriff native executable # Distroless: no shell, no package manager โ€” minimal attack surface # No baked-in certificates โ€” mount TLS certs at runtime via volumes or secrets -# Health probes handled externally by orchestrator (Kubernetes liveness/readiness) +# Health probes via management interface (port 9000, plain HTTP) FROM quay.io/quarkus/quarkus-distroless-image:2.0@sha256:0278fd70d9627df836295570da0fd22034ea664efc12a834a0532cea7556a87b LABEL org.opencontainers.image.title="API Sheriff" @@ -19,7 +19,7 @@ WORKDIR /app # Copy pre-built native executable COPY --chmod=0755 target/*-runner /app/application -EXPOSE 8443 +EXPOSE 8443 9000 USER nonroot ENTRYPOINT ["/app/application", "-Dquarkus.http.host=0.0.0.0"] diff --git a/api-sheriff/src/main/docker/Dockerfile.native.jfr b/api-sheriff/src/main/docker/Dockerfile.native.jfr index af7fbf15..14c49c67 100644 --- a/api-sheriff/src/main/docker/Dockerfile.native.jfr +++ b/api-sheriff/src/main/docker/Dockerfile.native.jfr @@ -21,7 +21,7 @@ COPY --chown=1001:root --chmod=0755 target/*-runner /app/application # Create JFR output directory with proper permissions RUN mkdir -p /tmp/jfr-output && chmod 777 /tmp/jfr-output -EXPOSE 8443 +EXPOSE 8443 9000 # Port probe health check using bash /dev/tcp (available in UBI micro) HEALTHCHECK --interval=15s --timeout=5s --start-period=15s --retries=3 \ diff --git a/api-sheriff/src/main/resources/application.properties b/api-sheriff/src/main/resources/application.properties index cac2ebc4..57b9a98b 100644 --- a/api-sheriff/src/main/resources/application.properties +++ b/api-sheriff/src/main/resources/application.properties @@ -8,6 +8,10 @@ quarkus.http.port=8080 quarkus.http.ssl-port=8443 quarkus.http.insecure-requests=redirect +# Management interface โ€” health/metrics on separate plain HTTP port +# Follows Keycloak pattern: application on 8443 (HTTPS), operations on 9000 (HTTP) +quarkus.management.enabled=true + # TLS Configuration quarkus.ssl.native=true quarkus.tls.protocols=TLSv1.3,TLSv1.2 diff --git a/benchmark-integration/pom.xml b/benchmark-integration/pom.xml index 410b443a..d7f1dca5 100644 --- a/benchmark-integration/pom.xml +++ b/benchmark-integration/pom.xml @@ -29,8 +29,9 @@ <!-- Integration test service URLs (host access via published ports) --> <integration.service.url>https://localhost:10443</integration.service.url> + <integration.management.url>http://localhost:19000</integration.management.url> <keycloak.url>https://localhost:1443</keycloak.url> - <quarkus.metrics.url>https://localhost:10443</quarkus.metrics.url> + <quarkus.metrics.url>http://localhost:19000</quarkus.metrics.url> <!-- WRK Configuration Properties --> <wrk.duration>60s</wrk.duration> @@ -217,6 +218,7 @@ </arguments> <environmentVariables> <INTEGRATION_SERVICE_URL>${integration.service.url}</INTEGRATION_SERVICE_URL> + <MANAGEMENT_URL>${integration.management.url}</MANAGEMENT_URL> <PROMETHEUS_URL>http://localhost:9090</PROMETHEUS_URL> <KEYCLOAK_URL>https://localhost:1090</KEYCLOAK_URL> </environmentVariables> diff --git a/benchmark-integration/src/main/resources/wrk-scripts/health_live_benchmark.sh b/benchmark-integration/src/main/resources/wrk-scripts/health_live_benchmark.sh index 77eb36be..999e3711 100755 --- a/benchmark-integration/src/main/resources/wrk-scripts/health_live_benchmark.sh +++ b/benchmark-integration/src/main/resources/wrk-scripts/health_live_benchmark.sh @@ -9,7 +9,7 @@ WRK_TIMEOUT="${WRK_TIMEOUT:-2s}" COMPOSE_DIR="${COMPOSE_DIR:?COMPOSE_DIR must be set}" BENCHMARK_NAME="healthLiveCheck" -TARGET_URL="https://api-sheriff:8443/q/health/live" +TARGET_URL="http://api-sheriff:9000/q/health/live" echo "=== BENCHMARK METADATA ===" echo "benchmark_name: ${BENCHMARK_NAME}" diff --git a/benchmark-integration/src/main/resources/wrk-scripts/pre-benchmark-health-check.sh b/benchmark-integration/src/main/resources/wrk-scripts/pre-benchmark-health-check.sh index 09332814..0e47ea9e 100755 --- a/benchmark-integration/src/main/resources/wrk-scripts/pre-benchmark-health-check.sh +++ b/benchmark-integration/src/main/resources/wrk-scripts/pre-benchmark-health-check.sh @@ -3,6 +3,7 @@ set -e INTEGRATION_SERVICE_URL="${INTEGRATION_SERVICE_URL:?INTEGRATION_SERVICE_URL must be set}" +MANAGEMENT_URL="${MANAGEMENT_URL:?MANAGEMENT_URL must be set}" PROMETHEUS_URL="${PROMETHEUS_URL:?PROMETHEUS_URL must be set}" KEYCLOAK_URL="${KEYCLOAK_URL:?KEYCLOAK_URL must be set}" @@ -31,7 +32,7 @@ check_service() { echo "=== Pre-Benchmark Health Check ===" -check_service "Quarkus (health/live)" "${INTEGRATION_SERVICE_URL}/q/health/live" +check_service "Quarkus (health/live)" "${MANAGEMENT_URL}/q/health/live" check_service "Prometheus" "${PROMETHEUS_URL}/-/ready" check_service "Keycloak" "${KEYCLOAK_URL}/health/ready" From fb686fae3c113b01ba046347190c64ef6ac0d213 Mon Sep 17 00:00:00 2001 From: Oliver Wolff <23139298+cuioss@users.noreply.github.com> Date: Thu, 5 Mar 2026 12:04:02 +0100 Subject: [PATCH 22/24] chore: Rename api-sheriff-integration-tests module to integration-tests Redundant prefix removed since the module is already inside the API-Sheriff repository. Updated all references across POMs, GitHub Actions workflows, shell scripts, and CLAUDE.md. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --- .github/workflows/claude.yml | 2 +- .github/workflows/integration-tests.yml | 6 +++--- CLAUDE.md | 4 ++-- benchmark-integration/pom.xml | 8 ++++---- .../docker-compose.jfr.yml | 0 .../docker-compose.yml | 0 .../pom.xml | 2 +- .../prometheus.yml | 0 .../scripts/benchmark-with-monitoring.sh | 2 +- .../scripts/build-native-if-needed.sh | 0 .../scripts/dump-keycloak-logs.sh | 2 +- .../scripts/start-integration-container.sh | 2 +- .../scripts/stop-integration-container.sh | 0 .../scripts/verify-environment.sh | 0 .../docker/certificates/generate-certificates.sh | 0 .../main/docker/certificates/generate-truststore.sh | 0 .../docker/certificates/localhost-truststore.p12 | Bin .../src/main/docker/certificates/localhost.crt | 0 .../src/main/docker/certificates/localhost.key | 0 .../src/main/docker/health-check.sh | 0 .../src/main/docker/keycloak/benchmark-realm.json | 0 .../src/main/docker/keycloak/integration-realm.json | 0 .../src/main/resources/application.properties | 0 .../src/main/resources/test-jwks.json | 0 .../src/main/resources/test-public-key.pem | 0 .../api/integration/ApiSheriffIntegrationIT.java | 0 .../api/integration/BaseIntegrationTest.java | 0 .../src/test/resources/keys/test_public_key.pem | 0 pom.xml | 2 +- 29 files changed, 15 insertions(+), 15 deletions(-) rename {api-sheriff-integration-tests => integration-tests}/docker-compose.jfr.yml (100%) rename {api-sheriff-integration-tests => integration-tests}/docker-compose.yml (100%) rename {api-sheriff-integration-tests => integration-tests}/pom.xml (99%) rename {api-sheriff-integration-tests => integration-tests}/prometheus.yml (100%) rename {api-sheriff-integration-tests => integration-tests}/scripts/benchmark-with-monitoring.sh (99%) rename {api-sheriff-integration-tests => integration-tests}/scripts/build-native-if-needed.sh (100%) rename {api-sheriff-integration-tests => integration-tests}/scripts/dump-keycloak-logs.sh (97%) rename {api-sheriff-integration-tests => integration-tests}/scripts/start-integration-container.sh (98%) rename {api-sheriff-integration-tests => integration-tests}/scripts/stop-integration-container.sh (100%) rename {api-sheriff-integration-tests => integration-tests}/scripts/verify-environment.sh (100%) rename {api-sheriff-integration-tests => integration-tests}/src/main/docker/certificates/generate-certificates.sh (100%) rename {api-sheriff-integration-tests => integration-tests}/src/main/docker/certificates/generate-truststore.sh (100%) rename {api-sheriff-integration-tests => integration-tests}/src/main/docker/certificates/localhost-truststore.p12 (100%) rename {api-sheriff-integration-tests => integration-tests}/src/main/docker/certificates/localhost.crt (100%) rename {api-sheriff-integration-tests => integration-tests}/src/main/docker/certificates/localhost.key (100%) rename {api-sheriff-integration-tests => integration-tests}/src/main/docker/health-check.sh (100%) rename {api-sheriff-integration-tests => integration-tests}/src/main/docker/keycloak/benchmark-realm.json (100%) rename {api-sheriff-integration-tests => integration-tests}/src/main/docker/keycloak/integration-realm.json (100%) rename {api-sheriff-integration-tests => integration-tests}/src/main/resources/application.properties (100%) rename {api-sheriff-integration-tests => integration-tests}/src/main/resources/test-jwks.json (100%) rename {api-sheriff-integration-tests => integration-tests}/src/main/resources/test-public-key.pem (100%) rename {api-sheriff-integration-tests => integration-tests}/src/test/java/de/cuioss/sheriff/api/integration/ApiSheriffIntegrationIT.java (100%) rename {api-sheriff-integration-tests => integration-tests}/src/test/java/de/cuioss/sheriff/api/integration/BaseIntegrationTest.java (100%) rename {api-sheriff-integration-tests => integration-tests}/src/test/resources/keys/test_public_key.pem (100%) diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index 80c0c62e..216fe3ee 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -49,4 +49,4 @@ jobs: additional_permissions: | actions: read - allowed_tools: "Bash(./mvnw*),Bash(./mvnw -Ppre-commit clean verify -DskipTests),Bash(./mvnw clean verify),Bash(./mvnw clean install),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl api-sheriff),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl api-sheriff-integration-tests),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl benchmark-integration),Bash(./mvnw clean install -pl api-sheriff),Bash(./mvnw clean install -pl api-sheriff-integration-tests),Bash(./mvnw clean install -pl benchmark-integration),Bash(git*),Bash(find*),Bash(gh*),Bash(java*)" + allowed_tools: "Bash(./mvnw*),Bash(./mvnw -Ppre-commit clean verify -DskipTests),Bash(./mvnw clean verify),Bash(./mvnw clean install),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl api-sheriff),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl integration-tests),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl benchmark-integration),Bash(./mvnw clean install -pl api-sheriff),Bash(./mvnw clean install -pl integration-tests),Bash(./mvnw clean install -pl benchmark-integration),Bash(git*),Bash(find*),Bash(gh*),Bash(java*)" diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 1cf52279..522c8287 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -18,11 +18,11 @@ jobs: if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name uses: cuioss/cuioss-organization/.github/workflows/reusable-maven-integration-tests.yml@8fce8938a4e92b4164650d083dbbf9c5601c6dfb # v0.6.2 with: - report-name: api-sheriff-integration-tests + report-name: integration-tests maven-args-input: | - verify -Pintegration-tests -pl api-sheriff-integration-tests -am + verify -Pintegration-tests -pl integration-tests -am reports-folder: | - api-sheriff-integration-tests/target/failsafe-reports + integration-tests/target/failsafe-reports secrets: RELEASE_APP_ID: ${{ secrets.RELEASE_APP_ID }} RELEASE_APP_PRIVATE_KEY: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} diff --git a/CLAUDE.md b/CLAUDE.md index 31304c38..f8717209 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -10,7 +10,7 @@ API Sheriff is a security-focused API Gateway with a lightweight approach, curre Multi-module Maven project: - `api-sheriff/` โ€” Deployable Quarkus application (core library, CDI producers, REST endpoints, native executable) -- `api-sheriff-integration-tests/` โ€” Integration test coordinator (Docker infrastructure, IT suites, scripts) +- `integration-tests/` โ€” Integration test coordinator (Docker infrastructure, IT suites, scripts) - `benchmark-integration/` โ€” WRK HTTP load testing benchmarks ## Build Commands @@ -29,7 +29,7 @@ Multi-module Maven project: ./mvnw test -Dtest=ClassName#methodName # Integration tests -./mvnw clean verify -Pintegration-tests -pl api-sheriff-integration-tests -am +./mvnw clean verify -Pintegration-tests -pl integration-tests -am # Integration benchmarks (WRK) ./mvnw clean verify -pl benchmark-integration -Pbenchmark diff --git a/benchmark-integration/pom.xml b/benchmark-integration/pom.xml index d7f1dca5..6090519b 100644 --- a/benchmark-integration/pom.xml +++ b/benchmark-integration/pom.xml @@ -22,10 +22,10 @@ <skip.container.lifecycle>false</skip.container.lifecycle> <!-- Scripts location --> - <integration.scripts.dir>${project.basedir}/../api-sheriff-integration-tests/scripts</integration.scripts.dir> + <integration.scripts.dir>${project.basedir}/../integration-tests/scripts</integration.scripts.dir> <!-- Docker compose directory for WRK benchmarks --> - <integration.compose.dir>${project.basedir}/../api-sheriff-integration-tests</integration.compose.dir> + <integration.compose.dir>${project.basedir}/../integration-tests</integration.compose.dir> <!-- Integration test service URLs (host access via published ports) --> <integration.service.url>https://localhost:10443</integration.service.url> @@ -166,7 +166,7 @@ <argument>-Pintegration-tests</argument> <argument>-DskipTests</argument> </arguments> - <workingDirectory>${project.basedir}/../api-sheriff-integration-tests</workingDirectory> + <workingDirectory>${project.basedir}/../integration-tests</workingDirectory> </configuration> </execution> @@ -346,7 +346,7 @@ <arguments> <argument>clean</argument> <argument>-pl</argument> - <argument>api-sheriff,api-sheriff-integration-tests</argument> + <argument>api-sheriff,integration-tests</argument> </arguments> <workingDirectory>${project.basedir}/..</workingDirectory> </configuration> diff --git a/api-sheriff-integration-tests/docker-compose.jfr.yml b/integration-tests/docker-compose.jfr.yml similarity index 100% rename from api-sheriff-integration-tests/docker-compose.jfr.yml rename to integration-tests/docker-compose.jfr.yml diff --git a/api-sheriff-integration-tests/docker-compose.yml b/integration-tests/docker-compose.yml similarity index 100% rename from api-sheriff-integration-tests/docker-compose.yml rename to integration-tests/docker-compose.yml diff --git a/api-sheriff-integration-tests/pom.xml b/integration-tests/pom.xml similarity index 99% rename from api-sheriff-integration-tests/pom.xml rename to integration-tests/pom.xml index 2525d5bf..cf430aa5 100644 --- a/api-sheriff-integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -10,7 +10,7 @@ <relativePath>../pom.xml</relativePath> </parent> - <artifactId>api-sheriff-integration-tests</artifactId> + <artifactId>integration-tests</artifactId> <packaging>jar</packaging> <name>API Sheriff Integration Tests</name> <description>Integration test coordinator for API Sheriff โ€” builds native containers and runs IT suites</description> diff --git a/api-sheriff-integration-tests/prometheus.yml b/integration-tests/prometheus.yml similarity index 100% rename from api-sheriff-integration-tests/prometheus.yml rename to integration-tests/prometheus.yml diff --git a/api-sheriff-integration-tests/scripts/benchmark-with-monitoring.sh b/integration-tests/scripts/benchmark-with-monitoring.sh similarity index 99% rename from api-sheriff-integration-tests/scripts/benchmark-with-monitoring.sh rename to integration-tests/scripts/benchmark-with-monitoring.sh index 57289ac5..5eb22be9 100755 --- a/api-sheriff-integration-tests/scripts/benchmark-with-monitoring.sh +++ b/integration-tests/scripts/benchmark-with-monitoring.sh @@ -6,7 +6,7 @@ set -e SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" -RESULTS_DIR="$PROJECT_ROOT/api-sheriff-integration-tests/target/monitoring-results" +RESULTS_DIR="$PROJECT_ROOT/integration-tests/target/monitoring-results" TIMESTAMP=$(date +%Y%m%d-%H%M%S) echo "๐Ÿ” API Sheriff Validation Benchmark with Comprehensive Monitoring" diff --git a/api-sheriff-integration-tests/scripts/build-native-if-needed.sh b/integration-tests/scripts/build-native-if-needed.sh similarity index 100% rename from api-sheriff-integration-tests/scripts/build-native-if-needed.sh rename to integration-tests/scripts/build-native-if-needed.sh diff --git a/api-sheriff-integration-tests/scripts/dump-keycloak-logs.sh b/integration-tests/scripts/dump-keycloak-logs.sh similarity index 97% rename from api-sheriff-integration-tests/scripts/dump-keycloak-logs.sh rename to integration-tests/scripts/dump-keycloak-logs.sh index 5fd00ffe..ed908389 100755 --- a/api-sheriff-integration-tests/scripts/dump-keycloak-logs.sh +++ b/integration-tests/scripts/dump-keycloak-logs.sh @@ -9,7 +9,7 @@ set -euo pipefail # Configuration -KEYCLOAK_CONTAINER_NAME="api-sheriff-integration-tests-keycloak-1" +KEYCLOAK_CONTAINER_NAME="integration-tests-keycloak-1" TIMESTAMP=$(date +"%Y-%m-%d_%H-%M-%S") KEYCLOAK_LOG_FILENAME="keycloak-logs-${TIMESTAMP}.txt" diff --git a/api-sheriff-integration-tests/scripts/start-integration-container.sh b/integration-tests/scripts/start-integration-container.sh similarity index 98% rename from api-sheriff-integration-tests/scripts/start-integration-container.sh rename to integration-tests/scripts/start-integration-container.sh index 3df75b00..6f371daf 100755 --- a/api-sheriff-integration-tests/scripts/start-integration-container.sh +++ b/integration-tests/scripts/start-integration-container.sh @@ -47,7 +47,7 @@ else echo "Expected: api-sheriff/target/*-runner file and api-sheriff image" echo "Available images:" docker images | grep api-sheriff || echo " No api-sheriff images found" - echo "Run: mvnw verify -Pintegration-tests -pl api-sheriff-integration-tests -am" + echo "Run: mvnw verify -Pintegration-tests -pl integration-tests -am" exit 1 fi diff --git a/api-sheriff-integration-tests/scripts/stop-integration-container.sh b/integration-tests/scripts/stop-integration-container.sh similarity index 100% rename from api-sheriff-integration-tests/scripts/stop-integration-container.sh rename to integration-tests/scripts/stop-integration-container.sh diff --git a/api-sheriff-integration-tests/scripts/verify-environment.sh b/integration-tests/scripts/verify-environment.sh similarity index 100% rename from api-sheriff-integration-tests/scripts/verify-environment.sh rename to integration-tests/scripts/verify-environment.sh diff --git a/api-sheriff-integration-tests/src/main/docker/certificates/generate-certificates.sh b/integration-tests/src/main/docker/certificates/generate-certificates.sh similarity index 100% rename from api-sheriff-integration-tests/src/main/docker/certificates/generate-certificates.sh rename to integration-tests/src/main/docker/certificates/generate-certificates.sh diff --git a/api-sheriff-integration-tests/src/main/docker/certificates/generate-truststore.sh b/integration-tests/src/main/docker/certificates/generate-truststore.sh similarity index 100% rename from api-sheriff-integration-tests/src/main/docker/certificates/generate-truststore.sh rename to integration-tests/src/main/docker/certificates/generate-truststore.sh diff --git a/api-sheriff-integration-tests/src/main/docker/certificates/localhost-truststore.p12 b/integration-tests/src/main/docker/certificates/localhost-truststore.p12 similarity index 100% rename from api-sheriff-integration-tests/src/main/docker/certificates/localhost-truststore.p12 rename to integration-tests/src/main/docker/certificates/localhost-truststore.p12 diff --git a/api-sheriff-integration-tests/src/main/docker/certificates/localhost.crt b/integration-tests/src/main/docker/certificates/localhost.crt similarity index 100% rename from api-sheriff-integration-tests/src/main/docker/certificates/localhost.crt rename to integration-tests/src/main/docker/certificates/localhost.crt diff --git a/api-sheriff-integration-tests/src/main/docker/certificates/localhost.key b/integration-tests/src/main/docker/certificates/localhost.key similarity index 100% rename from api-sheriff-integration-tests/src/main/docker/certificates/localhost.key rename to integration-tests/src/main/docker/certificates/localhost.key diff --git a/api-sheriff-integration-tests/src/main/docker/health-check.sh b/integration-tests/src/main/docker/health-check.sh similarity index 100% rename from api-sheriff-integration-tests/src/main/docker/health-check.sh rename to integration-tests/src/main/docker/health-check.sh diff --git a/api-sheriff-integration-tests/src/main/docker/keycloak/benchmark-realm.json b/integration-tests/src/main/docker/keycloak/benchmark-realm.json similarity index 100% rename from api-sheriff-integration-tests/src/main/docker/keycloak/benchmark-realm.json rename to integration-tests/src/main/docker/keycloak/benchmark-realm.json diff --git a/api-sheriff-integration-tests/src/main/docker/keycloak/integration-realm.json b/integration-tests/src/main/docker/keycloak/integration-realm.json similarity index 100% rename from api-sheriff-integration-tests/src/main/docker/keycloak/integration-realm.json rename to integration-tests/src/main/docker/keycloak/integration-realm.json diff --git a/api-sheriff-integration-tests/src/main/resources/application.properties b/integration-tests/src/main/resources/application.properties similarity index 100% rename from api-sheriff-integration-tests/src/main/resources/application.properties rename to integration-tests/src/main/resources/application.properties diff --git a/api-sheriff-integration-tests/src/main/resources/test-jwks.json b/integration-tests/src/main/resources/test-jwks.json similarity index 100% rename from api-sheriff-integration-tests/src/main/resources/test-jwks.json rename to integration-tests/src/main/resources/test-jwks.json diff --git a/api-sheriff-integration-tests/src/main/resources/test-public-key.pem b/integration-tests/src/main/resources/test-public-key.pem similarity index 100% rename from api-sheriff-integration-tests/src/main/resources/test-public-key.pem rename to integration-tests/src/main/resources/test-public-key.pem diff --git a/api-sheriff-integration-tests/src/test/java/de/cuioss/sheriff/api/integration/ApiSheriffIntegrationIT.java b/integration-tests/src/test/java/de/cuioss/sheriff/api/integration/ApiSheriffIntegrationIT.java similarity index 100% rename from api-sheriff-integration-tests/src/test/java/de/cuioss/sheriff/api/integration/ApiSheriffIntegrationIT.java rename to integration-tests/src/test/java/de/cuioss/sheriff/api/integration/ApiSheriffIntegrationIT.java diff --git a/api-sheriff-integration-tests/src/test/java/de/cuioss/sheriff/api/integration/BaseIntegrationTest.java b/integration-tests/src/test/java/de/cuioss/sheriff/api/integration/BaseIntegrationTest.java similarity index 100% rename from api-sheriff-integration-tests/src/test/java/de/cuioss/sheriff/api/integration/BaseIntegrationTest.java rename to integration-tests/src/test/java/de/cuioss/sheriff/api/integration/BaseIntegrationTest.java diff --git a/api-sheriff-integration-tests/src/test/resources/keys/test_public_key.pem b/integration-tests/src/test/resources/keys/test_public_key.pem similarity index 100% rename from api-sheriff-integration-tests/src/test/resources/keys/test_public_key.pem rename to integration-tests/src/test/resources/keys/test_public_key.pem diff --git a/pom.xml b/pom.xml index 150d088d..5165abdb 100644 --- a/pom.xml +++ b/pom.xml @@ -22,7 +22,7 @@ <url>https://github.com/cuioss/api-sheriff/</url> <modules> <module>api-sheriff</module> - <module>api-sheriff-integration-tests</module> + <module>integration-tests</module> <module>benchmark-integration</module> </modules> <scm> From ebf97c321e830f08f8d43004bae5e110d8d0a0eb Mon Sep 17 00:00:00 2001 From: Oliver Wolff <23139298+cuioss@users.noreply.github.com> Date: Thu, 5 Mar 2026 12:08:24 +0100 Subject: [PATCH 23/24] chore: Rename benchmark-integration module to benchmarks Shorter, cleaner name since the repository context already implies API Sheriff. Updated all references across POMs, GitHub Actions workflows, shell scripts, Dockerfile, documentation, and CLAUDE.md. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --- .github/workflows/benchmark.yml | 10 +++++----- .github/workflows/claude.yml | 2 +- CLAUDE.md | 4 ++-- README.adoc | 4 ++-- {benchmark-integration => benchmarks}/Dockerfile.wrk | 2 +- {benchmark-integration => benchmarks}/README.adoc | 4 ++-- .../doc/performance-scoring.adoc | 0 {benchmark-integration => benchmarks}/pom.xml | 2 +- .../scripts/benchmark-pages.py | 6 +++--- .../api/wrk/benchmark/WrkResultPostProcessor.java | 0 .../main/resources/wrk-scripts/api_health_benchmark.sh | 0 .../main/resources/wrk-scripts/api_health_check.lua | 0 .../resources/wrk-scripts/health_live_benchmark.sh | 0 .../main/resources/wrk-scripts/health_live_check.lua | 0 .../wrk-scripts/pre-benchmark-health-check.sh | 0 .../wrk/benchmark/GatewayEndpointBenchmarkTest.java | 0 .../api/wrk/benchmark/WrkResultPostProcessorTest.java | 0 .../src/test/resources/wrk-api-health-results.txt | 0 .../src/test/resources/wrk-health-results.txt | 0 integration-tests/docker-compose.yml | 2 +- integration-tests/scripts/benchmark-with-monitoring.sh | 2 +- pom.xml | 2 +- 22 files changed, 20 insertions(+), 20 deletions(-) rename {benchmark-integration => benchmarks}/Dockerfile.wrk (51%) rename {benchmark-integration => benchmarks}/README.adoc (79%) rename {benchmark-integration => benchmarks}/doc/performance-scoring.adoc (100%) rename {benchmark-integration => benchmarks}/pom.xml (99%) rename {benchmark-integration => benchmarks}/scripts/benchmark-pages.py (97%) rename {benchmark-integration => benchmarks}/src/main/java/de/cuioss/sheriff/api/wrk/benchmark/WrkResultPostProcessor.java (100%) rename {benchmark-integration => benchmarks}/src/main/resources/wrk-scripts/api_health_benchmark.sh (100%) rename {benchmark-integration => benchmarks}/src/main/resources/wrk-scripts/api_health_check.lua (100%) rename {benchmark-integration => benchmarks}/src/main/resources/wrk-scripts/health_live_benchmark.sh (100%) rename {benchmark-integration => benchmarks}/src/main/resources/wrk-scripts/health_live_check.lua (100%) rename {benchmark-integration => benchmarks}/src/main/resources/wrk-scripts/pre-benchmark-health-check.sh (100%) rename {benchmark-integration => benchmarks}/src/test/java/de/cuioss/sheriff/api/wrk/benchmark/GatewayEndpointBenchmarkTest.java (100%) rename {benchmark-integration => benchmarks}/src/test/java/de/cuioss/sheriff/api/wrk/benchmark/WrkResultPostProcessorTest.java (100%) rename {benchmark-integration => benchmarks}/src/test/resources/wrk-api-health-results.txt (100%) rename {benchmark-integration => benchmarks}/src/test/resources/wrk-health-results.txt (100%) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 586e9293..8de0af7b 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -74,7 +74,7 @@ jobs: - name: Prepare Historical Data for Benchmarks run: | - python3 benchmark-integration/scripts/benchmark-pages.py prepare-history \ + python3 benchmarks/scripts/benchmark-pages.py prepare-history \ --previous-pages-dir previous-pages/api-sheriff/benchmarks \ --output-dir "${GITHUB_WORKSPACE}/benchmark-history" @@ -82,17 +82,17 @@ jobs: run: | # Run WRK-based integration benchmarks with native image echo "Running WRK integration benchmarks with native Quarkus..." - ./mvnw --no-transfer-progress clean verify -pl benchmark-integration -Pbenchmark \ + ./mvnw --no-transfer-progress clean verify -pl benchmarks -Pbenchmark \ -Dbenchmark.history.dir="${GITHUB_WORKSPACE}/benchmark-history/integration" # Verify artifacts were generated echo "Integration benchmark artifacts generated:" - ls -la benchmark-integration/target/benchmark-results/ + ls -la benchmarks/target/benchmark-results/ - name: Assemble benchmark artifacts for deployment run: | - python3 benchmark-integration/scripts/benchmark-pages.py assemble \ - --integration-results benchmark-integration/target/benchmark-results/gh-pages-ready \ + python3 benchmarks/scripts/benchmark-pages.py assemble \ + --integration-results benchmarks/target/benchmark-results/gh-pages-ready \ --previous-pages-dir previous-pages/api-sheriff/benchmarks \ --output-dir gh-pages \ --commit-sha "${{ github.sha }}" diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index 216fe3ee..229bcc46 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -49,4 +49,4 @@ jobs: additional_permissions: | actions: read - allowed_tools: "Bash(./mvnw*),Bash(./mvnw -Ppre-commit clean verify -DskipTests),Bash(./mvnw clean verify),Bash(./mvnw clean install),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl api-sheriff),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl integration-tests),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl benchmark-integration),Bash(./mvnw clean install -pl api-sheriff),Bash(./mvnw clean install -pl integration-tests),Bash(./mvnw clean install -pl benchmark-integration),Bash(git*),Bash(find*),Bash(gh*),Bash(java*)" + allowed_tools: "Bash(./mvnw*),Bash(./mvnw -Ppre-commit clean verify -DskipTests),Bash(./mvnw clean verify),Bash(./mvnw clean install),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl api-sheriff),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl integration-tests),Bash(./mvnw -Ppre-commit clean verify -DskipTests -pl benchmarks),Bash(./mvnw clean install -pl api-sheriff),Bash(./mvnw clean install -pl integration-tests),Bash(./mvnw clean install -pl benchmarks),Bash(git*),Bash(find*),Bash(gh*),Bash(java*)" diff --git a/CLAUDE.md b/CLAUDE.md index f8717209..5139be9b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -11,7 +11,7 @@ API Sheriff is a security-focused API Gateway with a lightweight approach, curre Multi-module Maven project: - `api-sheriff/` โ€” Deployable Quarkus application (core library, CDI producers, REST endpoints, native executable) - `integration-tests/` โ€” Integration test coordinator (Docker infrastructure, IT suites, scripts) -- `benchmark-integration/` โ€” WRK HTTP load testing benchmarks +- `benchmarks/` โ€” WRK HTTP load testing benchmarks ## Build Commands @@ -32,7 +32,7 @@ Multi-module Maven project: ./mvnw clean verify -Pintegration-tests -pl integration-tests -am # Integration benchmarks (WRK) -./mvnw clean verify -pl benchmark-integration -Pbenchmark +./mvnw clean verify -pl benchmarks -Pbenchmark # Build native executable ./mvnw clean install -Pnative -pl api-sheriff -am -DskipTests diff --git a/README.adoc b/README.adoc index 24c5e0ab..50926856 100644 --- a/README.adoc +++ b/README.adoc @@ -34,7 +34,7 @@ image:https://img.shields.io/endpoint?url=https://cuioss.github.io/api-sheriff/b image:https://img.shields.io/endpoint?url=https://cuioss.github.io/api-sheriff/benchmarks/badges/integration-performance-badge.json[Integration Performance,link=https://cuioss.github.io/api-sheriff/benchmarks/integration-index.html] image:https://img.shields.io/endpoint?url=https://cuioss.github.io/api-sheriff/benchmarks/badges/integration-trend-badge.json[Integration Trend,link=https://cuioss.github.io/api-sheriff/benchmarks/integration-performance-trends.html] -xref:benchmark-integration/doc/performance-scoring.adoc[Understand Performance Metrics] +xref:benchmarks/doc/performance-scoring.adoc[Understand Performance Metrics] https://cuioss.github.io/api-sheriff/about.html[Generated Documentation on github-pages] @@ -69,7 +69,7 @@ Integration test coordinator โ€” Docker infrastructure, native container builds, Integration benchmarks using WRK HTTP load testing with containerized environments. -xref:benchmark-integration/doc/performance-scoring.adoc[Understand Performance Metrics] +xref:benchmarks/doc/performance-scoring.adoc[Understand Performance Metrics] == Deployment diff --git a/benchmark-integration/Dockerfile.wrk b/benchmarks/Dockerfile.wrk similarity index 51% rename from benchmark-integration/Dockerfile.wrk rename to benchmarks/Dockerfile.wrk index e75cdecc..317e37a6 100644 --- a/benchmark-integration/Dockerfile.wrk +++ b/benchmarks/Dockerfile.wrk @@ -1,5 +1,5 @@ FROM alpine:3.22 RUN apk add --no-cache wrk -COPY benchmark-integration/src/main/resources/wrk-scripts/*.lua /scripts/ +COPY benchmarks/src/main/resources/wrk-scripts/*.lua /scripts/ ENTRYPOINT ["wrk"] CMD ["--help"] diff --git a/benchmark-integration/README.adoc b/benchmarks/README.adoc similarity index 79% rename from benchmark-integration/README.adoc rename to benchmarks/README.adoc index 11fa1a09..70efcd9e 100644 --- a/benchmark-integration/README.adoc +++ b/benchmarks/README.adoc @@ -6,14 +6,14 @@ WRK-based HTTP benchmarks for API Sheriff endpoints with integration test infras [source,bash] ---- -./mvnw clean verify -pl benchmark-integration -Pbenchmark +./mvnw clean verify -pl benchmarks -Pbenchmark ---- For quick runs (shorter duration, assumes containers already running): [source,bash] ---- -./mvnw clean verify -pl benchmark-integration -Pbenchmark -Pquick +./mvnw clean verify -pl benchmarks -Pbenchmark -Pquick ---- == Performance Scoring diff --git a/benchmark-integration/doc/performance-scoring.adoc b/benchmarks/doc/performance-scoring.adoc similarity index 100% rename from benchmark-integration/doc/performance-scoring.adoc rename to benchmarks/doc/performance-scoring.adoc diff --git a/benchmark-integration/pom.xml b/benchmarks/pom.xml similarity index 99% rename from benchmark-integration/pom.xml rename to benchmarks/pom.xml index 6090519b..0731d721 100644 --- a/benchmark-integration/pom.xml +++ b/benchmarks/pom.xml @@ -9,7 +9,7 @@ <relativePath>../pom.xml</relativePath> </parent> - <artifactId>benchmark-integration</artifactId> + <artifactId>benchmarks</artifactId> <name>API Sheriff Integration Benchmarks</name> <description>WRK-based HTTP benchmarks for API Sheriff endpoints with integration test infrastructure</description> diff --git a/benchmark-integration/scripts/benchmark-pages.py b/benchmarks/scripts/benchmark-pages.py similarity index 97% rename from benchmark-integration/scripts/benchmark-pages.py rename to benchmarks/scripts/benchmark-pages.py index cef22a3e..69122763 100644 --- a/benchmark-integration/scripts/benchmark-pages.py +++ b/benchmarks/scripts/benchmark-pages.py @@ -9,13 +9,13 @@ Usage in CI: # Before Maven benchmark runs: - python3 benchmark-integration/scripts/benchmark-pages.py prepare-history \ + python3 benchmarks/scripts/benchmark-pages.py prepare-history \ --previous-pages-dir previous-pages/api-sheriff/benchmarks \ --output-dir "$GITHUB_WORKSPACE/benchmark-history" # After all Maven benchmark runs: - python3 benchmark-integration/scripts/benchmark-pages.py assemble \ - --integration-results benchmark-integration/target/benchmark-results/gh-pages-ready \ + python3 benchmarks/scripts/benchmark-pages.py assemble \ + --integration-results benchmarks/target/benchmark-results/gh-pages-ready \ --previous-pages-dir previous-pages/api-sheriff/benchmarks \ --output-dir gh-pages \ --commit-sha "$COMMIT_SHA" diff --git a/benchmark-integration/src/main/java/de/cuioss/sheriff/api/wrk/benchmark/WrkResultPostProcessor.java b/benchmarks/src/main/java/de/cuioss/sheriff/api/wrk/benchmark/WrkResultPostProcessor.java similarity index 100% rename from benchmark-integration/src/main/java/de/cuioss/sheriff/api/wrk/benchmark/WrkResultPostProcessor.java rename to benchmarks/src/main/java/de/cuioss/sheriff/api/wrk/benchmark/WrkResultPostProcessor.java diff --git a/benchmark-integration/src/main/resources/wrk-scripts/api_health_benchmark.sh b/benchmarks/src/main/resources/wrk-scripts/api_health_benchmark.sh similarity index 100% rename from benchmark-integration/src/main/resources/wrk-scripts/api_health_benchmark.sh rename to benchmarks/src/main/resources/wrk-scripts/api_health_benchmark.sh diff --git a/benchmark-integration/src/main/resources/wrk-scripts/api_health_check.lua b/benchmarks/src/main/resources/wrk-scripts/api_health_check.lua similarity index 100% rename from benchmark-integration/src/main/resources/wrk-scripts/api_health_check.lua rename to benchmarks/src/main/resources/wrk-scripts/api_health_check.lua diff --git a/benchmark-integration/src/main/resources/wrk-scripts/health_live_benchmark.sh b/benchmarks/src/main/resources/wrk-scripts/health_live_benchmark.sh similarity index 100% rename from benchmark-integration/src/main/resources/wrk-scripts/health_live_benchmark.sh rename to benchmarks/src/main/resources/wrk-scripts/health_live_benchmark.sh diff --git a/benchmark-integration/src/main/resources/wrk-scripts/health_live_check.lua b/benchmarks/src/main/resources/wrk-scripts/health_live_check.lua similarity index 100% rename from benchmark-integration/src/main/resources/wrk-scripts/health_live_check.lua rename to benchmarks/src/main/resources/wrk-scripts/health_live_check.lua diff --git a/benchmark-integration/src/main/resources/wrk-scripts/pre-benchmark-health-check.sh b/benchmarks/src/main/resources/wrk-scripts/pre-benchmark-health-check.sh similarity index 100% rename from benchmark-integration/src/main/resources/wrk-scripts/pre-benchmark-health-check.sh rename to benchmarks/src/main/resources/wrk-scripts/pre-benchmark-health-check.sh diff --git a/benchmark-integration/src/test/java/de/cuioss/sheriff/api/wrk/benchmark/GatewayEndpointBenchmarkTest.java b/benchmarks/src/test/java/de/cuioss/sheriff/api/wrk/benchmark/GatewayEndpointBenchmarkTest.java similarity index 100% rename from benchmark-integration/src/test/java/de/cuioss/sheriff/api/wrk/benchmark/GatewayEndpointBenchmarkTest.java rename to benchmarks/src/test/java/de/cuioss/sheriff/api/wrk/benchmark/GatewayEndpointBenchmarkTest.java diff --git a/benchmark-integration/src/test/java/de/cuioss/sheriff/api/wrk/benchmark/WrkResultPostProcessorTest.java b/benchmarks/src/test/java/de/cuioss/sheriff/api/wrk/benchmark/WrkResultPostProcessorTest.java similarity index 100% rename from benchmark-integration/src/test/java/de/cuioss/sheriff/api/wrk/benchmark/WrkResultPostProcessorTest.java rename to benchmarks/src/test/java/de/cuioss/sheriff/api/wrk/benchmark/WrkResultPostProcessorTest.java diff --git a/benchmark-integration/src/test/resources/wrk-api-health-results.txt b/benchmarks/src/test/resources/wrk-api-health-results.txt similarity index 100% rename from benchmark-integration/src/test/resources/wrk-api-health-results.txt rename to benchmarks/src/test/resources/wrk-api-health-results.txt diff --git a/benchmark-integration/src/test/resources/wrk-health-results.txt b/benchmarks/src/test/resources/wrk-health-results.txt similarity index 100% rename from benchmark-integration/src/test/resources/wrk-health-results.txt rename to benchmarks/src/test/resources/wrk-health-results.txt diff --git a/integration-tests/docker-compose.yml b/integration-tests/docker-compose.yml index b6c0bf35..2a8be1cc 100644 --- a/integration-tests/docker-compose.yml +++ b/integration-tests/docker-compose.yml @@ -112,7 +112,7 @@ services: wrk: build: context: .. - dockerfile: benchmark-integration/Dockerfile.wrk + dockerfile: benchmarks/Dockerfile.wrk networks: - api-sheriff profiles: diff --git a/integration-tests/scripts/benchmark-with-monitoring.sh b/integration-tests/scripts/benchmark-with-monitoring.sh index 5eb22be9..b4fe2a78 100755 --- a/integration-tests/scripts/benchmark-with-monitoring.sh +++ b/integration-tests/scripts/benchmark-with-monitoring.sh @@ -375,7 +375,7 @@ echo "" # Start benchmark with JFR recording START_TIME=$(date +%s) -$MAVEN_CMD verify -pl benchmark-integration -Pbenchmark > "$BENCHMARK_LOG" 2>&1 & +$MAVEN_CMD verify -pl benchmarks -Pbenchmark > "$BENCHMARK_LOG" 2>&1 & BENCHMARK_PID=$! # Wait for containers to start diff --git a/pom.xml b/pom.xml index 5165abdb..39126fb9 100644 --- a/pom.xml +++ b/pom.xml @@ -23,7 +23,7 @@ <modules> <module>api-sheriff</module> <module>integration-tests</module> - <module>benchmark-integration</module> + <module>benchmarks</module> </modules> <scm> <url>https://github.com/cuioss/api-sheriff/</url> From 8236639561d96e2148ff5b11ac8d1733208a2848 Mon Sep 17 00:00:00 2001 From: Oliver Wolff <23139298+cuioss@users.noreply.github.com> Date: Thu, 5 Mar 2026 12:13:11 +0100 Subject: [PATCH 24/24] chore: Update Keycloak from 26.2.5 to 26.5.4 with SHA pinning Pin image to digest for supply-chain security: quay.io/keycloak/keycloak:26.5.4@sha256:ae8efb0d218d8921334b03a2dbee7069a0b868240691c50a3ffc9f42fabba8b4 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --- integration-tests/docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/docker-compose.yml b/integration-tests/docker-compose.yml index 2a8be1cc..26f3bc26 100644 --- a/integration-tests/docker-compose.yml +++ b/integration-tests/docker-compose.yml @@ -5,7 +5,7 @@ services: keycloak: # NOTE: Dependabot cannot automatically update this image version. # Manual updates required. Check: https://quay.io/keycloak/keycloak - image: quay.io/keycloak/keycloak:26.2.5 + image: quay.io/keycloak/keycloak:26.5.4@sha256:ae8efb0d218d8921334b03a2dbee7069a0b868240691c50a3ffc9f42fabba8b4 command: - start-dev - --import-realm