project-nomad/install/verify_offline_bundle.sh

99 lines
3.7 KiB
Bash
Executable File

#!/bin/bash
# Project NOMAD Offline Artifact Bundle Verifier
###################################################################################################################################################################################################
#
# Inspects and verifies an offline artifact bundle without installing anything.
#
# Useful before transferring a bundle to removable media, and on the target
# before running the installer. Runs entirely offline.
#
# Usage:
# ./verify_offline_bundle.sh [/path/to/bundle]
#
###################################################################################################################################################################################################
set -Eeuo pipefail
RESET='\033[0m'
RED='\033[1;31m'
GREEN='\033[1;32m'
die() {
echo -e "${RED}#${RESET} $*" >&2
exit 1
}
BUNDLE="${1:-.}"
BUNDLE="$(cd -- "${BUNDLE}" 2>/dev/null && pwd)" || die "Bundle directory not found: ${1:-.}"
command -v sha256sum > /dev/null 2>&1 || die "sha256sum is required."
manifest_get() {
local key="$1"
awk -F= -v wanted="${key}" '$1 == wanted { sub(/^[^=]*=/, "", $0); print; exit }' "${BUNDLE}/manifest"
}
# Same required set the installer enforces, so a bundle that passes here will
# not fail validation on the target for a missing file.
required_files=(
manifest
SHA256SUMS
install_nomad.sh
packages/apt/Packages
packages/apt/Packages.gz
images/core-images.txt
images/core-images.tar
payload/nomad/management_compose.yaml
payload/nomad/compose.artifact.yml
payload/nomad/start_nomad.sh
payload/nomad/stop_nomad.sh
payload/nomad/update_nomad.sh
)
for required_file in "${required_files[@]}"; do
[[ -f "${BUNDLE}/${required_file}" ]] || die "Bundle is incomplete. Missing: ${required_file}"
done
echo "Verifying checksums..."
(cd "${BUNDLE}" && sha256sum -c SHA256SUMS > /dev/null) ||
die "Checksum verification failed — the bundle is corrupt or incomplete."
# ! -name '._*' skips macOS AppleDouble sidecars left on FAT/exFAT media.
deb_count="$(find "${BUNDLE}/packages/apt" -maxdepth 1 -name '*.deb' ! -name '._*' | wc -l | tr -d ' ')"
[[ "${deb_count}" -gt 0 ]] || die "Bundle contains no .deb packages."
image_count="$(grep -c '[^[:space:]]' "${BUNDLE}/images/core-images.txt" || true)"
[[ "${image_count}" -gt 0 ]] || die "Bundle lists no management images."
# Every service in the bundled compose file must appear in the pull-never
# override, or that service would still try to reach a registry on the target.
missing_overrides=''
while IFS= read -r service; do
grep -qE "^[[:space:]]+${service}:[[:space:]]*$" "${BUNDLE}/payload/nomad/compose.artifact.yml" ||
missing_overrides="${missing_overrides} ${service}"
done < <(awk '
/^services:[[:space:]]*$/ { in_services = 1; next }
/^[^[:space:]#]/ { in_services = 0 }
in_services && /^ [A-Za-z0-9._-]+:[[:space:]]*$/ {
gsub(/^ |:[[:space:]]*$/, "", $0)
print
}
' "${BUNDLE}/payload/nomad/management_compose.yaml")
[[ -z "${missing_overrides}" ]] ||
die "compose.artifact.yml is missing pull_policy overrides for:${missing_overrides}"
echo ''
printf 'Bundle format : %s\n' "$(manifest_get BUNDLE_FORMAT_VERSION)"
printf 'NOMAD commit : %s\n' "$(manifest_get NOMAD_COMMIT)"
printf 'Target : %s %s (%s)\n' \
"$(manifest_get TARGET_OS)" "$(manifest_get TARGET_VERSION)" "$(manifest_get TARGET_ARCH)"
printf 'NVIDIA toolkit: %s\n' "$(manifest_get WITH_NVIDIA_TOOLKIT)"
printf 'Created (UTC) : %s\n' "$(manifest_get CREATED_AT_UTC)"
printf 'Packages : %s .deb files\n' "${deb_count}"
printf 'Images : %s\n' "${image_count}"
echo ''
echo -e "${GREEN}#${RESET} Bundle verified. Checksums confirm transfer integrity, not publisher identity."