Host the x86-64 Steam client's Ubuntu 24.04 rootfs (#4)

fex-rootfs.json records FEX-Emu's Ubuntu 24.04 rootfs (2026-08-11) that droiddeck-steam-x64 unpacks as the optional x86-64 Steam client's system, at a release here. mirror-upstream.yml brings a file its upstream publishes outside GitHub into the catalog's release: it fetches the catalog's upstream link, refuses it unless sha256 and size match the catalog, uploads it with SHA256SUMS and MIRROR.md, and confirms the digest GitHub stored.

Co-authored-by: The412Banner <[email protected]>
This commit is contained in:
The412BannerandThe412Banner authored and GitHub committed 2026-10-17 20:53:35 -04:00
1 parent c175bfe130
commit 67c8cc99b3
3 files changed
+104 -1

No files matched your search

+88
View File
@@ -0,0 +1,88 @@
name: Mirror an upstream file
# Brings a file its upstream publishes outside GitHub into a release here, for a single-package
# catalog that names it: the catalog's "upstream" link is fetched, checked against the sha256 and
# size the catalog promises (tools/mirror/expectations.py), uploaded under the catalog's release,
# and its sha256 confirmed against what GitHub stored. A SHA256SUMS and a MIRROR.md naming this run
# go with it. Nothing is uploaded by hand.
on:
workflow_dispatch:
inputs:
catalog:
description: 'Single-package catalog naming the release, the file and its upstream link'
required: true
default: 'fex-rootfs.json'
permissions:
contents: write
jobs:
mirror:
runs-on: ubuntu-24.04
timeout-minutes: 60
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- name: Mirror
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
CATALOG: ${{ inputs.catalog }}
run: |
set -euo pipefail
case "$CATALOG" in ""|*[!a-z0-9.-]*|.*) echo "::error::catalog must be a file name in this repository"; exit 1 ;; esac
[ -f "$CATALOG" ] || { echo "::error::$CATALOG not found"; exit 1; }
tag=$(jq -r '.release // empty' "$CATALOG")
url=$(jq -r '.url // empty' "$CATALOG")
upstream=$(jq -r '.upstream // empty' "$CATALOG")
title=$(jq -r '.name // empty' "$CATALOG")
[ -n "$tag" ] && [ -n "$upstream" ] || { echo "::error::$CATALOG names no release or no upstream link"; exit 1; }
case "$url" in
"$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/releases/download/$tag/"*) ;;
*) echo "::error::$CATALOG's url is not on this repository's $tag release"; exit 1 ;;
esac
name=${url##*/}
work=$(mktemp -d)
python3 tools/mirror/expectations.py "$tag" "$CATALOG" > "$work/expect.json"
sha=$(jq -r --arg n "$name" '.[$n][0].sha256 // empty' "$work/expect.json")
size=$(jq -r --arg n "$name" '.[$n][0].size // empty' "$work/expect.json")
[ ${#sha} -eq 64 ] && [ -n "$size" ] || { echo "::error::$CATALOG gives $name no sha256 and size"; exit 1; }
stored() {
gh api "repos/$GITHUB_REPOSITORY/releases/tags/$tag" --jq '.assets[] | "\(.name) \(.digest // "")"' 2>/dev/null |
awk -v n="$name" '$1==n{print $2}'
}
if [ "$(stored)" = "sha256:$sha" ]; then
echo "$name is already on $tag with the catalog's sha256; nothing to do"
exit 0
fi
curl -fL --retry 3 --retry-delay 15 --max-time 3000 -o "$work/$name" "$upstream"
got_sha=$(sha256sum "$work/$name" | cut -d' ' -f1)
got_size=$(stat -c %s "$work/$name")
if [ "$got_sha" != "$sha" ] || [ "$got_size" != "$size" ]; then
echo "::error::$upstream is $got_size bytes, sha256 $got_sha; $CATALOG promises $size bytes, sha256 $sha"
exit 1
fi
(cd "$work" && sha256sum "$name" > SHA256SUMS)
{
echo "# Mirror of $upstream"
echo
echo "Run: $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID"
echo "Verified against: $CATALOG"
echo
echo "| asset | size | catalog check | origin |"
echo "|---|---|---|---|"
echo "| $name | $got_size | sha256 and size match | fetched from the upstream: $(echo "$upstream" | cut -d/ -f3) |"
} > "$work/MIRROR.md"
if ! gh release view "$tag" >/dev/null 2>&1; then
gh release create "$tag" --title "${title:-$tag}" --latest=false \
--notes "Mirrored by CI from $upstream: $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID. Checked against $CATALOG (sha256 and size); see MIRROR.md."
fi
gh release upload "$tag" "$work/$name" "$work/SHA256SUMS" "$work/MIRROR.md" --clobber
[ "$(stored)" = "sha256:$sha" ] || { echo "::error::GitHub stored $name as $(stored), not sha256:$sha"; exit 1; }
echo "$name mirrored to $tag ($got_size bytes, sha256 $sha)"
+3 -1
View File
@@ -40,10 +40,12 @@ LGPL-2.1-or-later.
DroidDeck reads its package catalogs from this repository's `main`: `components.json` (Windows
components), `desktop.json` (desktop and emulator packages), `linuxfs.json` (the Linux runtime) and
`steam-seed.json` (the Steam seed). `fex.json` records the FEX build the optional x86-64 Steam client
downloads; `droiddeck-steam-x64` in the app pins the same sha256. Every file they point at lives on a
downloads and `fex-rootfs.json` the x86-64 system it runs in (FEX-Emu's Ubuntu 24.04 rootfs);
`droiddeck-steam-x64` in the app pins the same sha256s. Every file they point at lives on a
release here, produced by a workflow in `.github/workflows/`:
`mirror-release.yml` brings an existing release in with every
asset checked against the catalog (and leaves `SHA256SUMS` + `MIRROR.md` naming the run),
`mirror-upstream.yml` does the same for a file its upstream publishes outside GitHub,
`component-snapshots.yml` records what a Windows component's installer leaves behind,
`build-desktop.yml`, `build-emulator-source.yml`, `mirror-appimages.yml` and `build-linuxfs.yml`
build the rest. Nothing on a release is uploaded by hand.
+13
View File
@@ -0,0 +1,13 @@
{
"schemaVersion": 1,
"category": "fex-rootfs",
"release": "fex-rootfs-ubuntu-24.04-2026-08-11",
"name": "x86-64 system for the x86-64 Steam client (Ubuntu 24.04)",
"version": "ubuntu-24.04-2026-08-11",
"url": "https://github.com/Droid-Deck/DroidDeck-Components/releases/download/fex-rootfs-ubuntu-24.04-2026-08-11/Ubuntu_24_04.sqsh",
"upstream": "https://rootfs.fex-emu.gg/Ubuntu_24_04/2026-08-11/Ubuntu_24_04.sqsh",
"sha256": "2854b06d3ff1b8f6e526135bfb6dd5b7b30ab3ab73e79ae933a3d9fed959a178",
"size": 525615104,
"file_size": 525615104,
"note": "FEX-Emu's Ubuntu 24.04 x86-64 rootfs (SquashFS, 2026-08-11), unmodified. droiddeck-steam-x64 downloads it once for the optional x86-64 Steam client, unpacks it as that client's own x86-64 system and pins this sha256. Fetched from rootfs.fex-emu.gg by mirror-upstream.yml."
}