Ctrl K
ComunidadGuías…

scripts/github-installer-release-assets.sh

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
#!/bin/sh
set -eu

command_name="${1:-}"
if [ "$#" -gt 0 ]; then shift; fi
tag=""
directory="dist"

usage() {
  cat <<'EOF'
Usage: github-installer-release-assets.sh upload --tag TAG [--directory DIR]
       github-installer-release-assets.sh download --tag TAG [--directory DIR]

Uploads or downloads the exact four historical installer assets while keeping
the GitHub Release in draft state, then verifies every asset digest.
EOF
}

case "$command_name" in
  -h|--help) usage; exit 0 ;;
esac

while [ "$#" -gt 0 ]; do
  case "$1" in
    --tag) tag="${2:-}"; shift 2 ;;
    --directory) directory="${2:-}"; shift 2 ;;
    -h|--help) usage; exit 0 ;;
    *) echo "Unknown argument: $1" >&2; usage >&2; exit 2 ;;
  esac
done
case "$command_name" in upload|download) ;; *) usage >&2; exit 2 ;; esac
if ! printf '%s' "$tag" | grep -Eq '^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$'; then
  echo "Release tag must be valid Vastora SemVer." >&2
  exit 2
fi
for required in awk cmp find gh grep jq mkdir mktemp sha256sum; do
  if ! command -v "$required" >/dev/null 2>&1; then
    echo "Required command is not installed: $required" >&2
    exit 1
  fi
done

expected_assets='["install.sh","vastora-center-install.tar.gz","vastora-center-install.tar.gz.sha256","vastora-release-manifest.json"]'
release_json="$(gh release view "$tag" --json isDraft,assets)"
if [ "$(printf '%s' "$release_json" | jq -r '.isDraft')" != "true" ]; then
  echo "GitHub Release $tag is not a draft; refusing installer asset mutation." >&2
  exit 1
fi
if ! printf '%s' "$release_json" | jq -e --argjson expected "$expected_assets" '([.assets[].name] - $expected) == []' >/dev/null; then
  echo "GitHub Release $tag contains an unexpected asset; refusing to replace it." >&2
  exit 1
fi

validate_assets() {
  asset_dir="$1"
  manifest="$asset_dir/vastora-release-manifest.json"
  for asset in install.sh vastora-center-install.tar.gz vastora-center-install.tar.gz.sha256 vastora-release-manifest.json; do
    if [ ! -f "$asset_dir/$asset" ]; then
      echo "GitHub installer release asset is missing: $asset" >&2
      return 1
    fi
  done
  version="${tag#v}"
  prefix="vastora/releases/$tag/"
  if ! jq -e --arg version "$version" --arg prefix "$prefix" '
    (.schema == 1) and (.version == $version) and
    (.centerImage | test("^ghcr\\.io/petauron/vastora-center@sha256:[0-9a-f]{64}$")) and
    ((.assets | keys | sort) == ["install.sh", "vastora-center-install.tar.gz", "vastora-center-install.tar.gz.sha256"]) and
    (.assets["install.sh"].key == ($prefix + "install.sh")) and
    (.assets["vastora-center-install.tar.gz"].key == ($prefix + "vastora-center-install.tar.gz")) and
    (.assets["vastora-center-install.tar.gz.sha256"].key == ($prefix + "vastora-center-install.tar.gz.sha256")) and
    (all(.assets[]; .sha256 | test("^[0-9a-f]{64}$")))
  ' "$manifest" >/dev/null; then
    echo "GitHub installer release manifest is invalid." >&2
    return 1
  fi
  for asset in install.sh vastora-center-install.tar.gz vastora-center-install.tar.gz.sha256; do
    expected="$(jq -r --arg asset "$asset" '.assets[$asset].sha256' "$manifest")"
    actual="$(sha256sum "$asset_dir/$asset" | awk 'NR == 1 {print tolower($1)}')"
    if [ "$actual" != "$expected" ]; then
      echo "GitHub installer release asset digest mismatch: $asset" >&2
      return 1
    fi
  done
}

if [ "$command_name" = "download" ]; then
  mkdir -p "$directory"
  if find "$directory" -mindepth 1 -maxdepth 1 -print -quit | grep -q .; then
    echo "Download directory must be empty: $directory" >&2
    exit 1
  fi
  gh release download "$tag" --dir "$directory"
  validate_assets "$directory"
  echo "Downloaded and verified GitHub installer assets for $tag."
  exit 0
fi

validate_assets "$directory"
temporary_dir="$(mktemp -d "${TMPDIR:-/tmp}/vastora-github-release.XXXXXX")"
cleanup() { rm -rf "$temporary_dir"; }
trap cleanup EXIT HUP INT TERM

# Retry only an individual missing upload, never rebuild or overwrite an asset.
# Refresh the draft after uncertain responses: the upload may have succeeded.
for asset in install.sh vastora-center-install.tar.gz vastora-center-install.tar.gz.sha256 vastora-release-manifest.json; do
  attempt=1
  while :; do
    release_json="$(gh release view "$tag" --json isDraft,assets)"
    if ! printf '%s' "$release_json" | jq -e --argjson expected "$expected_assets" '.isDraft == true and (([.assets[].name] - $expected) == [])' >/dev/null; then
      echo "Release changed during upload; refusing asset mutation." >&2
      exit 1
    fi
    if printf '%s' "$release_json" | jq -e --arg name "$asset" 'any(.assets[]; .name == $name)' >/dev/null; then
      mkdir -p "$temporary_dir/existing"
      gh release download "$tag" --pattern "$asset" --dir "$temporary_dir/existing"
      if ! cmp -s "$directory/$asset" "$temporary_dir/existing/$asset"; then
        echo "Existing GitHub asset differs: $asset; refusing replacement." >&2
        exit 1
      fi
      break
    fi
    if gh release upload "$tag" "$directory/$asset" >"$temporary_dir/upload.log" 2>&1; then
      break
    fi
    cat "$temporary_dir/upload.log" >&2
    if [ "$attempt" -ge 3 ] || ! grep -Eq 'HTTP (404|408|429|5[0-9][0-9])|[Tt]imeout|timed out|connection reset|unexpected EOF|TLS handshake' "$temporary_dir/upload.log"; then
      exit 1
    fi
    echo "Retrying missing upload $asset ($attempt/3)." >&2
    sleep "$((attempt * 2))"
    attempt="$((attempt + 1))"
  done
done

mkdir -p "$temporary_dir/verified"
temporary_assets="$temporary_dir/verified"
gh release download "$tag" --dir "$temporary_assets"
validate_assets "$temporary_assets"
for asset in install.sh vastora-center-install.tar.gz vastora-center-install.tar.gz.sha256 vastora-release-manifest.json; do
  if ! cmp -s "$directory/$asset" "$temporary_assets/$asset"; then
    echo "Downloaded GitHub Release asset differs from the uploaded file: $asset" >&2
    exit 1
  fi
done
release_json="$(gh release view "$tag" --json isDraft,assets)"
if ! printf '%s' "$release_json" | jq -e --argjson expected "$expected_assets" '.isDraft == true and ([.assets[].name] | sort) == ($expected | sort)' >/dev/null; then
  echo "GitHub Release does not contain exactly the verified installer assets in draft state." >&2
  exit 1
fi
echo "Uploaded and verified GitHub installer assets for $tag."