mirror of
https://git.quad4.io/RNS-Things/MeshChatX.git
synced 2026-04-19 22:25:47 +00:00
167 lines
5.6 KiB
Bash
Executable File
167 lines
5.6 KiB
Bash
Executable File
#!/bin/sh
|
|
# Build and install Python from official python.org source.
|
|
# Verifies: OpenPGP (.asc) when present, otherwise Sigstore (.sigstore) with cosign.
|
|
# https://www.python.org/download/sigstore/ PEP 761 (3.14+): PGP removed; Sigstore only.
|
|
#
|
|
# Usage: setup-python.sh [version]
|
|
# version: exact (3.14.x) or minor (3.14, resolved to latest patch).
|
|
set -eu
|
|
|
|
. "$(dirname "$0")/priv.sh"
|
|
|
|
# Sigstore identity and OIDC issuer per release (see python.org/download/sigstore).
|
|
sigstore_identity_for() {
|
|
_v="$1"
|
|
case "$_v" in
|
|
3.7.*) echo "nad@python.org|https://github.com/login/oauth" ;;
|
|
3.8.*|3.9.*) echo "lukasz@langa.pl|https://github.com/login/oauth" ;;
|
|
3.10.*|3.11.*) echo "pablogsal@python.org|https://accounts.google.com" ;;
|
|
3.12.*|3.13.*) echo "thomas@python.org|https://accounts.google.com" ;;
|
|
3.14.*|3.15.*) echo "hugo@python.org|https://github.com/login/oauth" ;;
|
|
3.16.*|3.17.*) echo "savannah@python.org|https://github.com/login/oauth" ;;
|
|
3.*.*) echo "savannah@python.org|https://github.com/login/oauth" ;;
|
|
*) echo "" ;;
|
|
esac
|
|
}
|
|
|
|
download_cosign() {
|
|
COSIGN_VERSION="${COSIGN_VERSION:-2.4.1}"
|
|
COSIGN_ARCH="linux-amd64"
|
|
case "$(uname -m)" in
|
|
aarch64|arm64) COSIGN_ARCH="linux-arm64" ;;
|
|
x86_64|amd64) COSIGN_ARCH="linux-amd64" ;;
|
|
x86_64-gnu) COSIGN_ARCH="linux-amd64" ;;
|
|
*)
|
|
echo "unsupported uname -m for cosign: $(uname -m)" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
COSIGN_BIN="/tmp/cosign-${COSIGN_VERSION}-${COSIGN_ARCH}"
|
|
if [ ! -x "$COSIGN_BIN" ]; then
|
|
curl -fsSL "https://github.com/sigstore/cosign/releases/download/v${COSIGN_VERSION}/cosign-${COSIGN_ARCH}" \
|
|
-o "$COSIGN_BIN"
|
|
chmod +x "$COSIGN_BIN"
|
|
fi
|
|
echo "$COSIGN_BIN"
|
|
}
|
|
|
|
PY_INPUT="${1:-3.14}"
|
|
|
|
CURRENT="$(python3 --version 2>/dev/null | sed 's/Python //')" || true
|
|
|
|
case "$PY_INPUT" in
|
|
*.*.*)
|
|
PY_VERSION="$PY_INPUT"
|
|
;;
|
|
*)
|
|
echo "Resolving latest Python ${PY_INPUT}.x from python.org"
|
|
PY_VERSION="$(curl -fsSL "https://www.python.org/ftp/python/" \
|
|
| grep -o "href=\"${PY_INPUT}\.[0-9]*/" \
|
|
| sed 's/href="//;s/\///' \
|
|
| sort -t. -k3 -n \
|
|
| tail -1)"
|
|
if [ -z "$PY_VERSION" ]; then
|
|
echo "Failed to resolve Python ${PY_INPUT}.x" >&2
|
|
exit 1
|
|
fi
|
|
echo "Resolved to ${PY_VERSION}"
|
|
;;
|
|
esac
|
|
|
|
if [ "$CURRENT" = "$PY_VERSION" ]; then
|
|
echo "Python ${PY_VERSION} already installed"
|
|
python3 --version
|
|
exit 0
|
|
fi
|
|
|
|
echo "Building Python ${PY_VERSION} from source (python.org)"
|
|
|
|
run_priv apt-get update -qq
|
|
run_priv apt-get install -y -qq \
|
|
build-essential gnupg curl \
|
|
libssl-dev zlib1g-dev libbz2-dev libreadline-dev \
|
|
libsqlite3-dev libffi-dev liblzma-dev libncurses-dev > /dev/null 2>&1
|
|
|
|
TARBALL="Python-${PY_VERSION}.tar.xz"
|
|
SRC_URL="https://www.python.org/ftp/python/${PY_VERSION}/${TARBALL}"
|
|
SIG_URL="${SRC_URL}.asc"
|
|
|
|
curl -fsSL "$SRC_URL" -o "/tmp/${TARBALL}"
|
|
|
|
SIG_HTTP="$(curl -sS -o "/tmp/${TARBALL}.asc" -w "%{http_code}" "$SIG_URL" || true)"
|
|
if [ "$SIG_HTTP" != "200" ]; then
|
|
rm -f "/tmp/${TARBALL}.asc"
|
|
fi
|
|
|
|
GPG_KEYS=""
|
|
case "$PY_VERSION" in
|
|
3.13.*|3.14.*)
|
|
GPG_KEYS="A035C8C19219BA821ECEA86B64E628F8D684696D 7169605F62C751356D054A26A821E680E5FA6305"
|
|
;;
|
|
3.11.*|3.12.*)
|
|
GPG_KEYS="A035C8C19219BA821ECEA86B64E628F8D684696D 7169605F62C751356D054A26A821E680E5FA6305"
|
|
;;
|
|
3.9.*|3.10.*)
|
|
GPG_KEYS="E3FF2839C048B25C084DEBE9B26995E310250568"
|
|
;;
|
|
*)
|
|
echo "No known GPG key for Python ${PY_VERSION}; skipping OpenPGP signature check" >&2
|
|
;;
|
|
esac
|
|
|
|
GPG_VERIFIED=0
|
|
if [ "$SIG_HTTP" = "200" ] && [ -n "$GPG_KEYS" ]; then
|
|
export GNUPGHOME="$(mktemp -d)"
|
|
for key in $GPG_KEYS; do
|
|
gpg --batch --keyserver keyserver.ubuntu.com --recv-keys "$key" 2>/dev/null || \
|
|
gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys "$key" 2>/dev/null || true
|
|
done
|
|
gpg --batch --verify "/tmp/${TARBALL}.asc" "/tmp/${TARBALL}"
|
|
rm -rf "$GNUPGHOME"
|
|
unset GNUPGHOME
|
|
echo "OpenPGP signature verified"
|
|
GPG_VERIFIED=1
|
|
fi
|
|
|
|
if [ "$GPG_VERIFIED" != "1" ]; then
|
|
SIGSTORE_URL="${SRC_URL}.sigstore"
|
|
SIGSTORE_HTTP="$(curl -sS -o "/tmp/${TARBALL}.sigstore" -w "%{http_code}" "$SIGSTORE_URL" || true)"
|
|
if [ "$SIGSTORE_HTTP" != "200" ]; then
|
|
rm -f "/tmp/${TARBALL}.sigstore"
|
|
echo "No OpenPGP signature (HTTP ${SIG_HTTP}) and no Sigstore bundle at ${SIGSTORE_URL} (HTTP ${SIGSTORE_HTTP})" >&2
|
|
exit 1
|
|
fi
|
|
II="$(sigstore_identity_for "$PY_VERSION")"
|
|
if [ -z "$II" ]; then
|
|
echo "No Sigstore identity mapping for Python ${PY_VERSION}" >&2
|
|
exit 1
|
|
fi
|
|
SIG_IDENTITY="$(echo "$II" | cut -d'|' -f1)"
|
|
SIG_ISSUER="$(echo "$II" | cut -d'|' -f2)"
|
|
COSIGN_BIN="$(download_cosign)"
|
|
"$COSIGN_BIN" verify-blob --new-bundle-format \
|
|
--certificate-oidc-issuer "$SIG_ISSUER" \
|
|
--certificate-identity "$SIG_IDENTITY" \
|
|
--bundle "/tmp/${TARBALL}.sigstore" \
|
|
"/tmp/${TARBALL}"
|
|
echo "Sigstore signature verified"
|
|
fi
|
|
|
|
cd /tmp
|
|
tar -xJf "${TARBALL}"
|
|
cd "Python-${PY_VERSION}"
|
|
|
|
BUILD_LOG="/tmp/python-build.log"
|
|
./configure --prefix=/usr/local --with-ensurepip=install > "$BUILD_LOG" 2>&1
|
|
make -j"$(nproc)" >> "$BUILD_LOG" 2>&1
|
|
run_priv make install >> "$BUILD_LOG" 2>&1
|
|
|
|
run_priv ln -sf /usr/local/bin/python3 /usr/local/bin/python
|
|
run_priv ln -sf /usr/local/bin/pip3 /usr/local/bin/pip
|
|
|
|
cd /
|
|
rm -rf "/tmp/${TARBALL}" "/tmp/${TARBALL}.asc" "/tmp/${TARBALL}.sigstore" "/tmp/Python-${PY_VERSION}" "$BUILD_LOG"
|
|
|
|
python3 --version
|
|
pip3 --version
|