#!/usr/bin/env bash # Refuse to turn a first-publish placeholder, a mutable tag, or an accidental # local image name into an apparently reproducible devnet. It also validates # the fully resolved normal Compose configuration, not merely images.env. set -euo pipefail cd "$(dirname "${BASH_SOURCE[0]}")" for tool in docker jq; do if ! command -v "$tool" >/dev/null 2>&1; then echo "required tool '$tool' is not installed; install it before running this script." >&2 exit 1 fi done # shellcheck source=images.env source ./images.env valid_digest() { [[ "$1" =~ ^ghcr\.io/riotbyte/crate-devnet-[a-z]+@sha256:[a-f0-9]{64}$ ]] } for image in "$JETSTREAM_IMAGE" "$CONSTELLATION_IMAGE" "$SLINGSHOT_IMAGE"; do if ! valid_digest "$image"; then echo "devnet images are not locked to published GHCR digests yet." >&2 echo "Follow the two-phase bootstrap procedure in e2e/README.md." >&2 exit 1 fi done if [[ ! -f .env ]]; then echo "devnet secrets are missing; run make e2e-setup first." >&2 exit 1 fi # Compose gives shell variables precedence over --env-file values. Clear the # three image variables and put the committed lock after local secrets so no # ambient shell or .env value can replace a digest. resolved="$(env \ -u JETSTREAM_IMAGE \ -u CONSTELLATION_IMAGE \ -u SLINGSHOT_IMAGE \ docker compose --env-file .env --env-file images.env config --format json)" printf '%s' "$resolved" | jq -e \ --arg jetstream "$JETSTREAM_IMAGE" \ --arg constellation "$CONSTELLATION_IMAGE" \ --arg slingshot "$SLINGSHOT_IMAGE" \ '.services.jetstream.image == $jetstream and .services.constellation.image == $constellation and .services.slingshot.image == $slingshot' \ >/dev/null \ || { echo "resolved Compose configuration does not match the committed image lock." >&2 exit 1 }