213 lines
8.5 KiB
Bash
Executable File
213 lines
8.5 KiB
Bash
Executable File
#!/bin/sh
|
|
# script/verify-build: assert the compiled DEBUG state of the emitted
|
|
# bundles. Our own extension to scripts-to-rule-them-all, run at the end of
|
|
# make build / make build-debug.
|
|
#
|
|
# Why this exists: DEBUG makes the publicly committed test recovery phrase the
|
|
# output of wallet creation, so a release artifact built with it live hands
|
|
# every new wallet to anyone who reads the repo. The test suite cannot see
|
|
# this, because it loads src/shared/constants.js outside a bundle and takes
|
|
# the fallback branch; the property only exists in the emitted output, so it
|
|
# has to be asserted against the emitted output.
|
|
#
|
|
# What it reads: dist/constants-bundles.txt, written by build.js from
|
|
# esbuild's metafile, naming every emitted bundle that contains
|
|
# src/shared/constants.js. Each of those must carry exactly one of the two
|
|
# BUILD_DEBUG_MARKER literals that constants.js folds down to.
|
|
#
|
|
# It fails rather than passes whenever it cannot determine a bundle's state.
|
|
# Minified output is not a stable contract, so "matched neither form" is not
|
|
# evidence of anything and must never read as green.
|
|
set -eu
|
|
|
|
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
|
|
|
|
MANIFEST="dist/constants-bundles.txt"
|
|
MARKER_ON="autistmask-build-debug=on"
|
|
MARKER_OFF="autistmask-build-debug=off"
|
|
|
|
# Set by read_marker.
|
|
MARKER=""
|
|
|
|
fail() {
|
|
echo "verify-build: FAIL: $*" >&2
|
|
exit 1
|
|
}
|
|
|
|
# Is the literal $1 present in the file $2? Match (grep exit 0) and no-match
|
|
# (exit 1) are answers about the emitted output. Anything else (exit 2: the
|
|
# file could not be read) is not an answer at all, and must not be reported as
|
|
# "no marker" — that would blame the bundle for a permissions or I/O fault.
|
|
has_marker() {
|
|
_hm_status=0
|
|
grep -q -F -e "$1" -- "$2" || _hm_status=$?
|
|
case "$_hm_status" in
|
|
0) return 0 ;;
|
|
1) return 1 ;;
|
|
*)
|
|
fail "grep exited $_hm_status reading $2, so the file could not be
|
|
searched and its DEBUG state was not checked at all. That is a permissions
|
|
or I/O fault on the artifact, not a change in the emitted output. Refusing
|
|
to report success."
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# Does the manifest list the path $1, as a whole line? Same discipline as
|
|
# has_marker: exit 0 and 1 are answers about the manifest, exit 2 means the
|
|
# manifest could not be read and is not an answer at all. Without this, an
|
|
# unreadable manifest reads as "this file is not listed" and every emitted
|
|
# bundle gets reported as an unlisted one.
|
|
is_listed() {
|
|
_il_status=0
|
|
grep -q -x -F -e "$1" -- "$MANIFEST" || _il_status=$?
|
|
case "$_il_status" in
|
|
0) return 0 ;;
|
|
1) return 1 ;;
|
|
*)
|
|
fail "grep exited $_il_status reading $MANIFEST, so it could not be
|
|
searched and nothing was established about which bundles it lists. That is
|
|
a permissions or I/O fault on the manifest, not a stale manifest. Refusing
|
|
to report success."
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# Read one bundle's DEBUG state into MARKER. Exactly one marker must be
|
|
# present. Both means the ternary in constants.js was never folded, which is
|
|
# what happens when the __BUILD_DEBUG__ define goes missing from build.js:
|
|
# DEBUG stops being known at build time. Neither means we are reading output
|
|
# we do not understand. Both are hard failures; neither is ever treated as
|
|
# absence of a problem.
|
|
read_marker() {
|
|
_file="$1"
|
|
_on=no
|
|
_off=no
|
|
if has_marker "$MARKER_ON" "$_file"; then _on=yes; fi
|
|
if has_marker "$MARKER_OFF" "$_file"; then _off=yes; fi
|
|
|
|
if [ "$_on" = yes ] && [ "$_off" = yes ]; then
|
|
fail "$_file carries both debug markers, so DEBUG was not resolved at
|
|
build time: the ternary in src/shared/constants.js survived into the
|
|
emitted output. This does not mean the debug branch is live in this
|
|
artifact: an unresolved __BUILD_DEBUG__ is undeclared in extension
|
|
context, so DEBUG evaluates to false at runtime. It does mean the
|
|
release/debug distinction is no longer enforced at build time, and which
|
|
way that fallback happens to evaluate is then an accident a refactor can
|
|
flip. Check that build.js still defines __BUILD_DEBUG__."
|
|
fi
|
|
if [ "$_on" = no ] && [ "$_off" = no ]; then
|
|
fail "$_file carries no debug marker, so its DEBUG state cannot be
|
|
determined. Either BUILD_DEBUG_MARKER is gone from src/shared/constants.js
|
|
or the emitted output changed shape. Refusing to report success."
|
|
fi
|
|
|
|
if [ "$_on" = yes ]; then
|
|
MARKER="$MARKER_ON"
|
|
else
|
|
MARKER="$MARKER_OFF"
|
|
fi
|
|
}
|
|
|
|
# The manifest says which bundles must carry a marker. This says no other
|
|
# emitted file may carry one, which catches a manifest that has gone stale
|
|
# or short rather than trusting whatever it happens to list.
|
|
#
|
|
# Deliberately unfiltered by extension. build.js selects manifest entries with
|
|
# an endsWith(".js") test; repeating that literal here would mean a bundle
|
|
# emitted under some other extension escaped the manifest AND this check at
|
|
# once, which is the correlated blind spot the two-source design exists to
|
|
# avoid. Every file under dist/ is searched, so build.js's filter is the only
|
|
# place the assumption lives and this check is what catches it being wrong.
|
|
#
|
|
# That claim only holds if the walk is exhaustive, so two things are enforced
|
|
# here rather than assumed:
|
|
#
|
|
# - find's exit status is checked. A subtree it cannot descend is reported on
|
|
# stderr and then simply missing from the listing, so an unchecked status
|
|
# turns "could not look" into "nothing was there" — the same conflation
|
|
# has_marker exists to prevent. The status cannot be read off a pipeline
|
|
# ending in sort, so the sort is a separate step.
|
|
# - symlinks are walked too (-type l), not skipped. A marker-carrying bundle
|
|
# reachable under an unlisted path in dist/ is a stale manifest whether the
|
|
# path is a link or a file, and grep reads through the link. A link that
|
|
# cannot be read through — dangling, or pointing at a directory — fails
|
|
# hard via has_marker's exit-2 path, which is the fail-closed answer: the
|
|
# build emits neither, so their DEBUG state is unproven, not fine.
|
|
check_unlisted_bundles() {
|
|
_find_status=0
|
|
_listing="$(find dist \( -type f -o -type l \) -print)" || _find_status=$?
|
|
[ "$_find_status" -eq 0 ] ||
|
|
fail "find exited $_find_status enumerating dist/, so part of the tree
|
|
was never walked and nothing was established about the files in it. Any
|
|
unlisted bundle there went unchecked. That is a permissions or I/O fault on
|
|
the artifact, not a stale manifest. Refusing to report success."
|
|
_listing="$(printf '%s\n' "$_listing" | sort)"
|
|
|
|
while read -r _file; do
|
|
[ -n "$_file" ] || continue
|
|
if is_listed "$_file"; then
|
|
continue
|
|
fi
|
|
if has_marker "$MARKER_ON" "$_file" ||
|
|
has_marker "$MARKER_OFF" "$_file"; then
|
|
fail "$_file carries a debug marker but is absent from $MANIFEST,
|
|
so the manifest no longer describes the emitted bundles."
|
|
fi
|
|
done <<EOF
|
|
$_listing
|
|
EOF
|
|
}
|
|
|
|
# The requested mode, read from our own environment using build.js's exact
|
|
# rule: only the literal 1 opts in. Deliberately not taken from anything
|
|
# build.js records about itself, so build.js cannot vouch for build.js.
|
|
expected_marker() {
|
|
if [ "${AUTISTMASK_DEBUG-}" = "1" ]; then
|
|
echo "$MARKER_ON"
|
|
else
|
|
echo "$MARKER_OFF"
|
|
fi
|
|
}
|
|
|
|
main() {
|
|
cd "$ROOT"
|
|
|
|
expected="$(expected_marker)"
|
|
echo "Verifying emitted bundles (expecting $expected)..."
|
|
|
|
[ -f "$MANIFEST" ] ||
|
|
fail "$MANIFEST is missing. build.js writes it at the end of a
|
|
successful build; run make build first."
|
|
[ -s "$MANIFEST" ] ||
|
|
fail "$MANIFEST is empty, so no emitted bundle was found to contain
|
|
src/shared/constants.js. That is never correct, so it is a failure and not
|
|
a pass."
|
|
[ -r "$MANIFEST" ] ||
|
|
fail "$MANIFEST is not readable, so nothing was inspected. That is a
|
|
permissions or I/O fault, not a pass."
|
|
|
|
count=0
|
|
while read -r file; do
|
|
[ -n "$file" ] || continue
|
|
[ -f "$file" ] ||
|
|
fail "$MANIFEST lists $file, which does not exist."
|
|
[ -s "$file" ] ||
|
|
fail "$MANIFEST lists $file, which is empty. An empty bundle
|
|
carries no marker and proves nothing, so this is a failure and not a pass."
|
|
read_marker "$file"
|
|
[ "$MARKER" = "$expected" ] ||
|
|
fail "$file is $MARKER but this build expects $expected."
|
|
echo " ok: $file ($MARKER)"
|
|
count=$((count + 1))
|
|
done <"$MANIFEST"
|
|
|
|
[ "$count" -gt 0 ] || fail "no bundles were inspected."
|
|
|
|
check_unlisted_bundles
|
|
|
|
echo "verify-build: $count bundle(s) verified $expected"
|
|
}
|
|
|
|
main "$@"
|