From be3496f57f17f55ed4e005c4c547f7c89dd2d0a5 Mon Sep 17 00:00:00 2001 From: Thomas Cederholm Date: Fri, 14 Jun 2024 08:47:38 +0200 Subject: [PATCH] fix: Add checksum (#1) --- .editorconfig | 12 + .github/dependabot.yml | 14 ++ .github/workflows/commit-msg.yaml | 27 ++ .github/workflows/commit.yaml | 59 +++++ .github/workflows/pre-commit.yaml | 23 ++ .java-version | 1 + .pre-commit-config.yaml | 21 ++ LICENSE | 21 ++ pom.xml | 232 ++++++++++++++++++ .../com/retailsvc/gcp/storage/Checksum.java | 32 +++ .../retailsvc/gcp/storage/ChecksumTest.java | 31 +++ 11 files changed, 473 insertions(+) create mode 100644 .editorconfig create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/commit-msg.yaml create mode 100644 .github/workflows/commit.yaml create mode 100644 .github/workflows/pre-commit.yaml create mode 100644 .java-version create mode 100644 .pre-commit-config.yaml create mode 100644 LICENSE create mode 100644 pom.xml create mode 100644 src/main/java/com/retailsvc/gcp/storage/Checksum.java create mode 100644 src/test/java/com/retailsvc/gcp/storage/ChecksumTest.java diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..b078fb8 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +trim_trailing_whitespace = true +end_of_line = lf +insert_final_newline = true + +[*.properties] +trim_trailing_whitespace = false diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..50e28b8 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,14 @@ +version: 2 +registries: + nexus-releases: + type: maven-repository + url: https://repo.extendaretail.com/repository/maven-releases/ + username: ${{ secrets.NEXUS_MAVEN_USERNAME }} + password: ${{ secrets.NEXUS_MAVEN_PASSWORD }} +updates: + - package-ecosystem: maven + registries: + - nexus-releases + directory: '/' + schedule: + interval: monthly diff --git a/.github/workflows/commit-msg.yaml b/.github/workflows/commit-msg.yaml new file mode 100644 index 0000000..c3a8eee --- /dev/null +++ b/.github/workflows/commit-msg.yaml @@ -0,0 +1,27 @@ +name: commit-msg +on: + pull_request: + types: + - edited + - opened + - reopened + - synchronize + +jobs: + commitlint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Lint pull request title + uses: extenda/actions/commitlint@v0 + with: + message: ${{ github.event.pull_request.title }} + + - name: Lint commit messages + if: always() + uses: extenda/actions/commitlint@v0 + with: + relaxed: ${{ contains(job.status, 'success') }} diff --git a/.github/workflows/commit.yaml b/.github/workflows/commit.yaml new file mode 100644 index 0000000..e0316af --- /dev/null +++ b/.github/workflows/commit.yaml @@ -0,0 +1,59 @@ +name: Commit +on: push + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version-file: .java-version + cache: 'maven' + + - name: Run tests + uses: extenda/actions/maven@v0 + with: + args: verify + service-account-key: ${{ secrets.SECRET_AUTH }} + + - name: Scan with SonarCloud + uses: extenda/actions/sonar-scanner@v0 + with: + sonar-host: https://sonarcloud.io + sonar-scanner: maven + main-branch: master + service-account-key: ${{ secrets.SECRET_AUTH }} + + release: + if: github.ref == 'refs/heads/master' + runs-on: ubuntu-latest + needs: + - test + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version-file: .java-version + cache: 'maven' + + - name: Create release + uses: extenda/actions/conventional-release@v0 + id: release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Build release + uses: extenda/actions/maven@v0 + with: + args: deploy -DskipTests + version: ${{ steps.release.outputs.version }} + service-account-key: ${{ secrets.SECRET_AUTH }} diff --git a/.github/workflows/pre-commit.yaml b/.github/workflows/pre-commit.yaml new file mode 100644 index 0000000..19e2497 --- /dev/null +++ b/.github/workflows/pre-commit.yaml @@ -0,0 +1,23 @@ +name: pre-commit +on: pull_request + +jobs: + pre-commit: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup Python + uses: actions/setup-python@v5 + + - uses: actions/setup-java@v4 + with: + java-version-file: .java-version + distribution: temurin + + - name: Run pre-commit + uses: pre-commit/actions@v3.0.1 + with: + extra_args: --from-ref=${{ github.event.pull_request.base.sha }} --to-ref=${{ github.sha }} diff --git a/.java-version b/.java-version new file mode 100644 index 0000000..aabe6ec --- /dev/null +++ b/.java-version @@ -0,0 +1 @@ +21 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..b63eee3 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,21 @@ +default_stages: [commit] + +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.5.0 + hooks: + - id: end-of-file-fixer + - id: trailing-whitespace + exclude: test/__snapshots__ + - repo: https://github.com/Lucas-C/pre-commit-hooks + rev: v1.5.4 + hooks: + - id: remove-crlf + - id: remove-tabs + args: [ --whitespaces-count=2 ] + - repo: https://github.com/extenda/pre-commit-hooks + rev: v0.9.0 + hooks: + - id: google-java-formatter + - id: commitlint + stages: [commit-msg] diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..08cc2f1 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Extenda Retail + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..413b779 --- /dev/null +++ b/pom.xml @@ -0,0 +1,232 @@ + + + + 4.0.0 + + com.retailsvc + hiiretail-gcp-storage-java + 0.0.1-local + + GCP Storage client + Project to ease interaction with GCP Storage + https://github.com/extenda/hiiretail-gcp-storage-java + + + + MIT License + https://www.opensource.org/licenses/mit-license.php + + + + + + thomas.cederholm@extendaretail.com + Thomas Cederholm + https://github.com/thced + thced + + + + + 21 + ${java.version} + UTF-8 + + ${project.build.directory}/surefire-reports + ${project.build.directory}/jacoco.exec, ${user.dir}/target/jacoco-it.exec + 3.26.0 + 26.41.0 + 0.8.12 + 5.10.1 + 3.13.0 + 3.4.1 + 3.3.1 + 3.2.5 + 3.2.5 + 5.12.0 + 2.0.9 + 1.19.8 + + + + scm:git:https://github.com/extenda/hiiretail-gcp-storage-java.git + HEAD + + + + + repo.extenda.io + Extenda Retail Releases + https://repo.extendaretail.com/repository/maven-releases + + + repo.extenda.io + Extenda Retail Snapshots + https://repo.extendaretail.com/repository/maven-snapshots + false + + + + + + + org.junit + junit-bom + ${version.junit-jupiter} + pom + import + + + com.google.cloud + libraries-bom + ${version.google-cloud} + pom + import + + + org.testcontainers + testcontainers-bom + ${version.testcontainers} + pom + import + + + org.mockito + mockito-junit-jupiter + ${version.mockito} + test + + + + + + + com.google.cloud + google-cloud-storage + + + org.slf4j + slf4j-api + ${version.slf4j} + compile + + + + org.junit.jupiter + junit-jupiter + test + + + org.testcontainers + junit-jupiter + test + + + org.testcontainers + gcloud + test + + + org.assertj + assertj-core + ${version.assertj} + test + + + org.mockito + mockito-junit-jupiter + test + + + org.slf4j + slf4j-simple + ${version.slf4j} + test + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${version.maven-compiler-plugin} + + + + org.apache.maven.plugins + maven-surefire-plugin + ${version.maven-surefire-plugin} + + @{argLine} -Dfile.encoding=UTF-8 + + + + org.apache.maven.plugins + maven-failsafe-plugin + ${version.maven-failsafe-plugin} + + @{argLine} -Dfile.encoding=UTF-8 + + + + + integration-test + verify + + + + + + org.apache.maven.plugins + maven-jar-plugin + ${version.maven-jar-plugin} + + + + org.apache.maven.plugins + maven-source-plugin + ${version.maven-source-plugin} + + + attach-sources + verify + + jar + + + + + + org.jacoco + jacoco-maven-plugin + ${version.jacoco-maven-plugin} + + + jacoco-surefire + + prepare-agent + + initialize + + ${project.build.directory}/jacoco.exec + true + + + + jacoco-report + + report + + verify + + ${project.build.directory}/jacoco.exec + ${project.reporting.outputDirectory}/jacoco + + + + + + + diff --git a/src/main/java/com/retailsvc/gcp/storage/Checksum.java b/src/main/java/com/retailsvc/gcp/storage/Checksum.java new file mode 100644 index 0000000..30f7c8f --- /dev/null +++ b/src/main/java/com/retailsvc/gcp/storage/Checksum.java @@ -0,0 +1,32 @@ +package com.retailsvc.gcp.storage; + +import com.google.common.hash.Hashing; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.Base64; +import java.util.Objects; + +public class Checksum { + + private Checksum() {} + + /** + * Hash and base64 encode byte contents. + * + * @param data the contents to make a checksum (crc32c) of. + * @return the calculated checksum + */ + public static String crc32cBase64(byte[] data) { + Objects.requireNonNull(data); + + var fn = Hashing.crc32c(); + + var hashCode = fn.hashBytes(data).asBytes(); + /* LittleEndian buffer to hold bytes */ + ByteBuffer littleEndian = ByteBuffer.wrap(hashCode).order(ByteOrder.LITTLE_ENDIAN); + /* Extract LittleEndian into BigEndian to reverse byte order */ + ByteBuffer bigEndian = ByteBuffer.allocate(Integer.BYTES).putInt(littleEndian.getInt()); + /* base64 encode bigEndian bytes */ + return Base64.getEncoder().encodeToString(bigEndian.array()); + } +} diff --git a/src/test/java/com/retailsvc/gcp/storage/ChecksumTest.java b/src/test/java/com/retailsvc/gcp/storage/ChecksumTest.java new file mode 100644 index 0000000..f576419 --- /dev/null +++ b/src/test/java/com/retailsvc/gcp/storage/ChecksumTest.java @@ -0,0 +1,31 @@ +package com.retailsvc.gcp.storage; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatException; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +import org.junit.jupiter.api.Test; + +class ChecksumTest { + + @Test + void testProducedChecksum() { + var input = + """ + Lorem ipsum dolor sit amet, consectetur adipiscing elit. + Donec porttitor, turpis id pretium dignissim, mauris nulla + elementum neque, quis tincidunt dui lacus porttitor arcu. + Proin quam tellus, tristique non eros quis, pharetra tempus + libero. Cras efficitur dapibus vehicula. + Integer pellentesque massa augue, id aliquam velit fermentum ut. + """ + .getBytes(); + var crc32c = assertDoesNotThrow(() -> Checksum.crc32cBase64(input)); + assertThat(crc32c).isEqualTo("aaOBSA=="); + } + + @Test + void testNullThrows() { + assertThatException().isThrownBy(() -> Checksum.crc32cBase64(null)); + } +}