build: remove dist/ when a release build fails (closes #333)
A failed release build no longer leaves a complete, loadable debug bundle in dist/ whose every wallet uses the publicly committed test recovery phrase. Each step of the release build runs through script/discard-dist-on-failure, which removes dist/ on failure, says on stderr that it did and why, and returns the step's own status. build-debug is deliberately unwrapped. script/verify-build is untouched.
This commit was merged in pull request #341.
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
#!/bin/sh
|
||||
# script/test-verify-build: exercise every failure mode of
|
||||
# script/verify-build. Our own extension to scripts-to-rule-them-all, run
|
||||
# from script/check so make check covers it.
|
||||
# script/verify-build, and what make build does with dist/ after one of them
|
||||
# (script/discard-dist-on-failure). Our own extension to
|
||||
# scripts-to-rule-them-all, run from script/check so make check covers it.
|
||||
#
|
||||
# Why this exists: verify-build is the build-integrity guard, and four separate
|
||||
# reviews of it each found a fresh vacuous pass — the grep exit-2 conflation,
|
||||
@@ -31,6 +32,7 @@ set -eu
|
||||
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
|
||||
VERIFY_BUILD="$ROOT/script/verify-build"
|
||||
DISCARD_DIST="$ROOT/script/discard-dist-on-failure"
|
||||
|
||||
MARKER_ON="autistmask-build-debug=on"
|
||||
MARKER_OFF="autistmask-build-debug=off"
|
||||
@@ -150,6 +152,7 @@ build_fixture() {
|
||||
|
||||
mkdir -p "$FIXTURE/script"
|
||||
ln -s "$VERIFY_BUILD" "$FIXTURE/script/verify-build"
|
||||
ln -s "$DISCARD_DIST" "$FIXTURE/script/discard-dist-on-failure"
|
||||
|
||||
mkdir -p "$FIXTURE/dist/chrome/src/popup" \
|
||||
"$FIXTURE/dist/chrome/src/content" \
|
||||
@@ -513,12 +516,125 @@ c_debug_build() {
|
||||
write_receipt
|
||||
}
|
||||
|
||||
c_no_dist() { rm -rf dist; }
|
||||
|
||||
# --- dist discard -----------------------------------------------------------
|
||||
#
|
||||
# make build wraps every step of the release path in
|
||||
# script/discard-dist-on-failure, so a release build that fails removes dist/:
|
||||
# with AUTISTMASK_DEBUG=1 exported it has already emitted a complete, loadable
|
||||
# debug bundle whose every wallet uses the publicly committed test recovery
|
||||
# phrase, and a loud failure alone does not stop someone loading dist/chrome/
|
||||
# anyway. make build-debug is deliberately not wrapped.
|
||||
#
|
||||
# Both directions are asserted against the state of dist/ ON DISK after the run,
|
||||
# not against the exit status: a case reading only the status would keep passing
|
||||
# if the removal quietly stopped happening, which is the flip this exists to
|
||||
# catch. The wrapper runs against the fixture — its ROOT is the fixture, via the
|
||||
# symlink in the fixture's script/ — with trivial commands standing in for the
|
||||
# build steps, because what is under test is what happens after a step says no,
|
||||
# not the step.
|
||||
|
||||
# discard_case <name> <setup> <status> <gone|kept> <want> <unwanted> [cmd...]
|
||||
discard_case() {
|
||||
_dc_name="$1"
|
||||
_dc_setup="$2"
|
||||
_dc_want_status="$3"
|
||||
_dc_want_dist="$4"
|
||||
_dc_want="$5"
|
||||
_dc_unwanted="$6"
|
||||
shift 6
|
||||
|
||||
build_fixture
|
||||
if ! (cd "$FIXTURE" && "$_dc_setup") >/dev/null 2>&1; then
|
||||
FAILED=$((FAILED + 1))
|
||||
echo " FAIL: $_dc_name"
|
||||
echo " the case's own setup failed, so nothing was tested."
|
||||
return 0
|
||||
fi
|
||||
|
||||
_dc_status=0
|
||||
_dc_out="$(cd "$FIXTURE" &&
|
||||
"$FIXTURE/script/discard-dist-on-failure" "$@" 2>&1)" || _dc_status=$?
|
||||
|
||||
_ok=yes
|
||||
_why=""
|
||||
|
||||
if [ "$_dc_status" -ne "$_dc_want_status" ]; then
|
||||
_ok=no
|
||||
_why="exit status $_dc_status, wanted $_dc_want_status"
|
||||
fi
|
||||
|
||||
# The assertion this case exists for: what is on disk now.
|
||||
if [ -e "$FIXTURE/dist" ] || [ -h "$FIXTURE/dist" ]; then
|
||||
_dc_dist=kept
|
||||
else
|
||||
_dc_dist=gone
|
||||
fi
|
||||
if [ "$_dc_dist" != "$_dc_want_dist" ]; then
|
||||
_ok=no
|
||||
_why="${_why:+$_why; }dist/ is $_dc_dist after the run, wanted"
|
||||
_why="$_why $_dc_want_dist"
|
||||
elif [ "$_dc_want_dist" = kept ] &&
|
||||
[ ! -f "$FIXTURE/dist/chrome/src/popup/index.js" ]; then
|
||||
# Kept has to mean intact: a dist/ emptied out is not one left alone.
|
||||
_ok=no
|
||||
_why="${_why:+$_why; }dist/ survived but its emitted bundle did not"
|
||||
fi
|
||||
|
||||
_dc_check_message "$_dc_want" want
|
||||
_dc_check_message "$_dc_unwanted" unwanted
|
||||
|
||||
if [ "$_ok" = yes ]; then
|
||||
PASSED=$((PASSED + 1))
|
||||
echo " ok: $_dc_name"
|
||||
return 0
|
||||
fi
|
||||
|
||||
FAILED=$((FAILED + 1))
|
||||
echo " FAIL: $_dc_name"
|
||||
echo " $_why"
|
||||
echo " --- discard-dist-on-failure output ---"
|
||||
printf '%s\n' "$_dc_out" | sed 's/^/ /'
|
||||
echo " --- end output ---"
|
||||
}
|
||||
|
||||
# Require ($2 = want) or forbid ($2 = unwanted) a substring in the wrapper's
|
||||
# output, updating _ok and _why. An empty substring asserts nothing. Same grep
|
||||
# discipline as everywhere else here: 0 and 1 are answers, anything else means
|
||||
# the message was never checked.
|
||||
_dc_check_message() {
|
||||
[ -n "$1" ] || return 0
|
||||
|
||||
_dcm_g=0
|
||||
printf '%s\n' "$_dc_out" | grep -q -F -e "$1" || _dcm_g=$?
|
||||
case "$_dcm_g" in
|
||||
0)
|
||||
[ "$2" = unwanted ] || return 0
|
||||
_ok=no
|
||||
_why="${_why:+$_why; }message contained: $1"
|
||||
;;
|
||||
1)
|
||||
[ "$2" = want ] || return 0
|
||||
_ok=no
|
||||
_why="${_why:+$_why; }message did not contain: $1"
|
||||
;;
|
||||
*)
|
||||
_ok=no
|
||||
_why="${_why:+$_why; }grep exited $_dcm_g matching the message, so the
|
||||
message was never checked"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# --- Makefile wiring --------------------------------------------------------
|
||||
|
||||
# The verifier cases above prove what verify-build does when it is told what to
|
||||
# expect. This proves the Makefile tells it — with the mode as an argument, on
|
||||
# a scrubbed environment, and identically whether or not AUTISTMASK_DEBUG is
|
||||
# exported in the shell that ran make. Read off `make -n`, so no build runs.
|
||||
# expect, and the discard cases prove what the wrapper does with dist/. This
|
||||
# proves the Makefile wires both up — the mode as an argument, on a scrubbed
|
||||
# environment, identically whether or not AUTISTMASK_DEBUG is exported in the
|
||||
# shell that ran make, and the wrapper on the release path only. Read off
|
||||
# `make -n`, so no build runs.
|
||||
check_makefile_wiring() {
|
||||
if ! command -v make >/dev/null 2>&1; then
|
||||
SKIPPED=$((SKIPPED + 1))
|
||||
@@ -537,6 +653,34 @@ check_makefile_wiring() {
|
||||
build-debug "verify-build --expect debug"
|
||||
_wiring_case "make build-debug scrubs AUTISTMASK_DEBUG for the verifier" \
|
||||
build-debug "env -u AUTISTMASK_DEBUG"
|
||||
|
||||
# The release path runs its steps through the wrapper, including the final
|
||||
# check-censored pass; the debug path runs none of them through it, which is
|
||||
# what keeps a failed debug build's dist/ on disk.
|
||||
_wiring_case "make build wraps its steps in discard-dist-on-failure" \
|
||||
build "script/discard-dist-on-failure"
|
||||
_wiring_case "make build wraps check-censored --require-dist too" \
|
||||
build "script/discard-dist-on-failure script/check-censored"
|
||||
_wiring_case_absent "make build-debug never discards its dist/" \
|
||||
build-debug "discard-dist-on-failure"
|
||||
}
|
||||
|
||||
# Run `make -n TARGET` with AUTISTMASK_DEBUG=1 exported, into _wc_out. Returns
|
||||
# non-zero, having already reported the failure, when make itself failed: a
|
||||
# recipe that could not be printed was never checked.
|
||||
_wiring_make_n() {
|
||||
AUTISTMASK_DEBUG=1
|
||||
export AUTISTMASK_DEBUG
|
||||
_wc_status=0
|
||||
_wc_out="$(cd "$ROOT" && make -n "$_wc_target" 2>&1)" || _wc_status=$?
|
||||
unset AUTISTMASK_DEBUG
|
||||
|
||||
[ "$_wc_status" -ne 0 ] || return 0
|
||||
|
||||
FAILED=$((FAILED + 1))
|
||||
echo " FAIL: $_wc_name"
|
||||
echo " make -n $_wc_target exited $_wc_status"
|
||||
return 1
|
||||
}
|
||||
|
||||
_wiring_case() {
|
||||
@@ -544,18 +688,7 @@ _wiring_case() {
|
||||
_wc_target="$2"
|
||||
_wc_want="$3"
|
||||
|
||||
AUTISTMASK_DEBUG=1
|
||||
export AUTISTMASK_DEBUG
|
||||
_wc_status=0
|
||||
_wc_out="$(cd "$ROOT" && make -n "$_wc_target" 2>&1)" || _wc_status=$?
|
||||
unset AUTISTMASK_DEBUG
|
||||
|
||||
if [ "$_wc_status" -ne 0 ]; then
|
||||
FAILED=$((FAILED + 1))
|
||||
echo " FAIL: $_wc_name"
|
||||
echo " make -n $_wc_target exited $_wc_status"
|
||||
return 0
|
||||
fi
|
||||
_wiring_make_n || return 0
|
||||
|
||||
_wc_g=0
|
||||
printf '%s\n' "$_wc_out" | grep -q -F -e "$_wc_want" || _wc_g=$?
|
||||
@@ -577,6 +710,34 @@ _wiring_case() {
|
||||
esac
|
||||
}
|
||||
|
||||
# The inverse: the recipe must NOT run something.
|
||||
_wiring_case_absent() {
|
||||
_wc_name="$1"
|
||||
_wc_target="$2"
|
||||
_wc_want="$3"
|
||||
|
||||
_wiring_make_n || return 0
|
||||
|
||||
_wc_g=0
|
||||
printf '%s\n' "$_wc_out" | grep -q -F -e "$_wc_want" || _wc_g=$?
|
||||
case "$_wc_g" in
|
||||
1)
|
||||
PASSED=$((PASSED + 1))
|
||||
echo " ok: $_wc_name"
|
||||
;;
|
||||
0)
|
||||
FAILED=$((FAILED + 1))
|
||||
echo " FAIL: $_wc_name"
|
||||
echo " make -n $_wc_target runs: $_wc_want"
|
||||
;;
|
||||
*)
|
||||
FAILED=$((FAILED + 1))
|
||||
echo " FAIL: $_wc_name"
|
||||
echo " grep exited $_wc_g, so the recipe was never checked"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
run_cases() {
|
||||
check_case "control: untouched dist passes" \
|
||||
no release 0 "2 bundle(s) $MARKER_OFF" c_control
|
||||
@@ -712,6 +873,18 @@ run_cases() {
|
||||
no release 1 "carries a debug marker but the build did not" \
|
||||
c_marker_on_plain_file
|
||||
|
||||
discard_case "a failed release build step removes dist/" \
|
||||
c_control 3 gone "dist/ WAS REMOVED" "" sh -c 'exit 3'
|
||||
|
||||
discard_case "a successful release build step leaves dist/ alone" \
|
||||
c_control 0 kept "" "REMOVED" true
|
||||
|
||||
discard_case "a failed release build step with no dist/ says there was none" \
|
||||
c_no_dist 3 gone "There was no dist/ to remove" "" sh -c 'exit 3'
|
||||
|
||||
discard_case "the wrapper given no command removes nothing" \
|
||||
c_control 1 kept "no command given" ""
|
||||
|
||||
check_makefile_wiring
|
||||
}
|
||||
|
||||
@@ -740,6 +913,10 @@ main() {
|
||||
echo "test-verify-build: $VERIFY_BUILD is missing or not executable" >&2
|
||||
exit 1
|
||||
}
|
||||
[ -x "$DISCARD_DIST" ] || {
|
||||
echo "test-verify-build: $DISCARD_DIST is missing or not executable" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo "Testing script/verify-build failure modes..."
|
||||
pick_sha256_tool
|
||||
|
||||
Reference in New Issue
Block a user