diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 805a546b..45ab8a59 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -18,8 +18,11 @@ Before we can merge this PR, please make sure that all the following items have checked off. If any of the checklist items are not applicable, please leave them but write a little note why. -- [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/provenance-io/p8e-cee-api/blob/main/CONTRIBUTING.md#pr-targeting)) -- [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. -- [ ] Wrote unit and integration -- [ ] Re-reviewed `Files changed` in the Github PR explorer -- [ ] Review `Unit Test Results` in the comment section below once CI passes +- [ ] Targeted PR against correct branch +- [ ] Tagged PR with **exactly one of** `patch`, `minor`, or `major`, adhering to [semantic versioning](https://semver.org/) +- [ ] Tagged PR with one or more of `feature`, `enhancement`, `fix`/`bugfix`, `chore`, `dependencies`, & `docs`, as applicable to the scope of the PR +- [ ] Acknowledge that by merging my changes to `main`, they are ready to be included in the next release, and otherwise would ask for a prerelease to be created against my branch +- [ ] Linked to GitHub issue with discussion and accepted design OR link to spec that describes this work +- [ ] Wrote unit and integration tests as applicable to the scope of the PR +- [ ] Re-reviewed `Files changed` in the GitHub PR explorer +- [ ] Reviewed `Test Results` in the comment section below once CI passes diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index aba52a63..a9bb1c69 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -25,15 +25,13 @@ jobs: if: inputs.linting || github.event.pull_request.draft == false steps: - name: Checkout Code - uses: actions/checkout@v3 - with: - fetch-depth: 0 + uses: actions/checkout@v4 - - name: Set up JDK 11 + - name: Set up JDK 17 uses: actions/setup-java@v3 with: - distribution: 'temurin' - java-version: '11' + distribution: 'zulu' + java-version: '17' - name: Linting run: ./gradlew clean ktlint detekt --parallel --refresh-dependencies @@ -43,13 +41,15 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - - name: Set up JDK 11 + - name: Set up JDK 17 uses: actions/setup-java@v3 with: - java-version: '11' - distribution: 'temurin' + java-version: '17' + distribution: 'zulu' + + # TODO: Figure out how to simplify integration test run below - name: Add Homebrew to PATH run: echo "/home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin" >> $GITHUB_PATH diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 42726136..9d4d19cf 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -28,11 +28,11 @@ jobs: - name: Checkout uses: actions/checkout@v3 - - name: Set up JDK 11 + - name: Set up JDK 17 uses: actions/setup-java@v3 with: - java-version: 11 - distribution: 'temurin' + java-version: 17 + distribution: 'zulu' - name: Add Homebrew to PATH run: echo "/home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin" >> $GITHUB_PATH @@ -50,37 +50,19 @@ jobs: - name: Set Image Details id: ci-release-create-outputs run: | - DOCKER_IMAGE=provenanceio/p8e-cee-api VERSION=$( echo ${{ github.event.release.tag_name }} | sed -e 's/^v//' ) if [ "$VERSION" == "" ] ; then VERSION=$( echo ${{ github.event.inputs.versionTag }} | sed -e 's/^v//' ) fi - TAGS="${DOCKER_IMAGE}:${VERSION}" - - if [ ${{ github.event.inputs.tagAsLatest }} == 'true' ] ; then - TAGS="${TAGS},${DOCKER_IMAGE}:latest" - fi - echo "version=${VERSION}" >> $GITHUB_OUTPUT - echo "tags=${TAGS}" >> $GITHUB_OUTPUT - echo "created=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT - - - 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 }} - name: Build and Push Docker Image - uses: docker/build-push-action@v3 - with: - file: service/docker/Dockerfile - context: . - push: true - tags: ${{ steps.ci-release-create-outputs.outputs.tags }} + env: + JIB_AUTH_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} + JIB_AUTH_PASSWORD: ${{ secrets.DOCKERHUB_TOKEN }} + DOCKER_IMAGE_NAME: provenanceio/p8e-cee-api:${{ steps.ci-release-create-outputs.outputs.version }} + TAG_DOCKER_IMAGE_AS_LATEST: ${{ github.event.inputs.tagAsLatest }} + run: ./gradlew :service:jib -Djib.console=plain -Pversion=${VERSION} - name: Install gpg secret key if: inputs.publishToMaven || github.event_name == 'release' diff --git a/.gitignore b/.gitignore index 1f42dc37..32504a2c 100644 --- a/.gitignore +++ b/.gitignore @@ -48,12 +48,12 @@ out/ /.datastore # Vault -service/docker/volumes/ -service/docker/vault/init.output -service/docker/vault/keys.output +service/local-docker/volumes/ +service/local-docker/vault/init.output +service/local-docker/vault/keys.output service/src/test/resources/volumes/ # Object store files -service/docker/object-store-1/ -service/docker/object-store-2/ +service/local-docker/object-store-1/ +service/local-docker/object-store-2/ diff --git a/.sdkmanrc b/.sdkmanrc index 2fe70516..1fc5c141 100644 --- a/.sdkmanrc +++ b/.sdkmanrc @@ -1 +1 @@ -java=11.0.20-tem +java=17.0.8-zulu diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index e69de29b..00000000 diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index c9f9cc24..727cc891 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -34,7 +34,7 @@ This Code of Conduct applies both within project spaces and in public spaces whe ## Enforcement -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at community@interchain.io. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at inbound@provenance.io. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index ac97b5b0..00000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,157 +0,0 @@ -# Preface - -The Provenance repository is built on the work of many open source projects including -the [Cosmos SDK]](https://github.com/cosmos/cosmos-sdk). The source code outside of the `/x/` -folder is largely based on a reference implementation of this SDK. The work inside the modules -folder represents the evolution of blockchain applications started at Figure Technologies in 2018. - -This project would not be possible without the dedication and support of the [Cosmos](https://cosmos.network) community. - -# Contributing - -- [Preface](#preface) -- [Contributing](#contributing) - - [Architecture Decision Records (ADR)](#architecture-decision-records-adr) - - [Pull Requests](#pull-requests) - - [Process for reviewing PRs](#process-for-reviewing-prs) - - [Updating Documentation](#updating-documentation) - - [Forking](#forking) - - [Dependencies](#dependencies) - - [Branching Model and Release](#branching-model-and-release) - - [PR Targeting](#pr-targeting) - - [Development Procedure](#development-procedure) - - [Pull Merge Procedure](#pull-merge-procedure) - - [Release Procedure](#release-procedure) - - [Point Release Procedure](#point-release-procedure) - -Thank you for considering making contributions to the Provenance! - -Contributing to this repo can mean many things such as participated in -discussion or proposing code changes. To ensure a smooth workflow for all -contributors, the general procedure for contributing has been established: - -1. Either [open](https://github.com/provenance-io/explorer-service/issues/new/choose) or - [find](https://github.com/provenance-io/explorer-service/issues) an issue you'd like to help with -2. Participate in thoughtful discussion on that issue -3. If you would like to contribute: - 1. If the issue is a proposal, ensure that the proposal has been accepted - 2. Ensure that nobody else has already begun working on this issue. If they have, - make sure to contact them to collaborate - 3. If nobody has been assigned for the issue and you would like to work on it, - make a comment on the issue to inform the community of your intentions - to begin work - 4. Follow standard Github best practices: fork the repo, branch from the - HEAD of `main`, make some commits, and submit a PR to `main` - 5. Be sure to submit the PR in `Draft` mode submit your PR early, even if - it's incomplete as this indicates to the community you're working on - something and allows them to provide comments early in the development process - 6. When the code is complete it can be marked `Ready for Review` - 7. Be sure to include a relevant change log entry in the `Unreleased` section - of `CHANGELOG.md` (see file for log format) - -Note that for very small or blatantly obvious problems (such as typos) it is -not required to an open issue to submit a PR, but be aware that for more complex -problems/features, if a PR is opened before an adequate design discussion has -taken place in a github issue, that PR runs a high likelihood of being rejected. - -Take a peek at our [coding repo](https://github.com/tendermint/coding) for -overall information on repository workflow and standards. Note, we use `make tools` for installing the linting tools. - -## Pull Requests - -To accommodate review process we suggest that PRs are categorically broken up. -Ideally each PR addresses only a single issue. Additionally, as much as possible -code refactoring and cleanup should be submitted as a separate PRs from bugfixes/feature-additions. - -### Process for reviewing PRs - -All PRs require two Reviews before merge (except docs changes, or variable name-changes which only require one). When reviewing PRs please use the following review explanations: - -- `LGTM` without an explicit approval means that the changes look good, but you haven't pulled down the code, run tests locally and thoroughly reviewed it. -- `Approval` through the GH UI means that you understand the code, documentation/spec is updated in the right places, you have pulled down and tested the code locally. In addition: - - You must also think through anything which ought to be included but is not - - You must think through whether any added code could be partially combined (DRYed) with existing code - - You must think through any potential security issues or incentive-compatibility flaws introduced by the changes - - Naming must be consistent with conventions and the rest of the codebase - - Code must live in a reasonable location, considering dependency structures (e.g. not importing testing modules in production code, or including example code modules in production code). - - if you approve of the PR, you are responsible for fixing any of the issues mentioned here and more -- If you sat down with the PR submitter and did a pairing review please note that in the `Approval`, or your PR comments. -- If you are only making "surface level" reviews, submit any notes as `Comments` without adding a review. - -## Branching Model and Release - -User-facing repos should adhere to the trunk based development branching model: https://trunkbaseddevelopment.com/. - -Libraries need not follow the model strictly, but would be wise to. - -### PR Targeting - -Ensure that you base and target your PR on the `main` branch. - -All feature additions should be targeted against `main`. Bug fixes for an outstanding release candidate -should be targeted against the release candidate branch. Release candidate branches themselves should be the -only pull requests targeted directly against main. - -### Development Procedure - -- the latest state of development is on `main` - -### Pull Merge Procedure - -- ensure pull branch is rebased on `main` -- merge pull request - -### Release Procedure - -If new commits are API breaking, a new major version will be released. Everything else can be considered the next -minor version to be released. - -- All new commits are merged into `main` -- The `CHANGELOG` will be updated as needed - -To create a new release: - -- Start on `main` -- Create the release version branch `release/vx.x.x` (aka `release`) -- On the `release` branch, prepare a new version section in the `CHANGELOG.md` - - At the top of latest changes add `## [vx.x.x](https://github.com/provenance-io/explorer-service/releases/tag/vx.x.x) - YYYY-MM-DD` - - Beneath that add `### Release Name: xxxxxx` and choose a unique name from [this list](https://en.wikipedia.org/wiki/List_of_explorers) - - All links must be link-ified: `python ./scripts/linkify.py CHANGELOG.md` - - Copy the latest release entries into a `RELEASE_CHANGELOG.md`, this is needed so the bot knows which entries to add to the release page on github. - - Commit changes to the `release` branch - - Push `release` branch up to github -- Tag the release (use `git tag -a vx.x.x -m "vx.x.x"`) -- Push the tag up (use `git push origin vx.x.x`) - - The release will happen automatically in github -- Create a PR from branch `release` to `main` to incorporate ONLY the `CHANGELOG.md` updates - - Do not push `RELEASE_CHANGELOG.md` to `main` -- Delete the `release` branch - -### Hotfix Procedure - -If a hotfix is needed against the current release, a hotfix branch will be created from the current version tag per the -follow procedure: - -- Start from tag `vx.x.x` -- Create a branch `hotfix/vx.x.(x+1)` (aka `hotfix`) -- The hotfix commit should be PR'd against both `main` and `hotfix` - - The `CHANGELOG` should be updated accordingly for both - -It is the PR's author's responsibility to fix merge conflicts, update changelog entries, and -ensure CI passes. If a PR originates from an external contributor, it may be a core team member's -responsibility to perform this process instead of the original author. -Lastly, it is core team's responsibility to ensure that the PR meets all the Hotfix criteria. - -When the hotfix is ready to be released: - -- Start on `hotfix/vx.x.(x+1)` (aka `hotfix`) -- On the `hotfix` branch, prepare a new version section in the `CHANGELOG.md` - - At the top of latest changes add `## [vx.x.x](https://github.com/provenance-io/explorer-service/releases/tag/vx.x.x) - YYYY-MM-DD` - - All links must be link-ified: `$ python ./scripts/linkify_changelog.py CHANGELOG.md` -- Copy the latest release entries into a `RELEASE_CHANGELOG.md` -- Tag the release (use `git tag -a vx.x.x -m "vx.x.x"`) -- Push the tag up (use `git push origin vx.x.x`) - - The release will happen automatically in github -- Create a PR into `main` containing ONLY `CHANGELOG.md` updates - -Do not push `RELEASE_CHANGELOG.md` to `main` -- Delete the `hotfix` branch diff --git a/build.gradle.kts b/build.gradle.kts index fa6a7b19..78a3daca 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,6 +1,5 @@ -@Suppress("DSL_SCOPE_VIOLATION") plugins { - kotlin("jvm") version "1.8.10" + kotlin("jvm") version "1.8.22" id("java") id("maven-publish") id("java-library") @@ -24,8 +23,8 @@ subprojects { allprojects { java { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 } tasks.withType { @@ -33,11 +32,10 @@ allprojects { freeCompilerArgs = listOf( "-Xjsr305=strict", "-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi", - "-Xskip-prerelease-check", // To support loan package contracts dependency using context receivers ) - jvmTarget = "11" - apiVersion = "1.6" - languageVersion = "1.6" + jvmTarget = "17" + apiVersion = "1.8" + languageVersion = "1.8" allWarningsAsErrors = true } } @@ -56,8 +54,8 @@ nexusPublishing { } java { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 } allprojects { diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 3604cdf8..1821bb40 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -11,6 +11,11 @@ plugins { `kotlin-dsl` } +java { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 +} + // For everything else repositories { mavenCentral() diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 847ba590..41c04dac 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,15 +1,15 @@ [versions] -kotlin = "1.8.10" +kotlin = "1.8.22" kotlin_coroutines = "1.6.4" assetClassification = "3.7.0" bouncyCastle = "1.70" detekt = "1.18.1" grpc = "1.51.3" hamkrest = "1.8.0.1" -jackson_databind = "2.12.6.1" -jackson_jsr310 = "2.12.+" -jackson_kotlinModule = "2.12.5" -jackson_protobuf = "0.9.9-jackson2.9-proto3" +jackson = "2.15.2" +jackson_protobuf = "0.9.14" +jakarta_servlet = "5.0.0" +jib = "3.4.0" kong_unirest = "3.13.6" kotest = "5.5.5" kotest_extensions_arrow = "1.2.+" @@ -29,11 +29,11 @@ provenance_client = "1.3.0" provenance_hdWallet = "0.1.15" provenance_kmsConnector = "0.3.6" provenance_proto = "1.13.1" -reactor = "3.4.9" +reactor = "3.5.10" redisson = "3.16.0" reflections = "0.9.10" -spring_boot = "2.5.6" -spring_dependencyManagement = "1.0.11.RELEASE" +spring_boot = "3.1.4" +spring_dependencyManagement = "1.1.3" spring_mockk = "3.0.1" springdoc = "1.5.13" springfox = "3.0.0" @@ -44,6 +44,7 @@ testContainers = "1.3.3" kotlin = { id = "kotlin", version.ref = "kotlin" } detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" } idea = { id = "idea" } +jib = { id = "com.google.cloud.tools.jib", version.ref = "jib" } nexus_publishing = { id = "io.github.gradle-nexus.publish-plugin", version.ref = "nexus_publishing" } protobuf = { id = "com.google.protobuf", version.ref = "protobuf_plugin" } spring_boot = { id = "org.springframework.boot", version.ref = "spring_boot" } @@ -87,10 +88,9 @@ assetClassification_client = { module = "tech.figure.classification.asset:ac-cli assetClassification_verifier = { module = "tech.figure.classification.asset:ac-verifier", version.ref = "assetClassification" } objectStore_gateway = { module = "tech.figure.objectstore.gateway:client", version.ref = "objectStore_gateway" } # Jackson -## TODO: Clean up Jackson versions -jackson_databind = { module = "com.fasterxml.jackson.core:jackson-databind", version.ref = "jackson_databind" } -jackson_datatype = { module = "com.fasterxml.jackson.datatype:jackson-datatype-jsr310", version.ref = "jackson_jsr310" } -jackson_kotlinModule = { module = "com.fasterxml.jackson.module:jackson-module-kotlin", version.ref = "jackson_kotlinModule" } +jackson_databind = { module = "com.fasterxml.jackson.core:jackson-databind", version.ref = "jackson" } +jackson_datatype = { module = "com.fasterxml.jackson.datatype:jackson-datatype-jsr310", version.ref = "jackson" } +jackson_kotlinModule = { module = "com.fasterxml.jackson.module:jackson-module-kotlin", version.ref = "jackson" } jackson_protobuf = { module = "com.hubspot.jackson:jackson-datatype-protobuf", version.ref = "jackson_protobuf" } # Google grpc_protobuf = { module = "io.grpc:grpc-protobuf", version.ref = "grpc" } @@ -100,6 +100,7 @@ protobuf_java_util = { module = "com.google.protobuf:protobuf-java-util", versio # Other bouncyCastle = { module = "org.bouncycastle:bcpkix-jdk15on", version.ref = "bouncyCastle" } bouncyCastle_provider = { module = "org.bouncycastle:bcprov-jdk15on", version.ref = "bouncyCastle" } +jakarta_servlet = { module = "jakarta.servlet:jakarta.servlet-api", version.ref = "jakarta_servlet" } kong_unirest = { module = "com.konghq:unirest-java", version.ref = "kong_unirest" } kotlin_logging = { module = "io.github.microutils:kotlin-logging-jvm", version.ref = "kotlin_logging" } ktlint = { module = "com.pinterest:ktlint", version.ref = "ktlint" } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 41d9927a..7f93135c 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index aa991fce..3fa8f862 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 1b6c7873..1aa94a42 100755 --- a/gradlew +++ b/gradlew @@ -55,7 +55,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -80,13 +80,11 @@ do esac done -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -APP_NAME="Gradle" +# This is normally unused +# shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -133,22 +131,29 @@ location of your Java installation." fi else JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -193,11 +198,15 @@ if "$cygwin" || "$msys" ; then done fi -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ @@ -205,6 +214,12 @@ set -- \ org.gradle.wrapper.GradleWrapperMain \ "$@" +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. diff --git a/gradlew.bat b/gradlew.bat index ac1b06f9..6689b85b 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -14,7 +14,7 @@ @rem limitations under the License. @rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +25,8 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute +if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/models/build.gradle.kts b/models/build.gradle.kts index 3cf8699d..95542a14 100644 --- a/models/build.gradle.kts +++ b/models/build.gradle.kts @@ -1,13 +1,12 @@ val ktlint: Configuration by configurations.creating -@Suppress("DSL_SCOPE_VIOLATION") plugins { alias(libs.plugins.detekt) `java-library` `maven-publish` } -java.sourceCompatibility = JavaVersion.VERSION_11 +java.sourceCompatibility = JavaVersion.VERSION_17 dependencies { ktlint(libs.ktlint) diff --git a/service/build.gradle.kts b/service/build.gradle.kts index 7d8e1fd9..93b78867 100644 --- a/service/build.gradle.kts +++ b/service/build.gradle.kts @@ -1,14 +1,14 @@ val ktlint: Configuration by configurations.creating -@Suppress("DSL_SCOPE_VIOLATION") plugins { alias(libs.plugins.detekt) + alias(libs.plugins.jib) alias(libs.plugins.spring.boot) alias(libs.plugins.spring.dependencyManagement) - kotlin("plugin.spring") version "1.8.10" + kotlin("plugin.spring") version "1.8.22" } -java.sourceCompatibility = JavaVersion.VERSION_11 +java.sourceCompatibility = JavaVersion.VERSION_17 dependencyManagement { applyMavenExclusions(false) @@ -30,40 +30,41 @@ dependencies { libs.kotlin.coroutines.reactor, libs.springBoot.starter, libs.springBoot.starter.actuator, - libs.springBoot.starter.jetty, libs.springBoot.starter.devTools, + libs.springBoot.starter.jetty, libs.springBoot.starter.security, libs.springBoot.starter.validation, - libs.reactor.core, // Needed to play nice with WebFlux Coroutines stuff + libs.assetClassification.client, + libs.assetClassification.verifier, + libs.bouncyCastle, + libs.bouncyCastle.provider, + libs.grpc.protobuf, + libs.grpc.stub, + libs.jackson.databind, + libs.jackson.datatype, + libs.jackson.kotlinModule, + libs.jackson.protobuf, + libs.jakarta.servlet, + libs.kong.unirest, libs.kotlin.logging, - libs.springfox.swagger, - libs.springfox.swagger.ui, - libs.swagger.annotations, + libs.objectStore.gateway, libs.p8eScope.encryption, libs.p8eScope.objectStore.client, libs.p8eScope.sdk, - libs.provenance.keyAccessLib, + libs.protobuf.java.util, + libs.provenance.client, libs.provenance.hdWallet, libs.provenance.hdWallet.bip39, - libs.provenance.client, - libs.provenance.protoKotlin, + libs.provenance.keyAccessLib, libs.provenance.loanPackage, - libs.jackson.databind, - libs.jackson.datatype, - libs.jackson.protobuf, - libs.jackson.kotlinModule, - libs.protobuf.java.util, - libs.kong.unirest, - libs.grpc.protobuf, - libs.grpc.stub, + libs.provenance.protoKotlin, + libs.reactor.core, // Needed to play nice with WebFlux Coroutines stuff libs.reflections, - libs.bouncyCastle, - libs.bouncyCastle.provider, - libs.springdoc.openApi.webFluxSupport, libs.springdoc.openApi.kotlinSupport, - libs.assetClassification.client, - libs.assetClassification.verifier, - libs.objectStore.gateway, + libs.springdoc.openApi.webFluxSupport, + libs.springfox.swagger, + libs.springfox.swagger.ui, + libs.swagger.annotations, ).forEach { dependency -> implementation(dependency) } @@ -82,15 +83,15 @@ dependencies { listOf( libs.hamkrest, - libs.mockk, - libs.kotlin.faker, - libs.kotlin.coroutines.test, - libs.spring.mockk, libs.kotest, libs.kotest.assertions, libs.kotest.assertions.arrow, libs.kotest.property, libs.kotest.spring, + libs.kotlin.coroutines.test, + libs.kotlin.faker, + libs.mockk, + libs.spring.mockk, libs.testContainers.core, ).forEach { testDependency -> testImplementation(testDependency) @@ -143,3 +144,62 @@ detekt { config = files("${rootDir.path}/detekt.yml") source = files("src/main/kotlin", "src/test/kotlin") } + +val latestTag: String? = "latest".takeIf { + System.getenv("TAG_DOCKER_IMAGE_AS_LATEST") == "true" || + System.getenv("GITHUB_REF_NAME") + ?.takeIf { it.isNotBlank() } + ?.let { githubRefName -> setOf("main").any { githubRefName.endsWith(it) } } + ?: false +} + +tasks.named("jib") { + dependsOn(tasks.named("bootJar")) +} + +tasks.named("jibDockerBuild") { + dependsOn(tasks.named("bootJar")) +} + +val jarFileName = "service.jar" +val mainClassName = "io.provenance.api.ApplicationKt" + +jib { + from { + auth { + username = System.getenv("JIB_AUTH_USERNAME") ?: "_json_key" + password = System.getenv("JIB_AUTH_PASSWORD") ?: "nopass" + } + image = "azul/zulu-openjdk:17.0.8.1" + } + to { + auth { + username = System.getenv("JIB_AUTH_USERNAME") ?: "_json_key" + password = System.getenv("JIB_AUTH_PASSWORD") ?: "nopass" + } + // The base tag should be specified with `image`, and additional tags with `tags, to control setting of `latest` + image = System.getenv("DOCKER_IMAGE_NAME") ?: "provenanceio/${rootProject.name}:${rootProject.version}" + tags = setOfNotNull(latestTag) + } + extraDirectories { + paths { + path { + setFrom(file("src/main/jib/")) + into = "/" + includes.set(listOf("service-configure")) + } + path { + setFrom(file("build/libs")) + into = "/" + includes.set(listOf(jarFileName)) + } + } + permissions = mapOf("/service-configure" to "755", jarFileName to "755") + } + container { + mainClass = mainClassName + ports = listOf("8080") + entrypoint = listOf("/bin/bash", "-c", "--", "/service-configure /$jarFileName") + creationTime = "USE_CURRENT_TIMESTAMP" + } +} diff --git a/service/docker/Dockerfile b/service/docker/Dockerfile deleted file mode 100644 index e716bb90..00000000 --- a/service/docker/Dockerfile +++ /dev/null @@ -1,31 +0,0 @@ -FROM gradle:7.3.3-jdk11 AS build -RUN gradle --version && java -version -WORKDIR /app - -# Only copy dependency-related files -COPY build.gradle.kts gradle.properties settings.gradle.kts buildSrc/build.gradle.kts /app/ - -# Only download dependencies -# Eat the expected build failure since no source code has been copied yet -RUN gradle clean build --no-daemon > /dev/null 2>&1 || true - -# Copy all files -COPY service /app/service/ -COPY models /app/models/ -COPY buildSrc /app/buildSrc/ -COPY .git /app/.git/ -COPY detekt.yml /app/ -COPY build.gradle.kts gradle.properties settings.gradle.kts /app/ -COPY CHANGELOG.md CODE_OF_CONDUCT.md CONTRIBUTING.md LICENSE README.md /app/ - -# Do the actual build -RUN gradle clean build --no-daemon - -FROM openjdk:11-jre - -ADD service/build/libs/*.jar /p8e-cee-api.jar -ADD service/docker/service-configure /configure - -EXPOSE 8080/tcp - -ENTRYPOINT /configure /p8e-cee-api.jar diff --git a/service/docker/bootstrap.env b/service/local-docker/bootstrap.env similarity index 100% rename from service/docker/bootstrap.env rename to service/local-docker/bootstrap.env diff --git a/service/docker/db-init/db-init.sql b/service/local-docker/db-init/db-init.sql similarity index 100% rename from service/docker/db-init/db-init.sql rename to service/local-docker/db-init/db-init.sql diff --git a/service/docker/dependencies.yaml b/service/local-docker/dependencies.yaml similarity index 100% rename from service/docker/dependencies.yaml rename to service/local-docker/dependencies.yaml diff --git a/service/docker/object-store-1.env b/service/local-docker/object-store-1.env similarity index 100% rename from service/docker/object-store-1.env rename to service/local-docker/object-store-1.env diff --git a/service/docker/object-store-2.env b/service/local-docker/object-store-2.env similarity index 100% rename from service/docker/object-store-2.env rename to service/local-docker/object-store-2.env diff --git a/service/docker/prov-init/config/addrbook.json b/service/local-docker/prov-init/config/addrbook.json similarity index 100% rename from service/docker/prov-init/config/addrbook.json rename to service/local-docker/prov-init/config/addrbook.json diff --git a/service/docker/prov-init/config/app.toml b/service/local-docker/prov-init/config/app.toml similarity index 100% rename from service/docker/prov-init/config/app.toml rename to service/local-docker/prov-init/config/app.toml diff --git a/service/docker/prov-init/config/config.toml b/service/local-docker/prov-init/config/config.toml similarity index 100% rename from service/docker/prov-init/config/config.toml rename to service/local-docker/prov-init/config/config.toml diff --git a/service/docker/prov-init/config/genesis.json b/service/local-docker/prov-init/config/genesis.json similarity index 100% rename from service/docker/prov-init/config/genesis.json rename to service/local-docker/prov-init/config/genesis.json diff --git a/service/docker/prov-init/config/gentx/gentx-e4c4c224b016aa26b423aeda4a74e79361ef5c56.json b/service/local-docker/prov-init/config/gentx/gentx-e4c4c224b016aa26b423aeda4a74e79361ef5c56.json similarity index 100% rename from service/docker/prov-init/config/gentx/gentx-e4c4c224b016aa26b423aeda4a74e79361ef5c56.json rename to service/local-docker/prov-init/config/gentx/gentx-e4c4c224b016aa26b423aeda4a74e79361ef5c56.json diff --git a/service/docker/prov-init/config/node_key.json b/service/local-docker/prov-init/config/node_key.json similarity index 100% rename from service/docker/prov-init/config/node_key.json rename to service/local-docker/prov-init/config/node_key.json diff --git a/service/docker/prov-init/config/priv_validator_key.json b/service/local-docker/prov-init/config/priv_validator_key.json similarity index 100% rename from service/docker/prov-init/config/priv_validator_key.json rename to service/local-docker/prov-init/config/priv_validator_key.json diff --git a/service/docker/prov-init/contracts/asset_definitions.json b/service/local-docker/prov-init/contracts/asset_definitions.json similarity index 100% rename from service/docker/prov-init/contracts/asset_definitions.json rename to service/local-docker/prov-init/contracts/asset_definitions.json diff --git a/service/docker/prov-init/data/priv_validator_state.json b/service/local-docker/prov-init/data/priv_validator_state.json similarity index 100% rename from service/docker/prov-init/data/priv_validator_state.json rename to service/local-docker/prov-init/data/priv_validator_state.json diff --git a/service/docker/prov-init/keyring-test/651a5e66d10381755083c5e4a7eec81da0d49086.address b/service/local-docker/prov-init/keyring-test/651a5e66d10381755083c5e4a7eec81da0d49086.address similarity index 100% rename from service/docker/prov-init/keyring-test/651a5e66d10381755083c5e4a7eec81da0d49086.address rename to service/local-docker/prov-init/keyring-test/651a5e66d10381755083c5e4a7eec81da0d49086.address diff --git a/service/docker/prov-init/keyring-test/validator.info b/service/local-docker/prov-init/keyring-test/validator.info similarity index 100% rename from service/docker/prov-init/keyring-test/validator.info rename to service/local-docker/prov-init/keyring-test/validator.info diff --git a/service/docker/vault/init-and-unseal.sh b/service/local-docker/vault/init-and-unseal.sh similarity index 100% rename from service/docker/vault/init-and-unseal.sh rename to service/local-docker/vault/init-and-unseal.sh diff --git a/service/docker/vault/secrets/local-controller-a.json b/service/local-docker/vault/secrets/local-controller-a.json similarity index 100% rename from service/docker/vault/secrets/local-controller-a.json rename to service/local-docker/vault/secrets/local-controller-a.json diff --git a/service/docker/vault/secrets/local-controller-b.json b/service/local-docker/vault/secrets/local-controller-b.json similarity index 100% rename from service/docker/vault/secrets/local-controller-b.json rename to service/local-docker/vault/secrets/local-controller-b.json diff --git a/service/docker/vault/secrets/local-dart.json b/service/local-docker/vault/secrets/local-dart.json similarity index 100% rename from service/docker/vault/secrets/local-dart.json rename to service/local-docker/vault/secrets/local-dart.json diff --git a/service/docker/vault/secrets/local-investor.json b/service/local-docker/vault/secrets/local-investor.json similarity index 100% rename from service/docker/vault/secrets/local-investor.json rename to service/local-docker/vault/secrets/local-investor.json diff --git a/service/docker/vault/secrets/local-originator.json b/service/local-docker/vault/secrets/local-originator.json similarity index 100% rename from service/docker/vault/secrets/local-originator.json rename to service/local-docker/vault/secrets/local-originator.json diff --git a/service/docker/vault/secrets/local-portfolio-manager.json b/service/local-docker/vault/secrets/local-portfolio-manager.json similarity index 100% rename from service/docker/vault/secrets/local-portfolio-manager.json rename to service/local-docker/vault/secrets/local-portfolio-manager.json diff --git a/service/docker/vault/secrets/local-servicer.json b/service/local-docker/vault/secrets/local-servicer.json similarity index 100% rename from service/docker/vault/secrets/local-servicer.json rename to service/local-docker/vault/secrets/local-servicer.json diff --git a/service/docker/vault/secrets/local-validator.json b/service/local-docker/vault/secrets/local-validator.json similarity index 100% rename from service/docker/vault/secrets/local-validator.json rename to service/local-docker/vault/secrets/local-validator.json diff --git a/service/docker/service-configure b/service/src/main/jib/service-configure similarity index 74% rename from service/docker/service-configure rename to service/src/main/jib/service-configure index dbd8aa75..cf1937b4 100755 --- a/service/docker/service-configure +++ b/service/src/main/jib/service-configure @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash set -e if [ -d "/vault/secrets" ]; then @@ -9,12 +9,13 @@ fi # Create the trust store and key store for java if [ "$KAFKA_SECURITY_PROTOCOL" != "" ]; then - echo -n ${KAFKA_TRUSTSTORE} | base64 -d > ${KAFKA_TRUSTSTORE_PATH} - echo -n ${KAFKA_KEYSTORE} | base64 -d > ${KAFKA_KEYSTORE_PATH} + echo -n "${KAFKA_TRUSTSTORE}" | base64 -d > "${KAFKA_TRUSTSTORE_PATH}" + echo -n "${KAFKA_KEYSTORE}" | base64 -d > "${KAFKA_KEYSTORE_PATH}" fi if [ "$JMX_ENABLED" = true ]; then JAVA_OPTS="$JAVA_OPTS -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/dumps/dump.bin -Dcom.sun.management.jmxremote.port=7199 -Dcom.sun.management.jmxremote.rmi.port=7199 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Djava.rmi.server.hostname=$POD_IP -Dcom.sun.management.jmxremote.local.only=false" fi -java $JAVA_OPTS -jar $1 +# shellcheck disable=SC2086 +exec java $JAVA_OPTS -jar $1 diff --git a/service/src/main/kotlin/io/provenance/api/frameworks/config/ProvenanceProperties.kt b/service/src/main/kotlin/io/provenance/api/frameworks/config/ProvenanceProperties.kt index f0113b36..ebe0932a 100644 --- a/service/src/main/kotlin/io/provenance/api/frameworks/config/ProvenanceProperties.kt +++ b/service/src/main/kotlin/io/provenance/api/frameworks/config/ProvenanceProperties.kt @@ -1,7 +1,7 @@ package io.provenance.api.frameworks.config import io.provenance.api.domain.usecase.common.originator.DefaultAudience -import javax.validation.constraints.NotNull +import jakarta.validation.constraints.NotNull import org.springframework.boot.context.properties.ConfigurationProperties import org.springframework.validation.annotation.Validated diff --git a/service/src/main/kotlin/io/provenance/api/frameworks/config/ServiceProps.kt b/service/src/main/kotlin/io/provenance/api/frameworks/config/ServiceProps.kt index 611b8c48..32a422e5 100644 --- a/service/src/main/kotlin/io/provenance/api/frameworks/config/ServiceProps.kt +++ b/service/src/main/kotlin/io/provenance/api/frameworks/config/ServiceProps.kt @@ -1,10 +1,8 @@ package io.provenance.api.frameworks.config import org.springframework.boot.context.properties.ConfigurationProperties -import org.springframework.boot.context.properties.ConstructorBinding import org.springframework.validation.annotation.Validated -@ConstructorBinding @ConfigurationProperties(prefix = "service") @Validated data class ServiceProps( diff --git a/service/src/main/kotlin/io/provenance/api/frameworks/config/VaultProperties.kt b/service/src/main/kotlin/io/provenance/api/frameworks/config/VaultProperties.kt index ba4d7445..bb2cc10f 100644 --- a/service/src/main/kotlin/io/provenance/api/frameworks/config/VaultProperties.kt +++ b/service/src/main/kotlin/io/provenance/api/frameworks/config/VaultProperties.kt @@ -1,7 +1,7 @@ package io.provenance.api.frameworks.config +import jakarta.validation.constraints.NotNull import org.springframework.boot.context.properties.ConfigurationProperties -import javax.validation.constraints.NotNull @ConfigurationProperties(prefix = "vault") class VaultProperties : LoggableProperties() { diff --git a/service/src/main/kotlin/io/provenance/api/frameworks/web/config/SecurityConfig.kt b/service/src/main/kotlin/io/provenance/api/frameworks/web/config/SecurityConfig.kt index 88aab600..a443737d 100644 --- a/service/src/main/kotlin/io/provenance/api/frameworks/web/config/SecurityConfig.kt +++ b/service/src/main/kotlin/io/provenance/api/frameworks/web/config/SecurityConfig.kt @@ -16,20 +16,37 @@ import org.springframework.security.web.server.SecurityWebFilterChain @EnableConfigurationProperties(value = [ServiceProps::class]) class SecurityConfig { @Bean - fun securityWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { - http.authorizeExchange { - it.pathMatchers("${Routes.MANAGE_BASE}/**", "${Routes.EXTERNAL_BASE}/**", "${Routes.INTERNAL_BASE}/**", "${Routes.DOCS_BASE}/**").permitAll() + fun securityWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain = http.apply { + authorizeExchange { spec -> + spec.pathMatchers( + "${Routes.MANAGE_BASE}/**", + "${Routes.EXTERNAL_BASE}/**", + "${Routes.INTERNAL_BASE}/**", + "${Routes.DOCS_BASE}/**" + ).permitAll() } - - return http.httpBasic().disable() - .formLogin().disable() - .logout().disable() - .csrf().disable() - .headers().frameOptions().disable() - .cache().disable() - .and() - .authorizeExchange() - .pathMatchers("/").permitAll() - .and().build() - } + httpBasic { spec -> + spec.disable() + } + formLogin { spec -> + spec.disable() + } + logout { spec -> + spec.disable() + } + csrf { spec -> + spec.disable() + } + headers { spec -> + spec.frameOptions { frameOptionsSpec -> + frameOptionsSpec.disable() + } + spec.cache { cacheSpec -> + cacheSpec.disable() + } + } + http.authorizeExchange { authorize -> + authorize.pathMatchers("/").permitAll() + } + }.build() } diff --git a/service/src/main/kotlin/io/provenance/api/util/MultiPartExtensions.kt b/service/src/main/kotlin/io/provenance/api/util/MultiPartExtensions.kt index 68a77d3f..2f640b45 100644 --- a/service/src/main/kotlin/io/provenance/api/util/MultiPartExtensions.kt +++ b/service/src/main/kotlin/io/provenance/api/util/MultiPartExtensions.kt @@ -3,6 +3,11 @@ package io.provenance.api.util import org.springframework.core.io.buffer.DataBufferUtils import org.springframework.http.codec.multipart.FilePart import reactor.core.publisher.Mono +import java.nio.ByteBuffer fun FilePart.awaitAllBytes(): Mono = - DataBufferUtils.join(this.content()).map { it.asByteBuffer().array() } + DataBufferUtils.join(this.content()).map { dataBuffer -> + ByteBuffer.allocate(dataBuffer.capacity()).also { byteBuffer -> + dataBuffer.toByteBuffer(byteBuffer) + }.array() + }