ship.sh
Rama main · réplica de lectura del repositorio original.
#!/usr/bin/env bash
# ── SHIP THE BROWSER: build, push, SIGN, and say what to do next ─────────────────────────────────
#
# The browser is built by hand on purpose (it is not in the webnpm pipeline), and for as long as that
# was three commands typed from memory, one of them kept being forgotten: the SIGNATURE. Every image
# the cluster runs is checked against the platform's cosign key, and an unsigned first-party image is
# refused at admission — so a browser built the old way would push fine, roll, and never start.
#
# So the three commands live here, in the order that works, with the signature not optional.
#
# Usage: ./ship.sh v407 # build, push, sign
# ./ship.sh v407 --roll # …and roll the tenant's browser straight away
#
# The tag is deliberately an argument with no default. A shipped browser is a version somebody chose.
set -euo pipefail
TAG="${1:-}"
ROLL="${2:-}"
IMAGE="wvdstoep/ghost-browser:${TAG}"
NS="${GB_NAMESPACE:-pod-mavicpro-fan}"
KEY="${COSIGN_KEY:-/etc/cosign/cosign.key}"
export COSIGN_PASSWORD="${COSIGN_PASSWORD:-}"
if [[ -z "$TAG" || ! "$TAG" =~ ^v[0-9]+$ ]]; then
echo "usage: ./ship.sh vNNN [--roll]"
echo " the last shipped tag: $(sudo kubectl get deploy ghost-browser -n "$NS" -o jsonpath='{.spec.template.spec.containers[0].image}' 2>/dev/null || echo unknown)"
exit 2
fi
# A tag that already exists in the registry is almost always a typo — the alternative is silently
# replacing the image a running browser is pinned to, which is the one mistake with no undo.
if sudo docker manifest inspect "$IMAGE" >/dev/null 2>&1; then
echo "✋ $IMAGE already exists in the registry. Pick the next tag."
exit 2
fi
echo "🔨 building $IMAGE"
sudo docker build -t "$IMAGE" .
echo "📤 pushing"
sudo docker push "$IMAGE"
# THE STEP THAT USED TO BE FORGOTTEN. Not best-effort here: this script exists so that a browser
# cannot be shipped unsigned, and a signing failure now is infinitely cheaper than a browser that
# will not start at 3am. tlog-free, same key the Kyverno policy carries.
echo "🔏 signing"
sudo COSIGN_PASSWORD="$COSIGN_PASSWORD" cosign sign --yes --tlog-upload=false --key "$KEY" "$IMAGE"
sudo cosign verify --key /etc/cosign/cosign.pub --insecure-ignore-tlog "$IMAGE" >/dev/null
echo " ✓ signature verifies"
echo ""
echo "✅ $IMAGE is shipped and signed."
echo ""
if [[ "$ROLL" == "--roll" ]]; then
# NEVER while a long browser job is in flight: every API call the job makes comes back
# `fetch failed`. The script asks rather than assuming, because only a person knows what is running.
echo "⚠️ rolling now — anything the browser is doing right now dies with the pod."
read -r -p " a pass or a build in flight? [y/N] to continue: " ans
if [[ "${ans:-N}" =~ ^[Yy]$ ]]; then
sudo kubectl set image "deploy/ghost-browser" -n "$NS" "ghost-browser=$IMAGE"
sudo kubectl rollout status "deploy/ghost-browser" -n "$NS" --timeout=300s
else
echo " not rolled."
fi
else
echo "To roll it now:"
echo " sudo kubectl set image deploy/ghost-browser -n $NS ghost-browser=$IMAGE"
fi
echo ""
echo "And bump the pin so a FRESH install gets this one too (a re-apply keeps whatever is running,"
echo "but a brand-new tenant's browser comes from the pin):"
echo " ai_agent_standalone/agent-cluster/provisioner/src/cluster-tools-manifests.js (opts.tag || '$TAG')"