#!/usr/bin/env bash set -euo pipefail # Helper: print registry "latest" tag digest and show which image each environment is running. # - Uses docker manifest inspect to read digests. # - Uses kubectl to read the deployed container image per namespace. # - Relies on deploy/env.sh for registry/repo/namespaces; will load secrets for registry auth if available. # # Usage: ./scripts/check-versions.sh ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" # shellcheck source=/dev/null source "$ROOT_DIR/deploy/env.sh" : "${SOPS_AGE_KEY_FILE:=$ROOT_DIR/creds/age-key.txt}" : "${ENCRYPTED_FILE:=$ROOT_DIR/creds/secrets.enc.env}" : "${SECRETS_FILE:=$ROOT_DIR/creds/secrets.env}" load_registry_creds() { # Try repo helper if present (may decrypt creds). if [[ -f "$ROOT_DIR/scripts/load-secrets.sh" ]]; then # shellcheck source=/dev/null source "$ROOT_DIR/scripts/load-secrets.sh" >/dev/null 2>&1 || true fi # Fallback: if secrets file is empty but encrypted exists, decrypt to temp. if [[ ! -s "$SECRETS_FILE" && -f "$ENCRYPTED_FILE" && -f "$SOPS_AGE_KEY_FILE" && -x "$(command -v sops || true)" ]]; then tmpfile=$(mktemp) SOPS_AGE_KEY_FILE="$SOPS_AGE_KEY_FILE" sops -d "$ENCRYPTED_FILE" >"$tmpfile" 2>/dev/null || true if [[ -s "$tmpfile" ]]; then # shellcheck source=/dev/null source "$tmpfile" || true fi rm -f "$tmpfile" elif [[ -s "$SECRETS_FILE" ]]; then # shellcheck source=/dev/null source "$SECRETS_FILE" >/dev/null 2>&1 || true fi } load_registry_creds REGISTRY_AUTH_STATE="missing" # Prefer repo kubeconfig if none set. if [[ -z "${KUBECONFIG:-}" && -f "$ROOT_DIR/creds/kubeconfig.yaml" ]]; then export KUBECONFIG="$ROOT_DIR/creds/kubeconfig.yaml" fi login_registry() { if ! command -v docker >/dev/null 2>&1; then REGISTRY_AUTH_STATE="no-docker" return fi if [[ -n "${REGISTRY_USERNAME:-}" && -n "${REGISTRY_PASSWORD:-}" ]]; then if docker login "$REGISTRY" -u "$REGISTRY_USERNAME" -p "$REGISTRY_PASSWORD" >/dev/null 2>&1; then REGISTRY_AUTH_STATE="logged-in" else REGISTRY_AUTH_STATE="login-failed" fi else REGISTRY_AUTH_STATE="no-creds" fi } manifest_digest() { local image="$1" if ! command -v docker >/dev/null 2>&1; then echo "" return fi local out out="$( { docker manifest inspect "$image" 2>/dev/null | python3 - <<'PY' import json,sys try: raw=sys.stdin.read().strip() if not raw: raise SystemExit data=json.loads(raw) except Exception: raise SystemExit # Prefer amd64 manifest when multi-arch. if "manifests" in data: m=[m for m in data["manifests"] if m.get("platform",{}).get("architecture")=="amd64"] if not m: m=data["manifests"] if m: print(m[0].get("digest","")) elif "config" in data and "digest" in data["config"]: print(data["config"]["digest"]) PY } || true )" echo "$out" } get_deployed_image() { local namespace="$1" kubectl -n "$namespace" get deploy "$DEPLOYMENT_NAME" -o jsonpath='{.spec.template.spec.containers[?(@.name=="'"$DEPLOYMENT_NAME"'")].image}' 2>/dev/null || true echo } login_registry LATEST_IMAGE="${REGISTRY}/${REGISTRY_REPO}:latest" LATEST_DIGEST="$(manifest_digest "$LATEST_IMAGE")" echo "Registry latest: $LATEST_IMAGE" if [[ -z "$LATEST_DIGEST" ]]; then echo " digest: unavailable (docker missing or unauthorized)" else echo " digest: $LATEST_DIGEST" fi if [[ -f "$ROOT_DIR/deploy/.last-image" ]]; then echo "Local last built: $(cat "$ROOT_DIR/deploy/.last-image")" fi echo if [[ "$REGISTRY_AUTH_STATE" != "logged-in" && "$REGISTRY_AUTH_STATE" != "missing" ]]; then echo "Note: registry auth not established (state: $REGISTRY_AUTH_STATE); digest comparison may be unavailable." echo " Export REGISTRY_USERNAME/REGISTRY_PASSWORD (via sops load) or run: docker login $REGISTRY" echo fi for row in "testing:$TEST_NAMESPACE" "staging:$STAGING_NAMESPACE" "prod:$PROD_NAMESPACE"; do env_name="${row%%:*}" ns="${row##*:}" img="$(get_deployed_image "$ns")" if [[ -z "$img" ]]; then echo "Env $env_name ($ns): no image found (missing deploy?)" continue fi digest="$(manifest_digest "$img")" match="no" if [[ -n "$LATEST_DIGEST" && -n "$digest" && "$LATEST_DIGEST" == "$digest" ]]; then match="yes" fi echo "Env $env_name ($ns):" echo " image: $img" if [[ -z "$digest" ]]; then echo " digest: unavailable (docker missing or unauthorized)" else echo " digest: $digest" fi echo " matches latest: $match" done