From 3a9b189720581d9ab31ae2d8d673dee8f6928b9f Mon Sep 17 00:00:00 2001 From: npub1t2tgm7d8f995uqvmnm8h88sg3wnpp9a5xysjf6dg3tjmgt3ltulqdp8ehr <5a968df9a7494b4e019b9ecf739e088ba61097b4312124e9a88ae5b42e3f5f3e@buzz.block.builderlab.xyz> Date: Sat, 1 Aug 2026 23:16:18 -0400 Subject: [PATCH] test: add safe Sprig Kubernetes preflight Co-authored-by: npub1t2tgm7d8f995uqvmnm8h88sg3wnpp9a5xysjf6dg3tjmgt3ltulqdp8ehr <5a968df9a7494b4e019b9ecf739e088ba61097b4312124e9a88ae5b42e3f5f3e@buzz.block.builderlab.xyz> Signed-off-by: npub1t2tgm7d8f995uqvmnm8h88sg3wnpp9a5xysjf6dg3tjmgt3ltulqdp8ehr <5a968df9a7494b4e019b9ecf739e088ba61097b4312124e9a88ae5b42e3f5f3e@buzz.block.builderlab.xyz> --- scripts/test-k8s-sprig-image-live.sh | 97 ++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100755 scripts/test-k8s-sprig-image-live.sh diff --git a/scripts/test-k8s-sprig-image-live.sh b/scripts/test-k8s-sprig-image-live.sh new file mode 100755 index 000000000..2e692eaa8 --- /dev/null +++ b/scripts/test-k8s-sprig-image-live.sh @@ -0,0 +1,97 @@ +#!/usr/bin/env bash +# Prove that a cluster can resolve and start the exact digest-qualified Sprig +# image that will be passed to the Kubernetes provider. This is intentionally a +# separate preflight: a Docker image existing in the host daemon does not imply +# that the kubelet's container runtime can resolve the same name and digest. +set -euo pipefail + +: "${BUZZ_K8S_TEST_CONTEXT:?set the explicit disposable/local kubectl context}" +: "${BUZZ_SPRIG_IMAGE:?set an immutable image reference (name@sha256:<64 hex>)}" + +if [[ ! "$BUZZ_SPRIG_IMAGE" =~ ^[^[:space:]@]+@sha256:[0-9a-fA-F]{64}$ ]]; then + echo "error: BUZZ_SPRIG_IMAGE must be name@sha256:<64 hex>" >&2 + exit 2 +fi + +CONTEXT="$BUZZ_K8S_TEST_CONTEXT" +IMAGE="$BUZZ_SPRIG_IMAGE" +PULL_POLICY="${BUZZ_K8S_TEST_PULL_POLICY:-IfNotPresent}" +case "$PULL_POLICY" in + Always|IfNotPresent|Never) ;; + *) echo "error: invalid BUZZ_K8S_TEST_PULL_POLICY: $PULL_POLICY" >&2; exit 2 ;; +esac + +MANAGED_BY="buzz-backend-kubernetes" +BINDING_VERSION="v1" +NAMESPACE="buzz-k8s-sprig-$(date +%s)-$RANDOM" +CREATED=0 + +cleanup() { + (( CREATED == 1 )) || return 0 + local managed binding foreign + managed="$(kubectl --context "$CONTEXT" get namespace "$NAMESPACE" \ + -o jsonpath='{.metadata.labels.app\.kubernetes\.io/managed-by}' 2>/dev/null || true)" + binding="$(kubectl --context "$CONTEXT" get namespace "$NAMESPACE" \ + -o jsonpath='{.metadata.labels.buzz\.block\.xyz/binding-version}' 2>/dev/null || true)" + if [[ "$managed" != "$MANAGED_BY" || "$binding" != "$BINDING_VERSION" ]]; then + echo "REFUSING cleanup: namespace ownership markers changed: $NAMESPACE" >&2 + return 1 + fi + foreign="$(kubectl --context "$CONTEXT" --namespace "$NAMESPACE" get pods -o json \ + | jq '[.items[] | select(.metadata.labels["app.kubernetes.io/managed-by"] != "buzz-backend-kubernetes" or .metadata.labels["buzz.block.xyz/binding-version"] != "v1")] | length')" + if [[ "$foreign" != 0 ]]; then + echo "REFUSING cleanup: namespace contains an unowned pod: $NAMESPACE" >&2 + return 1 + fi + kubectl --context "$CONTEXT" delete namespace "$NAMESPACE" --wait=true +} +trap cleanup EXIT + +# Fail before mutation if the named context is absent or inaccessible. Print the +# cluster identity so evidence cannot be mistaken for a different kubeconfig. +kubectl config get-contexts "$CONTEXT" >/dev/null +SERVER="$(kubectl config view --minify --context "$CONTEXT" -o jsonpath='{.clusters[0].cluster.server}')" +kubectl --context "$CONTEXT" get nodes -o name >/dev/null +printf 'context=%s\nserver=%s\nimage=%s\npull_policy=%s\nnamespace=%s\n' \ + "$CONTEXT" "$SERVER" "$IMAGE" "$PULL_POLICY" "$NAMESPACE" + +kubectl --context "$CONTEXT" create namespace "$NAMESPACE" +CREATED=1 +kubectl --context "$CONTEXT" label namespace "$NAMESPACE" \ + "app.kubernetes.io/managed-by=$MANAGED_BY" \ + "buzz.block.xyz/binding-version=$BINDING_VERSION" + +cat <&2 || true + exit 1 +fi + +kubectl --context "$CONTEXT" --namespace "$NAMESPACE" logs digest-resolution-probe +IMAGE_ID="$(kubectl --context "$CONTEXT" --namespace "$NAMESPACE" get pod digest-resolution-probe \ + -o jsonpath='{.status.containerStatuses[0].imageID}')" +RESOLVED_SPEC="$(kubectl --context "$CONTEXT" --namespace "$NAMESPACE" get pod digest-resolution-probe \ + -o jsonpath='{.spec.containers[0].image}')" +[[ "$RESOLVED_SPEC" == "$IMAGE" ]] +[[ -n "$IMAGE_ID" ]] +printf 'resolved_spec=%s\nimage_id=%s\nPASS: exact digest-qualified Sprig reference started\n' \ + "$RESOLVED_SPEC" "$IMAGE_ID"