|
| 1 | +#!/usr/bin/env bash |
| 2 | +# |
| 3 | +# Licensed to the Apache Software Foundation (ASF) under one |
| 4 | +# or more contributor license agreements. See the NOTICE file |
| 5 | +# distributed with this work for additional information |
| 6 | +# regarding copyright ownership. The ASF licenses this file |
| 7 | +# to you under the Apache License, Version 2.0 (the |
| 8 | +# "License"); you may not use this file except in compliance |
| 9 | +# with the License. You may obtain a copy of the License at |
| 10 | +# |
| 11 | +# https://www.apache.org/licenses/LICENSE-2.0 |
| 12 | +# |
| 13 | +# Unless required by applicable law or agreed to in writing, |
| 14 | +# software distributed under the License is distributed on an |
| 15 | +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| 16 | +# KIND, either express or implied. See the License for the |
| 17 | +# specific language governing permissions and limitations |
| 18 | +# under the License. |
| 19 | +# |
| 20 | +# |
| 21 | +# test-reproducible-builds.sh - Verify that the Geb build is reproducible. |
| 22 | +# |
| 23 | +# Required by ASF Security policy for projects that build/sign on CI: |
| 24 | +# https://cwiki.apache.org/confluence/display/SECURITY/Reproducible+Builds |
| 25 | +# |
| 26 | +# Builds all jar artifacts twice from a clean state and compares SHA-256 |
| 27 | +# checksums. SOURCE_DATE_EPOCH is set from the last git commit to ensure |
| 28 | +# timestamp-dependent outputs are deterministic. |
| 29 | +# |
| 30 | +# Any differing jars are preserved under etc/bin/results/ for inspection. |
| 31 | +# That directory is git-ignored. |
| 32 | +# |
| 33 | +# Must be run from within a Geb git checkout. Takes no arguments. |
| 34 | +# |
| 35 | +# Usage: |
| 36 | +# etc/bin/test-reproducible-builds.sh |
| 37 | +# |
| 38 | + |
| 39 | +set -euo pipefail |
| 40 | + |
| 41 | +export SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct) |
| 42 | + |
| 43 | +CWD=$(pwd) |
| 44 | +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) |
| 45 | +cd "${SCRIPT_DIR}/../.." |
| 46 | + |
| 47 | +rm -rf "${SCRIPT_DIR}/results" || true |
| 48 | +mkdir -p "${SCRIPT_DIR}/results/first" |
| 49 | +mkdir -p "${SCRIPT_DIR}/results/second" |
| 50 | + |
| 51 | +echo "================================================================" |
| 52 | +echo " Testing Reproducible Builds for Apache Groovy Geb" |
| 53 | +echo " SOURCE_DATE_EPOCH=${SOURCE_DATE_EPOCH}" |
| 54 | +echo "================================================================" |
| 55 | +echo "" |
| 56 | + |
| 57 | +echo "Cleaning project..." |
| 58 | +git clean -xdf --exclude='etc/bin' --exclude='.idea' --exclude='.gradle' |
| 59 | + |
| 60 | +echo "" |
| 61 | +echo "--- First build ---" |
| 62 | +./gradlew jar --rerun-tasks --no-build-cache |
| 63 | +find . -path ./etc -prune -o -type f -path '*/build/libs/*.jar' -print0 | while IFS= read -r -d '' f; do |
| 64 | + shasum -a 256 "$f" |
| 65 | +done | sort > "${SCRIPT_DIR}/results/first.txt" |
| 66 | +find . -path ./etc -prune -o -type f -path '*/build/libs/*.jar' -print0 | xargs -0 -I{} cp --parents {} "${SCRIPT_DIR}/results/first/" 2>/dev/null || \ |
| 67 | + find . -path ./etc -prune -o -type f -path '*/build/libs/*.jar' -print0 | while IFS= read -r -d '' f; do |
| 68 | + mkdir -p "${SCRIPT_DIR}/results/first/$(dirname "$f")" |
| 69 | + cp "$f" "${SCRIPT_DIR}/results/first/$f" |
| 70 | + done |
| 71 | + |
| 72 | +echo "" |
| 73 | +echo "--- Cleaning for second build ---" |
| 74 | +git clean -xdf --exclude='etc/bin' --exclude='.idea' --exclude='.gradle' |
| 75 | + |
| 76 | +echo "" |
| 77 | +echo "--- Second build ---" |
| 78 | +./gradlew jar --rerun-tasks --no-build-cache |
| 79 | +find . -path ./etc -prune -o -type f -path '*/build/libs/*.jar' -print0 | while IFS= read -r -d '' f; do |
| 80 | + shasum -a 256 "$f" |
| 81 | +done | sort > "${SCRIPT_DIR}/results/second.txt" |
| 82 | +find . -path ./etc -prune -o -type f -path '*/build/libs/*.jar' -print0 | while IFS= read -r -d '' f; do |
| 83 | + mkdir -p "${SCRIPT_DIR}/results/second/$(dirname "$f")" |
| 84 | + cp "$f" "${SCRIPT_DIR}/results/second/$f" |
| 85 | + done |
| 86 | + |
| 87 | +echo "" |
| 88 | +echo "--- Comparing builds ---" |
| 89 | +cd "${SCRIPT_DIR}/results" |
| 90 | +if diff -u first.txt second.txt > diff.txt 2>&1; then |
| 91 | + echo "✅ All jar artifacts are identical between the two builds." |
| 92 | + rm -f diff.txt |
| 93 | +else |
| 94 | + echo "❌ Some jar artifacts differ between builds:" |
| 95 | + cat diff.txt |
| 96 | + echo "" |
| 97 | + echo "Differing artifacts have been preserved in:" |
| 98 | + echo " ${SCRIPT_DIR}/results/first/" |
| 99 | + echo " ${SCRIPT_DIR}/results/second/" |
| 100 | +fi |
| 101 | + |
| 102 | +cd "$CWD" |
0 commit comments