Package through a pinned Node, not whatever the host has

Found the real cause of "-5: ipk verify failed": ares-package's own
packaging code (ar-async/fstream/tar, last touched 2017-2019) silently
zeroes every file's mtime in the ipk when run under a sufficiently new
Node (reproduced on v25.8.1; a Node-18 container was unaffected).
Confirmed by unpacking data.tar.gz from our built ipk (every entry
1970-01-01) versus webosbrew/hyperhdr-webos-loader's real published
ipk, structurally identical to ours (web app + native service, same
control file, same ares-cli) but with genuine October 2025 timestamps.
The archive still parses fine everywhere generic tooling looks —
Python's tarfile, our own ar/tar inspection — so nothing here ever
errors. The TV's own installer is what eventually rejects it, and it
gives no hint why.

This took three rounds of elimination to isolate: root elevation
wasn't it (Homebrew Channel's own root status was "ok"), and
system-wide native-code verification wasn't it either (a real
native-service app installed fine on the same TV). Comparing our ipk
against that known-good one byte-for-byte was what surfaced the
timestamp anomaly, and rebuilding under Node 18 reproduced correct
timestamps immediately.

build.sh now runs ares-package inside a pinned node:18 container by
default, falling back to the host's Node with a warning if Docker
isn't available. Rebuilt the actual release ipk this way and
regenerated manifest.json/repo.json against its corrected hash.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Rene Kievits
2026-08-26 12:51:13 +02:00
co-authored by Claude Opus 5
parent f622c3a0bf
commit f3a4cddfd6
2 changed files with 58 additions and 8 deletions
+44 -6
View File
@@ -68,17 +68,55 @@ EOF
echo "$toolchain"
}
check_ares() {
command -v ares-package >/dev/null 2>&1 || cat >&2 <<'EOF'
error: ares-package is not on PATH
PACKAGER_NODE_IMAGE="${PACKAGER_NODE_IMAGE:-node:18-bookworm-slim}"
npm install -g @webosose/ares-cli
check_ares() {
[ -f "$ROOT/node_modules/@webosose/ares-cli/bin/ares-package.js" ] && return 0
command -v ares-package >/dev/null 2>&1 && return 0
cat >&2 <<'EOF'
error: ares-cli is not installed
npm install
Then register the TV once (developer mode or the Homebrew Channel's ssh):
ares-setup-device --add tv --info "{'host':'192.168.1.20','port':9922,'username':'root'}"
EOF
command -v ares-package >/dev/null 2>&1
return 1
}
# ares-package's own packaging code (ar-async/fstream/tar, all last touched
# around 2017-2019) silently mishandles file metadata on very new Node
# releases: every mtime in the ipk comes out as 1970-01-01 instead of the real
# date. The archive still parses, so nothing here errors — the TV's installer
# is what eventually rejects it, as "ipk verify failed" with no clue why.
# Running the same ares-cli under a pinned, known-good Node avoids the whole
# class of bug regardless of what's on the host.
run_ares_package() {
local ares_js="$ROOT/node_modules/@webosose/ares-cli/bin/ares-package.js"
if [ -f "$ares_js" ] && command -v docker >/dev/null 2>&1; then
# Arguments are host paths under $ROOT; rewrite them to the container's
# mount point since nothing outside $ROOT is visible in there.
local args=() a
for a in "$@"; do
args+=("${a/#$ROOT//src}")
done
docker run --rm \
--volume "$ROOT:/src" \
--workdir /src \
--user "$(id -u):$(id -g)" \
--env HOME=/tmp \
"$PACKAGER_NODE_IMAGE" \
node /src/node_modules/@webosose/ares-cli/bin/ares-package.js "${args[@]}"
return
fi
if [ -f "$ares_js" ]; then
say "warning: no docker, running ares-package on the host's own Node ($(node --version 2>/dev/null))"
say " if the ipk fails to install with a vague error, re-run with docker installed"
node "$ares_js" "$@"
return
fi
ares-package "$@"
}
build_native() {
@@ -132,7 +170,7 @@ package() {
step "Packaging"
mkdir -p "$OUT_DIR"
rm -f "$OUT_DIR"/${APP_ID}_*.ipk
ares-package "$STAGE_APP" "$STAGE_SERVICE" -o "$OUT_DIR"
run_ares_package "$STAGE_APP" "$STAGE_SERVICE" -o "$OUT_DIR"
local ipk
ipk="$(ls -t "$OUT_DIR"/${APP_ID}_*.ipk | head -1)"