#!/usr/bin/env bash # Generate an integrity lock for an already-resolved Debian package bundle. set -Eeuo pipefail SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P) PROJECT_DIR=$(cd -- "$SCRIPT_DIR/.." && pwd -P) ARCHIVE_DIR=${1:-"$PROJECT_DIR/work/apt/archives"} LIST_DIR=${2:-"$PROJECT_DIR/work/apt/lists"} OUTPUT=${3:-"$SCRIPT_DIR/debian-packages.lock.tsv"} [[ -d "$ARCHIVE_DIR" && -d "$LIST_DIR" ]] || { echo "Usage: $0 [ARCHIVE-DIR LIST-DIR OUTPUT]" >&2 exit 2 } INDEX=$(mktemp) OUTPUT_TMP=$(mktemp) trap 'rm -f -- "$INDEX" "$OUTPUT_TMP"' EXIT for package_list in "$LIST_DIR"/*_Packages; do [[ -f "$package_list" ]] || continue case "$(basename -- "$package_list")" in security.debian.org_*) base_url=https://security.debian.org/debian-security ;; deb.debian.org_*) base_url=https://deb.debian.org/debian ;; *) continue ;; esac awk -v base_url="$base_url" ' /^Filename: / { filename=substr($0, 11) } /^Size: / { size=substr($0, 7) } /^SHA256: / { sha=substr($0, 9) } /^$/ { if (filename != "" && size != "" && sha != "") { print sha "\t" size "\t" base_url "/" filename } filename=size=sha="" } END { if (filename != "" && size != "" && sha != "") { print sha "\t" size "\t" base_url "/" filename } } ' "$package_list" >>"$INDEX" done LC_ALL=C sort -u -o "$INDEX" "$INDEX" printf '# filename\tsize\tsha256\turl\n' >"$OUTPUT_TMP" while IFS= read -r -d '' package_path; do filename=$(basename -- "$package_path") size=$(stat -c '%s' "$package_path") sha=$(sha256sum "$package_path" | awk '{print $1}') match=$(awk -F '\t' -v sha="$sha" -v size="$size" \ '$1 == sha && $2 == size { print; exit }' "$INDEX") [[ -n "$match" ]] || { echo "No signed package-index record for $filename" >&2 exit 1 } url=${match#*$'\t'} url=${url#*$'\t'} printf '%s\t%s\t%s\t%s\n' "$filename" "$size" "$sha" "$url" \ >>"$OUTPUT_TMP" done < <(find "$ARCHIVE_DIR" -maxdepth 1 -type f -name '*.deb' -print0 | sort -z) install -m 0644 "$OUTPUT_TMP" "$OUTPUT" echo "Locked $(($(wc -l <"$OUTPUT") - 1)) Debian packages in $OUTPUT"