fix: harden portal OTA release

This commit is contained in:
2026-09-20 19:44:05 +10:00
parent 7c5b50499e
commit 360b7cff86
20 changed files with 621 additions and 198 deletions
+3 -1
View File
@@ -11,6 +11,8 @@ tag="${1:-}"
[[ "${2:-}" == "" || "${2:-}" == "--tag" ]] || usage
root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
# shellcheck source=tools/lib/platformio.sh
source "$root/tools/lib/platformio.sh"
version="${tag#v}"
manifest_version="$(sed -n 's/.*"version": "\([^"]*\)".*/\1/p' "$root/library.json" | head -n 1)"
@@ -54,7 +56,7 @@ validate_reference docs/GETTING_STARTED.md
git -C "$root" diff --check
package_dir="$(mktemp -d)"
trap 'rm -rf "$package_dir"' EXIT
pio pkg pack "$root" --output "$package_dir/package.tar.gz" >/dev/null
wm_pio pkg pack "$root" --output "$package_dir/package.tar.gz" >/dev/null
echo "Validated release metadata and PlatformIO package for $tag"
if [[ "${2:-}" == "--tag" ]]; then
+60 -20
View File
@@ -1,6 +1,10 @@
#!/usr/bin/env bash
set -euo pipefail
# Keep standalone compilation predictable on laptops and shared workstations.
# A developer may explicitly raise this for an isolated local diagnosis.
export PLATFORMIO_RUN_JOBS="${PLATFORMIO_RUN_JOBS:-2}"
usage() {
cat <<'USAGE' >&2
Usage:
@@ -35,30 +39,32 @@ esac
[[ "$mode" != "hardware" || -e "$port" ]] || { echo "Serial port not found: $port" >&2; exit 1; }
root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
# shellcheck source=tools/lib/platformio.sh
source "$root/tools/lib/platformio.sh"
# shellcheck source=tools/lib/ota-fixture-identity.sh
source "$root/tools/lib/ota-fixture-identity.sh"
pio_for_platform() {
if [[ "$platform" != "esp32" ]]; then
pio "$@"
wm_pio "$@"
return
fi
# Keep the maintained Core 3.3.11 package form in a persistent project
# cache. It is never cleared by this script and avoids stale global
# package metadata selecting an incompatible uploader.
# cache shared by the maintained framework repositories. It is never
# cleared by this script and avoids stale global package metadata selecting
# an incompatible uploader without redownloading this same pinned graph.
local core_dir packages_dir cache_dir
core_dir="${WIFIMANAGER_PLATFORMIO_CORE_DIR:-${XDG_CACHE_HOME:-$HOME/.cache}/wifimanager-platformio/core-3.3.11}"
core_dir="${WIFIMANAGER_PLATFORMIO_CORE_DIR:-${XDG_CACHE_HOME:-$HOME/.cache}/arduino-framework-platformio/core-3.3.11}"
packages_dir="${WIFIMANAGER_PLATFORMIO_PACKAGES_DIR:-$core_dir/packages}"
cache_dir="${WIFIMANAGER_PLATFORMIO_CACHE_DIR:-$core_dir/cache}"
install -d -m 700 "$core_dir" "$packages_dir" "$cache_dir"
PLATFORMIO_CORE_DIR="$core_dir" PLATFORMIO_PACKAGES_DIR="$packages_dir" \
PLATFORMIO_CACHE_DIR="$cache_dir" pio "$@"
PLATFORMIO_CACHE_DIR="$cache_dir" wm_pio "$@"
}
assert_ota_fixture_pair() {
local fixture_platform="$1"
local firmware_a firmware_b firmware size capacity
firmware_a="$root/test/portal-harness/.pio/build/${fixture_platform}_ota_a/firmware.bin"
firmware_b="$root/test/portal-harness/.pio/build/${fixture_platform}_ota_b/firmware.bin"
local firmware_a="$1" firmware_b="$2" firmware size capacity
[[ -s "$firmware_a" && -s "$firmware_b" ]] || {
echo "Portal OTA fixture build did not produce both A and B images." >&2
return 1
@@ -72,7 +78,7 @@ assert_ota_fixture_pair() {
for firmware in "$firmware_a" "$firmware_b"; do
size="$(wc -c < "$firmware" | tr -d '[:space:]')"
(( size <= capacity )) || {
echo "ESP32 OTA fixture $(basename "$(dirname "$firmware")") is $size bytes; it exceeds the $capacity-byte app slot." >&2
echo "ESP32 OTA fixture $(basename "$firmware") is $size bytes; it exceeds the $capacity-byte app slot." >&2
return 1
}
done
@@ -80,10 +86,11 @@ assert_ota_fixture_pair() {
}
if [[ "$mode" == "hardware" ]]; then
# Keep serial flashing and portal-adapter work mutually exclusive.
# shellcheck source=tools/lib/portal-hardware-session.sh
source "$root/tools/lib/portal-hardware-session.sh"
wm_acquire_hardware_lock
# Unity uses only the named serial device; it does not own a portal AP or
# secondary adapter, so it may run beside an unrelated station test.
# shellcheck source=tools/lib/harness-locks.sh
source "$root/tools/lib/harness-locks.sh"
wm_harness_lock_serial_port "$port"
fi
if [[ "$mode" == "examples" ]]; then
@@ -100,14 +107,47 @@ if [[ "$mode" == "examples" ]]; then
fi
if [[ "$mode" == "ota-fixtures" ]]; then
fixture_platform="$platform"
if [[ "$fixture_platform" == "esp32" ]]; then
fixture_environment="${platform}_ota"
if [[ "$platform" == "esp32" ]]; then
"$root/tools/check-ota-partitions.sh"
fi
for image in a b; do
pio_for_platform run -d "$root/test/portal-harness" -e "${fixture_platform}_ota_${image}" </dev/null
done
assert_ota_fixture_pair "$fixture_platform"
# The A/B marker is the only changed source input. Capture each resulting
# binary before rebuilding the same platform environment so CI proves the
# update images differ without paying for duplicate dependency builds.
fixture_dir="$(mktemp -d "${TMPDIR:-/tmp}/wifimanager-ota-fixtures.XXXXXX")"
chmod 700 "$fixture_dir"
export WIFIMANAGER_OTA_IDENTITY_DIR="$fixture_dir/identity"
fixture_build_dir="$fixture_dir/build/$fixture_environment"
wm_lock_ota_fixture_environment "$fixture_environment"
wm_write_ota_fixture_identity A
fixture_a="$fixture_dir/ota-a.bin"
fixture_b="$fixture_dir/ota-b.bin"
cleanup_ota_fixture_build() {
wm_remove_ota_fixture_identity
rm -rf -- "$fixture_dir"
}
on_ota_fixture_build_signal() {
local status="$1"
# Remove the generated identity before leaving. EXIT will call the
# same idempotent cleanup once more, which is intentional.
trap - HUP INT TERM
cleanup_ota_fixture_build
exit "$status"
}
trap cleanup_ota_fixture_build EXIT
trap 'on_ota_fixture_build_signal 129' HUP
trap 'on_ota_fixture_build_signal 130' INT
trap 'on_ota_fixture_build_signal 143' TERM
PLATFORMIO_BUILD_DIR="$fixture_dir/build" \
pio_for_platform run -d "$root/test/portal-harness" -e "$fixture_environment" </dev/null
install -m 600 "$fixture_build_dir/firmware.bin" "$fixture_a"
wm_write_ota_fixture_identity B
PLATFORMIO_BUILD_DIR="$fixture_dir/build" \
pio_for_platform run -d "$root/test/portal-harness" -e "$fixture_environment" </dev/null
install -m 600 "$fixture_build_dir/firmware.bin" "$fixture_b"
assert_ota_fixture_pair "$fixture_a" "$fixture_b"
echo "WiFiManager portal OTA fixture compile check passed for $platform"
exit 0
fi