Files
voculinux/packaging/void/repo.sh
T
soubarnak 9bc04936b6 feat(void): add signed xbps repository pipeline
Build every template in smoke-gate order, index the full repository and
sign packages plus metadata with the RSA4096 key, in the pinned Void
container via podman. Fail-closed without a key: no key file, no repo.

Ticket #29 (needs #27, #28).
2026-11-06 06:29:22 +05:30

98 lines
3.7 KiB
Bash
Executable File

#!/bin/sh
# Signed xbps repository pipeline (ticket #29): build every template in
# smoke-gate order, index the full repository, and sign every binary
# package plus the repository metadata with the RSA4096 repository key.
# Runs in the pinned Void container via podman, never Docker; no host
# Void install needed.
#
# Usage: XBPS_SIGNING_KEY_FILE=/path/to/key.pem packaging/void/repo.sh
# or: XBPS_SIGNING_KEY_FILE=/path/to/key.pem just void-repo
#
# Options (all optional):
# --key-file PATH repository private key (default: $XBPS_SIGNING_KEY_FILE)
# --out-dir DIR stage the signed repo here (default: publish/xbps)
# --signed-by "N <m>" signer identity (default: Voculinux <xbps@voculinux.com>)
#
# The private key arrives as a file so CI can write the XBPS_SIGNING_KEY
# secret to disk with newlines intact:
#
# printf '%s' "$XBPS_SIGNING_KEY" > /tmp/xbps-sign-key.pem
# XBPS_SIGNING_KEY_FILE=/tmp/xbps-sign-key.pem packaging/void/repo.sh
#
# Fail-closed: a missing, unreadable, or non-RSA4096 key aborts before
# any container runs, so an unsigned repository can never publish.
set -eu
CDPATH=""
HERE=$(dirname -- "$0")
HERE=$(cd -- "$HERE" && pwd)
REPO_ROOT=$(cd -- "$HERE/../.." && pwd)
KEY_FILE=${XBPS_SIGNING_KEY_FILE:-}
OUT_DIR="$REPO_ROOT/publish/xbps"
SIGNEDBY="Voculinux <xbps@voculinux.com>"
while [ $# -gt 0 ]; do
case "$1" in
--key-file) KEY_FILE=${2:?usage: repo.sh --key-file PATH} ; shift 2 ;;
--out-dir) OUT_DIR=${2:?usage: repo.sh --out-dir DIR} ; shift 2 ;;
--signed-by) SIGNEDBY=${2:?usage: repo.sh --signed-by "Name <mail>"} ; shift 2 ;;
-*) echo "repo.sh: unknown option: $1" >&2 ; exit 1 ;;
*) echo "repo.sh: unexpected argument: $1" >&2 ; exit 1 ;;
esac
done
# Fail closed before any container runs: no key, no repo, no publish.
[ -n "$KEY_FILE" ] || {
echo "repo.sh: no signing key: pass --key-file or set XBPS_SIGNING_KEY_FILE" >&2
echo "repo.sh: CI writes the XBPS_SIGNING_KEY secret to a file first:" >&2
echo "repo.sh: printf '%s' \"\$XBPS_SIGNING_KEY\" > /tmp/xbps-sign-key.pem" >&2
exit 1
}
[ -r "$KEY_FILE" ] && [ -s "$KEY_FILE" ] || {
echo "repo.sh: signing key missing or empty: $KEY_FILE" >&2
echo "repo.sh: refusing to publish an unsigned repository" >&2
exit 1
}
openssl rsa -in "$KEY_FILE" -check -noout >/dev/null 2>&1 || {
echo "repo.sh: not a valid RSA private key: $KEY_FILE" >&2
echo "repo.sh: refusing to publish an unsigned repository" >&2
exit 1
}
openssl rsa -in "$KEY_FILE" -text -noout 2>/dev/null | head -1 | grep -q "4096 bit" || {
echo "repo.sh: signing key is not RSA4096: $KEY_FILE" >&2
echo "repo.sh: generate one with: openssl genrsa -out xbps-sign-key.pem 4096" >&2
exit 1
}
BASE_IMAGE=$(awk '$1 == "base-image" {print $3}' "$HERE/tool_checksums.txt")
VOID_COMMIT=$(awk '$1 == "void-packages" {print $3}' "$HERE/tool_checksums.txt")
[ -n "$BASE_IMAGE" ] && [ -n "$VOID_COMMIT" ] || {
echo "repo.sh: pins missing from tool_checksums.txt" >&2
exit 1
}
# One dependency order for the whole track: the signed repo builds the
# same set in the same order as the smoke gate (the app last), so a
# renamed or added template cannot silently drop out of either.
PKGS=$(awk -F'"' '/^PKGS=/{print $2; exit}' "$HERE/smoke.sh")
[ -n "$PKGS" ] || {
echo "repo.sh: could not read the package order from smoke.sh" >&2
exit 1
}
mkdir -p "$OUT_DIR"
echo "Pulling pinned base image: $BASE_IMAGE"
podman pull "$BASE_IMAGE"
podman run --rm \
-v "$REPO_ROOT/packaging/void/srcpkgs:/overlay:ro" \
-v "$HERE/container-repo.sh:/mnt/container-repo.sh:ro" \
-v "$KEY_FILE:/run/xbps-sign-key.pem:ro" \
-v "$OUT_DIR:/mnt/out" \
-e "VOID_COMMIT=$VOID_COMMIT" \
-e "PKGS=$PKGS" \
-e "SIGNEDBY=$SIGNEDBY" \
"$BASE_IMAGE" /bin/sh /mnt/container-repo.sh
echo "OK: signed repository staged in $OUT_DIR"