packages.arasaka.software is published from its own repository; the release only signs the rpm
Build / Desktop, server and tools (push) Successful in 1m4s

thepra/packages.arasaka.software now reads this repository's releases and publishes
them with every other joined app, so the daily packages and F-Droid jobs, their
scripts and the repository's F-Droid settings leave this repository. The release
still signs the rpm on its own page with the Arasaka key, as the README promises,
and the F-Droid listing stays in packaging/fdroid/metadata, read at each tag.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
thepraandClaude Opus 5.5 committed 2026-11-01 17:10:32 +01:00
1 parent 0c722c21d4
commit f41e1e178f
12 files changed
+42 -383

No files matched your search

-126
View File
@@ -1,126 +0,0 @@
#!/bin/sh
set -eu
version=${1:-}
here=$(pwd)
root=${PACKAGES_ROOT:-/var/www/packages.arasaka.software}
keep=${FDROID_KEEP:-3}
url=https://packages.arasaka.software/fdroid/repo
fingerprint=5F52CFF4F52F4E0B6DA6CD044BFCEAF78D1D42DB24F2470602DB7F19CBFDF846
id=software.arasaka.meweb
if [ -z "${MEWEB_KEYSTORE_B64:-}" ] || [ -z "${MEWEB_KEYSTORE_PASS:-}" ]; then
echo "::error::the repository secrets MEWEB_KEYSTORE_B64 and MEWEB_KEYSTORE_PASS are not set"
exit 1
fi
if [ -n "$version" ]; then
apk=$here/releases/$version/MeWeb-$version-android.apk
test -f "$apk"
major=$(echo "$version" | cut -d. -f1)
minor=$(echo "$version" | cut -d. -f2)
patch=$(echo "$version" | cut -d. -f3)
code=$((major * 10000 + minor * 100 + patch))
elif [ ! -e "$root/fdroid/repo" ]; then
echo "no repository at $root/fdroid/repo yet: the first release makes it"
exit 0
fi
tools/setup.sh --group fdroid
tools=$(cd "$here/tools/fdroid/linux-x64" && pwd -P)
uv=$tools/uv-x86_64-unknown-linux-gnu/uv
python=$(command -v python3)
JAVA_HOME=$(ls -d "$here"/tools/jdk/linux-x64/*/ | head -n 1)
ANDROID_HOME=$here/tools/android-sdk
PATH=$JAVA_HOME/bin:$PATH
export JAVA_HOME ANDROID_HOME PATH
exec 9>>"$root/.lock"
flock -w 2700 9
work=$(mktemp -d)
trap 'rm -rf "$work"' EXIT
keyless() {
env -u MEWEB_KEYSTORE_B64 -u MEWEB_KEYSTORE_PASS UV_CACHE_DIR="$tools/cache" "$@"
}
if [ -n "$version" ] && "$tools/current/bin/fdroid" --version > /dev/null 2>&1; then
install=$(readlink -f "$tools/current")
else
settled=$(date -u -d '14 days ago' +%Y-%m-%dT%H:%M:%SZ)
echo fdroidserver | keyless "$uv" pip compile -q --python "$python" --exclude-newer "$settled" --generate-hashes \
--no-header --no-annotate -o "$work/lock.txt" -
install=$tools/fdroidserver-$(sha256sum < "$work/lock.txt" | cut -c1-12)
if ! "$install/bin/fdroid" --version > /dev/null 2>&1; then
rm -rf "$install"
keyless "$uv" venv -q --python "$python" "$install"
keyless "$uv" pip sync -q --python "$install/bin/python" "$work/lock.txt"
cp "$work/lock.txt" "$install/lock.txt"
fi
fi
tool=$("$install/bin/fdroid" --version)
stamp=$( { cat "$install/lock.txt"; cd packaging/fdroid && find config.yml icon.png metadata -type f | LC_ALL=C sort | xargs sha256sum; } | sha256sum | cut -d' ' -f1)
if [ -z "$version" ] && [ "$(cat "$(readlink -f "$root/fdroid/repo")/../built-from" 2>/dev/null)" = "$stamp" ]; then
echo "nothing new: the repository is already built with fdroidserver $tool and this listing"
exit 0
fi
echo "fdroidserver $tool, $(basename "$install")"
(umask 077 && printf '%s' "$MEWEB_KEYSTORE_B64" | base64 -d > "$work/meweb.keystore")
MEWEB_KEYSTORE=$work/meweb.keystore
export MEWEB_KEYSTORE MEWEB_KEYSTORE_PASS
unset MEWEB_KEYSTORE_B64
held=$(keytool -J-Duser.language=en -list -v -keystore "$MEWEB_KEYSTORE" -storepass:env MEWEB_KEYSTORE_PASS -alias meweb | sed -n 's/^.*SHA256: *//p' | tr -d ':')
test "$held" = "$fingerprint"
state=$root/.fdroid
snap=$state/$(date -u +%Y%m%d%H%M%S)-${version:-tools}
mkdir -p "$snap/repo" "$snap/metadata" "$snap/tmp"
if [ -e "$root/fdroid/repo" ]; then
prior=$(readlink -f "$root/fdroid/repo")/..
for file in "$prior"/repo/*.apk; do
[ -e "$file" ] && ln "$file" "$snap/repo/"
done
for icons in "$prior"/repo/icons*; do
[ -d "$icons" ] && cp -a "$icons" "$snap/repo/"
done
cp -a "$prior/metadata/." "$snap/metadata/"
cp "$prior/repo/index-v2.json" "$snap/repo/"
if [ -f "$prior/tmp/apkcache.json" ]; then cp "$prior/tmp/apkcache.json" "$snap/tmp/"; fi
fi
cp packaging/fdroid/config.yml "$snap/config.yml"
chmod 600 "$snap/config.yml"
cp packaging/fdroid/icon.png "$snap/icon.png"
cp -r packaging/fdroid/metadata/. "$snap/metadata/"
if [ -n "$version" ]; then
rm -f "$snap/repo/${id}_$code.apk"
cp "$apk" "$snap/repo/${id}_$code.apk"
fi
(cd "$snap/repo" && ls "$id"_*.apk | sed 's/.*_\([0-9]*\)\.apk$/\1/' | sort -n | head -n "-$keep" | while read -r old; do
rm -f "${id}_$old.apk"
done)
newest=$(cd "$snap/repo" && ls "$id"_*.apk | sed 's/.*_\([0-9]*\)\.apk$/\1/' | sort -n | tail -n 1)
(cd "$snap" && "$install/bin/fdroid" update)
rm -rf "$snap/repo/status"
chmod -R u=rwX,go=rX "$snap/repo"
echo "$stamp" > "$snap/built-from"
mkdir -p "$root/fdroid"
ln -sfn "../.fdroid/$(basename "$snap")/repo" "$root/fdroid/repo.new"
mv -T -f "$root/fdroid/repo.new" "$root/fdroid/repo"
ls -1d "$state"/*/ | sort | head -n -3 | while read -r old; do
find "$old" -maxdepth 0 -mmin +1440 -exec rm -rf {} +
done
echo "published $root/fdroid/repo, newest ${id}_$newest.apk, with fdroidserver $tool"
if [ "$root" = /var/www/packages.arasaka.software ]; then
curl -fsS "$url/entry.jar" -o "$work/entry.jar"
signed=$(keytool -J-Duser.language=en -printcert -jarfile "$work/entry.jar" | sed -n 's/^.*SHA256: *//p' | head -n 1 | tr -d ':')
test "$signed" = "$fingerprint"
curl -fsS "$url/index-v2.json" | grep -Eq "\"versionCode\": ?$newest\b"
curl -fsSI "$url/${id}_$newest.apk" > /dev/null
echo "live at $url: newest $id $newest"
fi
ln -sfn "$(basename "$install")" "$tools/current.new"
mv -T -f "$tools/current.new" "$tools/current"
for old in "$tools"/fdroidserver-*; do
[ "$old" = "$install" ] || rm -rf "$old"
done
-124
View File
@@ -1,124 +0,0 @@
#!/bin/sh
set -eu
version=${1:-}
root=${PACKAGES_ROOT:-/var/www/packages.arasaka.software}
keep=${PACKAGES_KEEP:-5}
url=https://packages.arasaka.software
fingerprint=F92C166E9B1C13EDD1629E76888DCF969D133FB2
if [ -n "$version" ]; then
releases=$(pwd)/releases/$version
deb=$releases/MeWeb-$version-linux-x64.deb
rpm=$releases/MeWeb-$version-linux-x64.rpm
test -f "$deb"
test -f "$rpm"
elif [ ! -e "$root/apt" ] || [ ! -e "$root/rpm" ]; then
echo "no repositories at $root yet: the first release makes them"
exit 0
fi
tools=$(dpkg-query -W -f '${Package} ${Version}\n' apt-utils createrepo-c dpkg gnupg rpm)
named=$(echo "$tools" | paste -sd, - | sed 's/,/, /g')
stamp=$( { echo "$tools"; cat "$0"; } | sha256sum | cut -d' ' -f1)
exec 9>>"$root/.lock"
flock -w 2700 9
if [ -z "$version" ] && [ "$(cat "$(readlink -f "$root/apt")/../built-from" 2>/dev/null)" = "$stamp" ]; then
echo "nothing new: the repositories are already built with $named"
exit 0
fi
echo "$named"
keys=$(mktemp -d)
trap 'rm -rf "$keys"' EXIT
export GNUPGHOME="$keys"
printf '%s\n' "$PACKAGES_SIGNING_KEY" | gpg --batch --quiet --import
gpg --batch --with-colons --list-secret-keys | grep -q "^fpr:::::::::$fingerprint:$"
gpg --batch --armor --export "$fingerprint" > "$keys/public.asc"
if [ -n "$version" ]; then
rpmsign --define "__gpg /usr/bin/gpg" --define "_gpg_name $fingerprint" --define "_gpg_path $keys" --addsign "$rpm" >/dev/null
rpmkeys --dbpath "$keys/rpmdb" --import "$keys/public.asc"
rpmkeys --dbpath "$keys/rpmdb" -K "$rpm" | grep -q 'digests signatures OK'
full=$(dpkg-deb -f "$deb" Version)
test "$(dpkg-deb -f "$deb" Package)" = meweb
test "${full%-*}" = "$version"
debname=meweb_${full}_$(dpkg-deb -f "$deb" Architecture).deb
rpmname=$(rpm -qp --nosignature --qf '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}.rpm' "$rpm")
test "$(rpm -qp --nosignature --qf '%{NAME} %{VERSION}' "$rpm")" = "meweb $version"
fi
snap=$root/.snap/$(date -u +%Y%m%d%H%M%S)-${version:-tools}
mkdir -p "$snap/apt/pool/main" "$snap/rpm"
if [ -d "$root/apt/pool/main" ]; then cp -al "$root/apt/pool/main/." "$snap/apt/pool/main/"; fi
if [ -d "$root/rpm" ]; then
for folder in "$root"/rpm/*/; do
[ "$(basename "$folder")" = repodata ] || cp -al "$folder" "$snap/rpm/"
done
fi
mkdir -p "$snap/apt/pool/main/m/meweb" "$snap/rpm/meweb"
if [ -n "$version" ]; then
rm -f "$snap/apt/pool/main/m/meweb/$debname" "$snap/rpm/meweb/$rpmname"
cp "$deb" "$snap/apt/pool/main/m/meweb/$debname"
cp "$rpm" "$snap/rpm/meweb/$rpmname"
fi
for folder in "$snap/apt/pool/main/m/meweb" "$snap/rpm/meweb"; do
ls "$folder" | sed -E 's/^meweb[_-]([0-9.]+)-.*/\1/' | sort -uV | head -n "-$keep" | while read -r old; do
rm -f "$folder/meweb_$old-"* "$folder/meweb-$old-"*
done
done
if [ -z "$version" ]; then
debname=$(ls "$snap/apt/pool/main/m/meweb" | sort -V | tail -n 1)
rpmname=$(ls "$snap/rpm/meweb" | sort -V | tail -n 1)
full=$(dpkg-deb -f "$snap/apt/pool/main/m/meweb/$debname" Version)
fi
binary=$snap/apt/dists/stable/main/binary-amd64
mkdir -p "$binary"
(cd "$snap/apt" && apt-ftparchive packages pool) > "$binary/Packages"
gzip -9nc "$binary/Packages" > "$binary/Packages.gz"
(cd "$snap/apt/dists/stable" && apt-ftparchive \
-o APT::FTPArchive::Release::Origin=Arasaka -o APT::FTPArchive::Release::Label=Arasaka \
-o APT::FTPArchive::Release::Suite=stable -o APT::FTPArchive::Release::Codename=stable \
-o APT::FTPArchive::Release::Architectures=amd64 -o APT::FTPArchive::Release::Components=main \
-o APT::FTPArchive::Release::NotAutomatic=yes -o APT::FTPArchive::Release::ButAutomaticUpgrades=yes \
-o "APT::FTPArchive::Release::Description=Arasaka packages" release .) > "$keys/Release"
mv "$keys/Release" "$snap/apt/dists/stable/Release"
gpg --batch --yes --local-user "$fingerprint" --clearsign -o "$snap/apt/dists/stable/InRelease" "$snap/apt/dists/stable/Release"
gpg --batch --yes --local-user "$fingerprint" --armor --detach-sign -o "$snap/apt/dists/stable/Release.gpg" "$snap/apt/dists/stable/Release"
createrepo_c --quiet "$snap/rpm"
repodata=$snap/rpm/repodata
gpg --batch --yes --local-user "$fingerprint" --armor --detach-sign -o "$repodata/repomd.xml.asc" "$repodata/repomd.xml"
cp "$keys/public.asc" "$repodata/repomd.xml.key"
if [ -f "$root/rpm/repodata/repomd.xml" ]; then
grep -o 'repodata/[^"]*' "$root/rpm/repodata/repomd.xml" | while read -r href; do
[ -e "$snap/rpm/$href" ] || cp "$root/rpm/$href" "$snap/rpm/$href"
done
fi
chmod -R u=rwX,go=rX "$snap"
echo "$stamp" > "$snap/built-from"
for part in apt rpm; do
ln -sfn ".snap/$(basename "$snap")/$part" "$root/$part.new"
mv -T -f "$root/$part.new" "$root/$part"
done
ls -1d "$root"/.snap/* | sort | head -n -3 | while read -r old; do
find "$old" -maxdepth 0 -mmin +1440 -exec rm -rf {} +
done
echo "published $root/apt and $root/rpm, newest $debname and $rpmname"
if [ -n "$version" ]; then
(cd "$releases" && for file in $(ls | LC_ALL=C sort); do [ "$file" = SHA256SUMS.txt ] || sha256sum "$file"; done) > "$keys/sums"
mv "$keys/sums" "$releases/SHA256SUMS.txt"
fi
if [ "$root" = /var/www/packages.arasaka.software ]; then
curl -fsS "$url/apt/dists/stable/main/binary-amd64/Packages" | grep -qx "Version: $full"
curl -fsS "$url/apt/dists/stable/InRelease" > "$keys/InRelease"
gpg --batch --quiet --verify "$keys/InRelease"
curl -fsS "$url/rpm/repodata/repomd.xml" > "$keys/repomd.xml"
curl -fsS "$url/rpm/repodata/repomd.xml.asc" > "$keys/repomd.xml.asc"
gpg --batch --quiet --verify "$keys/repomd.xml.asc" "$keys/repomd.xml"
curl -fsSI "$url/rpm/meweb/$rpmname" > /dev/null
echo "live at $url: meweb $full"
fi
+1 -1
View File
@@ -8,7 +8,7 @@ fi
echo "VERSION=$version" >> "$GITHUB_ENV" echo "VERSION=$version" >> "$GITHUB_ENV"
echo "COMMIT=$(echo "$GITHUB_SHA" | cut -c1-8)" >> "$GITHUB_ENV" echo "COMMIT=$(echo "$GITHUB_SHA" | cut -c1-8)" >> "$GITHUB_ENV"
keep="$HOME/.cache/meweb" keep="$HOME/.cache/meweb"
for dir in tools/cache tools/jdk tools/packaging tools/android-sdk tools/fdroid; do for dir in tools/cache tools/jdk tools/packaging tools/android-sdk; do
mkdir -p "$keep/$dir" mkdir -p "$keep/$dir"
rm -rf "$dir" rm -rf "$dir"
ln -s "$keep/$dir" "$dir" ln -s "$keep/$dir" "$dir"
+19
View File
@@ -0,0 +1,19 @@
#!/bin/sh
set -eu
version=$1
releases=$(pwd)/releases/$version
rpm=$releases/MeWeb-$version-linux-x64.rpm
fingerprint=F92C166E9B1C13EDD1629E76888DCF969D133FB2
test -f "$rpm"
keys=$(mktemp -d)
trap 'rm -rf "$keys"' EXIT
export GNUPGHOME="$keys"
printf '%s\n' "$PACKAGES_SIGNING_KEY" | gpg --batch --quiet --import
gpg --batch --with-colons --list-secret-keys | grep -q "^fpr:::::::::$fingerprint:$"
gpg --batch --armor --export "$fingerprint" > "$keys/public.asc"
rpmsign --define "__gpg /usr/bin/gpg" --define "_gpg_name $fingerprint" --define "_gpg_path $keys" --addsign "$rpm" > /dev/null
rpmkeys --dbpath "$keys/rpmdb" --import "$keys/public.asc"
rpmkeys --dbpath "$keys/rpmdb" -K "$rpm" | grep -q 'digests signatures OK'
(cd "$releases" && for file in $(ls | LC_ALL=C sort); do [ "$file" = SHA256SUMS.txt ] || sha256sum "$file"; done) > "$keys/sums"
mv "$keys/sums" "$releases/SHA256SUMS.txt"
echo "signed $(basename "$rpm") with $fingerprint"
-22
View File
@@ -1,22 +0,0 @@
name: F-Droid tools
on:
schedule:
- cron: '23 5 * * *'
workflow_dispatch:
jobs:
refresh:
name: The newest F-Droid tools, tried on the repository
runs-on: nuvola
steps:
- uses: actions/checkout@v4
- name: Prepare
run: .gitea/scripts/prepare.sh
- name: Rebuild the repository on packages.arasaka.software when the tools or the listing changed
env:
MEWEB_KEYSTORE_B64: ${{ secrets.MEWEB_KEYSTORE_B64 }}
MEWEB_KEYSTORE_PASS: ${{ secrets.MEWEB_KEYSTORE_PASS }}
run: .gitea/scripts/fdroid.sh
-24
View File
@@ -1,24 +0,0 @@
name: Package tools
on:
schedule:
- cron: '43 5 * * *'
workflow_dispatch:
jobs:
refresh:
name: The box's updated package tools, tried on the apt and rpm repositories
runs-on: nuvola
steps:
- uses: actions/checkout@v4
- name: Check that the box brought the tools up to date this morning
run: |
systemctl show packages-tools -p Result -p ExecMainExitTimestamp
systemctl is-active --quiet packages-tools.timer
test "$(systemctl show packages-tools -p Result --value)" = success
- name: Rebuild the apt and rpm repositories on packages.arasaka.software when the tools changed
env:
PACKAGES_SIGNING_KEY: ${{ secrets.PACKAGES_SIGNING_KEY }}
run: .gitea/scripts/packages.sh
+2 -9
View File
@@ -43,21 +43,14 @@ jobs:
MEWEB_KEYSTORE_PASS: ${{ secrets.MEWEB_KEYSTORE_PASS }} MEWEB_KEYSTORE_PASS: ${{ secrets.MEWEB_KEYSTORE_PASS }}
run: .gitea/scripts/android.sh run: .gitea/scripts/android.sh
- name: The deb and rpm on packages.arasaka.software, the rpm signed - name: The rpm signed with the Arasaka packages key
if: ${{ github.ref_type == 'tag' }} if: ${{ github.ref_type == 'tag' }}
env: env:
PACKAGES_SIGNING_KEY: ${{ secrets.PACKAGES_SIGNING_KEY }} PACKAGES_SIGNING_KEY: ${{ secrets.PACKAGES_SIGNING_KEY }}
run: .gitea/scripts/packages.sh "$VERSION" run: .gitea/scripts/sign-rpm.sh "$VERSION"
- name: Publish the release - name: Publish the release
if: ${{ github.ref_type == 'tag' || inputs.publish == 'true' }} if: ${{ github.ref_type == 'tag' || inputs.publish == 'true' }}
env: env:
RELEASE_TOKEN: ${{ secrets.GITEA_TOKEN }} RELEASE_TOKEN: ${{ secrets.GITEA_TOKEN }}
run: .gitea/scripts/release.sh "v$VERSION" releases/"$VERSION"/* run: .gitea/scripts/release.sh "v$VERSION" releases/"$VERSION"/*
- name: The APK in the F-Droid repository on packages.arasaka.software
if: ${{ github.ref_type == 'tag' }}
env:
MEWEB_KEYSTORE_B64: ${{ secrets.MEWEB_KEYSTORE_B64 }}
MEWEB_KEYSTORE_PASS: ${{ secrets.MEWEB_KEYSTORE_PASS }}
run: .gitea/scripts/fdroid.sh "$VERSION"
-1
View File
@@ -17,7 +17,6 @@ appsettings.*.local.json
/tools/packaging/ /tools/packaging/
/tools/android-sdk/ /tools/android-sdk/
/tools/cache/ /tools/cache/
/tools/fdroid/
/tools/logs/ /tools/logs/
/.claude/settings.local.json /.claude/settings.local.json
/artifacts/ /artifacts/
+20 -53
View File
@@ -44,9 +44,8 @@ is root-owned, so CI uses the runner user's own `~/.dotnet` (passolo's `tools/re
| `MEWEB_KEYSTORE` | release step | a temporary file in `$RUNNER_TEMP` decoded by `.gitea/scripts/android.sh`, removed on exit | | `MEWEB_KEYSTORE` | release step | a temporary file in `$RUNNER_TEMP` decoded by `.gitea/scripts/android.sh`, removed on exit |
`build.yml` runs on every push to `master`; `release.yml` on a `v*` tag (publishes the Gitea release) or by hand `build.yml` runs on every push to `master`; `release.yml` on a `v*` tag (publishes the Gitea release) or by hand
(`publish: false` builds every platform and deploys the server only); `fdroid.yml` daily at 05:23 UTC or by hand (`publish: false` builds every platform and deploys the server only). Both run on `nuvola`, the instance-wide runner
(the F-Droid tools, below); `packages.yml` daily at 05:43 UTC or by hand (the deb and rpm tools, below). All four on the box (since 1 Nov 2026 it also takes the jobs labelled `build`),
run on the Arasaka org runner `nuvola`,
user `gitea-runner`, home `/var/lib/gitea-runner`: `tools/sdk.sh` installs the SDK from `global.json` into its user `gitea-runner`, home `/var/lib/gitea-runner`: `tools/sdk.sh` installs the SDK from `global.json` into its
`~/.dotnet` (the system SDK in `/opt/dotnet` is older and root-owned), and the JDK, nfpm and the Android SDK are `~/.dotnet` (the system SDK in `/opt/dotnet` is older and root-owned), and the JDK, nfpm and the Android SDK are
cached in `~/.cache/meweb`. There is deliberately no `pull_request` trigger: the runner is the production box. cached in `~/.cache/meweb`. There is deliberately no `pull_request` trigger: the runner is the production box.
@@ -161,58 +160,26 @@ The Android release key: alias `meweb`, certificate SHA-256
the network and the block without the publisher's server. A change to any knowledge file's format bumps the network and the block without the publisher's server. A change to any knowledge file's format bumps
`KnowledgeFeeder.Format` and the `"format":N` that `wait-knowledge.sh` waits for: the feeder rebuilds only when a `KnowledgeFeeder.Format` and the `"format":N` that `wait-knowledge.sh` waits for: the feeder rebuilds only when a
source changes or the format differs, and a release must not embed the previous build. source changes or the format differs, and a release must not embed the previous build.
- **The deb and rpm reach packages.arasaka.software from this repository's own release job.** On tags, - **packages.arasaka.software is fed from outside this repository** (since 1 Nov 2026). The private repository
`.gitea/scripts/packages.sh` runs on the `nuvola` runner (host mode, user `gitea-runner`, which owns `thepra/packages.arasaka.software` lists this app in `apps/meweb.yml`, reads every `v*` release from the Releases
`/var/www/packages.arasaka.software`). It imports the org secret `PACKAGES_SIGNING_KEY` into a throwaway tab every 15 minutes, and publishes the newest five debs and rpms, the newest three APKs in the F-Droid repository
`GNUPGHOME`, refuses any key but `F92C166E…3FB2`, signs the rpm in place, hard-links the current pool into a new and the newest Windows and macOS files under `/download/meweb/`, all signed with keys that live as `thepra`'s own
`.snap/` folder, adds this version, keeps the newest five, rebuilds and signs the apt (`InRelease`, `Release.gpg`) secrets. Its README is the reference. What this repository still owes it:
and rpm (`repomd.xml.asc`) metadata, carries over the files the previous `repomd.xml` named so a client mid-refresh - **The release must carry every file named in that entry and list each in `SHA256SUMS.txt`**, or the publisher
still finds them, swaps the `apt` and `rpm` links, rewrites `SHA256SUMS.txt` for the signed rpm, and checks the live leaves the version out and keeps serving the previous one. Renaming a release file means changing `apps/meweb.yml`
site. Never copy a package over a pool file: the pools are hard links into older snapshots, so it is `rm` then `cp`. in the same hour.
`PACKAGES_ROOT` and `PACKAGES_KEEP` exist for a test against a copy. YoloCICD, which used to do this, was erased on - **The rpm is signed here, before the release is published**, by `.gitea/scripts/sign-rpm.sh` with the Arasaka org
23 Oct 2026. `packaging/arasaka-repository.sh` is written into both maintainer scripts by `tools/release.cs`; it is secret `PACKAGES_SIGNING_KEY` (it refuses any key but `F92C166E…3FB2`), which then rewrites `SHA256SUMS.txt`, so
now maintained here by hand, and any change to a file it writes needs the old content's SHA-256 kept in the README's promise holds for the file on the release page too; the publisher sees the signature and keeps it.
- **The F-Droid listing stays in `packaging/fdroid/metadata/`** (English and Italian); the publisher reads it at the
release's tag. The repository's own settings and icon moved there.
- **The APK's signing key also signs the F-Droid index**, so `MEWEB_KEYSTORE_B64` exists twice: here, to sign the
APK, and as `thepra`'s `FDROID_KEYSTORE_B64`. The publisher refuses an APK signed by anything but `5f52cff4…f846`.
- `packaging/arasaka-repository.sh` is written into both maintainer scripts by `tools/release.cs`; it is
maintained here by hand, and any change to a file it writes needs the old content's SHA-256 kept in
`arasaka_repository_known`, or installed copies are treated as edited by hand and left alone. The package owns `arasaka_repository_known`, or installed copies are treated as edited by hand and left alone. The package owns
`/usr/share/arasaka-repository/meweb`, the marker that keeps the repository configured while any Arasaka package `/usr/share/arasaka-repository/meweb`, the marker that keeps the repository configured while any Arasaka package
is installed. The signing key's only copies are that secret and the owner's Nextcloud backup. is installed. The portal app (`arasaka.software`, `arasaka-portal`) carries a byte-identical copy; change both.
**The tools that build these two repositories are the box's own Ubuntu packages** (`apt-utils` for
`apt-ftparchive`, `createrepo-c`, `dpkg`, `gnupg`, `rpm`), and **a daily job keeps them current** (owner, 31 Oct
2026: the same daily update as the F-Droid tools). The runner cannot install packages, so the update is a root
timer on the box, `packages-tools.timer` at 05:13 UTC (source and setup in arasaka.software,
`deploy/packages.arasaka.software/`). It upgrades only those packages, from Ubuntu's updates and security
fixes, with package lists of its own, so it never brings the rest of the box forward. There is no two-week wait,
as there is for fdroidserver: Ubuntu reviews and signs these updates itself. `packages.yml` follows at 05:43 UTC. It fails if
the morning's update failed (it reads the result with `systemctl show`, which needs no rights), then runs this
script with no version. When the tools' versions or this script differ from what the live repositories were built
from (`built-from` beside each snapshot), it rebuilds and re-signs both from the current pools with no new package,
swaps the links and checks the live site; otherwise it says "nothing new" and names the versions. Unlike
fdroidserver, these tools cannot be kept beside an older copy, so a release uses whatever is installed; an update
that breaks them fails the next morning's job first.
- **The APK reaches an F-Droid repository on packages.arasaka.software from the same job** (31 Oct 2026), after the
release is published, so the repository can lag the release page but never lead it. `.gitea/scripts/fdroid.sh`
installs fdroidserver with uv from `setup.json` (its download cache in `tools/fdroid`, cached like the JDK), because
the box has no `ensurepip` and the apt package would bring 242 others. **Nothing pins fdroidserver; a daily job
keeps it current** (owner, 31 Oct 2026: a daily service, not patching it from time to time). `fdroid.yml` runs the
same script with no version at 05:23 UTC: it resolves the newest fdroidserver, and the newest of everything it
needs, published at least 14 days earlier (a bad upload has usually been pulled by then), against the box's own
`python3`, into a hash-locked list; a new list gets its own install, `fdroidserver-<hash of the list>` in the cache's
real path (an install's scripts carry the absolute path they were made at; 0.15.1 failed with `fdroid: not found` on
one made from a deleted folder). When that list or the listing in `packaging/fdroid/` differs from what the live
repository was built from (`built-from` beside each snapshot), it rebuilds the repository with it, and only once
that is live and verified does the install become `current` and the older ones go. A release uses `current` and
downloads nothing, so a new fdroidserver that breaks fails the daily job, never a release; the job's log names the
version. Every install runs with the signing key out of its environment.
It signs the repository with the APK's own key (`MEWEB_KEYSTORE_B64` and `MEWEB_KEYSTORE_PASS`, alias `meweb`), so
the F-Droid fingerprint is the certificate's `5F52CFF4…FDF846` and there is no second key to lose; it refuses any
other. It builds a new snapshot in
`/var/www/packages.arasaka.software/.fdroid/` from the live one (the APKs as hard links, so `rm` then `cp` as above;
the metadata, the icons, `apkcache.json` and the previous `index-v2.json`, which is where fdroidserver reads each
APK's first date; without the icons a rebuild with no new APK fails, because the cache skips extracting them), adds
this version (a release) or nothing (the daily job), keeps the newest three, runs `fdroid update`, deletes `repo/status/` (it names the
build machine's paths and `/etc/issue.net`), swaps the `fdroid/repo` link and checks the live signature. The key
was already never to be regenerated; now everyone who added the repository trusts only its fingerprint too. `packaging/fdroid/` holds the
repository's settings, its icon (the Arasaka emblem) and the app's listing in English and Italian; the download
page links to it and to Obtainium (`Endpoints.FDroid`, source `FDroidRepo`).
- **The server cannot ping**: `NoNewPrivileges` drops `ping`'s file capability and `ping_group_range` is closed, so - **The server cannot ping**: `NoNewPrivileges` drops `ping`'s file capability and `ping_group_range` is closed, so
the trace back to a caller uses `tracepath` (UDP, unprivileged) and keeps only public hops outside `Probe:Refuse`, the trace back to a caller uses `tracepath` (UDP, unprivileged) and keeps only public hops outside `Probe:Refuse`,
so the box's own network never reaches an app. so the box's own network never reaches an app.
-11
View File
@@ -1,11 +0,0 @@
repo_url: https://packages.arasaka.software/fdroid/repo
repo_name: Arasaka
repo_description: >-
Apps published by Arasaka di Hvozdikov Yevheniy, Busto Arsizio, Italy, such as “me-web?”.
Each app here is the same signed file as on its release page.
repo_icon: icon.png
archive_older: 0
repo_keyalias: meweb
keystore: {env: MEWEB_KEYSTORE}
keystorepass: {env: MEWEB_KEYSTORE_PASS}
keypass: {env: MEWEB_KEYSTORE_PASS}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

-12
View File
@@ -47,18 +47,6 @@
"kind": "tar", "kind": "tar",
"dest": "tools/jdk/osx-arm64", "dest": "tools/jdk/osx-arm64",
"check": "tools/jdk/osx-arm64/jdk-21.0.12+8/Contents/Home/bin/java" "check": "tools/jdk/osx-arm64/jdk-21.0.12+8/Contents/Home/bin/java"
},
{
"name": "uv",
"group": "fdroid",
"version": "0.13.1",
"license": "MIT or Apache-2.0 (build tool, not distributed)",
"rid": "linux-x64",
"url": "https://github.com/astral-sh/uv/releases/download/0.13.1/uv-x86_64-unknown-linux-gnu.tar.gz",
"sha256": "eadd9d27c134ab5ac1ffd4473b97a741407f3ea238288f03121fc4deddf90220",
"kind": "tar",
"dest": "tools/fdroid/linux-x64",
"check": "tools/fdroid/linux-x64/uv-x86_64-unknown-linux-gnu/uv"
} }
] ]
} }