mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-26 02:11:53 +00:00
365 lines
10 KiB
Bash
Executable File
365 lines
10 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
set -e
|
|
|
|
REPO="Start9Labs/start-os"
|
|
REGISTRY="https://alpha-registry-x.start9.com"
|
|
S3_BUCKET="s3://startos-images"
|
|
S3_CDN="https://startos-images.nyc3.cdn.digitaloceanspaces.com"
|
|
START9_GPG_KEY="2D63C217"
|
|
|
|
ARCHES="aarch64 aarch64-nonfree aarch64-nvidia riscv64 riscv64-nonfree x86_64 x86_64-nonfree x86_64-nvidia"
|
|
CLI_ARCHES="aarch64 riscv64 x86_64"
|
|
|
|
parse_run_id() {
|
|
local val="$1"
|
|
if [[ "$val" =~ /actions/runs/([0-9]+) ]]; then
|
|
echo "${BASH_REMATCH[1]}"
|
|
else
|
|
echo "$val"
|
|
fi
|
|
}
|
|
|
|
require_version() {
|
|
if [ -z "${VERSION:-}" ]; then
|
|
read -rp "VERSION: " VERSION
|
|
if [ -z "$VERSION" ]; then
|
|
>&2 echo '$VERSION required'
|
|
exit 2
|
|
fi
|
|
fi
|
|
}
|
|
|
|
release_dir() {
|
|
echo "$HOME/Downloads/v$VERSION"
|
|
}
|
|
|
|
ensure_release_dir() {
|
|
local dir
|
|
dir=$(release_dir)
|
|
if [ "$CLEAN" = "1" ]; then
|
|
rm -rf "$dir"
|
|
fi
|
|
mkdir -p "$dir"
|
|
cd "$dir"
|
|
}
|
|
|
|
enter_release_dir() {
|
|
local dir
|
|
dir=$(release_dir)
|
|
if [ ! -d "$dir" ]; then
|
|
>&2 echo "Release directory $dir does not exist. Run 'download' or 'pull' first."
|
|
exit 1
|
|
fi
|
|
cd "$dir"
|
|
}
|
|
|
|
cli_target_for() {
|
|
local arch=$1 os=$2
|
|
local pair="${arch}-${os}"
|
|
if [ "$pair" = "riscv64-linux" ]; then
|
|
echo "riscv64gc-unknown-linux-musl"
|
|
elif [ "$pair" = "riscv64-macos" ]; then
|
|
return 1
|
|
elif [ "$os" = "linux" ]; then
|
|
echo "${arch}-unknown-linux-musl"
|
|
elif [ "$os" = "macos" ]; then
|
|
echo "${arch}-apple-darwin"
|
|
fi
|
|
}
|
|
|
|
release_files() {
|
|
for file in *.iso *.squashfs *.deb; do
|
|
[ -f "$file" ] && echo "$file"
|
|
done
|
|
for file in start-cli_*; do
|
|
[[ "$file" == *.asc ]] && continue
|
|
[ -f "$file" ] && echo "$file"
|
|
done
|
|
}
|
|
|
|
resolve_gh_user() {
|
|
GH_USER=${GH_USER:-$(gh api user -q .login 2>/dev/null || true)}
|
|
GH_GPG_KEY=$(git config user.signingkey 2>/dev/null || true)
|
|
}
|
|
|
|
# --- Subcommands ---
|
|
|
|
cmd_download() {
|
|
require_version
|
|
|
|
if [ -z "${RUN_ID:-}" ]; then
|
|
read -rp "RUN_ID (OS images, leave blank to skip): " RUN_ID
|
|
fi
|
|
RUN_ID=$(parse_run_id "${RUN_ID:-}")
|
|
|
|
if [ -z "${ST_RUN_ID:-}" ]; then
|
|
read -rp "ST_RUN_ID (start-tunnel, leave blank to skip): " ST_RUN_ID
|
|
fi
|
|
ST_RUN_ID=$(parse_run_id "${ST_RUN_ID:-}")
|
|
|
|
if [ -z "${CLI_RUN_ID:-}" ]; then
|
|
read -rp "CLI_RUN_ID (start-cli, leave blank to skip): " CLI_RUN_ID
|
|
fi
|
|
CLI_RUN_ID=$(parse_run_id "${CLI_RUN_ID:-}")
|
|
|
|
ensure_release_dir
|
|
|
|
if [ -n "$RUN_ID" ]; then
|
|
for arch in $ARCHES; do
|
|
while ! gh run download -R $REPO "$RUN_ID" -n "$arch.squashfs" -D "$(pwd)"; do sleep 1; done
|
|
done
|
|
for arch in $ARCHES; do
|
|
while ! gh run download -R $REPO "$RUN_ID" -n "$arch.iso" -D "$(pwd)"; do sleep 1; done
|
|
done
|
|
fi
|
|
|
|
if [ -n "$ST_RUN_ID" ]; then
|
|
for arch in $CLI_ARCHES; do
|
|
while ! gh run download -R $REPO "$ST_RUN_ID" -n "start-tunnel_$arch.deb" -D "$(pwd)"; do sleep 1; done
|
|
done
|
|
fi
|
|
|
|
if [ -n "$CLI_RUN_ID" ]; then
|
|
for arch in $CLI_ARCHES; do
|
|
for os in linux macos; do
|
|
local target
|
|
target=$(cli_target_for "$arch" "$os") || continue
|
|
while ! gh run download -R $REPO "$CLI_RUN_ID" -n "start-cli_$target" -D "$(pwd)"; do sleep 1; done
|
|
mv start-cli "start-cli_${arch}-${os}"
|
|
done
|
|
done
|
|
fi
|
|
}
|
|
|
|
cmd_pull() {
|
|
require_version
|
|
ensure_release_dir
|
|
|
|
echo "Downloading release assets from tag v$VERSION..."
|
|
|
|
# Download debs and CLI binaries from the GH release
|
|
for file in $(gh release view -R $REPO "v$VERSION" --json assets -q '.assets[].name' | grep -E '\.(deb)$|^start-cli_'); do
|
|
gh release download -R $REPO "v$VERSION" -p "$file" -D "$(pwd)" --clobber
|
|
done
|
|
|
|
# Download ISOs and squashfs from S3 CDN
|
|
for arch in $ARCHES; do
|
|
for ext in squashfs iso; do
|
|
# Get the actual filename from the GH release asset list or body
|
|
local filename
|
|
filename=$(gh release view -R $REPO "v$VERSION" --json assets -q ".assets[].name" | grep "_${arch}\\.${ext}$" || true)
|
|
if [ -z "$filename" ]; then
|
|
filename=$(gh release view -R $REPO "v$VERSION" --json body -q .body | grep -oP "[^ ]*_${arch}\\.${ext}" | head -1 || true)
|
|
fi
|
|
if [ -n "$filename" ]; then
|
|
echo "Downloading $filename from S3..."
|
|
curl -fSL -o "$filename" "$S3_CDN/v$VERSION/$filename"
|
|
fi
|
|
done
|
|
done
|
|
}
|
|
|
|
cmd_register() {
|
|
require_version
|
|
enter_release_dir
|
|
start-cli --registry=$REGISTRY registry os version add "$VERSION" "v$VERSION" '' ">=0.3.5 <=$VERSION"
|
|
}
|
|
|
|
cmd_upload() {
|
|
require_version
|
|
enter_release_dir
|
|
|
|
for file in $(release_files); do
|
|
case "$file" in
|
|
*.iso|*.squashfs)
|
|
s3cmd put -P "$file" "$S3_BUCKET/v$VERSION/$file"
|
|
;;
|
|
*)
|
|
gh release upload -R $REPO "v$VERSION" "$file"
|
|
;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
cmd_index() {
|
|
require_version
|
|
enter_release_dir
|
|
|
|
for arch in $ARCHES; do
|
|
for file in *_"$arch".squashfs *_"$arch".iso; do
|
|
start-cli --registry=$REGISTRY registry os asset add --platform="$arch" --version="$VERSION" "$file" "$S3_CDN/v$VERSION/$file"
|
|
done
|
|
done
|
|
}
|
|
|
|
cmd_sign() {
|
|
require_version
|
|
enter_release_dir
|
|
resolve_gh_user
|
|
|
|
for file in $(release_files); do
|
|
gpg -u $START9_GPG_KEY --detach-sign --armor -o "${file}.start9.asc" "$file"
|
|
if [ -n "$GH_USER" ] && [ -n "$GH_GPG_KEY" ]; then
|
|
gpg -u "$GH_GPG_KEY" --detach-sign --armor -o "${file}.${GH_USER}.asc" "$file"
|
|
fi
|
|
done
|
|
|
|
gpg --export -a $START9_GPG_KEY > start9.key.asc
|
|
if [ -n "$GH_USER" ] && [ -n "$GH_GPG_KEY" ]; then
|
|
gpg --export -a "$GH_GPG_KEY" > "${GH_USER}.key.asc"
|
|
else
|
|
>&2 echo 'Warning: could not determine GitHub user or GPG signing key, skipping personal signature'
|
|
fi
|
|
tar -czvf signatures.tar.gz *.asc
|
|
|
|
gh release upload -R $REPO "v$VERSION" signatures.tar.gz --clobber
|
|
}
|
|
|
|
cmd_cosign() {
|
|
require_version
|
|
enter_release_dir
|
|
resolve_gh_user
|
|
|
|
if [ -z "$GH_USER" ] || [ -z "$GH_GPG_KEY" ]; then
|
|
>&2 echo 'Error: could not determine GitHub user or GPG signing key'
|
|
>&2 echo "Set GH_USER and/or configure git user.signingkey"
|
|
exit 1
|
|
fi
|
|
|
|
echo "Downloading existing signatures..."
|
|
gh release download -R $REPO "v$VERSION" -p "signatures.tar.gz" -D "$(pwd)" --clobber
|
|
tar -xzf signatures.tar.gz
|
|
|
|
echo "Adding personal signatures as $GH_USER..."
|
|
for file in $(release_files); do
|
|
gpg -u "$GH_GPG_KEY" --detach-sign --armor -o "${file}.${GH_USER}.asc" "$file"
|
|
done
|
|
|
|
gpg --export -a "$GH_GPG_KEY" > "${GH_USER}.key.asc"
|
|
|
|
echo "Re-packing signatures..."
|
|
tar -czvf signatures.tar.gz *.asc
|
|
|
|
gh release upload -R $REPO "v$VERSION" signatures.tar.gz --clobber
|
|
echo "Done. Personal signatures for $GH_USER added to v$VERSION."
|
|
}
|
|
|
|
cmd_notes() {
|
|
require_version
|
|
enter_release_dir
|
|
|
|
cat << EOF
|
|
# ISO Downloads
|
|
|
|
- [x86_64/AMD64]($S3_CDN/v$VERSION/$(ls *_x86_64-nonfree.iso))
|
|
- [x86_64/AMD64 + NVIDIA]($S3_CDN/v$VERSION/$(ls *_x86_64-nvidia.iso))
|
|
- [x86_64/AMD64-slim (FOSS-only)]($S3_CDN/v$VERSION/$(ls *_x86_64.iso) "Without proprietary software or drivers")
|
|
- [aarch64/ARM64]($S3_CDN/v$VERSION/$(ls *_aarch64-nonfree.iso))
|
|
- [aarch64/ARM64 + NVIDIA]($S3_CDN/v$VERSION/$(ls *_aarch64-nvidia.iso))
|
|
- [aarch64/ARM64-slim (FOSS-Only)]($S3_CDN/v$VERSION/$(ls *_aarch64.iso) "Without proprietary software or drivers")
|
|
- [RISCV64 (RVA23)]($S3_CDN/v$VERSION/$(ls *_riscv64-nonfree.iso))
|
|
- [RISCV64 (RVA23)-slim (FOSS-only)]($S3_CDN/v$VERSION/$(ls *_riscv64.iso) "Without proprietary software or drivers")
|
|
|
|
EOF
|
|
cat << 'EOF'
|
|
# StartOS Checksums
|
|
|
|
## SHA-256
|
|
```
|
|
EOF
|
|
sha256sum *.iso *.squashfs
|
|
cat << 'EOF'
|
|
```
|
|
|
|
## BLAKE-3
|
|
```
|
|
EOF
|
|
b3sum *.iso *.squashfs
|
|
cat << 'EOF'
|
|
```
|
|
|
|
# Start-Tunnel Checksums
|
|
|
|
## SHA-256
|
|
```
|
|
EOF
|
|
sha256sum start-tunnel*.deb
|
|
cat << 'EOF'
|
|
```
|
|
|
|
## BLAKE-3
|
|
```
|
|
EOF
|
|
b3sum start-tunnel*.deb
|
|
cat << 'EOF'
|
|
```
|
|
|
|
# start-cli Checksums
|
|
|
|
## SHA-256
|
|
```
|
|
EOF
|
|
release_files | grep '^start-cli_' | xargs sha256sum
|
|
cat << 'EOF'
|
|
```
|
|
|
|
## BLAKE-3
|
|
```
|
|
EOF
|
|
release_files | grep '^start-cli_' | xargs b3sum
|
|
cat << 'EOF'
|
|
```
|
|
EOF
|
|
}
|
|
|
|
cmd_full_release() {
|
|
cmd_download
|
|
cmd_register
|
|
cmd_upload
|
|
cmd_index
|
|
cmd_sign
|
|
cmd_notes
|
|
}
|
|
|
|
usage() {
|
|
cat << 'EOF'
|
|
Usage: manage-release.sh <subcommand>
|
|
|
|
Subcommands:
|
|
download Download artifacts from GitHub Actions runs
|
|
Requires: RUN_ID, ST_RUN_ID, CLI_RUN_ID (any combination)
|
|
pull Download an existing release from the GH tag and S3
|
|
register Register the version in the Start9 registry
|
|
upload Upload artifacts to GitHub Releases and S3
|
|
index Add assets to the registry index
|
|
sign Sign all artifacts with Start9 org key (+ personal key if available)
|
|
and upload signatures.tar.gz
|
|
cosign Add personal GPG signature to an existing release's signatures
|
|
(requires 'pull' first so you can verify assets before signing)
|
|
notes Print release notes with download links and checksums
|
|
full-release Run: download → register → upload → index → sign → notes
|
|
|
|
Environment variables:
|
|
VERSION (required) Release version
|
|
RUN_ID GitHub Actions run ID for OS images (download subcommand)
|
|
ST_RUN_ID GitHub Actions run ID for start-tunnel (download subcommand)
|
|
CLI_RUN_ID GitHub Actions run ID for start-cli (download subcommand)
|
|
GH_USER Override GitHub username (default: autodetected via gh cli)
|
|
CLEAN Set to 1 to wipe and recreate the release directory
|
|
EOF
|
|
}
|
|
|
|
case "${1:-}" in
|
|
download) cmd_download ;;
|
|
pull) cmd_pull ;;
|
|
register) cmd_register ;;
|
|
upload) cmd_upload ;;
|
|
index) cmd_index ;;
|
|
sign) cmd_sign ;;
|
|
cosign) cmd_cosign ;;
|
|
notes) cmd_notes ;;
|
|
full-release) cmd_full_release ;;
|
|
*) usage; exit 1 ;;
|
|
esac
|