diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml index 635b709..c6f94ab 100644 --- a/.gitea/workflows/build.yml +++ b/.gitea/workflows/build.yml @@ -106,6 +106,10 @@ jobs: run: | chmod +x scripts/generate-apt-repo.sh ./scripts/generate-apt-repo.sh + - name: Verify generated apt repository + run: | + chmod +x scripts/verify-apt-repo.sh + ./scripts/verify-apt-repo.sh - name: Upload deb package to Gitea release run: | . dist/package-info.env @@ -187,3 +191,7 @@ jobs: fi env: GITEA_SHA: ${{ gitea.sha }} + - name: Verify published apt endpoint + run: | + chmod +x scripts/verify-apt-repo.sh + ./scripts/verify-apt-repo.sh --remote diff --git a/README.md b/README.md index d0fdcd8..71862be 100644 --- a/README.md +++ b/README.md @@ -75,10 +75,32 @@ Releases werden als normale Releases angelegt, nicht als Pre-Releases. Der Workflow veröffentlicht zusätzlich einen einfachen Debian-Repo-Baum auf dem Branch `apt`. -Die Einbindung ist dann über die Raw-URL des Branches möglich, zum Beispiel: +Wichtig: APT braucht anonym erreichbare HTTP-Dateien wie `dists/stable/Release` +und `pool/...deb`. Ein funktionierendes `git ls-remote` reicht dafür nicht aus. + +Auf dieser Gitea-Instanz war die bisher dokumentierte Raw-URL für anonyme +HTTP-Clients nicht erreichbar und lieferte `404`. Genau daran scheitert dann +`apt update` auf Ubuntu, obwohl der `apt`-Branch in Git existiert. + +Deshalb gilt: + +- nutze für Clients nur eine wirklich öffentlich erreichbare statische HTTP-URL +- setze diese Basis-URL in `config/mesa-opt.conf` als `APT_PUBLIC_BASE_URL` +- der Workflow prüft dann nach dem Publish, ob `Release`, `Packages` und das + referenzierte `.deb` anonym abrufbar sind + +Beispiel für die Konfiguration: + +```bash +APT_SUITE="stable" +APT_COMPONENT="main" +APT_PUBLIC_BASE_URL="https://packages.example.tld/mesa-repo" +``` + +Die Einbindung auf dem Client sieht dann so aus: ```text -deb [trusted=yes] https://git.mp-mueller.de/magges/mesa-repo/raw/branch/apt stable main +deb [trusted=yes] https://packages.example.tld/mesa-repo stable main ``` Danach: @@ -92,6 +114,8 @@ Hinweis: - das Repo ist aktuell unsigniert - für APT wird deshalb hier `trusted=yes` verwendet +- `scripts/verify-apt-repo.sh --remote` prüft, ob die öffentliche URL wirklich + APT-tauglich ist - wenn du willst, kann ich als nächsten Schritt auch noch Release-Signierung mit GPG einbauen ## Wichtige Dateien @@ -100,6 +124,7 @@ Hinweis: - `scripts/build-mesa-opt.sh`: Build und Paketierung - `scripts/generate-release-notes.sh`: automatische Release-Notes aus Mesa-Commits - `scripts/generate-apt-repo.sh`: erzeugt den APT-Repo-Baum +- `scripts/verify-apt-repo.sh`: prüft Repo-Struktur und optional den öffentlichen APT-Endpunkt - `.gitea/workflows/build.yml`: Gitea-Workflow ## Benutzung diff --git a/config/mesa-opt.conf b/config/mesa-opt.conf index 23ae7d8..d8e8b08 100644 --- a/config/mesa-opt.conf +++ b/config/mesa-opt.conf @@ -2,6 +2,11 @@ PACKAGE_NAME="mesa-git" PACKAGE_VERSION_PREFIX="" PACKAGE_RELEASE="1" PACKAGE_ARCH="amd64" +APT_SUITE="stable" +APT_COMPONENT="main" +# Public static HTTP base URL for the generated apt tree, without trailing slash. +# Leave empty if the repo is only generated locally or published elsewhere. +APT_PUBLIC_BASE_URL="" UPSTREAM_GIT_URL="https://gitlab.freedesktop.org/mesa/mesa.git" UPSTREAM_GIT_REF="main" diff --git a/scripts/build-mesa-opt.sh b/scripts/build-mesa-opt.sh index f5521c0..42d8801 100644 --- a/scripts/build-mesa-opt.sh +++ b/scripts/build-mesa-opt.sh @@ -156,6 +156,10 @@ cat > "${DIST_DIR}/package-info.env" <&2 exit 1 @@ -87,3 +93,11 @@ append_checksum_block() { append_checksum_block "MD5Sum" md5sum append_checksum_block "SHA256" sha256sum append_checksum_block "SHA512" sha512sum + +if [[ -n "${APT_PUBLIC_BASE_URL:-}" ]]; then + printf 'deb [trusted=yes] %s %s %s\n' \ + "${APT_PUBLIC_BASE_URL%/}" \ + "${APT_SUITE}" \ + "${APT_COMPONENT}" \ + > "${APT_DIR}/${PACKAGE_NAME}-${APT_SUITE}.list" +fi diff --git a/scripts/verify-apt-repo.sh b/scripts/verify-apt-repo.sh new file mode 100644 index 0000000..e1741ef --- /dev/null +++ b/scripts/verify-apt-repo.sh @@ -0,0 +1,129 @@ +#!/usr/bin/env bash + +set -euo pipefail + +SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd) +ROOT_DIR=$(cd -- "${SCRIPT_DIR}/.." && pwd) +CONFIG_FILE="${ROOT_DIR}/config/mesa-opt.conf" +DIST_DIR="${ROOT_DIR}/dist" +APT_DIR="${DIST_DIR}/aptrepo" +DIST_ENV="${DIST_DIR}/package-info.env" +CHECK_REMOTE=0 + +usage() { + cat <<'EOF' +Usage: verify-apt-repo.sh [--remote] + +Checks that the generated apt repository is internally consistent. +With --remote, also verifies that the configured public HTTP base URL serves +the Release file, Packages index, and referenced package anonymously. +EOF +} + +while [[ $# -gt 0 ]]; do + case "$1" in + --remote) + CHECK_REMOTE=1 + shift + ;; + -h|--help) + usage + exit 0 + ;; + *) + echo "unknown argument: $1" >&2 + usage >&2 + exit 1 + ;; + esac +done + +if [[ -f "${CONFIG_FILE}" ]]; then + # shellcheck disable=SC1090 + source "${CONFIG_FILE}" +fi + +if [[ ! -f "${DIST_ENV}" ]]; then + echo "missing dist metadata: ${DIST_ENV}" >&2 + exit 1 +fi + +# shellcheck disable=SC1090 +source "${DIST_ENV}" + +APT_SUITE="${APT_SUITE:-stable}" +APT_COMPONENT="${APT_COMPONENT:-main}" +APT_ARCH="${APT_ARCH:-${PACKAGE_ARCH:-amd64}}" +PACKAGES_FILE="${APT_DIR}/dists/${APT_SUITE}/${APT_COMPONENT}/binary-${APT_ARCH}/Packages" +RELEASE_FILE="${APT_DIR}/dists/${APT_SUITE}/Release" + +require_cmd() { + local cmd + for cmd in "$@"; do + command -v "${cmd}" >/dev/null 2>&1 || { + echo "missing command: ${cmd}" >&2 + exit 1 + } + done +} + +require_cmd awk curl grep gzip + +[[ -f "${RELEASE_FILE}" ]] || { + echo "missing Release file: ${RELEASE_FILE}" >&2 + exit 1 +} + +[[ -f "${PACKAGES_FILE}" ]] || { + echo "missing Packages file: ${PACKAGES_FILE}" >&2 + exit 1 +} + +[[ -f "${PACKAGES_FILE}.gz" ]] || { + echo "missing Packages.gz file: ${PACKAGES_FILE}.gz" >&2 + exit 1 +} + +PACKAGE_RELATIVE_PATH="$(awk -F': ' '$1=="Filename" { print $2; exit }' "${PACKAGES_FILE}")" +[[ -n "${PACKAGE_RELATIVE_PATH}" ]] || { + echo "missing Filename entry in ${PACKAGES_FILE}" >&2 + exit 1 +} + +[[ -f "${APT_DIR}/${PACKAGE_RELATIVE_PATH}" ]] || { + echo "referenced package is missing: ${APT_DIR}/${PACKAGE_RELATIVE_PATH}" >&2 + exit 1 +} + +grep -q " ${APT_COMPONENT}/binary-${APT_ARCH}/Packages\$" "${RELEASE_FILE}" || { + echo "Release file does not reference Packages index" >&2 + exit 1 +} + +grep -q " ${APT_COMPONENT}/binary-${APT_ARCH}/Packages.gz\$" "${RELEASE_FILE}" || { + echo "Release file does not reference Packages.gz index" >&2 + exit 1 +} + +gzip -t "${PACKAGES_FILE}.gz" +echo "local apt repository structure looks valid" + +if [[ "${CHECK_REMOTE}" -eq 0 ]]; then + exit 0 +fi + +if [[ -z "${APT_PUBLIC_BASE_URL:-}" ]]; then + echo "APT_PUBLIC_BASE_URL is empty; skipping remote verification" + exit 0 +fi + +BASE_URL="${APT_PUBLIC_BASE_URL%/}" +RELEASE_URL="${BASE_URL}/dists/${APT_SUITE}/Release" +PACKAGES_URL="${BASE_URL}/dists/${APT_SUITE}/${APT_COMPONENT}/binary-${APT_ARCH}/Packages" +PACKAGE_URL="${BASE_URL}/${PACKAGE_RELATIVE_PATH}" + +curl -fsSL "${RELEASE_URL}" >/dev/null +curl -fsSL "${PACKAGES_URL}" >/dev/null +curl -fsSLI "${PACKAGE_URL}" >/dev/null + +echo "remote apt repository is reachable anonymously via ${BASE_URL}"