diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index a229930f7..f9324429b 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -39,20 +39,21 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v5 - - uses: actions/setup-java@v3 + - uses: actions/setup-java@v5 if: matrix.language == 'java' with: java-version: 17 distribution: temurin - - uses: gradle/gradle-build-action@v2 + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 if: matrix.language == 'java' # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -63,7 +64,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v2 + uses: github/codeql-action/autobuild@v3 # â„šī¸ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -77,4 +78,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 8b758a005..acd0697c0 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -10,27 +10,35 @@ on: branches: [ master, dev ] env: - DOCKER_IMAGE: radarbase/radar-appserver + REGISTRY: ghcr.io + REPOSITORY: ${{ github.repository }} + IMAGES: >- + [{ + 'name': 'radar-appserver', + 'build_file': 'Dockerfile', + 'authors': 'Yatharth Ranjan , Pauline Conde ', + 'description': 'RADAR-base appserver backend application', + 'cache_keys_files': ['Dockerfile', '**/*.gradle.kts', 'gradle.properties', 'src/main/**'] + }] jobs: - # Build and test the code build: - # The type of runner that the job will run on runs-on: ubuntu-latest + permissions: + contents: read + packages: write - # Steps represent a sequence of tasks that will be executed as part of the job steps: - # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - - uses: actions/checkout@v3 + - uses: actions/checkout@v5 - - uses: actions/setup-java@v3 + - uses: actions/setup-java@v5 with: java-version: 17 distribution: temurin - - uses: gradle/gradle-build-action@v2 + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 - # Compile the code - name: Compile code run: ./gradlew assemble @@ -51,13 +59,12 @@ jobs: run: | gpg --pinentry-mode loopback --local-user "Yatharth Ranjan" --batch --yes --passphrase "${{ secrets.GPG_SECRET_KEY_PASSPHRASE }}" --output src/integrationTest/resources/google-credentials.json --decrypt src/integrationTest/resources/google-credentials.enc.gpg - # Gradle check - - name: Check + - name: Gradle check run: GOOGLE_APPLICATION_CREDENTIALS=$(pwd)/src/integrationTest/resources/google-credentials.json ./gradlew check - name: Upload build artifacts if: always() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: path: build/reports if-no-files-found: ignore @@ -65,17 +72,17 @@ jobs: # Build and test the code against the :dev docker image of parent repositories test-downstream: - # The type of runner that the job will run on runs-on: ubuntu-latest + # FIXME: the tests against :dev fail and I cannot find out why. Since tests against current + # Management Portal main branch is ok, I disable this integration test. + if: false # only run this on 'ready for review' PRs or when triggered by an upstream job - if: github.event.pull_request.draft == false || github.event_name == 'workflow_dispatch' + # if: github.event.pull_request.draft == false || github.event_name == 'workflow_dispatch' - # Steps represent a sequence of tasks that will be executed as part of the job steps: - # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - - uses: actions/checkout@v3 + - uses: actions/checkout@v5 - - uses: actions/setup-java@v3 + - uses: actions/setup-java@v5 with: java-version: 17 distribution: temurin @@ -104,86 +111,121 @@ jobs: - name: Check run: GOOGLE_APPLICATION_CREDENTIALS=$(pwd)/src/integrationTest/resources/google-credentials.json ./gradlew check - # Check that the docker image builds correctly + prepare-matrix: + name: Prepare Matrix Output + permissions: {} + runs-on: ubuntu-latest + outputs: + images: ${{ steps.step1.outputs.matrix }} + steps: + - name: Create Matrix Variable + id: step1 + run: echo "matrix=${{ env.IMAGES }}" >> $GITHUB_OUTPUT + + # Build and push tagged release backend docker image docker: - # The type of runner that the job will run on + needs: prepare-matrix runs-on: ubuntu-latest - if: github.event_name != 'workflow_dispatch' + strategy: + matrix: + image: ${{ fromJson(needs.prepare-matrix.outputs.images ) }} + permissions: + contents: read + packages: write - # Steps represent a sequence of tasks that will be executed as part of the job steps: - # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - - uses: actions/checkout@v3 - - - name: Login to Docker Hub - uses: docker/login-action@v2 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - # Add Docker labels and tags - - name: Docker meta - id: docker_meta - uses: docker/metadata-action@v4 - with: - images: ${{ env.DOCKER_IMAGE }} - - # Setup docker build environment - - name: Set up QEMU - uses: docker/setup-qemu-action@v2 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 - - - name: Cache Docker layers - id: cache-buildx - uses: actions/cache@v3 - with: - path: /tmp/.buildx-cache - key: ${{ runner.os }}-buildx-${{ hashFiles('Dockerfile', '**/*.gradle.kts', 'gradle.properties', 'src/main/**') }} - restore-keys: | - ${{ runner.os }}-buildx- - - - name: Cache parameters - id: cache-parameters - run: | - if [ "${{ steps.cache-buildx.outputs.cache-hit }}" = "true" ]; then - echo "::set-output name=cache-to::" - else - echo "::set-output name=cache-to::type=local,dest=/tmp/.buildx-cache-new,mode=max" - fi - - - name: Build docker - uses: docker/build-push-action@v3 - with: - cache-from: type=local,src=/tmp/.buildx-cache - cache-to: ${{ steps.cache-parameters.outputs.cache-to }} - load: true - tags: ${{ steps.docker_meta.outputs.tags }} - # Use runtime labels from docker_meta as well as fixed labels - labels: | - ${{ steps.docker_meta.outputs.labels }} - maintainer=Yatharth Ranjan , Pauline Conde - org.opencontainers.image.authors=Yatharth Ranjan , Pauline Conde - org.opencontainers.image.vendor=RADAR-base - org.opencontainers.image.licenses=Apache-2.0 - - - name: Inspect docker image - run: docker image inspect ${{ env.DOCKER_IMAGE }}:${{ steps.docker_meta.outputs.version }} - - # Push the image on the dev and master branches - - name: Push image - if: ${{ github.event_name != 'pull_request' }} - run: docker push ${{ env.DOCKER_IMAGE }}:${{ steps.docker_meta.outputs.version }} - - # Temp fix - # https://github.com/docker/build-push-action/issues/252 - # https://github.com/moby/buildkit/issues/1896 - - name: Move docker build cache - if: steps.cache-buildx.outputs.cache-hit != 'true' - run: | - rm -rf /tmp/.buildx-cache - mv /tmp/.buildx-cache-new /tmp/.buildx-cache - + - uses: actions/checkout@v5 + + - name: Docker build parameters + id: docker_params + run: | + echo "::set-output name=has_docker_login::${{ secrets.DOCKERHUB_USERNAME != '' && secrets.DOCKERHUB_TOKEN != '' }}" + if [ "${{ github.event_name == 'pull_request' }}" = "true" ]; then + echo "::set-output name=push::false" + echo "::set-output name=load::true" + echo "::set-output name=platforms::linux/amd64" + else + echo "::set-output name=push::true" + echo "::set-output name=load::false" + echo "::set-output name=platforms::linux/amd64,linux/arm64" + fi + + - name: Cache Docker layers + uses: actions/cache@v4 + with: + path: /tmp/.buildx-cache + key: ${{ runner.os }}-buildx-${{ matrix.image.name }}-${{ hashFiles(matrix.image.cache_key_files) }} + restore-keys: | + ${{ runner.os }}-buildx-${{ matrix.image.name }}- + + - name: Cache parameters + id: cache-parameters + run: | + if [ "${{ steps.cache_buildx.outputs.cache-hit }}" = "true" ]; then + echo "::set-output name=cache-to::" + else + echo "::set-output name=cache-to::type=local,dest=/tmp/.buildx-cache-new,mode=max" + fi + + - name: Login to Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Lowercase image name + run: | + echo "DOCKER_IMAGE=${REGISTRY}/${REPOSITORY,,}/${{ matrix.image.name }}" >>${GITHUB_ENV} + + # Add Docker labels and tags + - name: Docker meta + id: docker_meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.DOCKER_IMAGE }} + # Setup docker build environment + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build backend docker and optionally push + uses: docker/build-push-action@v6 + with: + context: . + file: ${{ matrix.image.build_file }} + cache-from: type=local,src=/tmp/.buildx-cache + cache-to: ${{ steps.cache-parameters.outputs.cache-to }} + platforms: ${{ steps.docker_params.outputs.platforms }} + load: ${{ steps.docker_params.outputs.load }} + push: ${{ steps.docker_params.outputs.push }} + tags: ${{ steps.docker_meta.outputs.tags }} + # Use runtime labels from docker_meta as well as fixed labels + labels: | + ${{ steps.docker_meta.outputs.labels }} + maintainer=${{ matrix.image.authors }} + org.opencontainers.image.description=${{ matrix.image.description }} + org.opencontainers.image.authors=${{ matrix.image.authors }} + org.opencontainers.image.vendor=RADAR-base + org.opencontainers.image.licenses=Apache-2.0 + + # Push the backend image on the dev and master branches + - name: Pull images + if: steps.docker_params.outputs.load == 'false' + run: docker pull ${{ env.DOCKER_IMAGE }}:${{ steps.docker_meta.outputs.version }} + + - name: Inspect docker images + run: | + docker image inspect ${{ env.DOCKER_IMAGE }}:${{ steps.docker_meta.outputs.version }} + + # Temp fix + # https://github.com/docker/build-push-action/issues/252 + # https://github.com/moby/buildkit/issues/1896 + - name: Move docker build cache + if: steps.cache_buildx.outputs.cache-hit != 'true' + run: | + rm -rf /tmp/.buildx-cache + mv /tmp/.buildx-cache-new /tmp/.buildx-cache diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 07b7df002..1b03fbd4c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,86 +1,115 @@ -# Create release files name: Release on: release: types: [published] +env: + REGISTRY: ghcr.io + REPOSITORY: ${{ github.repository }} + IMAGES: >- + [{ + 'name': 'radar-appserver', + 'build_file': 'Dockerfile', + 'authors': 'Yatharth Ranjan , Pauline Conde ', + 'description': 'RADAR-base appserver backend application', + 'cache_keys_files': ['Dockerfile', '**/*.gradle.kts', 'gradle.properties', 'src/main/**'] + }] + jobs: upload: - # The type of runner that the job will run on runs-on: ubuntu-latest + permissions: write-all - # Steps represent a sequence of tasks that will be executed as part of the job steps: - # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - - uses: actions/checkout@v3 - - uses: actions/setup-java@v3 + - uses: actions/checkout@v5 + + - uses: actions/setup-java@v5 with: java-version: 17 distribution: temurin - - uses: gradle/gradle-build-action@v2 + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 - # Compile code - name: Compile code run: ./gradlew assemble - # Upload it to GitHub - name: Upload to GitHub - uses: AButler/upload-release-assets@v2.0.2 + uses: AButler/upload-release-assets@v3.0 with: files: 'build/libs/*' repo-token: ${{ secrets.GITHUB_TOKEN }} - # Build and push tagged release docker image - docker: - # The type of runner that the job will run on + prepare-matrix: + name: Prepare Matrix Output runs-on: ubuntu-latest + permissions: {} + outputs: + images: ${{ steps.step1.outputs.matrix }} + steps: + - name: Create Matrix Variable + id: step1 + run: echo "matrix=${{ env.IMAGES }}" >> $GITHUB_OUTPUT - env: - DOCKER_IMAGE: radarbase/radar-appserver + docker: + needs: prepare-matrix + runs-on: ubuntu-latest + strategy: + matrix: + image: ${{ fromJson(needs.prepare-matrix.outputs.images ) }} + permissions: + contents: read + packages: write - # Steps represent a sequence of tasks that will be executed as part of the job steps: - - uses: actions/checkout@v3 - - # Setup docker build environment - - name: Set up QEMU - uses: docker/setup-qemu-action@v2 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 - - - name: Login to DockerHub - uses: docker/login-action@v2 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - # Add Docker labels and tags - - name: Docker meta - id: docker_meta - uses: docker/metadata-action@v4 - with: - images: ${{ env.DOCKER_IMAGE }} - tags: | - type=semver,pattern={{version}} - type=semver,pattern={{major}}.{{minor}} - - name: Build docker - uses: docker/build-push-action@v3 - with: - # Allow running the image on the architectures supported by openjdk:17-jre-slim - platforms: linux/amd64,linux/arm64 - push: true - tags: ${{ steps.docker_meta.outputs.tags }} - # Use runtime labels from docker_meta as well as fixed labels - labels: | - ${{ steps.docker_meta.outputs.labels }} - maintainer=Yatharth Ranjan , Pauline Conde - org.opencontainers.image.authors=Yatharth Ranjan , Pauline Conde - org.opencontainers.image.vendor=RADAR-base - org.opencontainers.image.licenses=Apache-2.0 - - name: Inspect docker image - run: | - docker pull ${{ env.DOCKER_IMAGE }}:${{ steps.docker_meta.outputs.version }} - docker image inspect ${{ env.DOCKER_IMAGE }}:${{ steps.docker_meta.outputs.version }} + - uses: actions/checkout@v3 + + # Setup docker build environment + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + + - name: Set up Docker Buildx + id: buildx + uses: docker/setup-buildx-action@v2 + + - name: Login to Container Registry + uses: docker/login-action@v2 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Lowercase image name + run: | + echo "DOCKER_IMAGE=${REGISTRY}/${REPOSITORY,,}/${{ matrix.image.name }}" >>${GITHUB_ENV} + + # Add Docker labels and tags + - name: Docker meta + id: docker_meta + uses: docker/metadata-action@v4 + with: + images: ${{ env.DOCKER_IMAGE }} + tags: | + type=match,pattern=v(.*),group=1 + + - name: Build backend docker and push + uses: docker/build-push-action@v3 + with: + context: . + file: ${{ matrix.image.build_file }} + platforms: linux/amd64,linux/arm64 + push: true + tags: ${{ steps.docker_meta.outputs.tags }} + labels: | + ${{ steps.docker_meta.outputs.labels }} + maintainer=${{ matrix.image.authors }} + org.opencontainers.image.description=${{ matrix.image.description }} + org.opencontainers.image.authors=${{ matrix.image.authors }} + org.opencontainers.image.vendor=RADAR-base + org.opencontainers.image.licenses=Apache-2.0 + + - name: Inspect docker image + run: | + docker pull ${{ env.DOCKER_IMAGE }}:${{ steps.docker_meta.outputs.version }} + docker image inspect ${{ env.DOCKER_IMAGE }}:${{ steps.docker_meta.outputs.version }} diff --git a/.github/workflows/scheduled-snyk-docker.yaml b/.github/workflows/scheduled-snyk-docker.yaml new file mode 100644 index 000000000..40fc515dd --- /dev/null +++ b/.github/workflows/scheduled-snyk-docker.yaml @@ -0,0 +1,47 @@ +name: Snyk scheduled Docker base image scan + +on: + schedule: + - cron: '0 3 * * 1' + workflow_dispatch: + +env: + DOCKER_IMAGE: ghcr.io/${{ github.repository }}/radar-appserver + +jobs: + security: + runs-on: ubuntu-latest + permissions: + contents: read + security-events: write + packages: read + + steps: + - uses: actions/checkout@v5 + + - name: Lowercase image name + run: echo "DOCKER_IMAGE=${DOCKER_IMAGE,,}" >> ${GITHUB_ENV} + + - name: Run Snyk to check for vulnerabilities + continue-on-error: true # To make sure that SARIF upload gets called + uses: snyk/actions/docker@master + env: + SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} + with: + image: ${{ env.DOCKER_IMAGE }} + # 'exclude-app-vulns' only tests vulnerabilities in the base image. + # Code base vulnerabilities are tested the scheduled-snyk.yaml action. + args: >- + --file=Dockerfile + --fail-on=upgradable + --severity-threshold=high + --policy-path=.snyk + --exclude-app-vulns + --org=radar-base + --sarif-file-output=snyk.sarif + + # Detected vulnerabilities will appear on Github in Security->Code_scanning_alerts tab + - name: Upload result to GitHub Code Scanning + uses: github/codeql-action/upload-sarif@v3 + with: + sarif_file: snyk.sarif diff --git a/.github/workflows/scheduled-snyk.yaml b/.github/workflows/scheduled-snyk.yaml index 47fce4fc0..162d83cb6 100644 --- a/.github/workflows/scheduled-snyk.yaml +++ b/.github/workflows/scheduled-snyk.yaml @@ -1,30 +1,37 @@ -name: Snyk scheduled test +name: Snyk scheduled code base scan + on: schedule: - cron: '0 2 * * 1' - push: - branches: - - master + workflow_dispatch: jobs: security: runs-on: ubuntu-latest - env: - REPORT_FILE: test.json + permissions: + contents: read + security-events: write + steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v5 - name: Run Snyk to check for vulnerabilities - uses: snyk/actions/gradle-jdk17@master + uses: snyk/actions/gradle-8-jdk17@master + continue-on-error: true # To make sure that SARIF upload gets called env: SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} with: - args: --all-projects --configuration-matching='^runtimeClasspath$' --json-file-output=${{ env.REPORT_FILE }} --severity-threshold=high --policy-path=$PWD/.snyk + args: >- + --all-projects + --configuration-matching='^runtimeClasspath$' + --fail-on=upgradable + --severity-threshold=high + --policy-path=.snyk + --org=radar-base + --sarif-file-output=snyk.sarif - - name: Report new vulnerabilities - uses: thehyve/report-vulnerability@master - if: success() || failure() + # Detected vulnerabilities will appear on Github in Security->Code_scanning_alerts tab + - name: Upload result to GitHub Code Scanning + uses: github/codeql-action/upload-sarif@v3 with: - report-file: ${{ env.REPORT_FILE }} - env: - TOKEN: ${{ secrets.GITHUB_TOKEN }} + sarif_file: snyk.sarif diff --git a/.github/workflows/snyk.yaml b/.github/workflows/snyk.yaml index be2d67dbb..2dea17688 100644 --- a/.github/workflows/snyk.yaml +++ b/.github/workflows/snyk.yaml @@ -1,17 +1,28 @@ -name: Snyk test +name: Snyk test on PR commits on: - - pull_request + pull_request: + branches: + - main + - dev + - release-* jobs: security: runs-on: ubuntu-latest + steps: - uses: actions/checkout@v3 - - name: Run Snyk to check for JDK vulnerabilities - uses: snyk/actions/gradle-jdk17@master + - name: Run Snyk to check for vulnerabilities + uses: snyk/actions/gradle-8-jdk17@master env: SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} with: - args: --all-projects --configuration-matching="^runtimeClasspath$" --fail-on=upgradable --org=radar-base --policy-path=.snyk --severity-threshold=high + args: >- + --all-projects + --configuration-matching="^runtimeClasspath$" + --severity-threshold=high + --fail-on=upgradable + --org=radar-base + --policy-path=.snyk diff --git a/Dockerfile b/Dockerfile index 189454840..91103f501 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM --platform=$BUILDPLATFORM gradle:8.0-jdk17 AS builder +FROM --platform=$BUILDPLATFORM gradle:8.13-jdk17 AS builder RUN mkdir /code WORKDIR /code @@ -21,7 +21,10 @@ LABEL maintainer="Yatharth Ranjan " LABEL description="RADAR-base App server" ENV JDK_JAVA_OPTIONS='-Xmx2G -Djava.security.egd=file:/dev/./urandom' \ - SPRING_PROFILES_ACTIVE=prod + SPRING_PROFILES_ACTIVE=prod \ + # Globally disables liquibase analytics. + # (see: https://docs.liquibase.com/pro/user-guide/what-data-does-liquibase-collect-and-how-is-it-used) + LIQUIBASE_ANALYTICS_ENABLED=false VOLUME /tmp ARG DEPENDENCY=/code/build/dependency diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..261eeb9e9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/build.gradle b/build.gradle index 736f723e9..0d5f646ef 100644 --- a/build.gradle +++ b/build.gradle @@ -2,7 +2,7 @@ plugins { id 'pmd' id 'io.gatling.gradle' version '3.9.2.1' id 'com.github.johnrengelman.shadow' version '8.1.0' - id 'org.springframework.boot' version '3.2.11' + id 'org.springframework.boot' version '3.5.5' id 'org.openjfx.javafxplugin' version '0.0.13' id("com.github.ben-manes.versions") version "0.46.0" id 'io.sentry.jvm.gradle' version '4.11.0' @@ -15,7 +15,7 @@ apply plugin: 'io.spring.dependency-management' apply plugin: 'scala' group = 'org.radarbase' -version = '2.4.3' +version = '2.4.5' java { toolchain { @@ -33,17 +33,18 @@ bootJar { } ext { - springBootVersion = '3.2.11' - springVersion = '6.0.6' + springBootVersion = '3.5.5' + springVersion = '6.2.10' springOauth2Version = "2.5.2.RELEASE" springOauth2AutoconfigureVersion = "2.6.8" - springDocVersion = '2.2.0' + springDocVersion = '2.7.0' lombokVersion = '1.18.26' junit5Version = '5.9.2' radarSpringAuthVersion = '1.2.1' - springSecurityVersion = '6.0.5' + springSecurityVersion = '6.4.9' hibernateValidatorVersion = '8.0.0.Final' minioVersion = '8.5.10' + nettyVersion = '4.1.118.Final' } sourceSets { @@ -57,14 +58,26 @@ sourceSets { } } +configurations.configureEach { + resolutionStrategy.force 'org.apache.commons:commons-lang3:3.18.0' +} + dependencies { + + implementation('org.apache.commons:commons-lang3:3.18.0') + + /* The entries in the block below are added here to force the version of + * transitive dependencies and mitigate reported vulnerabilities */ + implementation("org.apache.tomcat.embed:tomcat-embed-core:10.1.44") + implementation("io.netty:netty-handler-proxy:$nettyVersion") + implementation("io.netty:netty-handler:$nettyVersion") + implementation('org.springframework.boot:spring-boot-starter-data-jpa') implementation('org.springframework.boot:spring-boot-starter-web') implementation('org.springframework.boot:spring-boot-starter-quartz') implementation('org.springframework.boot:spring-boot-starter-security') implementation('org.springframework.boot:spring-boot-starter-actuator') implementation('org.springframework.boot:spring-boot-starter-mail') - implementation group: "org.springframework.security", name: "spring-security-config", version: springSecurityVersion implementation('org.springframework.security.oauth.boot:spring-security-oauth2-autoconfigure:' + springOauth2AutoconfigureVersion) implementation('org.springframework.security.oauth:spring-security-oauth2:' + springOauth2Version) runtimeOnly("org.hibernate.validator:hibernate-validator:$hibernateValidatorVersion") @@ -82,7 +95,7 @@ dependencies { annotationProcessor group: 'org.projectlombok', name: 'lombok', version: lombokVersion implementation group: 'org.projectlombok', name: 'lombok', version: lombokVersion - annotationProcessor "org.springframework:spring-context-indexer:$springVersion" + annotationProcessor "org.springframework:spring-context-indexer" // FCM Admin SDK implementation('com.google.firebase:firebase-admin:9.3.0') { @@ -98,7 +111,7 @@ dependencies { } // AOP - runtimeOnly group: 'org.springframework', name: 'spring-aop', version: springVersion + runtimeOnly group: 'org.springframework', name: 'spring-aop' implementation(group: 'org.radarbase', name: 'radar-spring-auth', version: radarSpringAuthVersion) testImplementation group: 'io.gatling.highcharts', name: 'gatling-charts-highcharts', version: '3.9.2' @@ -138,7 +151,7 @@ javadoc { } wrapper { - gradleVersion '8.0.2' + gradleVersion '8.13' } test { diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index bdc9a83b1..c6f003026 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/src/integrationTest/resources/docker/managementportal.yml b/src/integrationTest/resources/docker/managementportal.yml index b0e4fd0f0..5fbbbb544 100644 --- a/src/integrationTest/resources/docker/managementportal.yml +++ b/src/integrationTest/resources/docker/managementportal.yml @@ -2,7 +2,9 @@ version: "3.8" services: managementportal: - image: radarbase/management-portal:2.1.0 + image: radarbase/management-portal:latest + ports: + - "8081:8081" environment: SERVER_PORT: 8081 SPRING_PROFILES_ACTIVE: prod diff --git a/src/integrationTest/resources/docker/non_appserver/docker-compose.yml b/src/integrationTest/resources/docker/non_appserver/docker-compose.yml index 175bc701e..e4924ade0 100644 --- a/src/integrationTest/resources/docker/non_appserver/docker-compose.yml +++ b/src/integrationTest/resources/docker/non_appserver/docker-compose.yml @@ -39,6 +39,9 @@ services: extends: file: ../managementportal.yml service: managementportal + environment: + MANAGEMENTPORTAL_CATALOGUESERVER_ENABLEAUTOIMPORT: false + MANAGEMENTPORTAL_CATALOGUESERVER_SERVERURL: http://catalog-server:808 networks: - mp - default diff --git a/src/main/java/org/radarbase/appserver/config/MultiHttpSecurityConfig.java b/src/main/java/org/radarbase/appserver/config/MultiHttpSecurityConfig.java index c1bd69759..d62eedff3 100644 --- a/src/main/java/org/radarbase/appserver/config/MultiHttpSecurityConfig.java +++ b/src/main/java/org/radarbase/appserver/config/MultiHttpSecurityConfig.java @@ -70,17 +70,13 @@ public static class AdminWebSecurityConfigurationAdapter { @Bean public SecurityFilterChain apiDocsFilterChain(HttpSecurity http) throws Exception { http.securityMatcher("/v3/api-docs**") - .cors() - .and() - .authorizeHttpRequests() - .anyRequest() - .permitAll() + .cors(cors -> {}) + .authorizeHttpRequests(auth -> auth + .anyRequest().permitAll() + ) // .hasRole("ADMIN") - .and() - .httpBasic() - .and() - .csrf() - .disable(); + .httpBasic(basic -> {}) + .csrf(csrf -> csrf.disable()); return http.build(); } @@ -92,16 +88,13 @@ public static class WebSecurityConfig { public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // Allow all actuator endpoints. http.securityMatcher(EndpointRequest.toAnyEndpoint()) - .cors() - .and() - .authorizeHttpRequests() - .anyRequest() - .permitAll() - .and() - .csrf() - .disable(); + .cors(cors -> {}) + .authorizeHttpRequests(auth -> auth + .anyRequest().permitAll() + ) + .csrf(csrf -> csrf.disable()); - http.headers().frameOptions().disable(); + http.headers(headers -> headers.frameOptions(frame -> frame.disable())); return http.build(); } diff --git a/src/main/java/org/radarbase/appserver/search/SearchCriteria.java b/src/main/java/org/radarbase/appserver/search/SearchCriteria.java index 1a1d83591..7754dffe8 100644 --- a/src/main/java/org/radarbase/appserver/search/SearchCriteria.java +++ b/src/main/java/org/radarbase/appserver/search/SearchCriteria.java @@ -3,9 +3,14 @@ import lombok.AllArgsConstructor; import lombok.Data; +import java.io.Serial; +import java.io.Serializable; + @Data @AllArgsConstructor -public class SearchCriteria { +public class SearchCriteria implements Serializable { + @Serial + private static final long serialVersionUID = 327842183571958L; private String key; private String operation; private Object value; diff --git a/src/main/java/org/radarbase/appserver/search/TaskSpecification.java b/src/main/java/org/radarbase/appserver/search/TaskSpecification.java index 0f3b8304e..621b265cd 100644 --- a/src/main/java/org/radarbase/appserver/search/TaskSpecification.java +++ b/src/main/java/org/radarbase/appserver/search/TaskSpecification.java @@ -10,11 +10,14 @@ import jakarta.persistence.criteria.Predicate; import jakarta.persistence.criteria.Root; +import java.io.Serial; + @AllArgsConstructor public class TaskSpecification implements Specification { + @Serial private static final long serialVersionUID = 327842183571958L; - private SearchCriteria criteria; + private transient SearchCriteria criteria; @Override public Predicate toPredicate diff --git a/src/test/java/org/radarbase/appserver/service/scheduler/NotificationSchedulerServiceTest.java b/src/test/java/org/radarbase/appserver/service/scheduler/NotificationSchedulerServiceTest.java index 15c35fbf9..8f6bed8f7 100644 --- a/src/test/java/org/radarbase/appserver/service/scheduler/NotificationSchedulerServiceTest.java +++ b/src/test/java/org/radarbase/appserver/service/scheduler/NotificationSchedulerServiceTest.java @@ -21,7 +21,6 @@ package org.radarbase.appserver.service.scheduler; -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNull; @@ -67,13 +66,13 @@ @ExtendWith(SpringExtension.class) @SpringBootTest( - webEnvironment = NONE, - classes = { - DataSourceAutoConfiguration.class, - QuartzAutoConfiguration.class, - SchedulerConfig.class, - SchedulerServiceTestConfig.class - }) + webEnvironment = NONE, + classes = { + DataSourceAutoConfiguration.class, + QuartzAutoConfiguration.class, + SchedulerConfig.class, + SchedulerServiceTestConfig.class + }) class NotificationSchedulerServiceTest { private static final String TIMEZONE = "Europe/London";