Files
sandwich-hime/scripts/release-check.sh
T
gamertan c11552b87a policy: maintain Linux as the release target
Publishes the exact allowlisted snapshot from the private Beta 2 development line. Historical platform evidence remains truthful; native Windows and macOS are no longer release gates or support promises. Material AI assistance was reviewed by the maintainer.

Signed-off-by: Cole Speelman <crspeelman@gmail.com>
2026-08-16 17:50:00 -04:00

313 lines
11 KiB
Bash
Executable File

#!/usr/bin/env bash
# SPDX-License-Identifier: AGPL-3.0-only
set -euo pipefail
repo_root=$(CDPATH= cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)
cd "$repo_root"
usage() {
cat <<'EOF'
Usage: scripts/release-check.sh --version vX.Y.Z [--runtime-tag sando/vX.Y.Z] [--public]
Runs a read-only release preflight. It never creates tags, commits, release
artifacts in the repository, pushes, or deploys.
--version Candidate compiler version.
--runtime-tag Existing runtime tag retained by a compiler-only release.
Omit only when publishing a matching new runtime tag.
--public Require the human-reviewed RC/final launch evidence bundle named
by HIMESAN_RELEASE_EVIDENCE_DIR. Canonical beta prereleases may
run their narrower publication preflight without this flag.
EOF
}
version=''
runtime_tag=''
public_release=0
while (( $# > 0 )); do
case "$1" in
--version)
[[ $# -ge 2 ]] || { usage >&2; exit 2; }
version=$2
shift 2
;;
--runtime-tag)
[[ $# -ge 2 ]] || { usage >&2; exit 2; }
runtime_tag=$2
shift 2
;;
--public)
public_release=1
shift
;;
-h | --help)
usage
exit 0
;;
*)
printf 'unknown argument: %s\n' "$1" >&2
usage >&2
exit 2
;;
esac
done
if [[ ! "$version" =~ ^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(-([0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*))?$ ]]; then
printf 'error: --version must be a canonical semantic version beginning with v (build metadata is not allowed)\n' >&2
exit 2
fi
prerelease=${BASH_REMATCH[5]:-}
if [[ "$prerelease" =~ (^|[.-])(0\.)?[0-9]{14}-[0-9a-f]{12,}$ ]]; then
printf 'error: --version must be a signed release tag, not a Go pseudo-version\n' >&2
exit 2
fi
if [[ -n "$prerelease" ]]; then
IFS=. read -r -a prerelease_identifiers <<<"$prerelease"
for identifier in "${prerelease_identifiers[@]}"; do
if [[ "$identifier" =~ ^[0-9]+$ && "$identifier" =~ ^0[0-9]+$ ]]; then
printf 'error: numeric prerelease identifiers must not contain leading zeroes: %s\n' "$identifier" >&2
exit 2
fi
done
fi
beta_release=0
if [[ "$prerelease" == beta || "$prerelease" == beta.* ]]; then
beta_release=1
fi
if (( public_release == 0 && beta_release == 0 )); then
printf 'error: RC and final release preflights require --public and the human-reviewed evidence bundle\n' >&2
exit 2
fi
paired_runtime_tag="sando/$version"
compiler_only=0
if [[ -z "$runtime_tag" ]]; then
runtime_tag=$paired_runtime_tag
elif [[ ! "$runtime_tag" =~ ^sando/v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(-([0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*))?$ ]]; then
printf 'error: --runtime-tag must be a canonical sando/v semantic version without build metadata\n' >&2
exit 2
else
runtime_prerelease=${BASH_REMATCH[5]:-}
if [[ "$runtime_prerelease" =~ (^|[.-])(0\.)?[0-9]{14}-[0-9a-f]{12,}$ ]]; then
printf 'error: --runtime-tag must identify a signed release, not a Go pseudo-version\n' >&2
exit 2
fi
if [[ -n "$runtime_prerelease" ]]; then
IFS=. read -r -a runtime_prerelease_identifiers <<<"$runtime_prerelease"
for identifier in "${runtime_prerelease_identifiers[@]}"; do
if [[ "$identifier" =~ ^[0-9]+$ && "$identifier" =~ ^0[0-9]+$ ]]; then
printf 'error: runtime numeric prerelease identifiers must not contain leading zeroes: %s\n' "$identifier" >&2
exit 2
fi
done
fi
if [[ "$runtime_tag" != "$paired_runtime_tag" ]]; then
compiler_only=1
fi
fi
if [[ -n "$(git status --porcelain=v1 --untracked-files=all)" ]]; then
printf 'error: release preflight requires a clean canonical checkout\n' >&2
exit 1
fi
origin_url=$(git remote get-url origin)
case "$origin_url" in
ssh://git@gitea.speelman.ca:2222/gamertan/sandwich-hime.git | \
git@gitea.speelman.ca:gamertan/sandwich-hime.git | \
https://gitea.speelman.ca/gamertan/sandwich-hime.git)
;;
*)
printf 'error: origin is not the canonical Gitea repository: %s\n' "$origin_url" >&2
exit 1
;;
esac
branch=$(git symbolic-ref --quiet --short HEAD || true)
if [[ "$branch" != main ]]; then
printf 'error: release preflight must run from canonical main, not %s\n' "${branch:-detached HEAD}" >&2
exit 1
fi
candidate_tags=("$version")
if (( compiler_only == 0 )); then
candidate_tags+=("$runtime_tag")
fi
for tag in "${candidate_tags[@]}"; do
if git rev-parse -q --verify "refs/tags/$tag" >/dev/null; then
printf 'error: candidate tag already exists locally: %s\n' "$tag" >&2
exit 1
fi
if ! remote_tags=$(git ls-remote --tags origin "refs/tags/$tag" "refs/tags/$tag^{}" 2>/dev/null); then
printf 'error: could not verify candidate tag against canonical origin: %s\n' "$tag" >&2
exit 1
fi
if [[ -n "$remote_tags" ]]; then
printf 'error: candidate tag already exists on canonical origin: %s\n' "$tag" >&2
exit 1
fi
done
if (( compiler_only == 1 )); then
if ! runtime_refs=$(git ls-remote --tags origin "refs/tags/$runtime_tag" "refs/tags/$runtime_tag^{}" 2>/dev/null); then
printf 'error: could not verify retained runtime tag against canonical origin: %s\n' "$runtime_tag" >&2
exit 1
fi
runtime_commit=$(printf '%s\n' "$runtime_refs" | awk '$2 ~ /\^\{\}$/ {print $1}')
if [[ -z "$runtime_commit" || ! "$runtime_commit" =~ ^[0-9a-f]{40}$ ]]; then
printf 'error: retained runtime tag is absent or is not annotated: %s\n' "$runtime_tag" >&2
exit 1
fi
if ! git cat-file -e "$runtime_commit^{commit}" 2>/dev/null; then
printf 'error: retained runtime tag commit is not present in canonical history: %s\n' "$runtime_tag" >&2
exit 1
fi
if [[ "$(git rev-parse HEAD:sando)" != "$(git rev-parse "$runtime_commit:sando")" ]]; then
printf 'error: compiler-only release changed the sando subtree retained at %s\n' "$runtime_tag" >&2
exit 1
fi
fi
artifact_dir=$(mktemp -d "${TMPDIR:-/tmp}/himesan-release-check.XXXXXXXX")
cleanup() {
if [[ -n "${artifact_dir:-}" && -d "$artifact_dir" ]]; then
rm -rf -- "$artifact_dir"
fi
}
trap cleanup EXIT HUP INT TERM
compiler_linker_flags="-X gamertan.com/sandwich-hime/internal/version.Compiler=$version"
candidate_binary="$artifact_dir/himesan-candidate"
printf '\n==> exact release candidate identity\n'
go build -trimpath -ldflags "$compiler_linker_flags" -o "$candidate_binary" ./cmd/himesan
candidate_go_version=$(go env GOVERSION)
expected_human_version="himesan $version (runtime ABI sando.v1, $candidate_go_version)"
actual_human_version=$("$candidate_binary" version)
if [[ "$actual_human_version" != "$expected_human_version" ]]; then
printf 'error: candidate human version mismatch\nexpected: %s\nactual: %s\n' \
"$expected_human_version" "$actual_human_version" >&2
exit 1
fi
expected_json_version=$(printf '{"compiler":"%s","runtime_abi":"sando.v1","go":"%s","features":["lsp-stdio"]}' "$version" "$candidate_go_version")
actual_json_version=$("$candidate_binary" version --json)
if [[ "$actual_json_version" != "$expected_json_version" ]]; then
printf 'error: candidate JSON version mismatch\nexpected: %s\nactual: %s\n' \
"$expected_json_version" "$actual_json_version" >&2
exit 1
fi
file_mtime() {
if stat --printf='%y' "$1" >/dev/null 2>&1; then
stat --printf='%y' "$1"
else
stat -f '%m' "$1"
fi
}
printf '\n==> candidate generated-output provenance compatibility\n'
golden_source=internal/compiler/testdata/golden/basic.sando
golden_output="$golden_source.go"
if ! grep -Fqx '// himesan:compiler 0.1.0-dev' "$golden_output"; then
printf 'error: golden fixture no longer provides development-to-release provenance coverage: %s\n' "$golden_output" >&2
exit 1
fi
golden_hash_before=$(git hash-object "$golden_output")
golden_mtime_before=$(file_mtime "$golden_output")
check_summary=$("$candidate_binary" check "$golden_source")
if [[ "$check_summary" != 'checked 1 .sando files: 1 current' ]]; then
printf 'error: candidate did not consider the development-produced golden current: %s\n' "$check_summary" >&2
exit 1
fi
for pass in 1 2; do
generate_summary=$("$candidate_binary" generate "$golden_source")
if [[ "$generate_summary" != 'generated 0, unchanged 1 (1 .sando files)' ]]; then
printf 'error: candidate generation pass %d reported unexpected changes: %s\n' "$pass" "$generate_summary" >&2
exit 1
fi
if [[ "$(git hash-object "$golden_output")" != "$golden_hash_before" ]]; then
printf 'error: candidate generation pass %d changed golden bytes\n' "$pass" >&2
exit 1
fi
if [[ "$(file_mtime "$golden_output")" != "$golden_mtime_before" ]]; then
printf 'error: candidate generation pass %d changed the golden mtime\n' "$pass" >&2
exit 1
fi
done
./scripts/check-licenses.sh
HIMESAN_RACE=1 ./scripts/verify.sh
printf '\n==> bounded compiler fuzz gates\n'
go test ./internal/compiler -run '^$' -fuzz '^FuzzCompileNeverPanics$' -fuzztime=20s
go test ./internal/compiler -run '^$' -fuzz '^FuzzGoDelimiterNeverPanics$' -fuzztime=20s
go test ./internal/lsp -run '^$' -fuzz '^FuzzFrameReaderNeverPanics$' -fuzztime=20s
go test ./internal/lsp -run '^$' -fuzz '^FuzzDocumentPositionNeverPanics$' -fuzztime=20s
printf '\n==> vulnerability scan (pinned golang.org/x/vuln v1.6.0)\n'
go run golang.org/x/vuln/cmd/govulncheck@v1.6.0 ./...
(
cd sando
go run golang.org/x/vuln/cmd/govulncheck@v1.6.0 ./...
)
printf '\n==> building supported Linux release binary\n'
for target in \
linux/amd64; do
target_os=${target%/*}
target_arch=${target#*/}
CGO_ENABLED=0 GOOS="$target_os" GOARCH="$target_arch" \
go build -trimpath -ldflags "$compiler_linker_flags" \
-o "$artifact_dir/himesan-$target_os-$target_arch" ./cmd/himesan
done
for required in \
scripts/verify-public-install.sh \
RELEASE.md \
SECURITY.md \
TRADEMARKS.md \
CLA.md; do
[[ -f "$required" ]] || { printf 'error: required release file is missing: %s\n' "$required" >&2; exit 1; }
done
if (( public_release == 1 )); then
evidence_dir=${HIMESAN_RELEASE_EVIDENCE_DIR:-}
if [[ -z "$evidence_dir" || ! -d "$evidence_dir" ]]; then
printf 'error: --public requires HIMESAN_RELEASE_EVIDENCE_DIR\n' >&2
exit 1
fi
for evidence in \
legal-review.md \
linux-platform.md \
security.md \
development-supervisor.md \
benchmark-methodology.md \
vanity-imports.md \
signing-and-recovery.md; do
if [[ ! -s "$evidence_dir/$evidence" ]]; then
printf 'error: public release evidence is missing or empty: %s\n' "$evidence_dir/$evidence" >&2
exit 1
fi
done
fi
if [[ -n "$(git status --porcelain=v1 --untracked-files=all)" ]]; then
printf 'error: release preflight left tracked changes or untracked artifacts in the canonical checkout\n' >&2
git status --short >&2
exit 1
fi
if (( public_release == 1 )); then
printf '\nHuman review is still required; evidence presence is not automatic approval.\n'
else
printf '\nBeta technical publication preflight passed. This does not establish RC/final launch evidence or production stability.\n'
fi
if (( compiler_only == 1 )); then
printf 'No tag, push, publication, or deployment was performed for %s; runtime remains %s.\n' "$version" "$runtime_tag"
else
printf 'No tag, push, publication, or deployment was performed for %s / %s.\n' "$version" "$runtime_tag"
fi