From 56cf7f4e8fdf297f126829552853bdea015d6435 Mon Sep 17 00:00:00 2001 From: Arnav Wadhwa <40817363+ArnavVWadhwa@users.noreply.github.com> Date: Fri, 28 Aug 2026 15:50:57 -0700 Subject: [PATCH 1/2] fix: fail the build when the patched avahi .deb fails to install --- .github/workflows/validate.yml | 11 +++++++++++ customize.sh | 17 +++++++++++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 3ae8552..f977f17 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -32,11 +32,22 @@ jobs: install -d -m 700 /etc/NetworkManager/system-connections install -m 600 /src/files/dpea-eth0.nmconnection \ /etc/NetworkManager/system-connections/dpea-eth0.nmconnection + # Simulate the real RPi OS Desktop base, which already ships stock avahi. + # A bare Trixie container does NOT, so without this the avahi-dpea + # file-overwrite conflict (a missing Replaces:) stays hidden here and only + # surfaces on the real image build. Installing stock avahi first makes CI + # reproduce that conflict, which is the whole point of this gate. + apt-get install -y avahi-daemon libnss-mdns bash /src/customize.sh echo "===== assertions =====" fail=0 command -v uv >/dev/null && echo "OK uv $(uv --version)" || { echo "FAIL uv"; fail=1; } dpkg -s avahi-dpea >/dev/null 2>&1 && echo "OK avahi-dpea installed" || { echo "FAIL avahi-dpea"; fail=1; } + # It must actually take OVER the stock daemon binary, not just install + # alongside it. Replaces: transfers file ownership to avahi-dpea. + dpkg -S /usr/sbin/avahi-daemon 2>/dev/null | grep -q '^avahi-dpea:' \ + && echo "OK /usr/sbin/avahi-daemon owned by avahi-dpea" \ + || { echo "FAIL avahi-daemon binary not replaced by avahi-dpea"; fail=1; } for line in "dtparam=i2c_arm=on" "dtparam=spi=on" "enable_uart=1" "dtoverlay=disable-bt"; do grep -qx "$line" /boot/firmware/config.txt && echo "OK config: $line" || { echo "FAIL config: $line"; fail=1; } done diff --git a/customize.sh b/customize.sh index 13a2355..2ed8982 100755 --- a/customize.sh +++ b/customize.sh @@ -1,9 +1,12 @@ -#!/bin/bash -e +#!/bin/bash # DPEA image customizations. Runs INSIDE the mounted image chroot (see build-image.sh), # and inside the CI validation container (see .github/workflows/validate.yml). # Expects /tmp/packages.txt already copied in, and the NetworkManager profile # already placed at /etc/NetworkManager/system-connections/dpea-eth0.nmconnection. +# Both callers invoke this as `bash customize.sh`, which ignores the shebang's +# flags, so set the strict flags in the body or a failed step is silently skipped. +set -euo pipefail export DEBIAN_FRONTEND=noninteractive # --- shared non-Python system packages --- @@ -25,7 +28,17 @@ grep -q '^i2c-dev' /etc/modules || echo 'i2c-dev' >> /etc/modules AVAHI_DEB_URL="${AVAHI_DEB_URL:-https://github.com/dpengineering/avahi_0.8/releases/latest/download/avahi-dpea_0.8_arm64.deb}" if curl -fLsS "$AVAHI_DEB_URL" -o /tmp/avahi.deb; then apt-get install -y /tmp/avahi.deb - echo 'avahi-daemon hold' | dpkg --set-selections || true + # The stock RPi OS Desktop base already ships avahi, so the .deb must overwrite + # its files (it declares Replaces: for them). A dpkg file-overwrite conflict can + # leave the package uninstalled while apt still exits 0, so assert it is actually + # present instead of trusting the exit code. + dpkg -s avahi-dpea >/dev/null 2>&1 \ + || { echo "ERROR: avahi-dpea did not install (dpkg file conflict / missing Replaces:?)" >&2; exit 1; } + # Refresh the linker cache so the patched libavahi-core (mDNS on 5358) it just + # dropped in is the one the daemon loads, not the stock lib it overwrote. + ldconfig + # Hold both so an apt upgrade cannot restore the stock 5353 build over ours. + apt-mark hold avahi-daemon avahi-dpea >/dev/null 2>&1 || true rm -f /tmp/avahi.deb else echo "ERROR: prebuilt 5358 avahi .deb not found at $AVAHI_DEB_URL" >&2 From 7d1b2ab1a820a7eaf77e74dbb333b9e687834929 Mon Sep 17 00:00:00 2001 From: Arnav Wadhwa <40817363+ArnavVWadhwa@users.noreply.github.com> Date: Fri, 28 Aug 2026 15:50:57 -0700 Subject: [PATCH 2/2] fix: skip the eth0 static check when eth0 has no carrier --- hardware-smoke-test.sh | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/hardware-smoke-test.sh b/hardware-smoke-test.sh index 40150dd..e25bb3d 100755 --- a/hardware-smoke-test.sh +++ b/hardware-smoke-test.sh @@ -5,8 +5,9 @@ # real device nodes, the serial mapping, live mDNS port, and the eth0 address. set -u -pass=0; fail=0 +pass=0; fail=0; skipped=0 chk(){ if eval "$2" >/dev/null 2>&1; then echo "PASS $1"; pass=$((pass+1)); else echo "FAIL $1"; fail=$((fail+1)); fi; } +skip(){ echo "SKIP $1 ($2)"; skipped=$((skipped+1)); } chk "uv installed" "command -v uv" chk "I2C device node present" "ls /dev/i2c-*" @@ -14,10 +15,17 @@ chk "SPI device node present" "ls /dev/spidev*" chk "/dev/serial0 -> ttyAMA0" "[ \"\$(readlink -f /dev/serial0)\" = /dev/ttyAMA0 ]" chk "avahi listening on 5358" "ss -lun | grep -q ':5358'" chk "avahi NOT on 5353" "! ss -lun | grep -q ':5353'" -chk "eth0 holds 172.17.21.2" "ip -4 addr show eth0 | grep -q '172.17.21.2'" +# The eth0 static (172.17.21.2) only activates when the link has carrier. Running +# this over wifi with no ethernet cable is not an image defect, so SKIP rather than +# FAIL when eth0 has no carrier; plug a cable (or the direct laptop link) and re-run. +if [ "$(cat /sys/class/net/eth0/carrier 2>/dev/null || echo 0)" = 1 ]; then + chk "eth0 holds 172.17.21.2" "ip -4 addr show eth0 | grep -q '172.17.21.2'" +else + skip "eth0 holds 172.17.21.2" "no ethernet carrier; plug a cable and re-run" +fi echo "----" -echo "$pass passed, $fail failed" +echo "$pass passed, $fail failed, $skipped skipped" echo echo "Manual direct-cable check: set another machine's ethernet to 172.17.21.1," echo "then from it: ping 172.17.21.2 and ssh @172.17.21.2"