PKG_VERSION/PKG_RELEASE were hand-written literals nobody bumped, so
v0.2.2 … v0.2.6 all shipped as `shaterd 0.2.0-r3` with different binaries
inside (v0.2.6's ELF is 5 491 616 B against r2's 5 488 336 B). Both opkg
and apk offer an upgrade only when the feed's version string differs from
the installed one, so `apk update` saw nothing new and the routers could
not be updated through the normal path at all.
ci/version.sh is now the single source of truth. It derives the version
from `git describe`:
tag `vX.Y.Z` -> PKG_VERSION=X.Y.Z PKG_RELEASE=1
off-tag build -> nearest tag + PKG_RELEASE=<commits since it> + 1
no tag/no git -> 0.0.0-r1 (below everything ever published)
Ordering verified with the real tools, not from memory — apk-tools 3.0.3
(`apk version -t`) and opkg 38eccbb1 (`opkg compare-versions`) agree that
0.2.0-r3 < 0.2.6-r2 < 0.2.6-r10 < 0.2.6-r12 < 0.2.7-r1 < 0.3.0-r1, so a
release always outranks the rolling builds that preceded it and rolling
builds grow monotonically between releases.
The value travels as SHATER_PKG_VERSION/SHATER_PKG_RELEASE in the SDK
build environment of BOTH lanes; the Makefiles keep a literal fallback so
a manual/offline build still works with no CI and no git. Because the
hand-off crosses docker, `su` and make's env import, ci/sdk-build.sh and
ci/sdk-build-apk.sh now ASSERT that the produced .ipk/.apk really carries
that version — the B4 failure mode was a stale version shipping silently,
and that can no longer happen quietly.
The binary agrees with the package: scripts/build-shaterd.sh takes
constant.Version from the same ci/version.sh (vX.Y.Z-rR[-g<sha>]) instead
of its own `git describe`, and the workflow computes it once per job.
Both build jobs now check out with fetch-depth: 0 — `git describe` needs
tags and ancestry, which the default shallow checkout has neither of.
byedpi is deliberately left alone: PKG_VERSION:=0.17.3 is upstream
ByeDPI's own version, what PKG_HASH pins and what tells an operator which
ByeDPI is installed. Stamping our tag on it would also be a downgrade —
every comparator reads 0.2.7 < 0.17.3 (component-wise, 2 < 17), verified.
Docs: INSTALL.md gains §2.1 (the scheme + the ordering evidence), and the
update sections of §5/§6 now explicitly warn against a bare `opkg upgrade`
/ `apk upgrade` and give the targeted form instead, quoting apk-tools 3:
"If list of packages is provided, only those packages are upgraded along
with needed dependencies". README.md and the release bodies match.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
121 lines
6.2 KiB
Bash
Executable File
121 lines
6.2 KiB
Bash
Executable File
#!/bin/sh
|
|
# ci/build-feed-apk.sh — build the signed **apk** feed for ONE arch (the 25.12
|
|
# lane — additive next to ci/build-feed.sh, which stays the opkg/24.10 lane).
|
|
#
|
|
# Usage: ci/build-feed-apk.sh <ARCH> <SDK_URL> <OUTDIR>
|
|
# e.g. ci/build-feed-apk.sh aarch64_cortex-a53 \
|
|
# https://downloads.immortalwrt.org/releases/25.12.1/targets/mediatek/filogic/immortalwrt-sdk-25.12.1-mediatek-filogic_gcc-14.3.0_musl.Linux-x86_64.tar.zst \
|
|
# out-apk/aarch64_cortex-a53
|
|
#
|
|
# This is the per-arch entrypoint the Gitea workflow's `build-apk` job calls.
|
|
# It runs on the CI RUNNER and:
|
|
# 1. asserts the prebuilt shaterd binary for this arch was already staged by
|
|
# scripts/build-shaterd.sh (same artifact-order contract as the opkg lane);
|
|
# 2. drives a plain `debian:bookworm` container (workspace shared via
|
|
# `--volumes-from`, same trick as ci/build-feed.sh) that downloads the
|
|
# ImmortalWrt 25.12 apk-SDK tarball and runs ci/sdk-build-apk.sh in it:
|
|
# compile the 4 packages as .apk, then `apk mkndx --sign` the per-arch
|
|
# `packages.adb` index. Unlike the usign lane (index signed on the runner),
|
|
# apk indexing NEEDS the SDK's host `apk` tool, so index+sign happen inside
|
|
# the container.
|
|
#
|
|
# Why the ImmortalWrt SDK (not openwrt/sdk images): the 25.12 fleet runs
|
|
# BananaWRT 25.12-mtk-vendor = ImmortalWrt 25.12 base (target mediatek/filogic,
|
|
# pkg arch aarch64_cortex-a53), and Docker Hub has no immortalwrt/sdk
|
|
# mediatek-filogic 25.12 tag — hence the official SDK tarball.
|
|
#
|
|
# Env:
|
|
# KEY_APK EC (prime256v1) PRIVATE key PEM (Gitea repo secret — the apk analog
|
|
# of KEY_BUILD). If set, packages.adb carries an embedded signature
|
|
# verifiable by dist/shater-apk.pem (routers: /etc/apk/keys/).
|
|
# If unset, an UNSIGNED index is produced (warning; not shippable —
|
|
# apk signatures are effectively mandatory).
|
|
set -eu
|
|
|
|
ARCH="${1:?arch required (x86_64 | aarch64_cortex-a53)}"
|
|
SDK_URL="${2:?ImmortalWrt SDK tarball URL required (.tar.zst)}"
|
|
OUT="${3:?output dir required}"
|
|
|
|
REPO="$(cd "$(dirname "$0")/.." && pwd)"
|
|
mkdir -p "$OUT"; OUT="$(cd "$OUT" && pwd)"
|
|
|
|
# --- 0) the prebuilt shaterd binary must already be staged for this arch ------
|
|
case "$ARCH" in
|
|
x86_64) sfx=amd64 ;;
|
|
aarch64_cortex-a53) sfx=arm64 ;;
|
|
*) echo "[apk-feed] ERROR: unsupported ARCH '$ARCH'"; exit 2 ;;
|
|
esac
|
|
if [ ! -f "$REPO/openwrt/shaterd/files/shaterd-$sfx.upx" ]; then
|
|
echo "[apk-feed] ERROR: openwrt/shaterd/files/shaterd-$sfx.upx not staged."
|
|
echo " Run scripts/build-shaterd.sh BEFORE ci/build-feed-apk.sh." >&2
|
|
exit 3
|
|
fi
|
|
|
|
[ -n "${KEY_APK:-}" ] || echo "[apk-feed] WARNING: KEY_APK not set — the apk index will be UNSIGNED"
|
|
|
|
chmod +x "$REPO"/ci/*.sh 2>/dev/null || true
|
|
|
|
# --- 0.4) package version from the git tag ------------------------------------
|
|
# Same contract as the opkg lane (ci/build-feed.sh): the workflow puts these in
|
|
# the job env via `ci/version.sh --env >> $GITHUB_ENV`; recompute here when run
|
|
# standalone. Passed into the container below and re-exported to the
|
|
# unprivileged build user in ci/sdk-build-apk.sh.
|
|
if [ -z "${SHATER_PKG_VERSION:-}" ] || [ -z "${SHATER_PKG_RELEASE:-}" ]; then
|
|
eval "$(sh "$REPO/ci/version.sh" --env)"
|
|
fi
|
|
echo "[apk-feed] package version: ${SHATER_PKG_VERSION}-r${SHATER_PKG_RELEASE}"
|
|
|
|
# --- 0.5) runner-side caches --------------------------------------------------
|
|
# All under $REPO/.cache so (a) actions/cache in the workflow can persist them
|
|
# between runs and (b) the nested container sees them via --volumes-from.
|
|
# sdk/ SDK tarballs (keyed in the workflow by tarball basename)
|
|
# dl/ package source tarballs — becomes CONFIG_DOWNLOAD_FOLDER inside the
|
|
# SDK; PKG_HASH still verifies every file, so stale = re-downloaded.
|
|
# apt/ debian:bookworm .deb archives for the host-deps install.
|
|
# The nested container runs the build as an unprivileged user -> must be writable
|
|
# (same reason as the chmod 0777 "$OUT" in ci/build-feed.sh).
|
|
CACHE="$REPO/.cache"
|
|
mkdir -p "$CACHE/sdk" "$CACHE/dl" "$CACHE/apt"
|
|
chmod -R a+rwX "$CACHE/dl" "$CACHE/apt" 2>/dev/null || true
|
|
|
|
# feeds/ git checkouts (actions/cache key: feeds-apk-<release>) — symlinked
|
|
# over the SDK's feeds dir inside the container (ci/sdk-build-apk.sh) so
|
|
# `scripts/feeds update -a` fetches deltas instead of re-cloning the
|
|
# ImmortalWrt feeds every run. Top-level chmod only: contents are created and
|
|
# owned by the container's uid-1000 build user (restore preserves ownership).
|
|
FEEDS_CACHE="$CACHE/feeds/apk"
|
|
mkdir -p "$FEEDS_CACHE"
|
|
chmod a+rwX "$CACHE" "$CACHE/feeds" "$FEEDS_CACHE" 2>/dev/null || true
|
|
|
|
# Fetch the SDK tarball ON THE RUNNER (restored cache -> own Gitea release-asset
|
|
# mirror -> upstream with stall-kill + retries) instead of the old bare
|
|
# `wget` inside the container, which hung whole runs when
|
|
# downloads.immortalwrt.org stalled mid-transfer.
|
|
SDK_TAR="$CACHE/sdk/$(basename "$SDK_URL")"
|
|
sh "$REPO/ci/fetch-sdk.sh" "$SDK_URL" "$SDK_TAR"
|
|
|
|
# --- 1) SDK build + index + sign inside a debian container -------------------
|
|
# `--volumes-from $(hostname)` shares THIS job container's workspace volume into
|
|
# the nested container (see ci/build-feed.sh for why a bare -v does not work on
|
|
# the act_runner DinD setup).
|
|
echo "[apk-feed] SDK build arch=$ARCH (ImmortalWrt 25.12 apk-SDK)"
|
|
docker pull -q debian:bookworm
|
|
docker run --rm --volumes-from "$(hostname)" \
|
|
-e ARCH="$ARCH" -e REPO="$REPO" -e OUT="$OUT" -e SDK_URL="$SDK_URL" \
|
|
-e SDK_TAR="$SDK_TAR" -e DL_DIR="$CACHE/dl" -e APT_CACHE="$CACHE/apt" \
|
|
-e FEEDS_CACHE="$FEEDS_CACHE" -e KEY_APK="${KEY_APK:-}" \
|
|
-e SHATER_PKG_VERSION="$SHATER_PKG_VERSION" \
|
|
-e SHATER_PKG_RELEASE="$SHATER_PKG_RELEASE" \
|
|
debian:bookworm bash "$REPO/ci/sdk-build-apk.sh"
|
|
|
|
# --- 2) sanity: the per-arch apk repo dir must be complete -------------------
|
|
[ -s "$OUT/packages.adb" ] || { echo "[apk-feed] ERROR: $OUT/packages.adb missing/empty" >&2; exit 4; }
|
|
apks=$(find "$OUT" -maxdepth 1 -name '*.apk' | wc -l)
|
|
[ "$apks" -ge 4 ] || { echo "[apk-feed] ERROR: expected >=4 .apk in $OUT, found $apks" >&2; exit 5; }
|
|
if [ -n "${KEY_APK:-}" ] && [ ! -s "$OUT/shater-apk.pem" ]; then
|
|
echo "[apk-feed] ERROR: signed feed but shater-apk.pem missing from $OUT" >&2; exit 6
|
|
fi
|
|
|
|
echo "[apk-feed] done arch=$ARCH -> $OUT"
|
|
ls -l "$OUT"
|