#!/usr/bin/env bash set -Eeuo pipefail : "${REGISTRY_SERVER:?Missing Gitea server URL}" : "${REGISTRY_REPOSITORY:?Missing owner/repository}" : "${REGISTRY_USER:?Configure CONTAINER_REGISTRY_USER}" : "${REGISTRY_TOKEN:?Configure CONTAINER_REGISTRY_TOKEN with package write access}" sha="$(git rev-parse HEAD)" [[ "$sha" =~ ^[0-9a-f]{40}$ ]] || exit 1 registry="${REGISTRY_SERVER#https://}" registry="${registry%/}" [[ "$REGISTRY_SERVER" = https://* && "$registry" != */* ]] || { echo "Registry must use HTTPS at the Gitea server root" >&2; exit 1; } repository="${REGISTRY_REPOSITORY,,}" [[ "$repository" =~ ^[a-z0-9._-]+/[a-z0-9._-]+$ ]] || exit 1 # Gitea packages belong to a user/organization, independently of repository ACLs. # A collaborator token cannot publish to another user's personal namespace. namespace="${REGISTRY_NAMESPACE:-$REGISTRY_USER}" namespace="${namespace,,}" [[ "$namespace" =~ ^[a-z0-9][a-z0-9._-]*$ ]] || { echo "Invalid registry namespace; use a Gitea username or organization" >&2; exit 1; } repository="$namespace/${repository#*/}" image="$registry/$repository:$sha" # Isolate credentials from the self-hosted runner's normal Docker configuration. export DOCKER_CONFIG DOCKER_CONFIG="$(mktemp -d)" context="$(mktemp -d)" trap 'rm -rf -- "$DOCKER_CONFIG" "$context"' EXIT # Build only the committed source, never untracked files from a shared runner. git archive HEAD | tar -x -C "$context" printf '%s' "$REGISTRY_TOKEN" | docker login "$registry" --username "$REGISTRY_USER" --password-stdin unset REGISTRY_TOKEN # On the shared runner, publish the exact image already verified by deployment. local_image="epicnext-cms:$sha" local_revision="$(docker image inspect --format '{{index .Config.Labels "org.opencontainers.image.revision"}}' "$local_image" 2>/dev/null || true)" local_id="$(docker image inspect --format '{{.Id}}' "$local_image" 2>/dev/null || true)" verified_id="$(docker image inspect --format '{{.Id}}' "epicnext-cms:verified-$sha" 2>/dev/null || true)" if [[ "$local_revision" = "$sha" && -n "$local_id" && "$local_id" = "$verified_id" ]]; then docker tag "$verified_id" "$image" echo "Reusing verified release image $local_image" else docker build --network=host --build-arg NEXT_DEPLOYMENT_ID="$sha" -t "$image" "$context" fi docker build --network=host --target migrations -t "$image-migrations" "$context" node scripts/verify-portable-image.mjs "$image" "$sha" # Publish only after the same application image passed both runtime configurations. docker push "$image-migrations" docker push "$image" echo "Published application and migrations: $image"