Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add gradle deterministic build and the GHA workflow and script to verify #413

Draft
wants to merge 16 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/workflows/release-push-image.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@ env:
REGISTRY: ghcr.io

jobs:
check-gradle:
name: Gradle
uses: ./.github/workflows/zxc-verify-gradle-build-determinism.yaml
with:
ref: ${{ github.event.inputs.ref || '' }}
java-distribution: ${{ inputs.java-distribution || 'temurin' }}
java-version: ${{ inputs.java-version || '21.0.4' }}

publish:
runs-on: block-node-linux-medium

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
set -o pipefail
set +e

readonly RELEASE_LIB_PATH="hedera-node/data/lib"
readonly RELEASE_APPS_PATH="hedera-node/data/apps"
readonly RELEASE_APPS_PATH="server/build/libs"

GROUP_ACTIVE="false"

Expand Down Expand Up @@ -63,86 +62,74 @@ start_group "Configuring Environment"
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 sha256sum command"
# if command -v sha256sum >/dev/null 2>&1; then
# SHA256SUM="$(command -v sha256sum)" || fail "ERROR (Exit Code: ${?})" "${?}"
# else
# fail "ERROR (Exit Code: ${?})" "${?}"
# fi
# end_task "DONE (Found: ${SHA256SUM})"
#
# 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)"
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 sha256sum command"
if command -v sha256sum >/dev/null 2>&1; then
SHA256SUM="$(command -v sha256sum)" || fail "ERROR (Exit Code: ${?})" "${?}"
else
fail "ERROR (Exit Code: ${?})" "${?}"
fi
end_task "DONE (Found: ${SHA256SUM})"

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 "Generating Application Hashes (${GITHUB_WORKSPACE}/${RELEASE_APPS_PATH}/*.jar)"
pushd "${GITHUB_WORKSPACE}/${RELEASE_APPS_PATH}" >/dev/null 2>&1 || fail "PUSHD ERROR (Exit Code: ${?})" "${?}"
${SHA256SUM} -b -- *.jar | sort -k 2 | tee -a "${TEMP_DIR}"/applications.sha256
popd >/dev/null 2>&1 || fail "POPD ERROR (Exit Code: ${?})" "${?}"
end_group

#start_group "Generating Library Hashes (${GITHUB_WORKSPACE}/${RELEASE_LIB_PATH}/*.jar)"
# pushd "${GITHUB_WORKSPACE}/${RELEASE_LIB_PATH}" >/dev/null 2>&1 || fail "PUSHD ERROR (Exit Code: ${?})" "${?}"
# ${SHA256SUM} -b -- *.jar | sort -k 2 | tee -a "${TEMP_DIR}"/libraries.sha256
# popd >/dev/null 2>&1 || fail "POPD ERROR (Exit Code: ${?})" "${?}"
#end_group
#
#start_group "Generating Application Hashes (${GITHUB_WORKSPACE}/${RELEASE_APPS_PATH}/*.jar)"
# pushd "${GITHUB_WORKSPACE}/${RELEASE_APPS_PATH}" >/dev/null 2>&1 || fail "PUSHD ERROR (Exit Code: ${?})" "${?}"
# ${SHA256SUM} -b -- *.jar | sort -k 2 | tee -a "${TEMP_DIR}"/applications.sha256
# popd >/dev/null 2>&1 || fail "POPD 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}" libraries.sha256 applications.sha256 >/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}/libraries.sha256" "${MANIFEST_PATH}/libraries.sha256" || fail "COPY ERROR (Exit Code: ${?})" "${?}"
# cp "${TEMP_DIR}/applications.sha256" "${MANIFEST_PATH}/applications.sha256" || 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"
# printf "applications=%s\n" "${MANIFEST_PATH}/applications.sha256"
# printf "libraries=%s\n" "${MANIFEST_PATH}/libraries.sha256"
# } >> "${GITHUB_OUTPUT}"
# end_task
#end_group
start_group "Generating Final Release Manifests"

start_task "Generating the manifest archive"
tar -czf "${TEMP_DIR}/manifest.tar.gz" -C "${TEMP_DIR}" applications.sha256 >/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}/applications.sha256" "${MANIFEST_PATH}/applications.sha256" || 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"
printf "applications=%s\n" "${MANIFEST_PATH}/applications.sha256"
} >> "${GITHUB_OUTPUT}"
end_task
end_group
177 changes: 173 additions & 4 deletions .github/workflows/zxc-verify-gradle-build-determinism.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ name: "ZXC: Verify Gradle Build Determinism"
# Z - Ensures sort order such that this script appears at the bottom of the UI
# X - Indicates it's not for direct user consumption
# C - Indicates this is a 'workflow_call' based reusable workflow

on:
workflow_call:
inputs:
Expand Down Expand Up @@ -53,10 +52,180 @@ permissions:
contents: read
packages: write

env:
GRADLE_MANIFEST_PATH: ${{ github.workspace }}/.manifests/gradle
GRADLE_MANIFEST_GENERATOR: .github/workflows/support/scripts/generate-gradle-artifact-baseline.sh
LC_ALL: C.UTF-8

jobs:
generate-baseline:
name: Generate Baseline
runs-on: network-node-linux-medium
runs-on: block-node-linux-medium
outputs:
sha: ${{ steps.commit.outputs.sha }}
path: ${{ steps.baseline.outputs.path }}
file: ${{ steps.baseline.outputs.file }}
name: ${{ steps.baseline.outputs.name }}
steps:
- name: Harden Runner
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
with:
egress-policy: audit

- name: Checkout Code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
ref: ${{ inputs.ref }}

- name: Setup Java
uses: actions/setup-java@8df1039502a15bceb9433410b1a100fbe190c53b # v4.5.0
with:
distribution: ${{ inputs.java-distribution }}
java-version: ${{ inputs.java-version }}

- name: Setup Gradle
uses: gradle/actions/setup-gradle@cc4fc85e6b35bafd578d5ffbc76a5518407e1af0 # v4.2.1
with:
cache-disabled: true

- name: Retrieve Commit Hash
id: commit
run: echo "sha=$(git rev-parse HEAD)" >> "${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 }}/gradle/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: Build Artifacts
id: gradle-build
run: ./gradlew assemble --scan

- name: Generate Manifest
id: manifest
env:
MANIFEST_PATH: ${{ env.GRADLE_MANIFEST_PATH }}
run: ${{ env.GRADLE_MANIFEST_GENERATOR }}

verify-artifacts:
name: "Verify Artifacts (${{ join(matrix.os, ', ') }})"
runs-on: ${{ matrix.os }}
needs:
- generate-baseline
strategy:
fail-fast: false
matrix:
os:
- ubuntu-22.04
- ubuntu-20.04
- windows-2022
- windows-2019
- block-node-linux-medium
- block-node-linux-large
steps:
- name: Print
run: echo "Hello, baseline!"
- name: Harden Runner
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
with:
egress-policy: audit

- name: Standardize Git Line Endings
run: |
git config --global core.autocrlf false
git config --global core.eol lf

- name: Checkout Code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
ref: ${{ inputs.ref }}

- name: Setup Python
uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
with:
python-version: 3.9

- name: Setup Java
uses: actions/setup-java@8df1039502a15bceb9433410b1a100fbe190c53b # v4.5.0
with:
distribution: ${{ inputs.java-distribution }}
java-version: ${{ inputs.java-version }}

- name: Setup Gradle
uses: gradle/actions/setup-gradle@cc4fc85e6b35bafd578d5ffbc76a5518407e1af0 # v4.2.1
with:
cache-disabled: true

# - 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@6fc4af4b145ae7821d527454aa9bd537d1f2dc5f # v2.1.7
# with:
# workload_identity_provider: "projects/235822363393/locations/global/workloadIdentityPools/hedera-builds-pool/providers/hedera-builds-gh-actions"
# service_account: "[email protected]"

# - name: Setup Google Cloud SDK
# uses: google-github-actions/setup-gcloud@6189d56e4096ee891640bb02ac264be376592d6a # v2.1.2
# 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 "${GRADLE_MANIFEST_PATH}"
cd "${GRADLE_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: Regenerate Manifest
id: regen-manifest
env:
MANIFEST_PATH: ${{ env.GRADLE_MANIFEST_PATH }}/regenerated
run: ${{ env.GRADLE_MANIFEST_GENERATOR }}

- name: Validate Applications
working-directory: ${{ github.workspace }}/server/build/libs
run: sha256sum -c "${GRADLE_MANIFEST_PATH}/applications.sha256"

# - name: Compare Library Manifests
# run: |
# if ! diff -u "${GRADLE_MANIFEST_PATH}/libraries.sha256" "${{ steps.regen-manifest.outputs.libraries }}" >/dev/null 2>&1; then
# echo "::group::Library Manifest Differences"
# diff -u "${GRADLE_MANIFEST_PATH}/libraries.sha256" "${{ steps.regen-manifest.outputs.libraries }}"
# echo "::endgroup::"
# exit 1
# fi
#
# - name: Compare Application Manifests
# run: |
# if ! diff -u "${GRADLE_MANIFEST_PATH}/applications.sha256" "${{ steps.regen-manifest.outputs.applications }}" >/dev/null 2>&1; then
# echo "::group::Application Manifest Differences"
# diff -u "${GRADLE_MANIFEST_PATH}/applications.sha256" "${{ steps.regen-manifest.outputs.applications }}"
# echo "::endgroup::"
# exit 1
# fi
#
# - name: Publish Manifests
# uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
# if: ${{ steps.regen-manifest.conclusion == 'success' && failure() && !cancelled() }}
# with:
# name: Gradle Manifests [${{ join(matrix.os, ', ') }}]
# path: ${{ env.GRADLE_MANIFEST_PATH }}/**
Binary file modified gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Expand Down
2 changes: 1 addition & 1 deletion gradlew
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
Expand Down
Loading
Loading