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).
98 lines
3.7 KiB
Bash
Executable File
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"
|