Commit Graph
3 Commits
Author SHA1 Message Date
claudeandbit 19e55c4a53 publish.sh: verify credentials and upload the index last; add next-version-code.sh
Closes #5
Closes #6

An F-Droid repo is a signed index plus the files it names, and a partial
upload could previously leave them disagreeing: aws s3 sync walks the tree
in its own order, so an interrupted publish could land the index before the
APKs it names, breaking the repo for every client until the upload finished
or was rolled back. publish.sh now uploads in two passes, unconditionally --
every non-index file first, the index (index-v1.json(.asc), index-v2.json,
entry.json, entry.jar) last -- so an interruption anywhere in pass 1 simply
leaves the repo describing the old state a little longer, never a mixture.
Credentials are also verified with one real authenticated call
(head-bucket) before either pass, rather than merely checking the
environment variables are non-empty, since an unusable-but-present
credential failing halfway through is exactly how a partial upload happens.

next-version-code.sh is the one implementation of the versionCode rule
(candidate = minutes since 2026-01-01Z, clamped to strictly exceed whatever
is already published for that applicationId), shared by CI and manual
builds so there is exactly one place this can drift. bit pointed out
(appended to #6) that the clamp is monotonic against *observed* state, not
monotonic by construction: two jobs starting in the same minute can both
read the same published value and race to publish the same versionCode on
different APKs. Nothing can prevent that wasted build, so publish.sh now
also refuses to overwrite an already-existing APK object before pass 1 --
turning the collision from a silent, permanent wrong state into a loud
failure at the last moment the information is reliable.

Tested offline (83 assertions: pure-stdlib suites for both scripts, the
real CLIs through with-nixpkgs.sh, and a small local HEAD-only S3 stub
proving the credential check is a real authenticated call and the
APK-collision refusal fires only when it should) and live against
fdroid-weblib-dev (7 more: a real publish observed mid-flight via a
same-process synchronization hook to prove the index is genuinely absent
while the file is already present, both objects reading back
byte-identical, and a second publish refused against a real
already-published APK with its bytes left unchanged).

Co-authored-by: bit <bit@das-labor.org>
2026-09-09 08:00:45 +00:00
claudeandbit 52f8de9993 README: narrow the "not hard-coded" claim to what is true
It said no organisation appears "in a path, URL or workflow reference",
while the usage examples immediately above necessarily contain
`https://git.chaosbit.de/weblib/fdroid-repo-ci@main` -- a consumer has to
type this repository's address, so it cannot not appear.

A rule a file visibly breaks is worse than no rule: the next person either
"fixes" the examples or stops trusting the section. So the claim now covers
what it should -- consumer-specific things, and any named consumer -- and
calls out this repo's own address as the one deliberate exception, which is
also a useful pointer to the exact lines to edit when the repo moves org.

Found in the cold re-read of #2.

Co-authored-by: bit <bit@das-labor.org>
2026-09-09 06:38:29 +00:00
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