diff --git a/.github/workflows/flow-artifact-determinism.yaml b/.github/workflows/flow-artifact-determinism.yaml index 4edfc21317d..54457467a12 100644 --- a/.github/workflows/flow-artifact-determinism.yaml +++ b/.github/workflows/flow-artifact-determinism.yaml @@ -49,7 +49,7 @@ permissions: contents: read jobs: - check: + check-gradle: name: Gradle uses: ./.github/workflows/zxc-verify-gradle-build-determinism.yaml with: @@ -59,3 +59,14 @@ jobs: secrets: gradle-cache-username: ${{ secrets.GRADLE_CACHE_USERNAME }} gradle-cache-password: ${{ secrets.GRADLE_CACHE_PASSWORD }} + + check-docker: + name: Docker + uses: ./.github/workflows/zxc-verify-docker-build-determinism.yaml + with: + ref: ${{ github.event.inputs.ref || '' }} + java-distribution: ${{ inputs.java-distribution || 'temurin' }} + java-version: ${{ inputs.java-version || '21.0.1' }} + secrets: + gradle-cache-username: ${{ secrets.GRADLE_CACHE_USERNAME }} + gradle-cache-password: ${{ secrets.GRADLE_CACHE_PASSWORD }} diff --git a/.github/workflows/node-flow-build-application.yaml b/.github/workflows/node-flow-build-application.yaml index 354b2e12a06..059955cb6ea 100644 --- a/.github/workflows/node-flow-build-application.yaml +++ b/.github/workflows/node-flow-build-application.yaml @@ -81,7 +81,7 @@ jobs: java-version: ${{ github.event.inputs.java-version || '21.0.1' }} java-distribution: ${{ github.event.inputs.java-distribution || 'temurin' }} enable-unit-tests: ${{ github.event_name == 'push' || github.event.inputs.enable-unit-tests == 'true' }} - enable-sonar-analysis: ${{ github.event_name == 'push' || github.event.inputs.enable-sonar-analysis == 'true' }} + enable-sonar-analysis: false enable-integration-tests: ${{ github.event_name == 'push' || github.event.inputs.enable-integration-tests == 'true' }} enable-hapi-tests-misc: ${{ github.event_name == 'push' || github.event.inputs.enable-hapi-tests == 'true' }} enable-hapi-tests-crypto: ${{ github.event_name == 'push' || github.event.inputs.enable-hapi-tests == 'true' }} diff --git a/.github/workflows/node-flow-pull-request-checks.yaml b/.github/workflows/node-flow-pull-request-checks.yaml index d08534a57b3..a953134d7b5 100644 --- a/.github/workflows/node-flow-pull-request-checks.yaml +++ b/.github/workflows/node-flow-pull-request-checks.yaml @@ -273,8 +273,8 @@ jobs: gradle-cache-password: ${{ secrets.GRADLE_CACHE_PASSWORD }} snyk-token: ${{ secrets.SNYK_TOKEN }} - artifact-determinism: - name: Artifact Determinism + gradle-determinism: + name: Gradle Determinism uses: ./.github/workflows/zxc-verify-gradle-build-determinism.yaml needs: - dependency-check @@ -287,3 +287,18 @@ jobs: secrets: gradle-cache-username: ${{ secrets.GRADLE_CACHE_USERNAME }} gradle-cache-password: ${{ secrets.GRADLE_CACHE_PASSWORD }} + + docker-determinism: + name: Docker Determinism + uses: ./.github/workflows/zxc-verify-docker-build-determinism.yaml + needs: + - dependency-check + - spotless + if: ${{ github.actor != 'dependabot[bot]' && github.event.pull_request.head.repo.full_name == github.repository }} + with: + ref: ${{ github.event.inputs.ref || '' }} + java-distribution: temurin + java-version: 21.0.1 + secrets: + gradle-cache-username: ${{ secrets.GRADLE_CACHE_USERNAME }} + gradle-cache-password: ${{ secrets.GRADLE_CACHE_PASSWORD }} diff --git a/.github/workflows/support/scripts/generate-docker-artifact-baseline.sh b/.github/workflows/support/scripts/generate-docker-artifact-baseline.sh new file mode 100755 index 00000000000..381026f1f0f --- /dev/null +++ b/.github/workflows/support/scripts/generate-docker-artifact-baseline.sh @@ -0,0 +1,175 @@ +#!/usr/bin/env bash +set -o pipefail +set +e + +readonly RELEASE_LIB_PATH="hedera-node/data/lib" +readonly RELEASE_APPS_PATH="hedera-node/data/apps" +readonly DOCKER_IMAGE_NAME="main-network-node" + +GROUP_ACTIVE="false" + +function fail { + printf '%s\n' "$1" >&2 ## Send message to stderr. Exclude >&2 if you don't want it that way. + if [[ "${GROUP_ACTIVE}" == "true" ]]; then + end_group + fi + exit "${2-1}" ## Return a code specified by $2 or 1 by default. +} + +function start_group { + if [[ "${GROUP_ACTIVE}" == "true" ]]; then + end_group + fi + + GROUP_ACTIVE="true" + printf "::group::%s\n" "${1}" +} + +function end_group { + GROUP_ACTIVE="false" + printf "::endgroup::\n" +} + +function log { + local message="${1}" + shift + # shellcheck disable=SC2059 + printf "${message}" "${@}" +} + +function log_line { + local message="${1}" + shift + # shellcheck disable=SC2059 + printf "${message}\n" "${@}" +} + +function start_task { + local message="${1}" + shift + # shellcheck disable=SC2059 + printf "${message} .....\t" "${@}" +} + +function end_task { + printf "%s\n" "${1:-DONE}" +} + +start_group "Configuring Environment" + # Access workflow environment variables + export GITHUB_WORKSPACE GITHUB_SHA GITHUB_OUTPUT MANIFEST_PATH DOCKER_REGISTRY DOCKER_TAG + + start_task "Initializing Temporary Directory" + TEMP_DIR="$(mktemp -d)" || fail "ERROR (Exit Code: ${?})" "${?}" + trap 'rm -rf "${TEMP_DIR}"' EXIT + end_task "DONE (Path: ${TEMP_DIR})" + + start_task "Resolving the GITHUB_WORKSPACE path" + # Ensure GITHUB_WORKSPACE is provided or default to the repository root + if [[ -z "${GITHUB_WORKSPACE}" || ! -d "${GITHUB_WORKSPACE}" ]]; then + GITHUB_WORKSPACE="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../../../" && pwd)" + fi + end_task "DONE (Path: ${GITHUB_WORKSPACE})" + + start_task "Resolving the GITHUB_OUTPUT path" + # Ensure GITHUB_OUTPUT is provided or default to the repository root + if [[ -z "${GITHUB_OUTPUT}" ]]; then + GITHUB_OUTPUT="${TEMP_DIR}/workflow-output.txt" + fi + end_task "DONE (Path: ${GITHUB_OUTPUT})" + + start_task "Resolving the GITHUB_SHA hash" + if [[ -z "${GITHUB_SHA}" ]]; then + GITHUB_SHA="$(git rev-parse HEAD | tr -d '[:space:]')" || fail "ERROR (Exit Code: ${?})" "${?}" + fi + end_task "DONE (Commit: ${GITHUB_SHA})" + + start_task "Resolving the MANIFEST_PATH variable" + if [[ -z "${MANIFEST_PATH}" ]]; then + MANIFEST_PATH="${GITHUB_WORKSPACE}/.manifests/gradle" + fi + end_task "DONE (Path: ${MANIFEST_PATH})" + + start_task "Ensuring the MANIFEST_PATH location is present" + if [[ ! -d "${MANIFEST_PATH}" ]]; then + mkdir -p "${MANIFEST_PATH}" || fail "ERROR (Exit Code: ${?})" "${?}" + fi + end_task + + start_task "Checking for the skopeo command" + if command -v skopeo >/dev/null 2>&1; then + SKOPEO="$(command -v skopeo)" || fail "ERROR (Exit Code: ${?})" "${?}" + export SKOPEO + else + fail "ERROR (Exit Code: ${?})" "${?}" + fi + end_task "DONE (Found: ${SKOPEO})" + + start_task "Checking for the JQ command" + if command -v jq >/dev/null 2>&1; then + JQ="$(command -v jq)" || fail "ERROR (Exit Code: ${?})" "${?}" + export JQ + else + fail "ERROR (Exit Code: ${?})" "${?}" + fi + end_task "DONE (Found: ${JQ})" + + start_task "Checking for prebuilt libraries" + ls -al "${GITHUB_WORKSPACE}/${RELEASE_LIB_PATH}"/*.jar >/dev/null 2>&1 || fail "ERROR (Exit Code: ${?})" "${?}" + end_task "FOUND (Path: ${GITHUB_WORKSPACE}/${RELEASE_LIB_PATH}/*.jar)" + + start_task "Checking for prebuilt applications" + ls -al "${GITHUB_WORKSPACE}/${RELEASE_APPS_PATH}"/*.jar >/dev/null 2>&1 || fail "ERROR (Exit Code: ${?})" "${?}" + end_task "FOUND (Path: ${GITHUB_WORKSPACE}/${RELEASE_APPS_PATH}/*.jar)" +end_group + +start_group "Prepare the Docker Image Information" + start_task "Resolving the DOCKER_REGISTRY variable" + if [[ -z "${DOCKER_REGISTRY}" ]]; then + DOCKER_REGISTRY="localhost:5000" + fi + end_task "DONE (Registry: ${DOCKER_REGISTRY})" + + start_task "Resolving the DOCKER_TAG variable" + if [[ -z "${DOCKER_TAG}" ]]; then + DOCKER_TAG="$(echo "${GITHUB_SHA}" | tr -d '[:space:]' | cut -c1-8)" + fi + end_task "DONE (Tag: ${DOCKER_TAG})" + + start_task "Resolving the Fully Qualified Image Name" + FQ_IMAGE_NAME="${DOCKER_REGISTRY}/${DOCKER_IMAGE_NAME}:${DOCKER_TAG}" + end_task "DONE (Image: ${FQ_IMAGE_NAME})" +end_group + +start_group "Generate Docker Image Manifest (linux/amd64)" + ${SKOPEO} --override-os linux --override-arch amd64 inspect --tls-verify=false "docker://${FQ_IMAGE_NAME}" | tee "${TEMP_DIR}/linux-amd64.manifest.json" || fail "SKOPEO ERROR (Exit Code: ${?})" "${?}" + ${JQ} -r '.Layers[]' "${TEMP_DIR}/linux-amd64.manifest.json" | tee "${TEMP_DIR}/linux-amd64.layers.json" >/dev/null 2>&1 || fail "JQ LAYER ERROR (Exit Code: ${?})" "${?}" + ${JQ} -r 'del(.RepoTags) | del(.LayersData) | del(.Digest)' "${TEMP_DIR}/linux-amd64.manifest.json" | tee "${TEMP_DIR}/linux-amd64.comparable.json" >/dev/null 2>&1 || fail "JQ COMP ERROR (Exit Code: ${?})" "${?}" +end_group + +start_group "Generate Docker Image Manifest (linux/arm64)" + ${SKOPEO} --override-os linux --override-arch arm64 inspect --tls-verify=false "docker://${FQ_IMAGE_NAME}" | tee "${TEMP_DIR}/linux-arm64.manifest.json" || fail "SKOPEO ERROR (Exit Code: ${?})" "${?}" + ${JQ} -r '.Layers[]' "${TEMP_DIR}/linux-arm64.manifest.json" | tee "${TEMP_DIR}/linux-arm64.layers.json" >/dev/null 2>&1 || fail "JQ LAYER ERROR (Exit Code: ${?})" "${?}" + ${JQ} -r 'del(.RepoTags) | del(.LayersData) | del(.Digest)' "${TEMP_DIR}/linux-arm64.manifest.json" | tee "${TEMP_DIR}/linux-arm64.comparable.json" >/dev/null 2>&1 || fail "JQ COMP ERROR (Exit Code: ${?})" "${?}" +end_group + +start_group "Generating Final Release Manifests" + + start_task "Generating the manifest archive" + tar -czf "${TEMP_DIR}/manifest.tar.gz" -C "${TEMP_DIR}" linux-amd64.manifest.json linux-amd64.layers.json linux-amd64.comparable.json linux-arm64.manifest.json linux-arm64.layers.json linux-arm64.comparable.json >/dev/null 2>&1 || fail "TAR ERROR (Exit Code: ${?})" "${?}" + end_task + + start_task "Copying the manifest files" + cp "${TEMP_DIR}/manifest.tar.gz" "${MANIFEST_PATH}/${GITHUB_SHA}.tar.gz" || fail "COPY ERROR (Exit Code: ${?})" "${?}" + cp "${TEMP_DIR}"/*.json "${MANIFEST_PATH}/" || fail "COPY ERROR (Exit Code: ${?})" "${?}" + end_task "DONE (Path: ${MANIFEST_PATH}/${GITHUB_SHA}.tar.gz)" + + start_task "Setting Step Outputs" + { + printf "path=%s\n" "${MANIFEST_PATH}" + printf "file=%s\n" "${MANIFEST_PATH}/${GITHUB_SHA}.tar.gz" + printf "name=%s\n" "${GITHUB_SHA}.tar.gz" + } >> "${GITHUB_OUTPUT}" + end_task +end_group + diff --git a/.github/workflows/zxc-verify-docker-build-determinism.yaml b/.github/workflows/zxc-verify-docker-build-determinism.yaml new file mode 100644 index 00000000000..3d85827e6fe --- /dev/null +++ b/.github/workflows/zxc-verify-docker-build-determinism.yaml @@ -0,0 +1,387 @@ +## +# Copyright (C) 2023 Hedera Hashgraph, LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +## + +name: "ZXC: Verify Docker Build Determinism" +on: + workflow_call: + inputs: + ref: + description: "The branch, tag, or commit to checkout:" + type: string + required: false + default: "" + java-distribution: + description: "Java JDK Distribution:" + type: string + required: false + default: "temurin" + java-version: + description: "Java JDK Version:" + type: string + required: false + default: "21.0.1" + + secrets: + gradle-cache-username: + description: "The username used to authenticate with the Gradle Build Cache Node." + required: true + gradle-cache-password: + description: "The password used to authenticate with the Gradle Build Cache Node." + required: true + +defaults: + run: + shell: bash + +permissions: + id-token: write + contents: read + +env: + GRADLE_CACHE_USERNAME: ${{ secrets.gradle-cache-username }} + GRADLE_CACHE_PASSWORD: ${{ secrets.gradle-cache-password }} + DOCKER_MANIFEST_GENERATOR: .github/workflows/support/scripts/generate-docker-artifact-baseline.sh + DOCKER_MANIFEST_PATH: ${{ github.workspace }}/.manifests/docker + DOCKER_REGISTRY: localhost:5000 + DOCKER_IMAGE_NAME: main-network-node + DOCKER_CONTEXT_PATH: hedera-node/infrastructure/docker/containers/production-next/main-network-node + +jobs: + generate-baseline: + name: Generate Baseline + runs-on: [self-hosted, Linux, medium, ephemeral] + outputs: + sha: ${{ steps.commit.outputs.sha }} + sha-abbrev: ${{ steps.commit.outputs.sha-abbrev }} + source-date: ${{ steps.commit.outputs.source-date }} + path: ${{ steps.baseline.outputs.path }} + file: ${{ steps.baseline.outputs.file }} + name: ${{ steps.baseline.outputs.name }} + steps: + - name: Checkout Code + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + ref: ${{ inputs.ref }} + + - name: Setup Java + uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3.13.0 + with: + distribution: ${{ inputs.java-distribution }} + java-version: ${{ inputs.java-version }} + + - name: Setup Gradle + uses: gradle/gradle-build-action@842c587ad8aa4c68eeba24c396e15af4c2e9f30a # v2.9.0 + with: + cache-disabled: true + + - name: Authenticate to Google Cloud + id: google-auth + uses: google-github-actions/auth@f105ef0cdb3b102a020be1767fcc8a974898b7c6 # v1.2.0 + with: + workload_identity_provider: "projects/235822363393/locations/global/workloadIdentityPools/hedera-builds-pool/providers/hedera-builds-gh-actions" + service_account: "swirlds-automation@hedera-registry.iam.gserviceaccount.com" + + - name: Setup Google Cloud SDK + uses: google-github-actions/setup-gcloud@e30db14379863a8c79331b04a9969f4c1e225e0b # v1.1.1 + + - name: Retrieve Commit Hash + id: commit + run: | + echo "sha=$(git rev-parse HEAD)" >> "${GITHUB_OUTPUT}" + echo "sha-abbrev=$(git rev-parse HEAD | tr -d '[:space:]' | cut -c1-8)" >> "${GITHUB_OUTPUT}" + echo "source-date=$(git log -1 --pretty=%ct)" >> "${GITHUB_OUTPUT}" + + - name: Baseline Existence Check + id: baseline + run: | + BASELINE_NAME="${{ steps.commit.outputs.sha }}.tar.gz" + BASELINE_PATH="gs://hedera-ci-ephemeral-artifacts/${{ github.repository }}/docker/baselines" + BASELINE_FILE="${BASELINE_PATH}/${BASELINE_NAME}" + BASELINE_EXISTS="false" + + if gsutil ls "${BASELINE_FILE}" >/dev/null 2>&1; then + BASELINE_EXISTS="true" + fi + + echo "exists=${BASELINE_EXISTS}" >> "${GITHUB_OUTPUT}" + echo "path=${BASELINE_PATH}" >> "${GITHUB_OUTPUT}" + echo "name=${BASELINE_NAME}" >> "${GITHUB_OUTPUT}" + echo "file=${BASELINE_FILE}" >> "${GITHUB_OUTPUT}" + + - name: Install Skopeo and JQ + if: ${{ steps.baseline.outputs.exists == 'false' && !failure() && !cancelled() }} + run: | + sudo apt-get update + sudo apt-get install --yes --no-install-recommends skopeo jq + + - name: Build Gradle Artifacts + id: gradle-build + if: ${{ steps.baseline.outputs.exists == 'false' && !failure() && !cancelled() }} + run: ./gradlew assemble --scan + + - name: Setup QEmu Support + uses: docker/setup-qemu-action@68827325e0b33c7199eb31dd4e31fbe9023e06e3 # v3.0.0 + if: ${{ steps.baseline.outputs.exists == 'false' && !failure() && !cancelled() }} + + - name: Setup Docker Buildx Support + uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0 + if: ${{ steps.baseline.outputs.exists == 'false' && !failure() && !cancelled() }} + with: + version: v0.12.0 + driver-opts: network=host + + - name: Setup Local Docker Registry + if: ${{ steps.baseline.outputs.exists == 'false' && !failure() && !cancelled() }} + run: docker run -d -p 5000:5000 --restart=always --name registry registry:latest + + - name: Show Docker Version + run: docker version + + - name: Show Docker Info + run: docker info + + - name: Prepare for Docker Build + if: ${{ steps.baseline.outputs.exists == 'false' && !failure() && !cancelled() }} + run: | + mkdir -p "${{ github.workspace }}/${{ env.DOCKER_CONTEXT_PATH }}/sdk/data" + + echo "::group::Copying Library Artifacts" + cp -Rvf "${{ github.workspace }}/hedera-node/data/lib" "${{ github.workspace }}/${{ env.DOCKER_CONTEXT_PATH }}/sdk/data/" + echo "::endgroup::" + + echo "::group::Copying Application Artifacts" + cp -Rvf "${{ github.workspace }}/hedera-node/data/apps" "${{ github.workspace }}/${{ env.DOCKER_CONTEXT_PATH }}/sdk/data/" + echo "::endgroup::" + + - name: Build Docker Image + uses: docker/build-push-action@4a13e500e55cf31b7a5d59a38ab2040ab0f42f56 # v5.1.0 + env: + SOURCE_DATE_EPOCH: ${{ steps.commit.outputs.source-date }} + if: ${{ steps.baseline.outputs.exists == 'false' && !failure() && !cancelled() }} + with: + push: true + no-cache: true + platforms: linux/amd64,linux/arm64 + build-args: | + SOURCE_DATE_EPOCH=${{ steps.commit.outputs.source-date }} + context: ${{ env.DOCKER_CONTEXT_PATH }} + tags: ${{ env.DOCKER_REGISTRY }}/${{ env.DOCKER_IMAGE_NAME }}:${{ steps.commit.outputs.sha-abbrev }} + + - name: Generate Manifest + id: manifest + env: + MANIFEST_PATH: ${{ env.DOCKER_MANIFEST_PATH }} + if: ${{ steps.baseline.outputs.exists == 'false' && !failure() && !cancelled() }} + run: ${{ env.DOCKER_MANIFEST_GENERATOR }} + + - name: Upload Baseline + if: ${{ steps.baseline.outputs.exists == 'false' && !failure() && !cancelled() }} + run: gsutil cp "${{ steps.manifest.outputs.file }}" "${{ steps.baseline.outputs.file }}" + + verify-artifacts: + name: "Verify Artifacts (${{ join(matrix.os, ', ') }})" + runs-on: ${{ matrix.os }} + needs: + - generate-baseline + strategy: + fail-fast: false + matrix: + # Windows is disabled due to GitHub not supporting Docker Desktop/Podman Desktop and Docker CE on Windows not + # supporting BuildKit and the Buildx plugin. + # The GitHub hosted ubuntu-22.04 runners are disabled temporarily due to the Azure VM causing docker container + # builds to be non-deterministic. Self-hosted runners using Ubuntu 22.04 are unaffected. + # The Self Hosted Large instance is temporarily disabled because it is running no longer supported version of + # Ubuntu 18.04. The Large instance will be upgraded to Ubuntu 22.04 in the near future. + os: + #- ubuntu-22.04 + - ubuntu-20.04 + - macos-12 + - macos-11 + #- windows-2022 + #- windows-2019 + - [self-hosted, Linux, medium, ephemeral] + #- [self-hosted, Linux, large, ephemeral] + steps: + - name: Standardize Git Line Endings + run: | + git config --global core.autocrlf false + git config --global core.eol lf + + - name: Checkout Code + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + ref: ${{ inputs.ref }} + + - name: Setup Python + uses: actions/setup-python@b64ffcaf5b410884ad320a9cfac8866006a109aa # v4.8.0 + with: + python-version: 3.9 + + - name: Setup Java + uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3.13.0 + with: + distribution: ${{ inputs.java-distribution }} + java-version: ${{ inputs.java-version }} + + - name: Setup Gradle + uses: gradle/gradle-build-action@842c587ad8aa4c68eeba24c396e15af4c2e9f30a # v2.9.0 + with: + cache-disabled: true + + - name: Install Skopeo and JQ (Linux) + if: ${{ runner.os == 'Linux' }} + run: | + sudo apt-get update + sudo apt-get install --yes --no-install-recommends skopeo jq + + - name: Install Skopeo and JQ (macOS) + if: ${{ runner.os == 'macOS' }} + run: brew install skopeo jq + + - name: Install Skopeo and JQ (Windows) + if: ${{ runner.os == 'Windows' }} + run: | + curl -L -o /usr/bin/jq.exe https://github.com/stedolan/jq/releases/latest/download/jq-win64.exe + curl -L -o /usr/bin/skopeo.exe https://github.com/passcod/winskopeo/releases/latest/download/skopeo.exe + + - name: Setup CoreUtils (macOS) + if: ${{ runner.os == 'macOS' }} + run: brew install coreutils + + - name: Authenticate to Google Cloud + id: google-auth + uses: google-github-actions/auth@f105ef0cdb3b102a020be1767fcc8a974898b7c6 # v1.2.0 + with: + workload_identity_provider: "projects/235822363393/locations/global/workloadIdentityPools/hedera-builds-pool/providers/hedera-builds-gh-actions" + service_account: "swirlds-automation@hedera-registry.iam.gserviceaccount.com" + + - name: Setup Google Cloud SDK + uses: google-github-actions/setup-gcloud@e30db14379863a8c79331b04a9969f4c1e225e0b # v1.1.1 + env: + CLOUDSDK_PYTHON: ${{ format('{0}{1}', env.pythonLocation, runner.os == 'Windows' && '\python.exe' || '/bin/python3') }} + + - name: Download Baseline + env: + CLOUDSDK_PYTHON: ${{ format('{0}{1}', env.pythonLocation, runner.os == 'Windows' && '\python.exe' || '/bin/python3') }} + run: | + mkdir -p "${DOCKER_MANIFEST_PATH}" + cd "${DOCKER_MANIFEST_PATH}" + gsutil cp "${{ needs.generate-baseline.outputs.file }}" . + tar -xzf "${{ needs.generate-baseline.outputs.name }}" + + - name: Build Artifacts + id: gradle-build + run: ./gradlew assemble --scan --no-build-cache + + - name: Set up Docker + uses: crazy-max/ghaction-setup-docker@d9be6cade441568ba10037bce5221b8f564981f1 # v3.0.0 + if: ${{ !contains(matrix.os, 'self-hosted') }} + with: + version: v24.0.7 + + - name: Setup QEmu Support + if: ${{ runner.os != 'Windows' }} + uses: docker/setup-qemu-action@68827325e0b33c7199eb31dd4e31fbe9023e06e3 # v3.0.0 + + - name: Setup Docker Buildx Support + uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0 + if: ${{ runner.os != 'Windows' }} + with: + version: v0.12.0 + driver-opts: network=host + + - name: Setup Local Docker Registry + run: docker run -d -p 5000:5000 --restart=always --name registry registry:latest + + - name: Show Docker Version + run: docker version + + - name: Show Docker Info + run: docker info + + - name: Prepare for Docker Build + run: | + mkdir -p "${{ github.workspace }}/${{ env.DOCKER_CONTEXT_PATH }}/sdk/data" + + echo "::group::Copying Library Artifacts" + cp -Rvf "${{ github.workspace }}/hedera-node/data/lib" "${{ github.workspace }}/${{ env.DOCKER_CONTEXT_PATH }}/sdk/data/" + echo "::endgroup::" + + echo "::group::Copying Application Artifacts" + cp -Rvf "${{ github.workspace }}/hedera-node/data/apps" "${{ github.workspace }}/${{ env.DOCKER_CONTEXT_PATH }}/sdk/data/" + echo "::endgroup::" + + - name: Build Docker Image + uses: docker/build-push-action@4a13e500e55cf31b7a5d59a38ab2040ab0f42f56 # v5.1.0 + env: + SOURCE_DATE_EPOCH: ${{ needs.generate-baseline.outputs.source-date }} + with: + push: true + no-cache: true + platforms: linux/amd64,linux/arm64 + build-args: | + SOURCE_DATE_EPOCH=${{ needs.generate-baseline.outputs.source-date }} + context: ${{ env.DOCKER_CONTEXT_PATH }} + tags: ${{ env.DOCKER_REGISTRY }}/${{ env.DOCKER_IMAGE_NAME }}:${{ needs.generate-baseline.outputs.sha-abbrev }} + + - name: Regenerate Manifest + id: regen-manifest + env: + MANIFEST_PATH: ${{ env.DOCKER_MANIFEST_PATH }}/regenerated + run: ${{ env.DOCKER_MANIFEST_GENERATOR }} + + - name: Validate Layers (linux/amd64) + run: | + if ! diff -u "${DOCKER_MANIFEST_PATH}/linux-amd64.layers.json" "${{ steps.regen-manifest.outputs.path }}/linux-amd64.layers.json" >/dev/null 2>&1; then + echo "::group::Layer Differences" + diff -u "${DOCKER_MANIFEST_PATH}/linux-amd64.layers.json" "${{ steps.regen-manifest.outputs.path }}/linux-amd64.layers.json" + echo "::endgroup::" + exit 1 + fi + + - name: Validate Layers (linux/arm64) + run: | + if ! diff -u "${DOCKER_MANIFEST_PATH}/linux-arm64.layers.json" "${{ steps.regen-manifest.outputs.path }}/linux-arm64.layers.json" >/dev/null 2>&1; then + echo "::group::Layer Differences" + diff -u "${DOCKER_MANIFEST_PATH}/linux-arm64.layers.json" "${{ steps.regen-manifest.outputs.path }}/linux-arm64.layers.json" + echo "::endgroup::" + exit 1 + fi + + - name: Validate Full Manifest (linux/amd64) + run: | + if ! diff -u "${DOCKER_MANIFEST_PATH}/linux-amd64.comparable.json" "${{ steps.regen-manifest.outputs.path }}/linux-amd64.comparable.json" >/dev/null 2>&1; then + echo "::group::Layer Differences" + diff -u "${DOCKER_MANIFEST_PATH}/linux-amd64.comparable.json" "${{ steps.regen-manifest.outputs.path }}/linux-amd64.comparable.json" + echo "::endgroup::" + exit 1 + fi + + - name: Validate Full Manifest (linux/arm64) + run: | + if ! diff -u "${DOCKER_MANIFEST_PATH}/linux-arm64.comparable.json" "${{ steps.regen-manifest.outputs.path }}/linux-arm64.comparable.json" >/dev/null 2>&1; then + echo "::group::Layer Differences" + diff -u "${DOCKER_MANIFEST_PATH}/linux-arm64.comparable.json" "${{ steps.regen-manifest.outputs.path }}/linux-arm64.comparable.json" + echo "::endgroup::" + exit 1 + fi + + - name: Publish Manifests + uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + if: ${{ steps.regen-manifest.conclusion == 'success' && failure() && !cancelled() }} + with: + name: Docker Manifests [${{ join(matrix.os, ', ') }}] + path: ${{ env.DOCKER_MANIFEST_PATH }}/** diff --git a/README.md b/README.md index c90a4cec05e..5f4289dcdd0 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,8 @@ -[![Build Application](https://github.com/hashgraph/hedera-services/actions/workflows/node-flow-build-application.yaml/badge.svg?branch=develop)](https://github.com/hashgraph/hedera-services/actions/workflows/flow-build-application.yaml) -[![codecov](https://codecov.io/github/hashgraph/hedera-services/coverage.svg?branch=master&token=ZPMV8C93DV)](README.md) +[![Node: Build Application](https://github.com/hashgraph/hedera-services/actions/workflows/node-flow-build-application.yaml/badge.svg)](https://github.com/hashgraph/hedera-services/actions/workflows/node-flow-build-application.yaml) +[![Artifact Determinism](https://github.com/hashgraph/hedera-services/actions/workflows/flow-artifact-determinism.yaml/badge.svg)](https://github.com/hashgraph/hedera-services/actions/workflows/flow-artifact-determinism.yaml) +[![Node: Performance Tests](https://github.com/hashgraph/hedera-services/actions/workflows/flow-node-performance-tests.yaml/badge.svg)](https://github.com/hashgraph/hedera-services/actions/workflows/flow-node-performance-tests.yaml) + +[![codecov](https://codecov.io/gh/hashgraph/hedera-services/graph/badge.svg?token=ZPMV8C93DV)](https://codecov.io/gh/hashgraph/hedera-services) [![Latest Version](https://img.shields.io/github/v/tag/hashgraph/hedera-services?sort=semver&label=version)](README.md) [![Made With](https://img.shields.io/badge/made_with-java-blue)](https://github.com/hashgraph/hedera-services/) [![Development Branch](https://img.shields.io/badge/docs-quickstart-green.svg)](hedera-node/docs/gradle-quickstart.md) @@ -15,7 +18,9 @@ nodes in the [Hedera public network](https://hedera.com). * _hedera-node/_ - implementation of Hedera services on the Platform. ## JVM -JDK 17 is required. The Temurin builds of [Eclipse Adoptium](https://adoptium.net/) are strongly recommended. +An [Eclipse Adoptium](https://adoptium.net/) build of the Java 21 JDK is required. If an Adoptium JDK is not installed, +the Gradle build will download an appropriate Adoptium JDK. The JDK version used to execute Gradle must be Java 21+ in +order for the `checkAllModuleInfo` task to succeed. ## Solidity Hedera Contracts support `pragma solidity <=0.8.9`.