| 1 | #!/usr/bin/env bash |
| 2 | # Prove that a remote release tag still points at the immutable source SHA |
| 3 | # resolved before a public release write. |
| 4 | set -euo pipefail |
| 5 | |
| 6 | if [[ $# -ne 3 ]]; then |
| 7 | echo "usage: $0 <remote-or-url> <vX.Y.Z> <expected-commit-sha>" >&2 |
| 8 | exit 2 |
| 9 | fi |
| 10 | |
| 11 | remote="$1" |
| 12 | tag="$2" |
| 13 | expected_sha="$3" |
| 14 | |
| 15 | if ! [[ "${tag}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then |
| 16 | echo "error: release tag '${tag}' must use vX.Y.Z" >&2 |
| 17 | exit 2 |
| 18 | fi |
| 19 | if ! [[ "${expected_sha}" =~ ^[0-9a-fA-F]{40}$ ]]; then |
| 20 | echo "error: expected commit SHA must be a full 40-character SHA-1" >&2 |
| 21 | exit 2 |
| 22 | fi |
| 23 | |
| 24 | remote_sha="$( |
| 25 | git ls-remote --tags "${remote}" "refs/tags/${tag}^{}" \ |
| 26 | | awk 'NR == 1 {print $1}' |
| 27 | )" |
| 28 | if [[ -z "${remote_sha}" ]]; then |
| 29 | remote_sha="$( |
| 30 | git ls-remote --tags "${remote}" "refs/tags/${tag}" \ |
| 31 | | awk 'NR == 1 {print $1}' |
| 32 | )" |
| 33 | fi |
| 34 | if [[ -z "${remote_sha}" ]]; then |
| 35 | echo "::error::Remote tag ${tag} does not exist on ${remote}." >&2 |
| 36 | exit 1 |
| 37 | fi |
| 38 | if [[ "${remote_sha}" != "${expected_sha}" ]]; then |
| 39 | echo "::error::Remote tag ${tag} moved before publication." >&2 |
| 40 | echo " expected: ${expected_sha}" >&2 |
| 41 | echo " remote : ${remote_sha}" >&2 |
| 42 | exit 1 |
| 43 | fi |
| 44 | |
| 45 | echo "Remote tag check OK: ${tag} -> ${remote_sha}" |
| 46 |