Skip to content

Commit 01624a7

Browse files
committed
Merge bitcoin/bitcoin#21462: guix: Add guix-{attest,verify} scripts
d420e5c guix-attest: Avoid incomplete sigdirs with ERR traps (Carl Dong) feda2c8 guix: Skip attesting to dist-archive (Carl Dong) d522d80 guix: Attest to inputs in inputs.SHA256SUMS (Carl Dong) f9e2960 guix: Construct $OUTDIR in ${DISTSRC}/output (Carl Dong) 022abc8 guix: Minor quoting fix in libexec/build.sh (Carl Dong) c83c4fa guix-attest: Allow skipping GPG signing with NO_SIGN (Carl Dong) 0e1c2e4 guix-attest: Use ascii-armor signatures (Carl Dong) b5fd89c guix-attest: Only use cross-platform flags for find+xargs (Carl Dong) 5926432 guix: Add guix-verify script (Carl Dong) 30daf76 guix: Add guix-attest script (Carl Dong) Pull request description: Adds replacements for `gsign` and `gverify`. Personally I'm not a big fan of using the word "sign" as it's been used to refer to both codesigning and GPG signing. ACKs for top commit: laanwj: Code review and tested ACK d420e5c Tree-SHA512: 93d82d201f4596eaea0e3825aa55b013dfb91790e6ccee79893833d37921513d7b4e735f0641103e1e2ea8308abe4cb6218b73160924708802f2e0e3f7f6caf1
2 parents 2e30e32 + d420e5c commit 01624a7

File tree

3 files changed

+343
-1
lines changed

3 files changed

+343
-1
lines changed

contrib/guix/guix-attest

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
#!/usr/bin/env bash
2+
export LC_ALL=C
3+
set -e -o pipefail
4+
5+
# Source the common prelude, which:
6+
# 1. Checks if we're at the top directory of the Bitcoin Core repository
7+
# 2. Defines a few common functions and variables
8+
#
9+
# shellcheck source=libexec/prelude.bash
10+
source "$(dirname "${BASH_SOURCE[0]}")/libexec/prelude.bash"
11+
12+
13+
###################
14+
## Sanity Checks ##
15+
###################
16+
17+
################
18+
# Required non-builtin commands should be invokable
19+
################
20+
21+
check_tools cat env basename mkdir xargs find
22+
if [ -z "$NO_SIGN" ]; then
23+
check_tools gpg
24+
fi
25+
26+
################
27+
# Required env vars should be non-empty
28+
################
29+
30+
cmd_usage() {
31+
cat <<EOF
32+
Synopsis:
33+
34+
env GUIX_SIGS_REPO=<path/to/guix.sigs> \\
35+
SIGNER=GPG_KEY_NAME[=SIGNER_NAME] \\
36+
[ NO_SIGN=1 ]
37+
./contrib/guix/guix-attest
38+
39+
Example w/o overriding signing name:
40+
41+
env GUIX_SIGS_REPO=/home/achow101/guix.sigs \\
42+
SIGNER=achow101 \\
43+
./contrib/guix/guix-attest
44+
45+
Example overriding signing name:
46+
47+
env GUIX_SIGS_REPO=/home/dongcarl/guix.sigs \\
48+
SIGNER=0x96AB007F1A7ED999=dongcarl \\
49+
./contrib/guix/guix-attest
50+
51+
Example w/o signing, just creating SHA256SUMS:
52+
53+
env GUIX_SIGS_REPO=/home/achow101/guix.sigs \\
54+
SIGNER=achow101 \\
55+
NO_SIGN=1 \\
56+
./contrib/guix/guix-attest
57+
58+
EOF
59+
}
60+
61+
if [ -z "$GUIX_SIGS_REPO" ] || [ -z "$SIGNER" ]; then
62+
cmd_usage
63+
exit 1
64+
fi
65+
66+
################
67+
# GUIX_SIGS_REPO should exist as a directory
68+
################
69+
70+
if [ ! -d "$GUIX_SIGS_REPO" ]; then
71+
cat << EOF
72+
ERR: The specified GUIX_SIGS_REPO is not an existent directory:
73+
74+
'$GUIX_SIGS_REPO'
75+
76+
Hint: Please clone the guix.sigs repository and point to it with the
77+
GUIX_SIGS_REPO environment variable.
78+
79+
EOF
80+
cmd_usage
81+
exit 1
82+
fi
83+
84+
################
85+
# The key specified in SIGNER should be usable
86+
################
87+
88+
IFS='=' read -r gpg_key_name signer_name <<< "$SIGNER"
89+
if [ -z "${signer_name}" ]; then
90+
signer_name="$gpg_key_name"
91+
fi
92+
93+
if [ -z "$NO_SIGN" ] && ! gpg --dry-run --list-secret-keys "${gpg_key_name}" >/dev/null 2>&1; then
94+
echo "ERR: GPG can't seem to find any key named '${gpg_key_name}'"
95+
exit 1
96+
fi
97+
98+
################
99+
# We should be able to find at least one output
100+
################
101+
102+
echo "Looking for build output directories in ${OUTDIR_BASE}"
103+
104+
shopt -s nullglob
105+
OUTDIRS=( "${OUTDIR_BASE}"/* ) # This expands to an array of directories...
106+
shopt -u nullglob
107+
108+
if (( ${#OUTDIRS[@]} )); then
109+
echo "Found build output directories:"
110+
for outdir in "${OUTDIRS[@]}"; do
111+
echo " '$outdir'"
112+
done
113+
echo
114+
else
115+
echo "ERR: Could not find any build output directories in ${OUTDIR_BASE}"
116+
exit 1
117+
fi
118+
119+
120+
##############
121+
## Attest ##
122+
##############
123+
124+
# Usage: out_name $outdir
125+
#
126+
# HOST: The output directory being attested
127+
#
128+
out_name() {
129+
basename "$1"
130+
}
131+
132+
# Usage: out_sig_dir $outdir
133+
#
134+
# outdir: The output directory being attested
135+
#
136+
out_sig_dir() {
137+
echo "$GUIX_SIGS_REPO/$VERSION/$(out_name "$1")/$signer_name"
138+
}
139+
140+
# Accumulate a list of signature directories that already exist...
141+
outdirs_already_attested_to=()
142+
143+
echo "Attesting to build outputs for version: '${VERSION}'"
144+
echo ""
145+
146+
# MAIN LOGIC: Loop through each output for VERSION and attest to output in
147+
# GUIX_SIGS_REPO as SIGNER, if attestation does not exist
148+
for outdir in "${OUTDIRS[@]}"; do
149+
if [ -e "${outdir}/SKIPATTEST.TAG" ]; then
150+
echo "${outname}: SKIPPING: Output directory marked with SKIPATTEST.TAG file"
151+
continue
152+
fi
153+
outname="$(out_name "$outdir")"
154+
outsigdir="$(out_sig_dir "$outdir")"
155+
if [ -e "$outsigdir" ]; then
156+
echo "${outname}: SKIPPING: Signature directory already exists in the specified guix.sigs repository"
157+
outdirs_already_attested_to+=("$outdir")
158+
else
159+
# Clean up incomplete sigdir if something fails (likely gpg)
160+
trap 'rm -rf "$outsigdir"' ERR
161+
162+
mkdir -p "$outsigdir"
163+
164+
(
165+
cd "$outdir"
166+
167+
if [ -e inputs.SHA256SUMS ]; then
168+
echo "${outname}: Including existent input SHA256SUMS"
169+
cat inputs.SHA256SUMS >> "$outsigdir"/SHA256SUMS
170+
fi
171+
172+
echo "${outname}: Hashing build outputs to produce SHA256SUMS"
173+
files="$(find -L . -type f ! -iname '*.SHA256SUMS')"
174+
if [ -n "$files" ]; then
175+
cut -c3- <<< "$files" | env LC_ALL=C sort | xargs sha256sum >> "$outsigdir"/SHA256SUMS
176+
else
177+
echo "ERR: ${outname}: No outputs found in '${outdir}'"
178+
exit 1
179+
fi
180+
)
181+
if [ -z "$NO_SIGN" ]; then
182+
echo "${outname}: Signing SHA256SUMS to produce SHA256SUMS.asc"
183+
gpg --detach-sign --local-user "$gpg_key_name" --armor --output "$outsigdir"/SHA256SUMS.asc "$outsigdir"/SHA256SUMS
184+
else
185+
echo "${outname}: Not signing SHA256SUMS as \$NO_SIGN is not empty"
186+
fi
187+
echo ""
188+
189+
trap - ERR # Reset ERR trap
190+
fi
191+
done
192+
193+
if (( ${#outdirs_already_attested_to[@]} )); then
194+
# ...so that we can print them out nicely in a warning message
195+
cat << EOF
196+
197+
WARN: Signature directories from '$signer_name' already exist in the specified
198+
guix.sigs repository for the following output directories and were
199+
skipped:
200+
201+
EOF
202+
for outdir in "${outdirs_already_attested_to[@]}"; do
203+
echo " '${outdir}'"
204+
echo " Corresponds to: '$(out_sig_dir "$outdir")'"
205+
echo ""
206+
done
207+
fi

contrib/guix/guix-verify

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
#!/usr/bin/env bash
2+
export LC_ALL=C
3+
set -e -o pipefail
4+
5+
# Source the common prelude, which:
6+
# 1. Checks if we're at the top directory of the Bitcoin Core repository
7+
# 2. Defines a few common functions and variables
8+
#
9+
# shellcheck source=libexec/prelude.bash
10+
source "$(dirname "${BASH_SOURCE[0]}")/libexec/prelude.bash"
11+
12+
13+
###################
14+
## Sanity Checks ##
15+
###################
16+
17+
################
18+
# Required non-builtin commands should be invokable
19+
################
20+
21+
check_tools cat diff gpg
22+
23+
################
24+
# Required env vars should be non-empty
25+
################
26+
27+
cmd_usage() {
28+
cat <<EOF
29+
Synopsis:
30+
31+
env GUIX_SIGS_REPO=<path/to/guix.sigs> ./contrib/guix/guix-verify
32+
33+
EOF
34+
}
35+
36+
if [ -z "$GUIX_SIGS_REPO" ]; then
37+
cmd_usage
38+
exit 1
39+
fi
40+
41+
################
42+
# GUIX_SIGS_REPO should exist as a directory
43+
################
44+
45+
if [ ! -d "$GUIX_SIGS_REPO" ]; then
46+
cat << EOF
47+
ERR: The specified GUIX_SIGS_REPO is not an existent directory:
48+
49+
'$GUIX_SIGS_REPO'
50+
51+
Hint: Please clone the guix.sigs repository and point to it with the
52+
GUIX_SIGS_REPO environment variable.
53+
54+
EOF
55+
cmd_usage
56+
exit 1
57+
fi
58+
59+
################
60+
# We should be able to find at least one output
61+
################
62+
63+
OUTSIGDIR_BASE="${GUIX_SIGS_REPO}/${VERSION}"
64+
echo "Looking for output signature directories in '${OUTSIGDIR_BASE}'"
65+
66+
shopt -s nullglob
67+
OUTSIGDIRS=( "$OUTSIGDIR_BASE"/* ) # This expands to an array of directories...
68+
shopt -u nullglob
69+
70+
if (( ${#OUTSIGDIRS[@]} )); then
71+
echo "Found output signature directories:"
72+
for outsigdir in "${OUTSIGDIRS[@]}"; do
73+
echo " '$outsigdir'"
74+
done
75+
echo
76+
else
77+
echo "ERR: Could not find any output signature directories in ${OUTSIGDIR_BASE}"
78+
exit 1
79+
fi
80+
81+
82+
##############
83+
## Verify ##
84+
##############
85+
86+
# MAIN LOGIC: Loop through each output for VERSION and check that the SHA256SUMS
87+
# and SHA256SUMS.asc file match between signers, using the first
88+
# available signer as the arbitrary comparison base.
89+
for outsigdir in "${OUTSIGDIRS[@]}"; do
90+
echo "BEGIN: Checking output signatures for $(basename "$outsigdir")"
91+
echo ""
92+
signer_dirs=( "$outsigdir"/* ) # This expands to an array of directories...
93+
compare_signer_dir="${signer_dirs[0]}" # ...we just want the first one
94+
for current_signer_dir in "${signer_dirs[@]}"; do
95+
if ! gpg --quiet --batch --verify "$current_signer_dir"/SHA256SUMS.asc "$current_signer_dir"/SHA256SUMS; then
96+
echo "ERR: Failed to verify GPG signature in '${current_signer_dir}/SHA256SUMS.asc'"
97+
echo ""
98+
echo "Hint: Either the signature is invalid or the public key is missing"
99+
echo ""
100+
elif ! diff --report-identical "$compare_signer_dir"/SHA256SUMS "$current_signer_dir"/SHA256SUMS; then
101+
echo "ERR: The SHA256SUMS attestation in these two directories differ:"
102+
echo " '${compare_signer_dir}'"
103+
echo " '${current_signer_dir}'"
104+
echo ""
105+
else
106+
echo "Verified: '${current_signer_dir}'"
107+
echo ""
108+
fi
109+
done
110+
echo "DONE: Checking output signatures for $(basename "$outsigdir")"
111+
echo ""
112+
echo ""
113+
done

contrib/guix/libexec/build.sh

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ Required environment variables as seen inside the container:
3333
OUTDIR: ${OUTDIR:?not set}
3434
EOF
3535

36+
ACTUAL_OUTDIR="${OUTDIR}"
37+
OUTDIR="${DISTSRC}/output"
38+
3639
#####################
3740
# Environment Setup #
3841
#####################
@@ -224,9 +227,25 @@ GIT_ARCHIVE="${DIST_ARCHIVE_BASE}/${DISTNAME}.tar.gz"
224227
# Create the source tarball if not already there
225228
if [ ! -e "$GIT_ARCHIVE" ]; then
226229
mkdir -p "$(dirname "$GIT_ARCHIVE")"
230+
touch "${DIST_ARCHIVE_BASE}"/SKIPATTEST.TAG
227231
git archive --prefix="${DISTNAME}/" --output="$GIT_ARCHIVE" HEAD
228232
fi
229233

234+
# tmpdir="$(mktemp -d)"
235+
# (
236+
# cd "$tmpdir"
237+
# mkdir -p inputs
238+
# ln -sf --target-directory=inputs "$GIT_ARCHIVE"
239+
240+
# mkdir -p "$OUTDIR"
241+
# find -L inputs -type f -print0 | xargs -0 sha256sum > "${OUTDIR}/inputs.SHA256SUMS"
242+
# )
243+
244+
mkdir -p "$OUTDIR"
245+
cat << EOF > "$OUTDIR"/inputs.SHA256SUMS
246+
$(sha256sum "$GIT_ARCHIVE" | cut -d' ' -f1) inputs/$(basename "$GIT_ARCHIVE")
247+
EOF
248+
230249
###########################
231250
# Binary Tarball Building #
232251
###########################
@@ -292,7 +311,8 @@ mkdir -p "$DISTSRC"
292311
# version symbols for Linux distro back-compatibility.
293312
make -C src --jobs=1 check-symbols ${V:+V=1}
294313

295-
mkdir -p ${OUTDIR}
314+
mkdir -p "$OUTDIR"
315+
296316
# Make the os-specific installers
297317
case "$HOST" in
298318
*mingw*)
@@ -427,3 +447,5 @@ mkdir -p "$DISTSRC"
427447
;;
428448
esac
429449
) # $DISTSRC
450+
451+
mv --no-target-directory "$OUTDIR" "$ACTUAL_OUTDIR"

0 commit comments

Comments
 (0)