#!/usr/bin/env bash # cxos/vendor/linux/fetch.sh — download + verify + extract Linux LTS tarball. # # Reads cxos/vendor/linux/PINNED.json. Hard-fails if SHA-256 mismatches or # (when --gpg is passed) the GPG signature does not validate against any of # the pinned signing keys. # # Usage: # cxos/vendor/linux/fetch.sh # SHA-256 only # cxos/vendor/linux/fetch.sh --gpg # require valid GPG signature # cxos/vendor/linux/fetch.sh --dry # print plan; no network # # Outputs: # cxos/vendor/linux/linux-.tar.xz (cached, gitignored) # cxos/vendor/linux/src/linux-/ (extracted, gitignored) set -euo pipefail DRY=0 GPG=0 for arg in "$@"; do case "$arg" in --dry) DRY=1 ;; --gpg) GPG=1 ;; -h|--help) sed -n '2,15p' "$0" | sed 's/^# \{0,1\}//' exit 0 ;; *) echo "fetch.sh: unknown arg: $arg" >&2 exit 2 ;; esac done HERE="$(cd "$(dirname "$0")" && pwd)" PINNED="$HERE/PINNED.json" if [[ ! -f "$PINNED" ]]; then echo "fetch.sh: missing $PINNED" >&2 exit 1 fi # Parse PINNED.json with python3 (always available in the dev container). read -r VERSION TARBALL_URL SIG_URL SHA256 EXTRACTED_DIR < <( python3 - "$PINNED" <<'PY' import json, sys d = json.load(open(sys.argv[1])) print(d["version"], d["tarball_url"], d["signature_url"], d["sha256"], d["extracted_dir"]) PY ) TARBALL="$HERE/linux-${VERSION}.tar.xz" SIGNATURE="$HERE/linux-${VERSION}.tar.sign" SRC_DIR="$HERE/src" echo "==> linux ${VERSION}" echo " tarball: ${TARBALL_URL}" echo " sha256 : ${SHA256}" echo " extract: ${SRC_DIR}/${EXTRACTED_DIR}" if [[ "$DRY" == "1" ]]; then echo "==> dry-run; nothing fetched" exit 0 fi mkdir -p "$SRC_DIR" # 1. Tarball ---------------------------------------------------------------- if [[ ! -f "$TARBALL" ]]; then echo "==> downloading $(basename "$TARBALL")" curl -fsSL --retry 3 -o "$TARBALL" "$TARBALL_URL" fi # 2. SHA-256 ---------------------------------------------------------------- echo "==> verifying sha256" ACTUAL_SHA="$(sha256sum "$TARBALL" | awk '{print $1}')" if [[ "$ACTUAL_SHA" != "$SHA256" ]]; then echo "fetch.sh: SHA-256 mismatch" >&2 echo " expected: $SHA256" >&2 echo " actual : $ACTUAL_SHA" >&2 rm -f "$TARBALL" exit 1 fi echo " ok" # 3. GPG (optional) --------------------------------------------------------- if [[ "$GPG" == "1" ]]; then if ! command -v gpg >/dev/null 2>&1; then echo "fetch.sh: --gpg requested but gpg not installed" >&2 exit 1 fi if [[ ! -f "$SIGNATURE" ]]; then echo "==> downloading $(basename "$SIGNATURE")" curl -fsSL --retry 3 -o "$SIGNATURE" "$SIG_URL" fi XZ_TMP="$(mktemp -d)" trap 'rm -rf "$XZ_TMP"' EXIT xz -dk -c "$TARBALL" > "$XZ_TMP/linux-${VERSION}.tar" echo "==> verifying gpg signature" # Pull the pinned keys' fingerprints; require at least one matching sig. FINGERPRINTS="$(python3 -c ' import json,sys for k in json.load(open(sys.argv[1]))["gpg_signing_keys"]: print(k["fingerprint"])' "$PINNED")" for fp in $FINGERPRINTS; do gpg --keyserver hkps://keys.openpgp.org --recv-keys "$fp" \ >/dev/null 2>&1 || true done if ! gpg --verify "$SIGNATURE" "$XZ_TMP/linux-${VERSION}.tar" 2>&1 \ | grep -qE 'Good signature.*('"$(echo "$FINGERPRINTS" | tr '\n' '|' | sed 's/|$//')"')'; then echo "fetch.sh: GPG verification failed" >&2 exit 1 fi echo " ok" fi # 4. Extract ---------------------------------------------------------------- if [[ ! -d "$SRC_DIR/$EXTRACTED_DIR" ]]; then echo "==> extracting" tar -xf "$TARBALL" -C "$SRC_DIR" fi echo "==> linux source ready: $SRC_DIR/$EXTRACTED_DIR"