From e232ea7de78721de30a5bcd2d2360d9808b8a98b Mon Sep 17 00:00:00 2001 From: Michael Mayer Date: Wed, 10 Jun 2026 18:25:05 +0000 Subject: [PATCH] Build: Verify SHA-256 checksums when installing s6-overlay & yt-dlp Stage each download in a temporary file and verify it against the SHA-256 published by the upstream release (s6-overlay per-asset .sha256, yt-dlp SHA2-256SUMS) before installing. Abort on mismatch and warn when no manifest is published so older pinned tags still install. --- scripts/dist/install-s6.sh | 45 ++++++++++++++++++++++++++++++---- scripts/dist/install-yt-dlp.sh | 38 +++++++++++++++++++++++++--- 2 files changed, 74 insertions(+), 9 deletions(-) diff --git a/scripts/dist/install-s6.sh b/scripts/dist/install-s6.sh index 62a271dbb..54279eddb 100755 --- a/scripts/dist/install-s6.sh +++ b/scripts/dist/install-s6.sh @@ -77,11 +77,46 @@ echo "-------------------------------------------------------------------------- # Create the destination directory if it does not already exist. mkdir -p "${S6_OVERLAY_DESTDIR}" -# Download and install the s6-overlay release from GitHub. -echo "Extracting \"$S6_NOARCH_URL\" to \"$S6_OVERLAY_DESTDIR\"..." -curl -fsSL "$S6_NOARCH_URL" | tar -C "${S6_OVERLAY_DESTDIR}" -Jxp +# Stage downloads in a temporary directory that is removed on exit. +S6_TMPDIR=$(mktemp -d) +trap 'rm -rf "${S6_TMPDIR}"' EXIT -echo "Extracting \"$S6_BINARY_URL\" to \"$S6_OVERLAY_DESTDIR\"..." -curl -fsSL "$S6_BINARY_URL" | tar -C "${S6_OVERLAY_DESTDIR}" -Jxp +# verify_sha256 checks a file against the SHA-256 published next to the release +# asset (.sha256), aborting on mismatch. It soft-fails when no checksum is +# published so pinned older tags without a manifest still install. +verify_sha256() { + local url="$1" file="$2" sumfile="$3" expected actual + if ! curl -fsSL "${url}.sha256" -o "${sumfile}" 2>/dev/null; then + echo "Warning: no published checksum at ${url}.sha256; skipping verification." 1>&2 + return 0 + fi + expected=$(awk '{print $1}' "${sumfile}") + if command -v sha256sum >/dev/null 2>&1; then + actual=$(sha256sum "${file}" | awk '{print $1}') + else + actual=$(shasum -a 256 "${file}" | awk '{print $1}') + fi + if [[ ${expected} != "${actual}" ]]; then + echo "Error: SHA-256 mismatch for $(basename "${file}")." 1>&2 + echo " expected: ${expected}" 1>&2 + echo " actual: ${actual}" 1>&2 + exit 1 + fi + echo "Checksum OK ($(basename "${file}"): ${actual})." +} + +# download_and_extract fetches a release tarball, verifies it, then extracts it. +download_and_extract() { + local url="$1" name="$2" archive="${S6_TMPDIR}/${2}" + echo "Downloading \"${url}\"..." + curl -fsSL "${url}" -o "${archive}" + verify_sha256 "${url}" "${archive}" "${archive}.sha256" + echo "Extracting \"${name}\" to \"${S6_OVERLAY_DESTDIR}\"..." + tar -C "${S6_OVERLAY_DESTDIR}" -Jxp -f "${archive}" +} + +# Download, verify, and install the s6-overlay release from GitHub. +download_and_extract "$S6_NOARCH_URL" "$ARCHIVE_NOARCH" +download_and_extract "$S6_BINARY_URL" "$ARCHIVE_BINARY" echo "Done." diff --git a/scripts/dist/install-yt-dlp.sh b/scripts/dist/install-yt-dlp.sh index 1448b62b4..6bea142bd 100755 --- a/scripts/dist/install-yt-dlp.sh +++ b/scripts/dist/install-yt-dlp.sh @@ -167,6 +167,7 @@ fi TAG_NAME="" ASSET_NAME="" ASSET_URL="" +CHECKSUM_URL="" while IFS= read -r release; do tag=$(echo "$release" | jq -r '.tag_name // empty') @@ -178,6 +179,8 @@ while IFS= read -r release; do TAG_NAME=$tag ASSET_NAME=$candidate ASSET_URL=$url + # yt-dlp publishes one SHA2-256SUMS manifest per release listing every asset. + CHECKSUM_URL=$(echo "$release" | jq -r '.assets[]? | select(.name == "SHA2-256SUMS") | .browser_download_url' | head -n1) break 2 fi done @@ -205,10 +208,37 @@ echo "DESTBIN : ${DESTBIN}" echo "--------------------------------------------------------------------------------" echo "Downloading the yt-dlp binary to \"${DESTBIN}\"..." -mkdir -p "${DESTDIR}" -curl --fail --silent --show-error --location "${GITHUB_URL}" -o "${DESTBIN}" +mkdir -p "${DESTDIR}/bin" +tmp_bin=$(mktemp) +trap 'rm -f "${tmp_bin}" "${tmp_bin}.sums"' EXIT +curl --fail --silent --show-error --location "${GITHUB_URL}" -o "${tmp_bin}" -echo "Changing permissions of \"${DESTBIN}\" to 755..." -chmod 755 "${DESTBIN}" +# Verify the binary against the release SHA2-256SUMS manifest before installing. +# Soft-fail when no manifest is published so older pinned tags still install. +if [[ -n ${CHECKSUM_URL} && ${CHECKSUM_URL} != "null" ]] && + curl --fail --silent --show-error --location "${CHECKSUM_URL}" -o "${tmp_bin}.sums" 2>/dev/null; then + expected=$(awk -v n="${ASSET_NAME}" '$2 == n {print $1}' "${tmp_bin}.sums") + if [[ -z ${expected} ]]; then + echo "Error: ${ASSET_NAME} not listed in SHA2-256SUMS; refusing to install." 1>&2 + exit 1 + fi + if command -v sha256sum >/dev/null 2>&1; then + actual=$(sha256sum "${tmp_bin}" | awk '{print $1}') + else + actual=$(shasum -a 256 "${tmp_bin}" | awk '{print $1}') + fi + if [[ ${expected} != "${actual}" ]]; then + echo "Error: SHA-256 mismatch for yt-dlp (${ASSET_NAME})." 1>&2 + echo " expected: ${expected}" 1>&2 + echo " actual: ${actual}" 1>&2 + exit 1 + fi + echo "Checksum OK (${actual})." +else + echo "Warning: no published checksum for ${ASSET_NAME}; skipping verification." 1>&2 +fi + +echo "Installing yt-dlp to \"${DESTBIN}\" with permissions 755..." +install -m 755 "${tmp_bin}" "${DESTBIN}" echo "Done."