Files
fdroid-repo-ci/test_with_nixpkgs.sh
claudeandbit 3f14c01b00 Build the shared F-Droid publishing tooling: sign, index, publish
Adds sign-apk.sh (align-check + apksigner), fdroid-update.sh (fdroid
update over a binary repo, signing the index with its own separate
key), publish.sh (S3-compatible upload) and the composite action
tying them together, matching weblib-ci's shape.

zipalign is not a standalone nixpkgs attribute; resolved by measurement
rather than assumption that Gradle/AGP already aligns its output (Android's
own docs, corroborated by fdroidserver never shelling out to zipalign) and
added check_zip_alignment.py as the safety net, since apksigner itself does
not check alignment at all. nixpkgs is pinned via a committed nixpkgs-pin
revision, since this repo has no flake.lock of its own for with-nixpkgs.sh
to read (fdroid-repo-ci#1, weblib-ci#9) -- a missing or malformed pin fails
loudly rather than degrading to an unpinned nix shell.

No consumer repo, bucket, hostname or channel name is hard-coded: which
repo holds the keys and runs the publish has already changed once during
this issue and may again, so every example uses a placeholder.

42 offline/local-only test assertions across five suites (run_tests.sh),
including fault injection on the alignment check, the password/argument
validation, and the with-nixpkgs.sh fail-loud paths.

Co-authored-by: bit <bit@das-labor.org>
2026-09-09 06:34:36 +00:00

62 lines
3.1 KiB
Bash
Executable File

#!/usr/bin/env bash
#
# Offline tests for with-nixpkgs.sh's fail-loud paths. Deliberately does not
# exercise the happy path here -- resolving a real `github:nixos/nixpkgs/...`
# reference needs network (or an already-warm local cache) the same way
# weblib-ci's own with-nixpkgs.sh does, and weblib-ci does not carry an
# automated test for that half either. It was measured by hand instead (see
# the PR description) by running `with-nixpkgs.sh apksigner apksigner
# version` and `with-nixpkgs.sh "fdroidserver jdk21 apksigner" bash -c
# 'which fdroid jarsigner apksigner'` and reading the resolved store paths
# back.
#
# What *is* fully offline and belongs in an automated suite: every way this
# script is supposed to refuse rather than silently fall back to an unpinned
# `nix shell nixpkgs#foo` -- none of these reach `nix` at all, so they run
# with no network and no local nix store required.
set -euo pipefail
here=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
source "$here/test_lib.sh"
work=$(mktemp -d)
trap 'rm -rf "$work"' EXIT
# --- too few arguments -------------------------------------------------
assert_failure "too few args exits non-zero" \
bash "$here/with-nixpkgs.sh" onlyoneattr
# --- missing pin file ---------------------------------------------------
mkdir -p "$work/no-pin"
cp "$here/with-nixpkgs.sh" "$work/no-pin/"
out=$(bash "$work/no-pin/with-nixpkgs.sh" apksigner true 2>&1) && rc=0 || rc=$?
if [ "${rc:-0}" -ne 0 ]; then pass "missing pin exits non-zero"; else fail "missing pin exits non-zero (got 0)"; fi
assert_contains "missing pin names the problem, not a stack trace" "$out" "no $work/no-pin/nixpkgs-pin"
assert_contains "missing pin says it refuses to fall back" "$out" "refusing to fall back"
# --- malformed pin (not 40 hex chars) -----------------------------------
mkdir -p "$work/bad-pin"
cp "$here/with-nixpkgs.sh" "$work/bad-pin/"
echo "not-a-revision" > "$work/bad-pin/nixpkgs-pin"
out=$(bash "$work/bad-pin/with-nixpkgs.sh" apksigner true 2>&1) && rc=0 || rc=$?
if [ "${rc:-0}" -ne 0 ]; then pass "malformed pin exits non-zero"; else fail "malformed pin exits non-zero (got 0)"; fi
assert_contains "malformed pin names what's wrong" "$out" "does not hold a 40-character"
# --- a well-formed pin is accepted up to the point of invoking nix ------
# (proves the regex/parsing logic itself, without needing nix on PATH or
# reachable: a bogus command name still gets past validation and only fails
# once nix actually tries to run it.)
mkdir -p "$work/good-pin"
cp "$here/with-nixpkgs.sh" "$work/good-pin/"
echo "0123456789abcdef0123456789abcdef01234567" > "$work/good-pin/nixpkgs-pin"
out=$(bash "$work/good-pin/with-nixpkgs.sh" apksigner true 2>&1) && rc=0 || rc=$?
# whatever happens next is nix's business (missing binary, no network,
# etc) -- the point is it got *past* this script's own validation, i.e. it
# must not repeat either of the loud-failure messages above.
if [[ "$out" != *"refusing to fall back"* ]] && [[ "$out" != *"does not hold a 40-character"* ]]; then
pass "well-formed pin passes this script's own validation"
else
fail "well-formed pin passes this script's own validation (got: $out)"
fi
report_and_exit