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>
This commit is contained in:
Executable
+57
@@ -0,0 +1,57 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Tests for publish.sh -- the one script in this repo that needs real
|
||||
# network to do its actual job (fdroid-repo-ci#1), so its happy path against
|
||||
# a genuine bucket is out of scope here. What this asserts instead:
|
||||
#
|
||||
# * argument/credential validation, offline;
|
||||
# * `--dry-run` builds the exact command a real run would use, offline;
|
||||
# * a real invocation against a closed local port fails on the network call
|
||||
# itself, not on argument parsing -- proving the command it built is
|
||||
# well-formed, without needing a real bucket or reaching beyond loopback.
|
||||
set -euo pipefail
|
||||
here=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
source "$here/test_lib.sh"
|
||||
|
||||
work=$(mktemp -d)
|
||||
trap 'rm -rf "$work"' EXIT
|
||||
mkdir -p "$work/repo"
|
||||
echo '{}' > "$work/repo/index-v2.json"
|
||||
|
||||
echo "--- missing credentials are refused, not sent as empty ---"
|
||||
assert_failure "publish.sh refuses with no AWS_ACCESS_KEY_ID" \
|
||||
env -u AWS_ACCESS_KEY_ID -u AWS_SECRET_ACCESS_KEY \
|
||||
bash "$here/publish.sh" "$work/repo" mybucket https://s3.example.invalid
|
||||
|
||||
export AWS_ACCESS_KEY_ID=AKIAFAKETESTKEY
|
||||
export AWS_SECRET_ACCESS_KEY=fake-secret-not-real
|
||||
|
||||
echo "--- missing local directory is refused ---"
|
||||
assert_failure "publish.sh refuses a non-existent local directory" \
|
||||
bash "$here/publish.sh" "$work/does-not-exist" mybucket https://s3.example.invalid
|
||||
|
||||
echo "--- --dry-run builds the right command, touches no network ---"
|
||||
out=$(bash "$here/publish.sh" --dry-run "$work/repo" mybucket https://s3.example.invalid myprefix)
|
||||
assert_contains "dry-run names the destination bucket and prefix" "$out" "s3://mybucket/myprefix"
|
||||
assert_contains "dry-run names the endpoint" "$out" "--endpoint-url https://s3.example.invalid"
|
||||
assert_contains "dry-run goes through with-nixpkgs.sh, same as every other script" "$out" "with-nixpkgs.sh"
|
||||
if echo "$out" | grep -q -- --delete; then
|
||||
fail "dry-run does not silently add --delete (it did!)"
|
||||
else
|
||||
pass "dry-run does not silently add --delete"
|
||||
fi
|
||||
|
||||
echo "--- --dry-run with no prefix omits the trailing slash entirely ---"
|
||||
out_noprefix=$(bash "$here/publish.sh" --dry-run "$work/repo" mybucket https://s3.example.invalid)
|
||||
assert_contains "no-prefix dry-run targets the bucket root" "$out_noprefix" "s3://mybucket "
|
||||
|
||||
echo "--- a real invocation fails on the network call, not on arguments ---"
|
||||
# port 1 is a reserved, unassigned TCP port -- nothing listens there, so this
|
||||
# never leaves the loopback interface and needs no real network access.
|
||||
real_out=$(bash "$here/publish.sh" "$work/repo" mybucket "http://127.0.0.1:1" 2>&1) && rc=0 || rc=$?
|
||||
if [ "${rc:-0}" -ne 0 ]; then pass "publish.sh against a closed port exits non-zero"; else
|
||||
fail "publish.sh against a closed port exits non-zero (got 0)"
|
||||
fi
|
||||
assert_contains "the failure is a connection error, not an argument error" "$real_out" "Could not connect"
|
||||
|
||||
report_and_exit
|
||||
Reference in New Issue
Block a user