diff --git a/.github/workflows/sdk-ci.yaml b/.github/workflows/sdk-ci.yaml index 1ce8b56..86ab047 100644 --- a/.github/workflows/sdk-ci.yaml +++ b/.github/workflows/sdk-ci.yaml @@ -1,4 +1,4 @@ -name: Python/Kotlin CI +name: Python/Kotlin/Java CI on: pull_request: workflow_dispatch: @@ -53,6 +53,44 @@ jobs: - name: Run Kotlin tests run: ./gradlew test working-directory: kotlin + + java-test: + needs: generate-cdylibs + runs-on: ${{ matrix.runs-on }} + strategy: + matrix: + # This should stay in sync with the `os_matrix` above + runs-on: + [ + "buildjet-2vcpu-ubuntu-2004", + "buildjet-4vcpu-ubuntu-2204-arm", + "macos-12", + "macos-14", + ] + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-java@v4 + with: + distribution: "temurin" + java-version: "21" + - uses: actions/download-artifact@v4 + with: + name: ${{ join(matrix.runs-on) }}- + path: ${{ github.workspace }}/java/src/main/resources/ + - if: startsWith(matrix.runs-on, 'buildjet') + uses: Swatinem/rust-cache@v2 + with: + cache-provider: buildjet + - if: startsWith(matrix.runs-on, 'macos') + uses: Swatinem/rust-cache@v2 + with: + cache-provider: github + - name: Generate Java files + run: cargo run --bin uniffi-bindgen-java generate --library resources/libironcore_alloy.* --out-dir java + working-directory: java/src/main + - name: Run Java tests + run: ./gradlew test + working-directory: java python-test: needs: generate-cdylibs diff --git a/.github/workflows/sdk-release.yaml b/.github/workflows/sdk-release.yaml index 7be650a..bcb857e 100644 --- a/.github/workflows/sdk-release.yaml +++ b/.github/workflows/sdk-release.yaml @@ -1,4 +1,4 @@ -name: Python/Kotlin Release +name: Python/Kotlin/Java Release on: # https://docs.github.com/en/developers/webhooks-and-events/webhook-events-and-payloads#release # The Bump Version workflow will make a Github release if it isn't a prerelease version @@ -11,13 +11,13 @@ jobs: generate-cdylibs: uses: IronCoreLabs/workflows/.github/workflows/rust-artifact.yaml@rust-artifact-v0 with: - os_matrix: '["buildjet-2vcpu-ubuntu-2204", "buildjet-4vcpu-ubuntu-2204-arm", "macos-12", "macos-14"]' + os_matrix: '["buildjet-2vcpu-ubuntu-2004", "buildjet-4vcpu-ubuntu-2204-arm", "macos-12", "macos-14"]' build_profile: "release" secrets: inherit kotlin-release: needs: generate-cdylibs - runs-on: buildjet-2vcpu-ubuntu-2204 + runs-on: buildjet-2vcpu-ubuntu-2004 steps: - uses: actions/checkout@v4 - uses: actions/download-artifact@v4 @@ -25,7 +25,7 @@ jobs: path: ${{ github.workspace }}/kotlin/src/main/resources/ - name: Rename directories run: | - mv buildjet-2vcpu-ubuntu-2204- linux-x86-64 + mv buildjet-2vcpu-ubuntu-2004- linux-x86-64 mv buildjet-4vcpu-ubuntu-2204-arm- linux-arm mv macos-12- darwin-x86-64 mv macos-14- darwin-aarch64 @@ -54,9 +54,52 @@ jobs: ORG_GRADLE_PROJECT_sonatypeUsername: ${{ secrets.SONATYPE_USERNAME }} ORG_GRADLE_PROJECT_sonatypePassword: ${{ secrets.SONATYPE_PASSWORD }} + java-release: + needs: generate-cdylibs + runs-on: buildjet-2vcpu-ubuntu-2004 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-java@v4 + with: + distribution: "temurin" + java-version: "21" + - uses: actions/download-artifact@v4 + with: + path: ${{ github.workspace }}/java/src/main/resources/ + - name: Rename directories + run: | + mv buildjet-2vcpu-ubuntu-2004- linux-x86-64 + mv buildjet-4vcpu-ubuntu-2204-arm- linux-arm + mv macos-12- darwin-x86-64 + mv macos-14- darwin-aarch64 + working-directory: java/src/main/resources/ + - name: Decrypt GPG key and gradle.properties + uses: IronCoreLabs/ironhide-actions/decrypt@v3 + with: + keys: ${{ secrets.IRONHIDE_KEYS }} + input: .github/9FA43559.asc.iron .github/gradle.properties.iron + - name: Move gradle properties and GPG key + run: mv .github/gradle.properties java/gradle.properties + - name: Import GPG key + run: gpg --batch --import .github/9FA43559.asc + - name: Export GPG signing key + run: gpg --export-secret-keys > /tmp/9FA43559.asc + - uses: Swatinem/rust-cache@v2 + with: + cache-provider: buildjet + - name: Generate Java files + run: cargo run --bin uniffi-bindgen-java generate --library resources/linux-x86-64/libironcore_alloy.so --out-dir java + working-directory: java/src/main + - name: Publish + run: ./gradlew publish + working-directory: java + env: + ORG_GRADLE_PROJECT_sonatypeUsername: ${{ secrets.SONATYPE_USERNAME }} + ORG_GRADLE_PROJECT_sonatypePassword: ${{ secrets.SONATYPE_PASSWORD }} + python-release: needs: generate-cdylibs - runs-on: buildjet-2vcpu-ubuntu-2204 + runs-on: buildjet-2vcpu-ubuntu-2004 steps: - uses: actions/checkout@v4 - uses: actions/download-artifact@v4 @@ -64,7 +107,7 @@ jobs: path: ${{ github.workspace }}/python/ironcore-alloy - name: Rename directories run: | - mv buildjet-2vcpu-ubuntu-2204- linux-x86-64 + mv buildjet-2vcpu-ubuntu-2004- linux-x86-64 mv buildjet-4vcpu-ubuntu-2204-arm- linux-arm mv macos-12- darwin-x86-64 mv macos-14- darwin-aarch64 diff --git a/CHANGELOG.md b/CHANGELOG.md index 67f2807..e34c163 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## 0.11.0 (Unreleased) +## 0.11.1 Breaking changes: @@ -9,6 +9,7 @@ Breaking changes: Other changes: +- Added Java bindings, `ironcore-alloy-java` - Added batch functionality to all SDK traits. - Fixed a bug where Standard Attached wasn't accessible for SaaS Shield clients. - Added rekey functionality for standard_attached data. diff --git a/Cargo.lock b/Cargo.lock index db9c7fa..ee3dcdc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -85,9 +85,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstream" -version = "0.6.14" +version = "0.6.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" dependencies = [ "anstyle", "anstyle-parse", @@ -106,27 +106,27 @@ checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" [[package]] name = "anstyle-parse" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.3" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" dependencies = [ "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.3" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" dependencies = [ "anstyle", "windows-sys 0.52.0", @@ -202,9 +202,9 @@ checksum = "0c24e9d990669fbd16806bff449e4ac644fd9b1fca014760087732fe4102f131" [[package]] name = "async-compat" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f68a707c1feb095d8c07f8a65b9f506b117d30af431cab89374357de7c11461b" +checksum = "7bab94bde396a3f7b4962e396fdad640e241ed797d4d8d77fc8c237d14c58fc0" dependencies = [ "futures-core", "futures-io", @@ -491,9 +491,9 @@ dependencies = [ [[package]] name = "colorchoice" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" [[package]] name = "convert_case" @@ -1015,6 +1015,7 @@ dependencies = [ "base85", "bytes", "camino", + "cargo_metadata", "convert_case", "criterion", "futures", @@ -1040,6 +1041,7 @@ dependencies = [ "thiserror", "tokio", "uniffi", + "uniffi-bindgen-java", "uniffi_bindgen", "z85", ] @@ -1074,9 +1076,9 @@ dependencies = [ [[package]] name = "is_terminal_polyfill" -version = "1.70.0" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itertools" @@ -1917,6 +1919,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" dependencies = [ "smawk", + "unicode-linebreak", + "unicode-width", ] [[package]] @@ -2098,6 +2102,12 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "unicode-linebreak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" + [[package]] name = "unicode-normalization" version = "0.1.23" @@ -2113,23 +2123,54 @@ version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +[[package]] +name = "unicode-width" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" + [[package]] name = "uniffi" -version = "0.28.0" -source = "git+https://github.com/mozilla/uniffi-rs#56f4ed8a66e12d2eb76d94718584d64f4dd21e06" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2db87def739fe4183947f8419d572d1849a4a09355eba4e988a2105cfd0ac6a7" dependencies = [ "anyhow", "camino", + "cargo_metadata", "clap", "uniffi_bindgen", "uniffi_core", "uniffi_macros", ] +[[package]] +name = "uniffi-bindgen-java" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "397a3d5592deef36e0c0a1559694eb866d7486899298376fb555aa3a3c84c2e5" +dependencies = [ + "anyhow", + "askama", + "camino", + "cargo_metadata", + "clap", + "heck", + "once_cell", + "paste", + "regex", + "serde", + "textwrap", + "toml", + "uniffi_bindgen", + "uniffi_meta", +] + [[package]] name = "uniffi_bindgen" -version = "0.28.0" -source = "git+https://github.com/mozilla/uniffi-rs#56f4ed8a66e12d2eb76d94718584d64f4dd21e06" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a112599c9556d1581e4a3d72019a74c2c3e122cc27f4af12577a429c4d5e614" dependencies = [ "anyhow", "askama", @@ -2145,14 +2186,14 @@ dependencies = [ "textwrap", "toml", "uniffi_meta", - "uniffi_testing", "uniffi_udl", ] [[package]] name = "uniffi_checksum_derive" -version = "0.28.0" -source = "git+https://github.com/mozilla/uniffi-rs#56f4ed8a66e12d2eb76d94718584d64f4dd21e06" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a22dbe67c1c957ac6e7611bdf605a6218aa86b0eebeb8be58b70ae85ad7d73dc" dependencies = [ "quote", "syn", @@ -2160,8 +2201,9 @@ dependencies = [ [[package]] name = "uniffi_core" -version = "0.28.0" -source = "git+https://github.com/mozilla/uniffi-rs#56f4ed8a66e12d2eb76d94718584d64f4dd21e06" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a0c35aaad30e3a9e6d4fe34e358d64dbc92ee09045b48591b05fc9f12e0905b" dependencies = [ "anyhow", "async-compat", @@ -2175,8 +2217,9 @@ dependencies = [ [[package]] name = "uniffi_macros" -version = "0.28.0" -source = "git+https://github.com/mozilla/uniffi-rs#56f4ed8a66e12d2eb76d94718584d64f4dd21e06" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db66474c5c61b0f7afc3b4995fecf9b72b340daa5ca0ef3da7778d75eb5482ea" dependencies = [ "bincode", "camino", @@ -2192,8 +2235,9 @@ dependencies = [ [[package]] name = "uniffi_meta" -version = "0.28.0" -source = "git+https://github.com/mozilla/uniffi-rs#56f4ed8a66e12d2eb76d94718584d64f4dd21e06" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d898893f102e0e39b8bcb7e3d2188f4156ba280db32db9e8af1f122d057e9526" dependencies = [ "anyhow", "bytes", @@ -2203,8 +2247,9 @@ dependencies = [ [[package]] name = "uniffi_testing" -version = "0.28.0" -source = "git+https://github.com/mozilla/uniffi-rs#56f4ed8a66e12d2eb76d94718584d64f4dd21e06" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c6aa4f0cf9d12172d84fc00a35a6c1f3522b526daad05ae739f709f6941b9b6" dependencies = [ "anyhow", "camino", @@ -2215,8 +2260,9 @@ dependencies = [ [[package]] name = "uniffi_udl" -version = "0.28.0" -source = "git+https://github.com/mozilla/uniffi-rs#56f4ed8a66e12d2eb76d94718584d64f4dd21e06" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b044e9c519e0bb51e516ab6f6d8f4f4dcf900ce30d5ad07c03f924e2824f28e" dependencies = [ "anyhow", "textwrap", @@ -2254,9 +2300,9 @@ dependencies = [ [[package]] name = "utf8parse" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "version_check" @@ -2386,7 +2432,8 @@ dependencies = [ [[package]] name = "weedle2" version = "5.0.0" -source = "git+https://github.com/mozilla/uniffi-rs#56f4ed8a66e12d2eb76d94718584d64f4dd21e06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "998d2c24ec099a87daf9467808859f9d82b61f1d9c9701251aea037f514eae0e" dependencies = [ "nom", ] diff --git a/Cargo.toml b/Cargo.toml index ff606b5..885d2bd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,10 +42,11 @@ ring = "0.17" serde = { version = "1.0.204", features = ["derive"] } serde_json = { version = "1.0.117", features = ["float_roundtrip"] } thiserror = "1.0.63" -uniffi = { git = "https://github.com/mozilla/uniffi-rs", features = [ - "tokio", - "cli", +uniffi = { version = "0.28.1", features = [ + "tokio", + "cli", ] } +uniffi-bindgen-java = "0.1.0" z85 = "3.0.5" [dev-dependencies] @@ -55,13 +56,14 @@ assertables = "7.0.1" base64 = "0.22.0" base85 = "2.0.0" camino = "1.1" +cargo_metadata = "0.15" criterion = { version = "0.5", features = ["async_tokio"] } hex = "0.4.3" hex-literal = "0.4.1" lazy_static = "1.4" proptest = "1.5.0" tokio = { version = "1.39", features = ["macros", "rt-multi-thread"] } -uniffi_bindgen = { git = "https://github.com/mozilla/uniffi-rs" } +uniffi_bindgen = "0.28.1" z85 = "3.0.5" [features] @@ -83,6 +85,10 @@ name = "ironcore_alloy" name = "uniffi-bindgen" path = "uniffi-bindgen.rs" +[[bin]] +name = "uniffi-bindgen-java" +path = "uniffi-bindgen-java.rs" + # used to create the smallest cdylib binary we can to ship with the library in each ecosystem. # 6.9M vs 1.5M in initial testing. Can further have `strip` (the Unix utility) run on it to save ~0.2 MB more. # WARNING: be careful changing this, since downstream integration tests (in "core/tests") depend on this profile. diff --git a/README.md b/README.md index 41aa385..4db6349 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ to protect the private or sensitive data your apps process. ## Language Support -- [Java](https://central.sonatype.com/artifact/com.ironcorelabs/ironcore-alloy) +- [Java](https://central.sonatype.com/artifact/com.ironcorelabs/ironcore-alloy-java) - [Kotlin](https://central.sonatype.com/artifact/com.ironcorelabs/ironcore-alloy) - [Python](https://pypi.org/project/ironcore-alloy) - Rust - Depend on this repo using a git dependency. @@ -56,7 +56,7 @@ cargo test --features integration_tests ## Benchmarks -We provide benchmarks of ironcore-alloy in both [Rust](./benches/README.md) and [Kotlin](./kotlin/benchmarks/src/README.md). These benchmark folders each contain a Docker Compose file that will start up a TSP with a predefined configuration for testing purposes. +We provide benchmarks of ironcore-alloy in [Rust](./benches/README.md), [Kotlin](./kotlin/benchmarks/src/README.md), [Java](https://github.com/IronCoreLabs/ironcore-alloy/tree/main/java/src/jmh/java/com/ironcorelabs/ironcore_alloy_java), and [Python](https://github.com/IronCoreLabs/ironcore-alloy/blob/main/python/ironcore-alloy/bench.py). These benchmark folders each contain a Docker Compose file that will start up a TSP with a predefined configuration for testing purposes. ## License diff --git a/RELEASING.md b/RELEASING.md index b9e654d..2218e5d 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -1,6 +1,6 @@ # Release Checklist -- Update to the new version number using the [Bump Version](https://github.com/IronCoreLabs/ironcore-alloy/actions/workflows/bump-version.yaml) workflow. This will be used as the Rust/Python/Kotlin version number. -- The [Python/Kotlin Release](https://github.com/IronCoreLabs/ironcore-alloy/actions/workflows/sdk-release.yaml) action will automatically publish the Python/Kotlin SDKs. +- Update to the new version number using the [Bump Version](https://github.com/IronCoreLabs/ironcore-alloy/actions/workflows/bump-version.yaml) workflow. This will be used as the Rust/Python/Kotlin/Java version number. +- The [Python/Kotlin/Java Release](https://github.com/IronCoreLabs/ironcore-alloy/actions/workflows/sdk-release.yaml) action will automatically publish the Python/Kotlin/Java SDKs. - When the JVM artifacts have been deployed, go to https://oss.sonatype.org, log in using the `icl-devops` username and - password from `sonatype-info.txt`, and find the new release in the _Staging Repositories_. Close that repository and then release it in order to actually push the package out to the public repo. \ No newline at end of file + password from `sonatype-info.txt`, and find the new release in the _Staging Repositories_. Close that repository and then release it in order to actually push the package out to the public repo. diff --git a/benches/README.md b/benches/README.md index ebb3b43..ee5b6bd 100644 --- a/benches/README.md +++ b/benches/README.md @@ -86,7 +86,7 @@ The TSP's tenant logging mechanism has some tunable limits. By default, a TSP sh ## Other Languages -There are also benchmarks available in [Kotlin](https://github.com/IronCoreLabs/ironcore-alloy/tree/main/kotlin/benchmarks/src) and [Python](https://github.com/IronCoreLabs/ironcore-alloy/blob/main/python/ironcore-alloy/bench.py). +There are also benchmarks available in [Kotlin](https://github.com/IronCoreLabs/ironcore-alloy/tree/main/kotlin/benchmarks/src), [Java](https://github.com/IronCoreLabs/ironcore-alloy/tree/main/java/src/jmh/java/com/ironcorelabs/ironcore_alloy_java), and [Python](https://github.com/IronCoreLabs/ironcore-alloy/blob/main/python/ironcore-alloy/bench.py). ## Results diff --git a/flake.nix b/flake.nix index a86e8da..3c51bc2 100644 --- a/flake.nix +++ b/flake.nix @@ -22,22 +22,28 @@ [ rusttoolchain pkg-config - pkgs.openssl + openssl # used when generating kotlin bindings in core - pkgs.ktlint + ktlint # used when running kotlin tests - pkgs.kotlin + kotlin # used when generating python bindings in core - pkgs.yapf - pkgs.curl + yapf + curl # used when running python tests - pkgs.python310 + python310 # used when building python distributions - pkgs.hatch + hatch + # used when building java distributions + openjdk21 + (callPackage gradle-packages.gradle_8 { + java = openjdk21; + }) (pkgs.google-cloud-sdk.withExtraComponents [ pkgs.google-cloud-sdk.components.gke-gcloud-auth-plugin ]) ] ++ pkgs.lib.optionals pkgs.stdenv.isDarwin [ pkgs.darwin.apple_sdk.frameworks.SystemConfiguration ]; LD_LIBRARY_PATH = "${pkgs.stdenv.cc.cc.lib}/lib"; + JAVA_HOME = if pkgs.stdenv.isDarwin then "${pkgs.openjdk21}" else "${pkgs.openjdk21}/lib/openjdk"; }; }); diff --git a/java/.gitignore b/java/.gitignore new file mode 100644 index 0000000..2e56f35 --- /dev/null +++ b/java/.gitignore @@ -0,0 +1,11 @@ +# Ignore Gradle project-specific cache directory +.gradle +# Ignore Gradle build output directory +build +src/main/java/com/ironcorelabs/ironcore_alloy_java/*.java +src/main/resources/libironcore_alloy.* +gradle.properties +.settings +.project +.gitattributes +.classpath diff --git a/java/README.md b/java/README.md new file mode 100644 index 0000000..9058f5d --- /dev/null +++ b/java/README.md @@ -0,0 +1,23 @@ +# Java build and publish info + +## Build + +Ensure the library and source have been created, typically done by running `cargo t` in `../`. + +## Testing + +`./gradlew test` + +## Benchmarking + +You can run the benchmarks `./gradlew bench`. + +More information about the benchmarks is in its [README](/java/src/jmh/java/com/ironcorelabs/ironcore_alloy_java/README.md). + +## Publishing + +You can test publishing `./gradlew publishToMavenLocal`. + +### Signing information + +The `.github/gradle.properties.iron` file contains all the signing information. It should be decrypted and put in the `java` directory. It mandates that the signing key be put in `/tmp/9FA43559.asc`, which is the decrypted gpg key. diff --git a/java/build.gradle.kts b/java/build.gradle.kts new file mode 100644 index 0000000..e160903 --- /dev/null +++ b/java/build.gradle.kts @@ -0,0 +1,90 @@ +import org.gradle.api.tasks.testing.logging.TestExceptionFormat +import org.gradle.api.tasks.testing.logging.TestLogEvent + +version = "0.11.1-SNAPSHOT" + +group = "com.ironcorelabs" + +plugins { + // Apply the java-library plugin for API and implementation separation. + `java-library` + `maven-publish` + signing + id("io.github.gradle-nexus.publish-plugin") version "2.0.0-rc-1" + id("com.dorongold.task-tree") version "2.1.1" + + // benchmark deps + id("me.champeau.jmh") version "0.7.2" +} + +dependencies { + // Use the JUnit 5 integration. + testImplementation("org.junit.jupiter:junit-jupiter:5.9.1") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") + implementation("net.java.dev.jna:jna:5.14.0") +} + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(21)) + } + withSourcesJar() + withJavadocJar() + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 +} + +nexusPublishing { repositories { sonatype() } } + +publishing { + publications { + create("mavenJava") { + from(components["java"]) + groupId = "com.ironcorelabs" + artifactId = "ironcore-alloy-java" + pom { + name.set("IronCore Labs Alloy SDK") + description.set("IronCore Alloy bindings for Java.") + url.set("https://ironcorelabs.com") + licenses { + license { + name.set("GNU Affero General Public License v3 or later (AGPLv3+)") + url.set("https://www.gnu.org/licenses/agpl-3.0.en.html#license-text") + } + } + developers { + developer { + id.set("IronCore Labs") + name.set("IronCore Labs") + email.set("code@ironcorelabs.com") + } + } + scm { + connection.set("scm:git@github.com:IronCoreLabs/ironcore-alloy.git") + url.set("https://github.com/IronCoreLabs") + } + } + } + } +} + +repositories { + // Use Maven Central for resolving dependencies. + mavenCentral() +} + +tasks.test { + // Use JUnit Platform for unit tests. + useJUnitPlatform() + testLogging { + exceptionFormat = TestExceptionFormat.FULL + events = mutableSetOf(TestLogEvent.FAILED, TestLogEvent.PASSED, TestLogEvent.SKIPPED) + showStandardStreams = true + } +} + +signing { + useGpgCmd() + sign(publishing.publications["mavenJava"]) +} + diff --git a/java/gradle/wrapper/gradle-wrapper.jar b/java/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..ccebba7 Binary files /dev/null and b/java/gradle/wrapper/gradle-wrapper.jar differ diff --git a/java/gradle/wrapper/gradle-wrapper.properties b/java/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..fc10b60 --- /dev/null +++ b/java/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.1-bin.zip +networkTimeout=10000 +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/java/gradlew b/java/gradlew new file mode 100755 index 0000000..2fe81a7 --- /dev/null +++ b/java/gradlew @@ -0,0 +1,183 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# 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 +# +# https://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. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$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"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +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. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/java/gradlew.bat b/java/gradlew.bat new file mode 100644 index 0000000..62bd9b9 --- /dev/null +++ b/java/gradlew.bat @@ -0,0 +1,103 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="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 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/java/settings.gradle.kts b/java/settings.gradle.kts new file mode 100644 index 0000000..9e7d546 --- /dev/null +++ b/java/settings.gradle.kts @@ -0,0 +1,10 @@ +/* + * This file was generated by the Gradle 'init' task. + * + * The settings file is used to specify which projects to include in your build. + * + * Detailed information about configuring a multi-project build in Gradle can be found + * in the user manual at https://docs.gradle.org/8.0.1/userguide/multi_project_builds.html + */ + +rootProject.name = "ironcore-alloy" diff --git a/java/src/jmh/java/com/ironcorelabs/ironcore_alloy_java/README.md b/java/src/jmh/java/com/ironcorelabs/ironcore_alloy_java/README.md new file mode 100644 index 0000000..52dcdc8 --- /dev/null +++ b/java/src/jmh/java/com/ironcorelabs/ironcore_alloy_java/README.md @@ -0,0 +1,102 @@ +# ironcore-alloy Java Benchmarks + +This directory contains a benchmark suite for the Java version of ironcore-alloy. +To build and run the benchmark, just execute the following commands from this directory: + +``` +docker compose up -d +cd /java +./gradlew jmh +``` + +## Tenant Security Proxy + +In order to run the benchmarks, ironcore-alloy needs to connect to a _Tenant Security Proxy (TSP)_. +This service is provided as a Docker container, so it is easy to run the proxy on any computer that has Docker +installed. IronCore Labs hosts the Docker container on a publicly accessible container registry, so you can pull +the image from there and run it locally. + +In addition to the Docker containers, you need a configuration file that specifies how the TSP should communicate +with the IronCore Labs Configuration Broker and Data Control Platform, which work together to enable the end-to-end +encryption that keeps all of the tenant KMS configuration information secure. To simplify the process of running +these examples, we have created a demo vendor and tenants that you can use for the examples; all the necessary +configuration information is included in the [demo-tsp.conf](demo-tsp.conf) file in this directory. + +**NOTE:** Normally, the file containing the configuration would be generated by the vendor and loaded into a +Kubernetes secret or similar mechanism for securely loading the configuration into the docker container. We +have included this configuration in the repository as a convenience. Also note that these accounts are all +created in IronCore's staging infrastructure. + +Production TSPs will often be accompanied by one or more +[Tenant Security Logdriver](https://ironcorelabs.com/docs/saas-shield/tenant-security-logdriver/overview/) instances. +Because the purpose of this benchmark is to demonstrate the capabilities of ironcore-alloy Java, we have chosen to not include +Logdriver in it. If you wish to modify the Docker Compose file to include Logdriver, be sure to consult its +[Deployment](https://ironcorelabs.com/docs/saas-shield/tenant-security-logdriver/deployment/) page to learn how to properly configure it +based on the resources you have available. + +The following `docker compose` command will get a TSP running on your computer with the provided configuration: + +``` +docker compose up +``` + +This starts the TSP locally listening on port 32804. The benchmark expects to connect to the TSP at that address. + +To connect with and use the TSP, you need to supply a couple more configuration values: +the first is the API key that the TSP uses to authenticate requests from ironcore-alloy, +and the second is the tenant ID to use. + +The API key value is specified in the `demo-tsp.conf` file. You can just set the environment variable to the +same value: + +`export API_KEY=0WUaXesNgbTAuLwn` + +The benchmark can be run using a different cloud KMS by selecting a different tenant configured for our demo SaaS vendor. +There are six tenants defined; their IDs are the following: + +- tenant-gcp +- tenant-aws +- tenant-azure +- tenant-gcp-l +- tenant-aws-l +- tenant-azure-l + +The last three are similar to the first three, but they have _key leasing_ enabled. + +By default, the benchmark will use the `tenant-gcp-l` tenant. If you would like to experiment with a different tenant, just do: + +```bash +export TENANT_ID=