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>
96 lines
3.4 KiB
Bash
Executable File
96 lines
3.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# Upload a repo/ tree -- signed APKs plus the signed index -- to an
|
|
# S3-compatible bucket.
|
|
#
|
|
# AWS_ACCESS_KEY_ID=... AWS_SECRET_ACCESS_KEY=... \
|
|
# bash publish.sh <repo-root>/repo <bucket> <endpoint-url> [<prefix>]
|
|
#
|
|
# Bucket, endpoint and prefix are all arguments, never baked in here: this
|
|
# repo does not know, and per fdroid-repo-ci#1 must never come to know, which
|
|
# bucket or host any consumer publishes to. Credentials come from the
|
|
# standard AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY/AWS_SESSION_TOKEN
|
|
# environment variables that `aws` itself reads -- nothing here parses or
|
|
# forwards them as arguments.
|
|
#
|
|
# Region is required by the `aws` CLI even against a non-AWS S3-compatible
|
|
# backend that ignores it; set AWS_DEFAULT_REGION if the endpoint cares,
|
|
# otherwise the placeholder below is never actually consulted.
|
|
#
|
|
# Uses `aws s3 sync`, not `cp --recursive`: re-publishing re-uploads only
|
|
# what changed. Does **not** pass `--delete` by default -- an F-Droid repo
|
|
# normally keeps every APK it has ever served (older index entries can still
|
|
# point at them), so silently pruning the remote on every publish is the
|
|
# wrong default. Pass `--delete` as an extra argument if a caller genuinely
|
|
# wants the remote pruned to match local.
|
|
#
|
|
# `fdroid update` needs no network; this is the one script in this repo that
|
|
# does (fdroid-repo-ci#1), and is accordingly the one script whose happy path
|
|
# the test suite cannot exercise against a real bucket. `--dry-run` prints
|
|
# the exact command this script would run -- including the `with-nixpkgs.sh`
|
|
# pin -- and exits without touching the network, which is what the test
|
|
# suite asserts against. (A PATH-stubbed `aws` cannot do this job: `nix
|
|
# shell` puts the packages it was asked for at the *front* of PATH, ahead of
|
|
# anything already there, so a stub earlier on the caller's PATH would simply
|
|
# be shadowed by the real `aws` from awscli2.) Separately, the test suite
|
|
# also runs this for real against a closed local port, to confirm the
|
|
# constructed command is well-formed and genuinely attempts a network call
|
|
# rather than failing on argument parsing.
|
|
#
|
|
# Pins awscli2 via with-nixpkgs.sh/nixpkgs-pin, next to this script.
|
|
set -euo pipefail
|
|
|
|
here=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
|
|
|
if [ "$#" -lt 3 ]; then
|
|
cat >&2 <<'USAGE'
|
|
usage: publish.sh [--dry-run] <local-repo-dir> <bucket> <endpoint-url> [<prefix>] [extra aws s3 sync args...]
|
|
|
|
Credentials: AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY (and optionally
|
|
AWS_SESSION_TOKEN) must already be exported -- never passed as arguments.
|
|
USAGE
|
|
exit 2
|
|
fi
|
|
|
|
dry_run=false
|
|
if [ "$1" = "--dry-run" ]; then
|
|
dry_run=true
|
|
shift
|
|
fi
|
|
|
|
local_dir=$1
|
|
bucket=$2
|
|
endpoint=$3
|
|
shift 3
|
|
|
|
prefix=""
|
|
if [ "$#" -gt 0 ] && [[ $1 != -* ]]; then
|
|
prefix=$1
|
|
shift
|
|
fi
|
|
|
|
extra_args=("$@")
|
|
|
|
[ -d "$local_dir" ] || { echo "publish.sh: no such directory: $local_dir" >&2; exit 2; }
|
|
: "${AWS_ACCESS_KEY_ID:?publish.sh: AWS_ACCESS_KEY_ID is not set}"
|
|
: "${AWS_SECRET_ACCESS_KEY:?publish.sh: AWS_SECRET_ACCESS_KEY is not set}"
|
|
|
|
dest="s3://$bucket"
|
|
if [ -n "$prefix" ]; then
|
|
dest="$dest/${prefix#/}"
|
|
fi
|
|
|
|
cmd=(bash "$here/with-nixpkgs.sh" awscli2 aws s3 sync "$local_dir" "$dest"
|
|
--endpoint-url "$endpoint"
|
|
--region "${AWS_DEFAULT_REGION:-us-east-1}"
|
|
"${extra_args[@]}")
|
|
|
|
if [ "$dry_run" = true ]; then
|
|
printf '%q ' "${cmd[@]}"
|
|
printf '\n'
|
|
exit 0
|
|
fi
|
|
|
|
echo "publish.sh: syncing $local_dir -> $dest (endpoint $endpoint)"
|
|
exec "${cmd[@]}"
|