Skip to content

Commit 4cc35da

Browse files
committed
Rewrite guix-{attest,verify} for new hier
1 parent 28a9c9b commit 4cc35da

File tree

2 files changed

+132
-110
lines changed

2 files changed

+132
-110
lines changed

contrib/guix/guix-attest

Lines changed: 63 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -99,24 +99,34 @@ fi
9999
# We should be able to find at least one output
100100
################
101101

102-
echo "Looking for build output directories in ${OUTDIR_BASE}"
102+
echo "Looking for build output SHA256SUMS fragments in ${OUTDIR_BASE}"
103103

104104
shopt -s nullglob
105-
OUTDIRS=( "${OUTDIR_BASE}"/* ) # This expands to an array of directories...
105+
OUTDIRS=( "$OUTDIR_BASE"/*/SHA256SUMS.part ) # This expands to an array of directories...
106106
shopt -u nullglob
107107

108+
noncodesigned_fragments=()
109+
codesigned_fragments=()
110+
108111
if (( ${#OUTDIRS[@]} )); then
109-
echo "Found build output directories:"
112+
echo "Found build output SHA256SUMS fragments:"
110113
for outdir in "${OUTDIRS[@]}"; do
111114
echo " '$outdir'"
115+
case "$outdir" in
116+
"$OUTDIR_BASE"/*-codesigned/SHA256SUMS.part)
117+
codesigned_fragments+=("$outdir")
118+
;;
119+
*)
120+
noncodesigned_fragments+=("$outdir")
121+
;;
122+
esac
112123
done
113124
echo
114125
else
115-
echo "ERR: Could not find any build output directories in ${OUTDIR_BASE}"
126+
echo "ERR: Could not find any build output SHA256SUMS fragments in ${OUTDIR_BASE}"
116127
exit 1
117128
fi
118129

119-
120130
##############
121131
## Attest ##
122132
##############
@@ -126,82 +136,65 @@ fi
126136
# HOST: The output directory being attested
127137
#
128138
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"
139+
basename "$(dirname "$1")"
138140
}
139141

140-
# Accumulate a list of signature directories that already exist...
141-
outdirs_already_attested_to=()
142-
143142
echo "Attesting to build outputs for version: '${VERSION}'"
144143
echo ""
145144

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")
145+
outsigdir="$GUIX_SIGS_REPO/$VERSION/$signer_name"
146+
mkdir -p "$outsigdir"
147+
(
148+
cd "$outsigdir"
149+
150+
if [ -e "noncodesigned.SHA256SUMS" ]; then
151+
echo "noncodesigned.SHA256SUMS already exists, using..."
152+
elif (( ${#noncodesigned_fragments[@]} )); then
153+
cat "${noncodesigned_fragments[@]}" \
154+
| sort -u \
155+
| sort -k2 \
156+
> noncodesigned.SHA256SUMS
158157
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
158+
echo "no noncodesigned outputs found"
159+
fi
171160

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
161+
if [ -e noncodesigned.SHA256SUMS ]; then
162+
# noncodesigned.SHA256SUMS already exists, or was produced, let's sanity
163+
# check it.
164+
( cd "$OUTDIR_BASE"; sha256sum -c "$outsigdir"/noncodesigned.SHA256SUMS )
165+
166+
# Now produce all.SHA256SUMS manifest
167+
if [ -e "all.SHA256SUMS" ]; then
168+
echo "all.SHA256SUMS already there!"
169+
elif (( ${#codesigned_fragments[@]} )); then
170+
cat "${OUTDIRS[@]}" \
171+
| sort -u \
172+
| sort -k2 \
173+
> all.SHA256SUMS
184174
else
185-
echo "${outname}: Not signing SHA256SUMS as \$NO_SIGN is not empty"
175+
echo "no codesigned outputs found"
186176
fi
187-
echo ""
188177

189-
trap - ERR # Reset ERR trap
178+
if [ -e all.SHA256SUMS ]; then
179+
( cd "$OUTDIR_BASE"; sha256sum -c "$outsigdir"/all.SHA256SUMS )
180+
fi
190181
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
196182

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:
200183

201-
EOF
202-
for outdir in "${outdirs_already_attested_to[@]}"; do
203-
echo " '${outdir}'"
204-
echo " Corresponds to: '$(out_sig_dir "$outdir")'"
184+
if [ -z "$NO_SIGN" ]; then
185+
echo "Signing SHA256SUMS to produce SHA256SUMS.asc"
186+
for i in *.SHA256SUMS; do
187+
if [ ! -e "$i".asc ]; then
188+
gpg --detach-sign \
189+
--local-user "$gpg_key_name" \
190+
--armor \
191+
--output "$i".asc "$i"
192+
else
193+
echo "Signature already there"
194+
fi
195+
done
196+
else
197+
echo "Not signing SHA256SUMS as \$NO_SIGN is not empty"
198+
fi
205199
echo ""
206-
done
207-
fi
200+
)

contrib/guix/guix-verify

Lines changed: 69 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -56,58 +56,87 @@ cmd_usage
5656
exit 1
5757
fi
5858

59-
################
60-
# We should be able to find at least one output
61-
################
59+
##############
60+
## Verify ##
61+
##############
6262

6363
OUTSIGDIR_BASE="${GUIX_SIGS_REPO}/${VERSION}"
64-
echo "Looking for output signature directories in '${OUTSIGDIR_BASE}'"
64+
echo "Looking for signature directories in '${OUTSIGDIR_BASE}'"
65+
echo ""
66+
67+
# Usage: verify compare_manifest current_manifest
68+
verify() {
69+
local compare_manifest="$1"
70+
local current_manifest="$2"
71+
if ! gpg --quiet --batch --verify "$current_manifest".asc "$current_manifest" 1>&2; then
72+
echo "ERR: Failed to verify GPG signature in '${current_manifest}'"
73+
echo ""
74+
echo "Hint: Either the signature is invalid or the public key is missing"
75+
echo ""
76+
elif ! diff --report-identical "$compare_manifest" "$current_manifest" 1>&2; then
77+
echo "ERR: The SHA256SUMS attestation in these two directories differ:"
78+
echo " '${compare_manifest}'"
79+
echo " '${current_manifest}'"
80+
echo ""
81+
else
82+
echo "Verified: '${current_manifest}'"
83+
echo ""
84+
fi
85+
}
6586

6687
shopt -s nullglob
67-
OUTSIGDIRS=( "$OUTSIGDIR_BASE"/* ) # This expands to an array of directories...
88+
all_noncodesigned=( "$OUTSIGDIR_BASE"/*/noncodesigned.SHA256SUMS )
6889
shopt -u nullglob
6990

70-
if (( ${#OUTSIGDIRS[@]} )); then
71-
echo "Found output signature directories:"
72-
for outsigdir in "${OUTSIGDIRS[@]}"; do
73-
echo " '$outsigdir'"
91+
echo "--------------------"
92+
echo ""
93+
if (( ${#all_noncodesigned[@]} )); then
94+
compare_noncodesigned="${all_noncodesigned[0]}"
95+
96+
for current_manifest in "${all_noncodesigned[@]}"; do
97+
verify "$compare_noncodesigned" "$current_manifest"
7498
done
75-
echo
99+
100+
echo "DONE: Checking output signatures for noncodesigned.SHA256SUMS"
101+
echo ""
76102
else
77-
echo "ERR: Could not find any output signature directories in ${OUTSIGDIR_BASE}"
78-
exit 1
103+
echo "WARN: No signature directories with noncodesigned.SHA256SUMS found"
104+
echo ""
79105
fi
80106

107+
shopt -s nullglob
108+
all_all=( "$OUTSIGDIR_BASE"/*/all.SHA256SUMS )
109+
shopt -u nullglob
81110

82-
##############
83-
## Verify ##
84-
##############
111+
echo "--------------------"
112+
echo ""
113+
if (( ${#all_all[@]} )); then
114+
compare_all="${all_all[0]}"
85115

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
116+
for current_manifest in "${all_all[@]}"; do
117+
verify "$compare_all" "$current_manifest"
109118
done
110-
echo "DONE: Checking output signatures for $(basename "$outsigdir")"
119+
120+
# Sanity check: there should be no entries that exist in
121+
# noncodesigned.SHA256SUMS that doesn't exist in all.SHA256SUMS
122+
if [[ "$(comm -23 <(sort "$compare_noncodesigned") <(sort "$compare_all") | wc -c)" -ne 0 ]]; then
123+
echo "ERR: There are unique lines in noncodesigned.SHA256SUMS which"
124+
echo " do not exist in all.SHA256SUMS, something went very wrong."
125+
exit 1
126+
fi
127+
128+
echo "DONE: Checking output signatures for all.SHA256SUMS"
111129
echo ""
130+
else
131+
echo "WARN: No signature directories with all.SHA256SUMS found"
132+
echo ""
133+
fi
134+
135+
echo "===================="
136+
echo ""
137+
if (( ${#all_noncodesigned[@]} + ${#all_all[@]} == 0 )); then
138+
echo "ERR: Unable to perform any verifications as no signature directories"
139+
echo " were found"
112140
echo ""
113-
done
141+
exit 1
142+
fi

0 commit comments

Comments
 (0)