Skip to content

Commit d0d8f2a

Browse files
ViktorTigerstromguggero
authored andcommitted
lightning-terminal: ensure reproducible releases
This update modifies the release.sh script to ensure that release files are reproducible, generating identical hashes when rebuilt. Previously, the script did not set fixed timestamps for the files, resulting in different hashes across rebuilds. Additionally, the release.sh script has been updated to align more closely with the behavior of the lnd release script, ensuring consistency and coherence across repositories for users.
1 parent 65144f2 commit d0d8f2a

File tree

1 file changed

+79
-12
lines changed

1 file changed

+79
-12
lines changed

release.sh

Lines changed: 79 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,61 @@ POOL_PKG="github.com/lightninglabs/pool"
1717
TAP_PKG="github.com/lightninglabs/taproot-assets"
1818
PACKAGE=lightning-terminal
1919

20+
# Needed for setting file timestamps to get reproducible archives.
21+
BUILD_DATE="2020-01-01 00:00:00"
22+
BUILD_DATE_STAMP="202001010000.00"
23+
24+
# reproducible_tar_gzip creates a reproducible tar.gz file of a directory. This
25+
# includes setting all file timestamps and ownership settings uniformly.
26+
function reproducible_tar_gzip() {
27+
local dir=$1
28+
local tar_cmd=tar
29+
30+
# MacOS has a version of BSD tar which doesn't support setting the --mtime
31+
# flag. We need gnu-tar, or gtar for short to be installed for this script to
32+
# work properly.
33+
tar_version=$(tar --version)
34+
if [[ ! "$tar_version" =~ "GNU tar" ]]; then
35+
if ! command -v "gtar"; then
36+
echo "GNU tar is required but cannot be found!"
37+
echo "On MacOS please run 'brew install gnu-tar' to install gtar."
38+
exit 1
39+
fi
40+
41+
# We have gtar installed, use that instead.
42+
tar_cmd=gtar
43+
fi
44+
45+
# Pin down the timestamp time zone.
46+
export TZ=UTC
47+
48+
find "${dir}" -print0 | LC_ALL=C sort -r -z | $tar_cmd \
49+
"--mtime=${BUILD_DATE}" --no-recursion --null --mode=u+rw,go+r-w,a+X \
50+
--owner=0 --group=0 --numeric-owner -c -T - | gzip -9n > "${dir}.tar.gz"
51+
52+
rm -r "${dir}"
53+
}
54+
55+
# reproducible_zip creates a reproducible zip file of a directory. This
56+
# includes setting all file timestamps.
57+
function reproducible_zip() {
58+
local dir=$1
59+
60+
# Pin down file name encoding and timestamp time zone.
61+
export TZ=UTC
62+
63+
# Set the date of each file in the directory that's about to be packaged to
64+
# the same timestamp and make sure the same permissions are used everywhere.
65+
chmod -R 0755 "${dir}"
66+
touch -t "${BUILD_DATE_STAMP}" "${dir}"
67+
find "${dir}" -print0 | LC_ALL=C sort -r -z | xargs -0r touch \
68+
-t "${BUILD_DATE_STAMP}"
69+
70+
find "${dir}" | LC_ALL=C sort -r | zip -o -X -r -@ "${dir}.zip"
71+
72+
rm -r "${dir}"
73+
}
74+
2075
# green prints one line of green text (if the terminal supports it).
2176
function green() {
2277
echo -e "\e[0;32m${1}\e[0m"
@@ -37,20 +92,27 @@ function build_release() {
3792

3893
green " - Packaging vendor"
3994
go mod vendor
40-
tar -czf vendor.tar.gz vendor
95+
reproducible_tar_gzip vendor
4196

4297
maindir=$PACKAGE-$tag
4398
mkdir -p $maindir
99+
mv vendor.tar.gz "${maindir}/"
44100

45-
cp vendor.tar.gz $maindir/
46-
rm vendor.tar.gz
47-
rm -r vendor
101+
# Don't use tag in source directory, otherwise our file names get too long and
102+
# tar starts to package them non-deterministically.
103+
package_source="${PACKAGE}-source"
48104

49-
package_source="${maindir}/${PACKAGE}-source-${tag}.tar"
50-
git archive -o "${package_source}" HEAD
51-
gzip -f "${package_source}" >"${package_source}.gz"
105+
# The git archive command doesn't support setting timestamps and file
106+
# permissions. That's why we unpack the tar again, then use our reproducible
107+
# method to create the final archive.
108+
git archive -o "${maindir}/${package_source}.tar" HEAD
52109

53110
cd "${maindir}"
111+
mkdir -p ${package_source}
112+
tar -xf "${package_source}.tar" -C ${package_source}
113+
rm "${package_source}.tar"
114+
reproducible_tar_gzip ${package_source}
115+
mv "${package_source}.tar.gz" "${package_source}-$tag.tar.gz"
54116

55117
for i in $sys; do
56118
os=$(echo $i | cut -f1 -d-)
@@ -79,16 +141,21 @@ function build_release() {
79141
env CGO_ENABLED=0 GOOS=$os GOARCH=$arch GOARM=$arm go build -v -trimpath -ldflags="${ldflags}" -tags="${buildtags}" ${TAP_PKG}/cmd/tapcli
80142
popd
81143

144+
# Add the hashes for the individual binaries as well for easy verification
145+
# of a single installed binary.
146+
shasum -a 256 "${dir}/"* >> "manifest-$tag.txt"
147+
82148
if [[ $os == "windows" ]]; then
83-
zip -r "${dir}.zip" "${dir}"
149+
reproducible_zip "${dir}"
84150
else
85-
tar -cvzf "${dir}.tar.gz" "${dir}"
151+
reproducible_tar_gzip "${dir}"
86152
fi
87-
88-
rm -r "${dir}"
89153
done
90154

91-
shasum -a 256 * >manifest-$tag.txt
155+
# Add the hash of the packages too, then sort by the second column (name).
156+
shasum -a 256 lightning-terminal-* vendor* >> "manifest-$tag.txt"
157+
LC_ALL=C sort -k2 -o "manifest-$tag.txt" "manifest-$tag.txt"
158+
cat "manifest-$tag.txt"
92159
}
93160

94161
# usage prints the usage of the whole script.

0 commit comments

Comments
 (0)