Skip to content

Commit ca4a647

Browse files
authored
Merge pull request #185 from freedomofpress/182-build-tarballs-dynamically
Builds source tarballs dynamically
2 parents d58dfcf + bca2d57 commit ca4a647

File tree

1 file changed

+68
-6
lines changed

1 file changed

+68
-6
lines changed

scripts/build-debianpackage

Lines changed: 68 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,29 +27,93 @@ TOP_BUILDDIR="$HOME/debbuild/packaging"
2727
mkdir -p "$TOP_BUILDDIR"
2828
rm -rf "${TOP_BUILDDIR:?}/${PKG_NAME}"
2929
mkdir -p "${TOP_BUILDDIR}/${PKG_NAME}"
30+
# Move changelog into place (we have separate changelogs for each platform)
31+
PLATFORM="$(lsb_release -sc)"
3032

3133
# Validate required args.
3234
if [[ -z "${PKG_NAME:-}" ]]; then
3335
echo "Set PKG_NAME of the build";
3436
exit 1
3537
fi
3638

39+
40+
# Look up most recent release from GitHub repo
41+
function find_latest_version() {
42+
repo_url="https://github.com/freedomofpress/${PKG_NAME}/releases"
43+
curl -s "$repo_url" \
44+
| perl -nE '$_ =~ m#/releases/tag/(v?[\d\.]+)\"# and say $1' \
45+
| head -n 1
46+
}
47+
3748
if [[ -z "${PKG_VERSION:-}" ]]; then
38-
echo "Set PKG_VERSION of the build";
39-
exit 1
49+
echo "PKG_VERSION not set, inferring from recent releases..."
50+
PKG_VERSION="$(find_latest_version)"
51+
if [[ -z "$PKG_VERSION" ]]; then
52+
echo "Failed to infer version"
53+
exit 1
54+
else
55+
echo "Using PKG_VERSION: $PKG_VERSION"
56+
fi
4057
fi
4158

4259
# Copy over the debian directory (including new changelog) from repo
4360
cp -r "$CUR_DIR/$PKG_NAME/" "$TOP_BUILDDIR/"
4461

62+
# Ensures that a given git tag is signed with the prod release key
63+
# If "rc" is in the tag name, this will fail.
64+
function verify_git_tag() {
65+
local d
66+
local t
67+
d="$1"
68+
t="$2"
69+
prod_fingerprint="22245C81E3BAEB4138B36061310F561200F4AD77"
70+
if ! git -C "$build_dir" tag --verify "$PKG_VERSION" 2>&1 \
71+
| grep -q -F "using RSA key $prod_fingerprint" ; then
72+
echo "Failed to verify $PKG_VERSION, not signed with $prod_fingerprint" >&2
73+
exit 2
74+
fi
75+
}
76+
77+
# Dynamically generate a tarball, from the Python source code,
78+
# that is byte-for-byte reproducible. Infers timestamp
79+
# from the changelog, same as for the deb package.
80+
function build_source_tarball() {
81+
repo_url="https://github.com/freedomofpress/${PKG_NAME}"
82+
build_dir="/tmp/${PKG_NAME}"
83+
rm -rf "$build_dir"
84+
git clone "$repo_url" "$build_dir"
85+
86+
# Verify tag, using only the prod key
87+
verify_git_tag "$build_dir" "$PKG_VERSION"
88+
89+
# Tag is verified, proceed with checkout
90+
git -C "$build_dir" checkout "$PKG_VERSION"
91+
(cd "$build_dir" && LC_ALL="C.UTF-8" python setup.py sdist)
92+
93+
# Initial tarball will contain timestamps from NOW, let's repack
94+
# with timestamps from the changelog, which is static.
95+
raw_tarball="$(find "${build_dir}/dist/" | grep -P '\.tar.gz$' | head -n1)"
96+
dch_time="$(date "+%Y-%m-%d %H:%M:%S %z" -d@$(dpkg-parsechangelog --file $PKG_NAME/debian/changelog-$PLATFORM -STimestamp)) "
97+
(cd "$build_dir" && tar -xzf "dist/$(basename $raw_tarball)")
98+
tarball_basename="$(basename "$raw_tarball")"
99+
# Repack with tar only, so env vars are respected
100+
(cd "$build_dir" && tar -cf "${tarball_basename%.gz}" --mode=go=rX,u+rw,a-s --mtime="$dch_time" --sort=name --owner=root:0 --group=root:0 "${tarball_basename%.tar.gz}" 1>&2)
101+
# Then gzip it separately, so we can pass args
102+
(cd "$build_dir" && gzip --no-name "${tarball_basename%.gz}")
103+
(cd "$build_dir" && mv "$tarball_basename" dist/)
104+
echo "$raw_tarball"
105+
}
106+
45107
# If the package is contained in the list, it should be a python package. In
46108
# that case, we should extract tarball, and validate wheel hashes.
47109
if [[ "${PKG_NAME}" =~ ^(securedrop-client|securedrop-proxy|securedrop-export|securedrop-log)$ ]]; then
48110
echo "${PKG_NAME} is a Python package"
49111

50112
if [[ -z "${PKG_PATH:-}" ]]; then
51-
# Try to find tarball in a reasonable location
52-
candidate_pkg_path="$(realpath "${CUR_DIR}/../${PKG_NAME}/dist/${PKG_NAME}-${PKG_VERSION}.tar.gz")"
113+
# Build from source
114+
echo "PKG_PATH not set, building from source (version $PKG_VERSION)..."
115+
build_source_tarball
116+
candidate_pkg_path="$(find /tmp/$PKG_NAME/dist -type f -iname '*.tar.gz')"
53117
if [[ -f "$candidate_pkg_path" ]]; then
54118
PKG_PATH="$candidate_pkg_path"
55119
echo "Found tarball at $PKG_PATH, override with PKG_PATH..."
@@ -80,8 +144,6 @@ fi
80144

81145
printf "Building package '%s' from version '%s'...\\n" "$PKG_NAME" "$PKG_VERSION"
82146

83-
# Move changelog into place (we have separate changelogs for each platform)
84-
PLATFORM="$(lsb_release -sc)"
85147
echo "$TOP_BUILDDIR/$PKG_NAME/"
86148
mv "$TOP_BUILDDIR/$PKG_NAME/debian/changelog-$PLATFORM" "$TOP_BUILDDIR/$PKG_NAME/debian/changelog"
87149

0 commit comments

Comments
 (0)