mirror of
https://github.com/buckit-io/buckit.git
synced 2026-09-11 21:39:03 +00:00
deploy: e3737b39dd
This commit is contained in:
+43
@@ -0,0 +1,43 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Buckit Pages</title>
|
||||
<style>
|
||||
:root { color-scheme: light; --bg: #f3f5f9; --surface: #ffffff; --border: #d8dee9; --text: #0f172a; --muted: #475569; --link: #0f766e; --shadow: 0 18px 40px rgba(15, 23, 42, 0.08); }
|
||||
* { box-sizing: border-box; }
|
||||
body { margin: 0; font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; background: var(--bg); color: var(--text); }
|
||||
.page { max-width: 920px; margin: 0 auto; padding: 40px 20px 64px; }
|
||||
.hero, .panel { background: var(--surface); border: 1px solid var(--border); border-radius: 14px; box-shadow: var(--shadow); }
|
||||
.hero { padding: 28px; margin-bottom: 24px; }
|
||||
.eyebrow { display: inline-block; padding: 6px 10px; border-radius: 999px; background: #dcfce7; color: #166534; font-size: 12px; font-weight: 700; text-transform: uppercase; }
|
||||
h1 { margin: 14px 0 10px; font-size: 34px; line-height: 1.1; }
|
||||
p { margin: 0; color: var(--muted); line-height: 1.6; }
|
||||
.panel { padding: 24px; }
|
||||
.link-list { display: grid; gap: 14px; }
|
||||
.link-card { display: block; padding: 16px 18px; border: 1px solid var(--border); border-radius: 12px; background: #f8fafc; color: var(--text); text-decoration: none; }
|
||||
.link-card strong { display: block; margin-bottom: 6px; }
|
||||
.link-card span { color: var(--muted); }
|
||||
a { color: var(--link); text-decoration: none; }
|
||||
a:hover { text-decoration: underline; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="page">
|
||||
<section class="hero">
|
||||
<span class="eyebrow">Static Pages</span>
|
||||
<h1>Buckit Pages</h1>
|
||||
<p>Static indexes published through GitHub Pages for Buckit server release navigation and self-update discovery.</p>
|
||||
</section>
|
||||
<section class="panel">
|
||||
<div class="link-list">
|
||||
<a class="link-card" href="./server/">
|
||||
<strong>Server release assets</strong>
|
||||
<span>Open the Buckit server release and archive indexes.</span>
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Executable
+237
@@ -0,0 +1,237 @@
|
||||
#!/bin/sh
|
||||
# install-binary.sh — standalone-binary installer helper for buckit.
|
||||
#
|
||||
# Downloads the buckit binary for this host (Linux or macOS) for the latest
|
||||
# stable release to a predictable filename (buckit), verifies its published
|
||||
# SHA-256 checksum, and leaves it in place so you can run it directly. It does
|
||||
# NOT install it onto your PATH, and it does NOT register a service.
|
||||
#
|
||||
# On Linux, for a package-managed install with a systemd service, use
|
||||
# install-linux.sh instead, which downloads the .deb/.rpm/.apk for this host.
|
||||
#
|
||||
# Also published as install-linux-binary.sh and install-mac.sh, the per-platform
|
||||
# names this script replaced. Those URLs serve this same script.
|
||||
#
|
||||
# Usage:
|
||||
# curl -fsSL https://buckit-io.github.io/buckit/install-binary.sh | sh
|
||||
# ./buckit --help # run it from where it was downloaded
|
||||
#
|
||||
# Environment overrides:
|
||||
# BUCKIT_PAGES_BASE gh-pages base URL
|
||||
# (default: https://buckit-io.github.io/buckit)
|
||||
# BUCKIT_RELEASE_BASE release download base
|
||||
# (default: https://github.com/buckit-io/buckit/releases/download)
|
||||
# BUCKIT_VERSION pin a release tag (e.g. RELEASE.2026-05-11T17-20-40Z)
|
||||
# instead of resolving the latest stable release
|
||||
# BUCKIT_DOWNLOAD_DIR directory to download the binary into
|
||||
# (default: the current directory)
|
||||
|
||||
set -eu
|
||||
|
||||
PAGES_BASE="${BUCKIT_PAGES_BASE:-https://buckit-io.github.io/buckit}"
|
||||
RELEASE_BASE="${BUCKIT_RELEASE_BASE:-https://github.com/buckit-io/buckit/releases/download}"
|
||||
|
||||
# Set by resolve_release.
|
||||
TAG=""
|
||||
POINTER_SHA=""
|
||||
|
||||
err() {
|
||||
echo "install-binary.sh: $*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
info() {
|
||||
echo "==> $*"
|
||||
}
|
||||
|
||||
# detect_platform sets OS and ARCH to the Go-style tuple naming the published
|
||||
# release assets, and validates the architecture against what is published for
|
||||
# that platform: Linux ships amd64 and arm64, macOS ships Apple Silicon only.
|
||||
detect_platform() {
|
||||
uname_s="$(uname -s)"
|
||||
case "$uname_s" in
|
||||
Linux) OS="linux" ;;
|
||||
Darwin) OS="darwin" ;;
|
||||
*) err "this installer is for Linux and macOS (detected '$uname_s'). On Windows use install-windows.ps1" ;;
|
||||
esac
|
||||
|
||||
uname_m="$(uname -m)"
|
||||
case "$OS:$uname_m" in
|
||||
linux:x86_64 | linux:amd64) ARCH="amd64" ;;
|
||||
linux:aarch64 | linux:arm64) ARCH="arm64" ;;
|
||||
darwin:arm64 | darwin:aarch64) ARCH="arm64" ;;
|
||||
darwin:x86_64 | darwin:amd64) err "unsupported architecture '$uname_m'. Only Apple Silicon (arm64) builds are published for macOS." ;;
|
||||
*) err "unsupported architecture '$uname_m' on $OS." ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# validate_tag rejects anything that is not a plain release identifier. Both
|
||||
# the pinned BUCKIT_VERSION and the pointer-resolved tag go through this, so a
|
||||
# value like '../../evil' cannot reach the download URL as path traversal.
|
||||
validate_tag() {
|
||||
case "$1" in
|
||||
RELEASE.?*) ;;
|
||||
*) err "unexpected release tag '$1' (expected RELEASE.*)" ;;
|
||||
esac
|
||||
# Only the characters real release tags use. Rejects '/', whitespace,
|
||||
# control characters, and URL delimiters such as '?' and '#'.
|
||||
case "$1" in
|
||||
*[!A-Za-z0-9._-]*) err "release tag '$1' contains unsupported characters" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# normalize_sha lowercases a hex digest and requires exactly 64 hex characters,
|
||||
# so a truncated or malformed checksum record can never be compared as if it
|
||||
# were a valid digest. Echoes the normalized digest.
|
||||
normalize_sha() {
|
||||
_sha="$(printf '%s' "$1" | tr 'ABCDEF' 'abcdef')"
|
||||
case "$_sha" in
|
||||
"" | *[!0-9a-f]*) err "malformed sha256 digest: '$1'" ;;
|
||||
esac
|
||||
[ "${#_sha}" -eq 64 ] || err "malformed sha256 digest: '$1'"
|
||||
printf '%s' "$_sha"
|
||||
}
|
||||
|
||||
# fetch URL -> stdout
|
||||
fetch() {
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
curl -fsSL "$1"
|
||||
elif command -v wget >/dev/null 2>&1; then
|
||||
wget -qO- "$1"
|
||||
else
|
||||
err "need curl or wget to download"
|
||||
fi
|
||||
}
|
||||
|
||||
# fetch_to URL FILE
|
||||
fetch_to() {
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
curl -fsSL "$1" -o "$2"
|
||||
elif command -v wget >/dev/null 2>&1; then
|
||||
wget -qO "$2" "$1"
|
||||
else
|
||||
err "need curl or wget to download"
|
||||
fi
|
||||
}
|
||||
|
||||
# sha256_of FILE -> normalized hex digest on stdout. The hash utility runs on
|
||||
# its own rather than inside a pipeline, so a failure surfaces instead of being
|
||||
# masked by the exit status of a downstream parser.
|
||||
sha256_of() {
|
||||
if command -v sha256sum >/dev/null 2>&1; then
|
||||
_hash_out="$(sha256sum "$1")" || err "sha256sum failed on $1"
|
||||
elif command -v shasum >/dev/null 2>&1; then
|
||||
_hash_out="$(shasum -a 256 "$1")" || err "shasum failed on $1"
|
||||
else
|
||||
err "need sha256sum or shasum to verify the download"
|
||||
fi
|
||||
normalize_sha "$(printf '%s\n' "$_hash_out" | awk 'NR==1{print $1}')"
|
||||
}
|
||||
|
||||
# resolve_release sets TAG, and POINTER_SHA when the release was resolved from
|
||||
# the gh-pages pointer. A pinned BUCKIT_VERSION leaves POINTER_SHA empty: the
|
||||
# pointer only ever describes the latest release, so it cannot vouch for an
|
||||
# arbitrary pinned version.
|
||||
resolve_release() {
|
||||
if [ -n "${BUCKIT_VERSION:-}" ]; then
|
||||
validate_tag "$BUCKIT_VERSION"
|
||||
TAG="$BUCKIT_VERSION"
|
||||
POINTER_SHA=""
|
||||
return
|
||||
fi
|
||||
|
||||
pointer_url="$PAGES_BASE/server/buckit/release/$OS-$ARCH/buckit.sha256sum"
|
||||
# Pointer format: "<sha256> buckit.<tag>"
|
||||
pointer="$(fetch "$pointer_url")" || err "could not fetch release pointer at $pointer_url"
|
||||
|
||||
name="$(printf '%s\n' "$pointer" | awk 'NR==1{print $2}')"
|
||||
case "$name" in
|
||||
buckit.*) ;;
|
||||
*) err "unexpected release pointer payload: $pointer" ;;
|
||||
esac
|
||||
|
||||
TAG="${name#buckit.}"
|
||||
validate_tag "$TAG"
|
||||
POINTER_SHA="$(normalize_sha "$(printf '%s\n' "$pointer" | awk 'NR==1{print $1}')")"
|
||||
}
|
||||
|
||||
main() {
|
||||
detect_platform
|
||||
info "platform: $OS-$ARCH"
|
||||
|
||||
resolve_release
|
||||
[ -n "$TAG" ] || err "could not resolve a release tag"
|
||||
info "release: $TAG"
|
||||
|
||||
asset="buckit-$OS-$ARCH.$TAG"
|
||||
download_url="$RELEASE_BASE/$TAG/$asset"
|
||||
|
||||
dldir="${BUCKIT_DOWNLOAD_DIR:-.}"
|
||||
mkdir -p "$dldir"
|
||||
binfile="$dldir/buckit"
|
||||
|
||||
# Refuse to run when the destination is a directory. 'mv' would move the
|
||||
# temp file inside it and the script would report success while leaving
|
||||
# nothing runnable at the path it prints.
|
||||
[ ! -d "$binfile" ] || err "$binfile is a directory — remove it or set BUCKIT_DOWNLOAD_DIR"
|
||||
|
||||
# Download to a temporary sibling and only move it into the predictable
|
||||
# path after the checksum verifies, so a failed or interrupted download
|
||||
# can never clobber an existing good binary or leave a partial/unverified
|
||||
# file at the path the printed command references.
|
||||
tmpfile="$(mktemp "$dldir/.buckit.XXXXXX")" || err "could not create temp file in $dldir"
|
||||
trap 'rm -f "$tmpfile"' EXIT
|
||||
|
||||
info "downloading $asset"
|
||||
fetch_to "$download_url" "$tmpfile" || err "download failed: $download_url"
|
||||
|
||||
info "fetching published checksum"
|
||||
# Capture the payload first: piping the fetch straight into a parser would
|
||||
# hide a failed transfer behind the parser's exit status.
|
||||
checksum_payload="$(fetch "$download_url.sha256sum")" ||
|
||||
err "could not fetch checksum at $download_url.sha256sum"
|
||||
release_sha="$(normalize_sha "$(printf '%s\n' "$checksum_payload" | awk 'NR==1{print $1}')")"
|
||||
|
||||
# The binary and the checksum beside it come from the same origin, so that
|
||||
# digest alone only proves the download was not corrupted in transit. The
|
||||
# gh-pages pointer publishes the same digest from a separate origin;
|
||||
# when it is available, require the two to agree before trusting either.
|
||||
if [ -n "$POINTER_SHA" ]; then
|
||||
if [ "$POINTER_SHA" != "$release_sha" ]; then
|
||||
err "published digests disagree (pages $POINTER_SHA, release $release_sha) — refusing to continue"
|
||||
fi
|
||||
want_sha="$POINTER_SHA"
|
||||
info "sha256 cross-checked against the release pointer"
|
||||
else
|
||||
want_sha="$release_sha"
|
||||
fi
|
||||
|
||||
got_sha="$(sha256_of "$tmpfile")"
|
||||
if [ "$got_sha" != "$want_sha" ]; then
|
||||
err "checksum mismatch (expected $want_sha, got $got_sha) — refusing to continue"
|
||||
fi
|
||||
info "sha256 verified"
|
||||
|
||||
chmod 0755 "$tmpfile"
|
||||
|
||||
# Clear the quarantine attribute so Gatekeeper doesn't block the unsigned
|
||||
# binary on first run. macOS only; harmless to skip elsewhere.
|
||||
if [ "$OS" = "darwin" ] && command -v xattr >/dev/null 2>&1; then
|
||||
xattr -d com.apple.quarantine "$tmpfile" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
mv -f "$tmpfile" "$binfile"
|
||||
trap - EXIT
|
||||
|
||||
echo
|
||||
echo "Downloaded and verified:"
|
||||
echo " $binfile"
|
||||
echo
|
||||
echo "Run it from here:"
|
||||
echo " \"$binfile\""
|
||||
echo
|
||||
echo "(Move it onto your PATH to call 'buckit' from anywhere.)"
|
||||
echo
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Executable
+237
@@ -0,0 +1,237 @@
|
||||
#!/bin/sh
|
||||
# install-binary.sh — standalone-binary installer helper for buckit.
|
||||
#
|
||||
# Downloads the buckit binary for this host (Linux or macOS) for the latest
|
||||
# stable release to a predictable filename (buckit), verifies its published
|
||||
# SHA-256 checksum, and leaves it in place so you can run it directly. It does
|
||||
# NOT install it onto your PATH, and it does NOT register a service.
|
||||
#
|
||||
# On Linux, for a package-managed install with a systemd service, use
|
||||
# install-linux.sh instead, which downloads the .deb/.rpm/.apk for this host.
|
||||
#
|
||||
# Also published as install-linux-binary.sh and install-mac.sh, the per-platform
|
||||
# names this script replaced. Those URLs serve this same script.
|
||||
#
|
||||
# Usage:
|
||||
# curl -fsSL https://buckit-io.github.io/buckit/install-binary.sh | sh
|
||||
# ./buckit --help # run it from where it was downloaded
|
||||
#
|
||||
# Environment overrides:
|
||||
# BUCKIT_PAGES_BASE gh-pages base URL
|
||||
# (default: https://buckit-io.github.io/buckit)
|
||||
# BUCKIT_RELEASE_BASE release download base
|
||||
# (default: https://github.com/buckit-io/buckit/releases/download)
|
||||
# BUCKIT_VERSION pin a release tag (e.g. RELEASE.2026-05-11T17-20-40Z)
|
||||
# instead of resolving the latest stable release
|
||||
# BUCKIT_DOWNLOAD_DIR directory to download the binary into
|
||||
# (default: the current directory)
|
||||
|
||||
set -eu
|
||||
|
||||
PAGES_BASE="${BUCKIT_PAGES_BASE:-https://buckit-io.github.io/buckit}"
|
||||
RELEASE_BASE="${BUCKIT_RELEASE_BASE:-https://github.com/buckit-io/buckit/releases/download}"
|
||||
|
||||
# Set by resolve_release.
|
||||
TAG=""
|
||||
POINTER_SHA=""
|
||||
|
||||
err() {
|
||||
echo "install-binary.sh: $*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
info() {
|
||||
echo "==> $*"
|
||||
}
|
||||
|
||||
# detect_platform sets OS and ARCH to the Go-style tuple naming the published
|
||||
# release assets, and validates the architecture against what is published for
|
||||
# that platform: Linux ships amd64 and arm64, macOS ships Apple Silicon only.
|
||||
detect_platform() {
|
||||
uname_s="$(uname -s)"
|
||||
case "$uname_s" in
|
||||
Linux) OS="linux" ;;
|
||||
Darwin) OS="darwin" ;;
|
||||
*) err "this installer is for Linux and macOS (detected '$uname_s'). On Windows use install-windows.ps1" ;;
|
||||
esac
|
||||
|
||||
uname_m="$(uname -m)"
|
||||
case "$OS:$uname_m" in
|
||||
linux:x86_64 | linux:amd64) ARCH="amd64" ;;
|
||||
linux:aarch64 | linux:arm64) ARCH="arm64" ;;
|
||||
darwin:arm64 | darwin:aarch64) ARCH="arm64" ;;
|
||||
darwin:x86_64 | darwin:amd64) err "unsupported architecture '$uname_m'. Only Apple Silicon (arm64) builds are published for macOS." ;;
|
||||
*) err "unsupported architecture '$uname_m' on $OS." ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# validate_tag rejects anything that is not a plain release identifier. Both
|
||||
# the pinned BUCKIT_VERSION and the pointer-resolved tag go through this, so a
|
||||
# value like '../../evil' cannot reach the download URL as path traversal.
|
||||
validate_tag() {
|
||||
case "$1" in
|
||||
RELEASE.?*) ;;
|
||||
*) err "unexpected release tag '$1' (expected RELEASE.*)" ;;
|
||||
esac
|
||||
# Only the characters real release tags use. Rejects '/', whitespace,
|
||||
# control characters, and URL delimiters such as '?' and '#'.
|
||||
case "$1" in
|
||||
*[!A-Za-z0-9._-]*) err "release tag '$1' contains unsupported characters" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# normalize_sha lowercases a hex digest and requires exactly 64 hex characters,
|
||||
# so a truncated or malformed checksum record can never be compared as if it
|
||||
# were a valid digest. Echoes the normalized digest.
|
||||
normalize_sha() {
|
||||
_sha="$(printf '%s' "$1" | tr 'ABCDEF' 'abcdef')"
|
||||
case "$_sha" in
|
||||
"" | *[!0-9a-f]*) err "malformed sha256 digest: '$1'" ;;
|
||||
esac
|
||||
[ "${#_sha}" -eq 64 ] || err "malformed sha256 digest: '$1'"
|
||||
printf '%s' "$_sha"
|
||||
}
|
||||
|
||||
# fetch URL -> stdout
|
||||
fetch() {
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
curl -fsSL "$1"
|
||||
elif command -v wget >/dev/null 2>&1; then
|
||||
wget -qO- "$1"
|
||||
else
|
||||
err "need curl or wget to download"
|
||||
fi
|
||||
}
|
||||
|
||||
# fetch_to URL FILE
|
||||
fetch_to() {
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
curl -fsSL "$1" -o "$2"
|
||||
elif command -v wget >/dev/null 2>&1; then
|
||||
wget -qO "$2" "$1"
|
||||
else
|
||||
err "need curl or wget to download"
|
||||
fi
|
||||
}
|
||||
|
||||
# sha256_of FILE -> normalized hex digest on stdout. The hash utility runs on
|
||||
# its own rather than inside a pipeline, so a failure surfaces instead of being
|
||||
# masked by the exit status of a downstream parser.
|
||||
sha256_of() {
|
||||
if command -v sha256sum >/dev/null 2>&1; then
|
||||
_hash_out="$(sha256sum "$1")" || err "sha256sum failed on $1"
|
||||
elif command -v shasum >/dev/null 2>&1; then
|
||||
_hash_out="$(shasum -a 256 "$1")" || err "shasum failed on $1"
|
||||
else
|
||||
err "need sha256sum or shasum to verify the download"
|
||||
fi
|
||||
normalize_sha "$(printf '%s\n' "$_hash_out" | awk 'NR==1{print $1}')"
|
||||
}
|
||||
|
||||
# resolve_release sets TAG, and POINTER_SHA when the release was resolved from
|
||||
# the gh-pages pointer. A pinned BUCKIT_VERSION leaves POINTER_SHA empty: the
|
||||
# pointer only ever describes the latest release, so it cannot vouch for an
|
||||
# arbitrary pinned version.
|
||||
resolve_release() {
|
||||
if [ -n "${BUCKIT_VERSION:-}" ]; then
|
||||
validate_tag "$BUCKIT_VERSION"
|
||||
TAG="$BUCKIT_VERSION"
|
||||
POINTER_SHA=""
|
||||
return
|
||||
fi
|
||||
|
||||
pointer_url="$PAGES_BASE/server/buckit/release/$OS-$ARCH/buckit.sha256sum"
|
||||
# Pointer format: "<sha256> buckit.<tag>"
|
||||
pointer="$(fetch "$pointer_url")" || err "could not fetch release pointer at $pointer_url"
|
||||
|
||||
name="$(printf '%s\n' "$pointer" | awk 'NR==1{print $2}')"
|
||||
case "$name" in
|
||||
buckit.*) ;;
|
||||
*) err "unexpected release pointer payload: $pointer" ;;
|
||||
esac
|
||||
|
||||
TAG="${name#buckit.}"
|
||||
validate_tag "$TAG"
|
||||
POINTER_SHA="$(normalize_sha "$(printf '%s\n' "$pointer" | awk 'NR==1{print $1}')")"
|
||||
}
|
||||
|
||||
main() {
|
||||
detect_platform
|
||||
info "platform: $OS-$ARCH"
|
||||
|
||||
resolve_release
|
||||
[ -n "$TAG" ] || err "could not resolve a release tag"
|
||||
info "release: $TAG"
|
||||
|
||||
asset="buckit-$OS-$ARCH.$TAG"
|
||||
download_url="$RELEASE_BASE/$TAG/$asset"
|
||||
|
||||
dldir="${BUCKIT_DOWNLOAD_DIR:-.}"
|
||||
mkdir -p "$dldir"
|
||||
binfile="$dldir/buckit"
|
||||
|
||||
# Refuse to run when the destination is a directory. 'mv' would move the
|
||||
# temp file inside it and the script would report success while leaving
|
||||
# nothing runnable at the path it prints.
|
||||
[ ! -d "$binfile" ] || err "$binfile is a directory — remove it or set BUCKIT_DOWNLOAD_DIR"
|
||||
|
||||
# Download to a temporary sibling and only move it into the predictable
|
||||
# path after the checksum verifies, so a failed or interrupted download
|
||||
# can never clobber an existing good binary or leave a partial/unverified
|
||||
# file at the path the printed command references.
|
||||
tmpfile="$(mktemp "$dldir/.buckit.XXXXXX")" || err "could not create temp file in $dldir"
|
||||
trap 'rm -f "$tmpfile"' EXIT
|
||||
|
||||
info "downloading $asset"
|
||||
fetch_to "$download_url" "$tmpfile" || err "download failed: $download_url"
|
||||
|
||||
info "fetching published checksum"
|
||||
# Capture the payload first: piping the fetch straight into a parser would
|
||||
# hide a failed transfer behind the parser's exit status.
|
||||
checksum_payload="$(fetch "$download_url.sha256sum")" ||
|
||||
err "could not fetch checksum at $download_url.sha256sum"
|
||||
release_sha="$(normalize_sha "$(printf '%s\n' "$checksum_payload" | awk 'NR==1{print $1}')")"
|
||||
|
||||
# The binary and the checksum beside it come from the same origin, so that
|
||||
# digest alone only proves the download was not corrupted in transit. The
|
||||
# gh-pages pointer publishes the same digest from a separate origin;
|
||||
# when it is available, require the two to agree before trusting either.
|
||||
if [ -n "$POINTER_SHA" ]; then
|
||||
if [ "$POINTER_SHA" != "$release_sha" ]; then
|
||||
err "published digests disagree (pages $POINTER_SHA, release $release_sha) — refusing to continue"
|
||||
fi
|
||||
want_sha="$POINTER_SHA"
|
||||
info "sha256 cross-checked against the release pointer"
|
||||
else
|
||||
want_sha="$release_sha"
|
||||
fi
|
||||
|
||||
got_sha="$(sha256_of "$tmpfile")"
|
||||
if [ "$got_sha" != "$want_sha" ]; then
|
||||
err "checksum mismatch (expected $want_sha, got $got_sha) — refusing to continue"
|
||||
fi
|
||||
info "sha256 verified"
|
||||
|
||||
chmod 0755 "$tmpfile"
|
||||
|
||||
# Clear the quarantine attribute so Gatekeeper doesn't block the unsigned
|
||||
# binary on first run. macOS only; harmless to skip elsewhere.
|
||||
if [ "$OS" = "darwin" ] && command -v xattr >/dev/null 2>&1; then
|
||||
xattr -d com.apple.quarantine "$tmpfile" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
mv -f "$tmpfile" "$binfile"
|
||||
trap - EXIT
|
||||
|
||||
echo
|
||||
echo "Downloaded and verified:"
|
||||
echo " $binfile"
|
||||
echo
|
||||
echo "Run it from here:"
|
||||
echo " \"$binfile\""
|
||||
echo
|
||||
echo "(Move it onto your PATH to call 'buckit' from anywhere.)"
|
||||
echo
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Executable
+236
@@ -0,0 +1,236 @@
|
||||
#!/bin/sh
|
||||
# install-linux.sh — Linux native-package installer helper for buckit.
|
||||
#
|
||||
# Detects this host's package manager (dnf/yum/zypper, apt/apt-get/dpkg, or
|
||||
# apk), downloads the matching .rpm/.deb/.apk for the latest stable release to
|
||||
# a predictable filename (buckit.rpm / buckit.deb / buckit.apk), verifies its
|
||||
# published SHA-256 checksum, and prints the command to install it. It does
|
||||
# NOT run the package manager for you — the final install (which needs root)
|
||||
# is left to you to review and run.
|
||||
#
|
||||
# Usage:
|
||||
# curl -fsSL https://buckit-io.github.io/buckit/install-linux.sh | sh
|
||||
# sudo dnf install ./buckit.rpm # or apt/apk, per the printed command
|
||||
#
|
||||
# Environment overrides:
|
||||
# BUCKIT_PAGES_BASE gh-pages base URL
|
||||
# (default: https://buckit-io.github.io/buckit)
|
||||
# BUCKIT_RELEASE_BASE release download base
|
||||
# (default: https://github.com/buckit-io/buckit/releases/download)
|
||||
# BUCKIT_VERSION pin a release tag (e.g. RELEASE.2026-05-11T17-20-40Z)
|
||||
# instead of resolving the latest stable release
|
||||
# BUCKIT_DOWNLOAD_DIR directory to download the package into
|
||||
# (default: the current directory)
|
||||
|
||||
set -eu
|
||||
|
||||
PAGES_BASE="${BUCKIT_PAGES_BASE:-https://buckit-io.github.io/buckit}"
|
||||
RELEASE_BASE="${BUCKIT_RELEASE_BASE:-https://github.com/buckit-io/buckit/releases/download}"
|
||||
|
||||
err() {
|
||||
echo "install-linux.sh: $*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
info() {
|
||||
echo "==> $*"
|
||||
}
|
||||
|
||||
# detect_sudo sets SUDO to the privilege-escalation prefix for install
|
||||
# commands: empty when already root, "sudo " when sudo is available, otherwise
|
||||
# empty with a warning (the printed command must then be run as root).
|
||||
detect_sudo() {
|
||||
if [ "$(id -u)" -eq 0 ]; then
|
||||
SUDO=""
|
||||
elif command -v sudo >/dev/null 2>&1; then
|
||||
SUDO="sudo "
|
||||
else
|
||||
SUDO=""
|
||||
info "not running as root and sudo not found — run the install command below as root"
|
||||
fi
|
||||
}
|
||||
|
||||
# detect_arch sets ARCH to the Go-style arch tuple (amd64 / arm64) and
|
||||
# requires a Linux host — native packages are Linux-only.
|
||||
detect_arch() {
|
||||
os="$(uname -s)"
|
||||
[ "$os" = "Linux" ] || err "this installer is for Linux (detected '$os'). For a standalone binary use install-binary.sh; on Windows use install-windows.ps1"
|
||||
|
||||
arch="$(uname -m)"
|
||||
case "$arch" in
|
||||
x86_64 | amd64) ARCH="amd64" ;;
|
||||
arm64 | aarch64) ARCH="arm64" ;;
|
||||
*) err "unsupported architecture '$arch'. Supported: amd64, arm64." ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# detect_pkg sets PKG (rpm|deb|apk) and INSTALL_CMD (the command prefix used
|
||||
# to install a local package file) based on the available package manager.
|
||||
# Requires SUDO to be set first (see detect_sudo).
|
||||
detect_pkg() {
|
||||
if command -v dnf >/dev/null 2>&1; then
|
||||
PKG="rpm"
|
||||
INSTALL_CMD="${SUDO}dnf install"
|
||||
elif command -v yum >/dev/null 2>&1; then
|
||||
PKG="rpm"
|
||||
INSTALL_CMD="${SUDO}yum install"
|
||||
elif command -v zypper >/dev/null 2>&1; then
|
||||
PKG="rpm"
|
||||
INSTALL_CMD="${SUDO}zypper install"
|
||||
elif command -v apt >/dev/null 2>&1; then
|
||||
PKG="deb"
|
||||
INSTALL_CMD="${SUDO}apt install"
|
||||
elif command -v apt-get >/dev/null 2>&1; then
|
||||
PKG="deb"
|
||||
INSTALL_CMD="${SUDO}apt-get install"
|
||||
elif command -v apk >/dev/null 2>&1; then
|
||||
PKG="apk"
|
||||
INSTALL_CMD="${SUDO}apk add --allow-untrusted"
|
||||
elif command -v rpm >/dev/null 2>&1; then
|
||||
PKG="rpm"
|
||||
INSTALL_CMD="${SUDO}rpm -i"
|
||||
elif command -v dpkg >/dev/null 2>&1; then
|
||||
PKG="deb"
|
||||
INSTALL_CMD="${SUDO}dpkg -i"
|
||||
else
|
||||
err "no supported package manager found (need dnf/yum/zypper, apt/dpkg, or apk)"
|
||||
fi
|
||||
}
|
||||
|
||||
# fetch URL -> stdout
|
||||
fetch() {
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
curl -fsSL "$1"
|
||||
elif command -v wget >/dev/null 2>&1; then
|
||||
wget -qO- "$1"
|
||||
else
|
||||
err "need curl or wget to download"
|
||||
fi
|
||||
}
|
||||
|
||||
# fetch_to URL FILE
|
||||
fetch_to() {
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
curl -fsSL "$1" -o "$2"
|
||||
elif command -v wget >/dev/null 2>&1; then
|
||||
wget -qO "$2" "$1"
|
||||
else
|
||||
err "need curl or wget to download"
|
||||
fi
|
||||
}
|
||||
|
||||
# sha256_of FILE -> hex digest on stdout
|
||||
sha256_of() {
|
||||
if command -v sha256sum >/dev/null 2>&1; then
|
||||
sha256sum "$1" | awk '{print $1}'
|
||||
elif command -v shasum >/dev/null 2>&1; then
|
||||
shasum -a 256 "$1" | awk '{print $1}'
|
||||
else
|
||||
err "need sha256sum or shasum to verify the download"
|
||||
fi
|
||||
}
|
||||
|
||||
# resolve_tag echoes the release tag to install, either the pinned
|
||||
# BUCKIT_VERSION or the latest stable tag from the gh-pages pointer.
|
||||
resolve_tag() {
|
||||
if [ -n "${BUCKIT_VERSION:-}" ]; then
|
||||
echo "$BUCKIT_VERSION"
|
||||
return
|
||||
fi
|
||||
|
||||
pointer_url="$PAGES_BASE/server/buckit/release/linux-$ARCH/buckit.sha256sum"
|
||||
# Pointer format: "<sha256> buckit.<tag>"
|
||||
pointer="$(fetch "$pointer_url")" || err "could not fetch release pointer at $pointer_url"
|
||||
name="$(echo "$pointer" | awk '{print $2}')"
|
||||
tag="${name#buckit.}"
|
||||
case "$tag" in
|
||||
RELEASE.*) ;;
|
||||
*) err "unexpected release pointer payload: $pointer" ;;
|
||||
esac
|
||||
echo "$tag"
|
||||
}
|
||||
|
||||
# pkg_version TAG -> nfpm package version, mirroring the release workflow:
|
||||
# RELEASE.2026-05-11T17-20-40Z[.rcN] -> 20260511172040.0.0
|
||||
pkg_version() {
|
||||
echo "$1" | sed 's/^RELEASE\.//' | sed 's/\.rc[0-9]*$//' | tr -d '\-:TZ' | sed 's/$/.0.0/'
|
||||
}
|
||||
|
||||
main() {
|
||||
detect_arch
|
||||
detect_sudo
|
||||
detect_pkg
|
||||
info "platform: linux-$ARCH ($PKG)"
|
||||
|
||||
tag="$(resolve_tag)"
|
||||
[ -n "$tag" ] || err "could not resolve a release tag"
|
||||
info "release: $tag"
|
||||
|
||||
pkgver="$(pkg_version "$tag")"
|
||||
|
||||
# Build the package filename. nfpm maps amd64->x86_64 / arm64->aarch64
|
||||
# for rpm and apk; deb keeps the Debian arch names.
|
||||
case "$PKG" in
|
||||
rpm)
|
||||
case "$ARCH" in
|
||||
amd64) pkgarch="x86_64" ;;
|
||||
arm64) pkgarch="aarch64" ;;
|
||||
esac
|
||||
asset="buckit-${pkgver}.${pkgarch}.rpm"
|
||||
;;
|
||||
deb)
|
||||
asset="buckit_${pkgver}_${ARCH}.deb"
|
||||
;;
|
||||
apk)
|
||||
case "$ARCH" in
|
||||
amd64) pkgarch="x86_64" ;;
|
||||
arm64) pkgarch="aarch64" ;;
|
||||
esac
|
||||
asset="buckit_${pkgver}_${pkgarch}.apk"
|
||||
;;
|
||||
esac
|
||||
|
||||
download_url="$RELEASE_BASE/$tag/$asset"
|
||||
|
||||
# Save to a predictable filename (buckit.rpm / buckit.deb / buckit.apk) so
|
||||
# the install command is stable and copy-pasteable in docs. The "./" form
|
||||
# also matters for apt, which treats a path without a slash as a package
|
||||
# name rather than a local file.
|
||||
dldir="${BUCKIT_DOWNLOAD_DIR:-.}"
|
||||
mkdir -p "$dldir"
|
||||
pkgfile="$dldir/buckit.$PKG"
|
||||
|
||||
# Download to a temporary sibling and only move it into the predictable
|
||||
# path after the checksum verifies. A failed or interrupted download then
|
||||
# can never clobber an existing good package or leave a partial/unverified
|
||||
# file at the path the printed install command references.
|
||||
tmpfile="$(mktemp "$dldir/.buckit.$PKG.XXXXXX")" || err "could not create temp file in $dldir"
|
||||
trap 'rm -f "$tmpfile"' EXIT
|
||||
|
||||
info "downloading $asset"
|
||||
fetch_to "$download_url" "$tmpfile" || err "download failed: $download_url"
|
||||
|
||||
info "fetching published checksum"
|
||||
want_sha="$(fetch "$download_url.sha256sum" | awk '{print $1}')" ||
|
||||
err "could not fetch checksum at $download_url.sha256sum"
|
||||
[ -n "$want_sha" ] || err "release checksum is empty"
|
||||
|
||||
got_sha="$(sha256_of "$tmpfile")"
|
||||
if [ "$got_sha" != "$want_sha" ]; then
|
||||
err "checksum mismatch (expected $want_sha, got $got_sha) — refusing to continue"
|
||||
fi
|
||||
info "sha256 verified"
|
||||
|
||||
mv -f "$tmpfile" "$pkgfile"
|
||||
trap - EXIT
|
||||
|
||||
echo
|
||||
echo "Downloaded and verified:"
|
||||
echo " $pkgfile"
|
||||
echo
|
||||
echo "To install, run:"
|
||||
echo " $INSTALL_CMD \"$pkgfile\""
|
||||
echo
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Executable
+237
@@ -0,0 +1,237 @@
|
||||
#!/bin/sh
|
||||
# install-binary.sh — standalone-binary installer helper for buckit.
|
||||
#
|
||||
# Downloads the buckit binary for this host (Linux or macOS) for the latest
|
||||
# stable release to a predictable filename (buckit), verifies its published
|
||||
# SHA-256 checksum, and leaves it in place so you can run it directly. It does
|
||||
# NOT install it onto your PATH, and it does NOT register a service.
|
||||
#
|
||||
# On Linux, for a package-managed install with a systemd service, use
|
||||
# install-linux.sh instead, which downloads the .deb/.rpm/.apk for this host.
|
||||
#
|
||||
# Also published as install-linux-binary.sh and install-mac.sh, the per-platform
|
||||
# names this script replaced. Those URLs serve this same script.
|
||||
#
|
||||
# Usage:
|
||||
# curl -fsSL https://buckit-io.github.io/buckit/install-binary.sh | sh
|
||||
# ./buckit --help # run it from where it was downloaded
|
||||
#
|
||||
# Environment overrides:
|
||||
# BUCKIT_PAGES_BASE gh-pages base URL
|
||||
# (default: https://buckit-io.github.io/buckit)
|
||||
# BUCKIT_RELEASE_BASE release download base
|
||||
# (default: https://github.com/buckit-io/buckit/releases/download)
|
||||
# BUCKIT_VERSION pin a release tag (e.g. RELEASE.2026-05-11T17-20-40Z)
|
||||
# instead of resolving the latest stable release
|
||||
# BUCKIT_DOWNLOAD_DIR directory to download the binary into
|
||||
# (default: the current directory)
|
||||
|
||||
set -eu
|
||||
|
||||
PAGES_BASE="${BUCKIT_PAGES_BASE:-https://buckit-io.github.io/buckit}"
|
||||
RELEASE_BASE="${BUCKIT_RELEASE_BASE:-https://github.com/buckit-io/buckit/releases/download}"
|
||||
|
||||
# Set by resolve_release.
|
||||
TAG=""
|
||||
POINTER_SHA=""
|
||||
|
||||
err() {
|
||||
echo "install-binary.sh: $*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
info() {
|
||||
echo "==> $*"
|
||||
}
|
||||
|
||||
# detect_platform sets OS and ARCH to the Go-style tuple naming the published
|
||||
# release assets, and validates the architecture against what is published for
|
||||
# that platform: Linux ships amd64 and arm64, macOS ships Apple Silicon only.
|
||||
detect_platform() {
|
||||
uname_s="$(uname -s)"
|
||||
case "$uname_s" in
|
||||
Linux) OS="linux" ;;
|
||||
Darwin) OS="darwin" ;;
|
||||
*) err "this installer is for Linux and macOS (detected '$uname_s'). On Windows use install-windows.ps1" ;;
|
||||
esac
|
||||
|
||||
uname_m="$(uname -m)"
|
||||
case "$OS:$uname_m" in
|
||||
linux:x86_64 | linux:amd64) ARCH="amd64" ;;
|
||||
linux:aarch64 | linux:arm64) ARCH="arm64" ;;
|
||||
darwin:arm64 | darwin:aarch64) ARCH="arm64" ;;
|
||||
darwin:x86_64 | darwin:amd64) err "unsupported architecture '$uname_m'. Only Apple Silicon (arm64) builds are published for macOS." ;;
|
||||
*) err "unsupported architecture '$uname_m' on $OS." ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# validate_tag rejects anything that is not a plain release identifier. Both
|
||||
# the pinned BUCKIT_VERSION and the pointer-resolved tag go through this, so a
|
||||
# value like '../../evil' cannot reach the download URL as path traversal.
|
||||
validate_tag() {
|
||||
case "$1" in
|
||||
RELEASE.?*) ;;
|
||||
*) err "unexpected release tag '$1' (expected RELEASE.*)" ;;
|
||||
esac
|
||||
# Only the characters real release tags use. Rejects '/', whitespace,
|
||||
# control characters, and URL delimiters such as '?' and '#'.
|
||||
case "$1" in
|
||||
*[!A-Za-z0-9._-]*) err "release tag '$1' contains unsupported characters" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# normalize_sha lowercases a hex digest and requires exactly 64 hex characters,
|
||||
# so a truncated or malformed checksum record can never be compared as if it
|
||||
# were a valid digest. Echoes the normalized digest.
|
||||
normalize_sha() {
|
||||
_sha="$(printf '%s' "$1" | tr 'ABCDEF' 'abcdef')"
|
||||
case "$_sha" in
|
||||
"" | *[!0-9a-f]*) err "malformed sha256 digest: '$1'" ;;
|
||||
esac
|
||||
[ "${#_sha}" -eq 64 ] || err "malformed sha256 digest: '$1'"
|
||||
printf '%s' "$_sha"
|
||||
}
|
||||
|
||||
# fetch URL -> stdout
|
||||
fetch() {
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
curl -fsSL "$1"
|
||||
elif command -v wget >/dev/null 2>&1; then
|
||||
wget -qO- "$1"
|
||||
else
|
||||
err "need curl or wget to download"
|
||||
fi
|
||||
}
|
||||
|
||||
# fetch_to URL FILE
|
||||
fetch_to() {
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
curl -fsSL "$1" -o "$2"
|
||||
elif command -v wget >/dev/null 2>&1; then
|
||||
wget -qO "$2" "$1"
|
||||
else
|
||||
err "need curl or wget to download"
|
||||
fi
|
||||
}
|
||||
|
||||
# sha256_of FILE -> normalized hex digest on stdout. The hash utility runs on
|
||||
# its own rather than inside a pipeline, so a failure surfaces instead of being
|
||||
# masked by the exit status of a downstream parser.
|
||||
sha256_of() {
|
||||
if command -v sha256sum >/dev/null 2>&1; then
|
||||
_hash_out="$(sha256sum "$1")" || err "sha256sum failed on $1"
|
||||
elif command -v shasum >/dev/null 2>&1; then
|
||||
_hash_out="$(shasum -a 256 "$1")" || err "shasum failed on $1"
|
||||
else
|
||||
err "need sha256sum or shasum to verify the download"
|
||||
fi
|
||||
normalize_sha "$(printf '%s\n' "$_hash_out" | awk 'NR==1{print $1}')"
|
||||
}
|
||||
|
||||
# resolve_release sets TAG, and POINTER_SHA when the release was resolved from
|
||||
# the gh-pages pointer. A pinned BUCKIT_VERSION leaves POINTER_SHA empty: the
|
||||
# pointer only ever describes the latest release, so it cannot vouch for an
|
||||
# arbitrary pinned version.
|
||||
resolve_release() {
|
||||
if [ -n "${BUCKIT_VERSION:-}" ]; then
|
||||
validate_tag "$BUCKIT_VERSION"
|
||||
TAG="$BUCKIT_VERSION"
|
||||
POINTER_SHA=""
|
||||
return
|
||||
fi
|
||||
|
||||
pointer_url="$PAGES_BASE/server/buckit/release/$OS-$ARCH/buckit.sha256sum"
|
||||
# Pointer format: "<sha256> buckit.<tag>"
|
||||
pointer="$(fetch "$pointer_url")" || err "could not fetch release pointer at $pointer_url"
|
||||
|
||||
name="$(printf '%s\n' "$pointer" | awk 'NR==1{print $2}')"
|
||||
case "$name" in
|
||||
buckit.*) ;;
|
||||
*) err "unexpected release pointer payload: $pointer" ;;
|
||||
esac
|
||||
|
||||
TAG="${name#buckit.}"
|
||||
validate_tag "$TAG"
|
||||
POINTER_SHA="$(normalize_sha "$(printf '%s\n' "$pointer" | awk 'NR==1{print $1}')")"
|
||||
}
|
||||
|
||||
main() {
|
||||
detect_platform
|
||||
info "platform: $OS-$ARCH"
|
||||
|
||||
resolve_release
|
||||
[ -n "$TAG" ] || err "could not resolve a release tag"
|
||||
info "release: $TAG"
|
||||
|
||||
asset="buckit-$OS-$ARCH.$TAG"
|
||||
download_url="$RELEASE_BASE/$TAG/$asset"
|
||||
|
||||
dldir="${BUCKIT_DOWNLOAD_DIR:-.}"
|
||||
mkdir -p "$dldir"
|
||||
binfile="$dldir/buckit"
|
||||
|
||||
# Refuse to run when the destination is a directory. 'mv' would move the
|
||||
# temp file inside it and the script would report success while leaving
|
||||
# nothing runnable at the path it prints.
|
||||
[ ! -d "$binfile" ] || err "$binfile is a directory — remove it or set BUCKIT_DOWNLOAD_DIR"
|
||||
|
||||
# Download to a temporary sibling and only move it into the predictable
|
||||
# path after the checksum verifies, so a failed or interrupted download
|
||||
# can never clobber an existing good binary or leave a partial/unverified
|
||||
# file at the path the printed command references.
|
||||
tmpfile="$(mktemp "$dldir/.buckit.XXXXXX")" || err "could not create temp file in $dldir"
|
||||
trap 'rm -f "$tmpfile"' EXIT
|
||||
|
||||
info "downloading $asset"
|
||||
fetch_to "$download_url" "$tmpfile" || err "download failed: $download_url"
|
||||
|
||||
info "fetching published checksum"
|
||||
# Capture the payload first: piping the fetch straight into a parser would
|
||||
# hide a failed transfer behind the parser's exit status.
|
||||
checksum_payload="$(fetch "$download_url.sha256sum")" ||
|
||||
err "could not fetch checksum at $download_url.sha256sum"
|
||||
release_sha="$(normalize_sha "$(printf '%s\n' "$checksum_payload" | awk 'NR==1{print $1}')")"
|
||||
|
||||
# The binary and the checksum beside it come from the same origin, so that
|
||||
# digest alone only proves the download was not corrupted in transit. The
|
||||
# gh-pages pointer publishes the same digest from a separate origin;
|
||||
# when it is available, require the two to agree before trusting either.
|
||||
if [ -n "$POINTER_SHA" ]; then
|
||||
if [ "$POINTER_SHA" != "$release_sha" ]; then
|
||||
err "published digests disagree (pages $POINTER_SHA, release $release_sha) — refusing to continue"
|
||||
fi
|
||||
want_sha="$POINTER_SHA"
|
||||
info "sha256 cross-checked against the release pointer"
|
||||
else
|
||||
want_sha="$release_sha"
|
||||
fi
|
||||
|
||||
got_sha="$(sha256_of "$tmpfile")"
|
||||
if [ "$got_sha" != "$want_sha" ]; then
|
||||
err "checksum mismatch (expected $want_sha, got $got_sha) — refusing to continue"
|
||||
fi
|
||||
info "sha256 verified"
|
||||
|
||||
chmod 0755 "$tmpfile"
|
||||
|
||||
# Clear the quarantine attribute so Gatekeeper doesn't block the unsigned
|
||||
# binary on first run. macOS only; harmless to skip elsewhere.
|
||||
if [ "$OS" = "darwin" ] && command -v xattr >/dev/null 2>&1; then
|
||||
xattr -d com.apple.quarantine "$tmpfile" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
mv -f "$tmpfile" "$binfile"
|
||||
trap - EXIT
|
||||
|
||||
echo
|
||||
echo "Downloaded and verified:"
|
||||
echo " $binfile"
|
||||
echo
|
||||
echo "Run it from here:"
|
||||
echo " \"$binfile\""
|
||||
echo
|
||||
echo "(Move it onto your PATH to call 'buckit' from anywhere.)"
|
||||
echo
|
||||
}
|
||||
|
||||
main "$@"
|
||||
@@ -0,0 +1,150 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Windows installer helper for buckit.
|
||||
|
||||
.DESCRIPTION
|
||||
Downloads the Windows (x86_64) buckit executable for the latest stable
|
||||
release to a predictable filename (buckit.exe), verifies its published
|
||||
SHA-256 checksum, and prints how to put it on your PATH. It does NOT install
|
||||
it for you.
|
||||
|
||||
.EXAMPLE
|
||||
irm https://buckit-io.github.io/buckit/install-windows.ps1 | iex
|
||||
|
||||
.NOTES
|
||||
Environment overrides:
|
||||
BUCKIT_PAGES_BASE gh-pages base URL
|
||||
(default: https://buckit-io.github.io/buckit)
|
||||
BUCKIT_RELEASE_BASE release download base
|
||||
(default: https://github.com/buckit-io/buckit/releases/download)
|
||||
BUCKIT_VERSION pin a release tag (e.g. RELEASE.2026-05-11T17-20-40Z)
|
||||
instead of resolving the latest stable release
|
||||
BUCKIT_DOWNLOAD_DIR directory to download the executable into
|
||||
(default: the current directory)
|
||||
#>
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$ProgressPreference = 'SilentlyContinue'
|
||||
|
||||
function Get-EnvOrDefault($name, $default) {
|
||||
$value = [Environment]::GetEnvironmentVariable($name)
|
||||
if ([string]::IsNullOrEmpty($value)) { return $default }
|
||||
return $value
|
||||
}
|
||||
|
||||
$PagesBase = Get-EnvOrDefault 'BUCKIT_PAGES_BASE' 'https://buckit-io.github.io/buckit'
|
||||
$ReleaseBase = Get-EnvOrDefault 'BUCKIT_RELEASE_BASE' 'https://github.com/buckit-io/buckit/releases/download'
|
||||
|
||||
function Fetch-String($url) {
|
||||
return (Invoke-WebRequest -UseBasicParsing -Uri $url).Content
|
||||
}
|
||||
|
||||
# Require Windows. $IsWindows is an automatic variable on PowerShell Core 6+
|
||||
# (where this script may run cross-platform); it is undefined on Windows
|
||||
# PowerShell 5.1, which only runs on Windows — so treat undefined as Windows.
|
||||
if (($null -ne $IsWindows) -and (-not $IsWindows)) {
|
||||
throw "install-windows.ps1 is for Windows. On Linux or macOS use install-binary.sh"
|
||||
}
|
||||
|
||||
# Resolve the release tag: pinned BUCKIT_VERSION or the latest stable tag from
|
||||
# the gh-pages pointer (format: "<sha256> buckit.exe.<tag>").
|
||||
# Normalize-Sha lowercases a hex digest and requires exactly 64 hex characters,
|
||||
# so a truncated or malformed checksum record can never be compared as if it
|
||||
# were a valid digest.
|
||||
function Normalize-Sha($value) {
|
||||
$sha = "$value".Trim().ToLower()
|
||||
if ($sha -notmatch '^[0-9a-f]{64}$') {
|
||||
throw "install-windows.ps1: malformed sha256 digest: '$value'"
|
||||
}
|
||||
return $sha
|
||||
}
|
||||
|
||||
# Assert-Tag rejects anything that is not a plain release identifier, so a
|
||||
# value like '../../evil' cannot reach the download URL as path traversal.
|
||||
function Assert-Tag($value) {
|
||||
if ($value -notmatch '^RELEASE\.[A-Za-z0-9._-]+$') {
|
||||
throw "install-windows.ps1: unexpected release tag '$value'"
|
||||
}
|
||||
}
|
||||
|
||||
# A pinned BUCKIT_VERSION leaves $pointerSha empty: the pointer only ever
|
||||
# describes the latest release, so it cannot vouch for an arbitrary pin.
|
||||
$pointerSha = ''
|
||||
$tag = [Environment]::GetEnvironmentVariable('BUCKIT_VERSION')
|
||||
if ([string]::IsNullOrEmpty($tag)) {
|
||||
$pointerUrl = "$PagesBase/server/buckit/release/windows-amd64/buckit.sha256sum"
|
||||
try {
|
||||
$pointer = (Fetch-String $pointerUrl).Trim()
|
||||
} catch {
|
||||
throw "install-windows.ps1: could not fetch release pointer at $pointerUrl"
|
||||
}
|
||||
$fields = ($pointer -split '\r?\n')[0] -split '\s+'
|
||||
$name = $fields[1]
|
||||
if ($name -notlike 'buckit.exe.*') {
|
||||
throw "install-windows.ps1: unexpected release pointer payload: $pointer"
|
||||
}
|
||||
$tag = $name -replace '^buckit\.exe\.', ''
|
||||
$pointerSha = Normalize-Sha $fields[0]
|
||||
}
|
||||
Assert-Tag $tag
|
||||
Write-Host "==> release: $tag"
|
||||
|
||||
$asset = "buckit-windows-amd64.exe.$tag"
|
||||
$downloadUrl = "$ReleaseBase/$tag/$asset"
|
||||
|
||||
$dlDir = Get-EnvOrDefault 'BUCKIT_DOWNLOAD_DIR' (Get-Location).Path
|
||||
New-Item -ItemType Directory -Force -Path $dlDir | Out-Null
|
||||
$exeFile = Join-Path $dlDir 'buckit.exe'
|
||||
|
||||
# Refuse to run when the destination is a directory. Move-Item would move the
|
||||
# temp file inside it and the script would report success while leaving nothing
|
||||
# runnable at the path it prints.
|
||||
if (Test-Path -LiteralPath $exeFile -PathType Container) {
|
||||
throw "install-windows.ps1: $exeFile is a directory - remove it or set BUCKIT_DOWNLOAD_DIR"
|
||||
}
|
||||
|
||||
# Download to a temporary sibling and only move it into the predictable path
|
||||
# after the checksum verifies, so a failed download cannot clobber an existing
|
||||
# good executable or leave a partial/unverified file.
|
||||
$tmpFile = Join-Path $dlDir ".buckit.$([System.IO.Path]::GetRandomFileName()).tmp"
|
||||
try {
|
||||
Write-Host "==> downloading $asset"
|
||||
Invoke-WebRequest -UseBasicParsing -Uri $downloadUrl -OutFile $tmpFile
|
||||
|
||||
Write-Host "==> fetching published checksum"
|
||||
$releaseSha = Normalize-Sha (((Fetch-String "$downloadUrl.sha256sum").Trim() -split '\s+')[0])
|
||||
|
||||
# The binary and the checksum beside it come from the same origin, so that
|
||||
# digest alone only proves the download was not corrupted in transit. The
|
||||
# gh-pages pointer publishes the same digest from a separate origin;
|
||||
# when it is available, require the two to agree before trusting either.
|
||||
if ($pointerSha) {
|
||||
if ($pointerSha -ne $releaseSha) {
|
||||
throw "install-windows.ps1: published digests disagree (pages $pointerSha, release $releaseSha) - refusing to continue"
|
||||
}
|
||||
$wantSha = $pointerSha
|
||||
Write-Host "==> sha256 cross-checked against the release pointer"
|
||||
} else {
|
||||
$wantSha = $releaseSha
|
||||
}
|
||||
|
||||
$gotSha = (Get-FileHash -Algorithm SHA256 -Path $tmpFile).Hash.ToLower()
|
||||
if ($gotSha -ne $wantSha) {
|
||||
throw "install-windows.ps1: checksum mismatch (expected $wantSha, got $gotSha) — refusing to continue"
|
||||
}
|
||||
Write-Host "==> sha256 verified"
|
||||
|
||||
Move-Item -Force -Path $tmpFile -Destination $exeFile
|
||||
} finally {
|
||||
if (Test-Path $tmpFile) { Remove-Item -Force $tmpFile }
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "Downloaded and verified:"
|
||||
Write-Host " $exeFile"
|
||||
Write-Host ""
|
||||
Write-Host "Run it from here:"
|
||||
Write-Host " & `"$exeFile`""
|
||||
Write-Host ""
|
||||
Write-Host "(Add its folder to your PATH to call 'buckit' from anywhere.)"
|
||||
Write-Host ""
|
||||
@@ -0,0 +1,63 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Buckit Releases</title>
|
||||
<style>
|
||||
:root { color-scheme: light; --bg: #f3f5f9; --surface: #ffffff; --surface-alt: #f8fafc; --border: #d8dee9; --text: #0f172a; --muted: #475569; --link: #0f766e; --shadow: 0 18px 40px rgba(15, 23, 42, 0.08); }
|
||||
* { box-sizing: border-box; }
|
||||
body { margin: 0; font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; background: var(--bg); color: var(--text); }
|
||||
.page { max-width: 1080px; margin: 0 auto; padding: 40px 20px 64px; }
|
||||
.hero, .panel { background: var(--surface); border: 1px solid var(--border); border-radius: 14px; box-shadow: var(--shadow); }
|
||||
.hero { padding: 28px; margin-bottom: 24px; }
|
||||
.eyebrow { display: inline-block; padding: 6px 10px; border-radius: 999px; background: #dcfce7; color: #166534; font-size: 12px; font-weight: 700; text-transform: uppercase; }
|
||||
h1 { margin: 14px 0 10px; font-size: 34px; line-height: 1.1; }
|
||||
.subhead { margin: 0; max-width: 720px; color: var(--muted); line-height: 1.6; }
|
||||
.actions { margin-top: 18px; }
|
||||
.button { display: inline-flex; align-items: center; justify-content: center; min-height: 42px; padding: 0 16px; border-radius: 10px; border: 1px solid #99f6e4; background: #f0fdfa; color: var(--link); text-decoration: none; font-weight: 600; }
|
||||
.panel { padding: 24px; }
|
||||
.table-wrap { overflow-x: auto; border: 1px solid var(--border); border-radius: 12px; background: var(--surface-alt); }
|
||||
table { border-collapse: collapse; width: 100%; }
|
||||
th, td { text-align: left; padding: 14px 16px; border-bottom: 1px solid var(--border); }
|
||||
th { background: #eef2f7; font-weight: 600; font-size: 12px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.04em; }
|
||||
tbody tr:last-child td { border-bottom: 0; }
|
||||
a { color: var(--link); text-decoration: none; }
|
||||
a:hover { text-decoration: underline; }
|
||||
@media (max-width: 720px) {
|
||||
.page { padding: 24px 16px 48px; }
|
||||
.hero, .panel { padding: 20px; }
|
||||
h1 { font-size: 28px; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="page">
|
||||
<section class="hero">
|
||||
<span class="eyebrow">Release Archive</span>
|
||||
<h1>Buckit Releases</h1>
|
||||
<p class="subhead">Stable Buckit releases published to GitHub. Open any release to inspect artifacts, checksums, and signed binaries, or jump back to the current release landing page.</p>
|
||||
<div class="actions">
|
||||
<a class="button" href="../release/">Open latest release</a>
|
||||
</div>
|
||||
</section>
|
||||
<section class="panel">
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>Date</th><th>Release</th><th>Downloads</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td>2026-08-08</td><td><a href="https://github.com/buckit-io/buckit/releases/tag/RELEASE.2026-08-08T00-55-02Z">RELEASE.2026-08-08T00-55-02Z</a></td><td><a href="https://github.com/buckit-io/buckit/releases/tag/RELEASE.2026-08-08T00-55-02Z">Assets →</a></td></tr>
|
||||
<tr><td>2026-08-05</td><td><a href="https://github.com/buckit-io/buckit/releases/tag/RELEASE.2026-08-05T18-01-10Z">RELEASE.2026-08-05T18-01-10Z</a></td><td><a href="https://github.com/buckit-io/buckit/releases/tag/RELEASE.2026-08-05T18-01-10Z">Assets →</a></td></tr>
|
||||
<tr><td>2026-08-04</td><td><a href="https://github.com/buckit-io/buckit/releases/tag/RELEASE.2026-08-04T03-21-12Z">RELEASE.2026-08-04T03-21-12Z</a></td><td><a href="https://github.com/buckit-io/buckit/releases/tag/RELEASE.2026-08-04T03-21-12Z">Assets →</a></td></tr>
|
||||
<tr><td>2026-07-30</td><td><a href="https://github.com/buckit-io/buckit/releases/tag/RELEASE.2026-07-30T00-12-49Z">RELEASE.2026-07-30T00-12-49Z</a></td><td><a href="https://github.com/buckit-io/buckit/releases/tag/RELEASE.2026-07-30T00-12-49Z">Assets →</a></td></tr>
|
||||
<tr><td>2026-07-29</td><td><a href="https://github.com/buckit-io/buckit/releases/tag/RELEASE.2026-07-29T17-06-43Z">RELEASE.2026-07-29T17-06-43Z</a></td><td><a href="https://github.com/buckit-io/buckit/releases/tag/RELEASE.2026-07-29T17-06-43Z">Assets →</a></td></tr>
|
||||
<tr><td>2026-07-29</td><td><a href="https://github.com/buckit-io/buckit/releases/tag/RELEASE.2026-07-29T17-06-42Z">RELEASE.2026-07-29T17-06-42Z</a></td><td><a href="https://github.com/buckit-io/buckit/releases/tag/RELEASE.2026-07-29T17-06-42Z">Assets →</a></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html><html><head>
|
||||
<title>Index of /server/buckit/</title>
|
||||
<style>
|
||||
body { font-family: monospace; max-width: 800px; margin: 2em auto; }
|
||||
a { display: block; padding: 2px 0; }
|
||||
hr { margin: 1em 0; }
|
||||
</style>
|
||||
</head><body>
|
||||
<h2>Index of /server/buckit/</h2><hr><pre>
|
||||
<a href="../">../</a>
|
||||
<a href="release/">release/</a>
|
||||
</pre><hr></body></html>
|
||||
@@ -0,0 +1 @@
|
||||
f6cfe0241b9d96107ff36969edca6662df78c7af713c1d1a49d4a3b988031839 buckit.RELEASE.2026-08-08T00-55-02Z
|
||||
@@ -0,0 +1,219 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Buckit RELEASE.2026-08-08T00-55-02Z</title>
|
||||
<style>
|
||||
:root { color-scheme: light; --bg: #f3f5f9; --surface: #ffffff; --surface-alt: #f8fafc; --border: #d8dee9; --text: #0f172a; --muted: #475569; --link: #0f766e; --link-hover: #115e59; --accent: #dcfce7; --accent-text: #166534; --shadow: 0 18px 40px rgba(15, 23, 42, 0.08); }
|
||||
* { box-sizing: border-box; }
|
||||
body { margin: 0; font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; background: var(--bg); color: var(--text); }
|
||||
.page { max-width: 1080px; margin: 0 auto; padding: 40px 20px 64px; }
|
||||
.hero, .panel { background: var(--surface); border: 1px solid var(--border); border-radius: 14px; box-shadow: var(--shadow); }
|
||||
.hero { padding: 28px; margin-bottom: 24px; }
|
||||
.eyebrow { display: inline-block; padding: 6px 10px; border-radius: 999px; background: var(--accent); color: var(--accent-text); font-size: 12px; font-weight: 700; letter-spacing: 0; text-transform: uppercase; }
|
||||
h1 { margin: 14px 0 10px; font-size: 34px; line-height: 1.1; }
|
||||
.subhead { margin: 0 0 20px; max-width: 760px; color: var(--muted); font-size: 16px; line-height: 1.6; }
|
||||
.hero-actions, .meta { display: flex; flex-wrap: wrap; gap: 12px; }
|
||||
.meta { margin-top: 18px; }
|
||||
.meta-item { padding: 10px 12px; border: 1px solid var(--border); border-radius: 10px; background: var(--surface-alt); min-width: 160px; }
|
||||
.meta-label { display: block; font-size: 12px; color: var(--muted); margin-bottom: 4px; }
|
||||
.meta-value { font-size: 14px; font-weight: 600; }
|
||||
.button, .text-link { color: var(--link); text-decoration: none; font-weight: 600; }
|
||||
.button { display: inline-flex; align-items: center; justify-content: center; min-height: 42px; padding: 0 16px; border-radius: 10px; border: 1px solid #99f6e4; background: #f0fdfa; }
|
||||
.button:hover, .text-link:hover { color: var(--link-hover); }
|
||||
.panel { padding: 24px; margin-bottom: 24px; }
|
||||
.panel:last-child { margin-bottom: 0; }
|
||||
.section-title { margin: 0 0 8px; font-size: 24px; }
|
||||
.section-copy { margin: 0 0 20px; color: var(--muted); line-height: 1.6; }
|
||||
.cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 16px; }
|
||||
.card { border: 1px solid var(--border); border-radius: 12px; background: var(--surface-alt); padding: 18px; }
|
||||
.card h3 { margin: 0 0 8px; font-size: 18px; }
|
||||
.card p { margin: 0 0 16px; color: var(--muted); font-size: 14px; line-height: 1.5; }
|
||||
.card-links { display: grid; gap: 10px; }
|
||||
.download { display: inline-flex; align-items: center; justify-content: center; min-height: 40px; padding: 0 14px; border-radius: 10px; background: #0f172a; color: #ffffff; text-decoration: none; font-weight: 600; }
|
||||
.download:hover { background: #1e293b; }
|
||||
.aux-links { display: flex; flex-wrap: wrap; gap: 12px; }
|
||||
.table-wrap { overflow-x: auto; border: 1px solid var(--border); border-radius: 12px; background: var(--surface-alt); }
|
||||
table { width: 100%; border-collapse: collapse; }
|
||||
th, td { text-align: left; padding: 14px 16px; border-bottom: 1px solid var(--border); vertical-align: top; }
|
||||
th { font-size: 12px; text-transform: uppercase; color: var(--muted); background: #eef2f7; letter-spacing: 0.04em; }
|
||||
tbody tr:last-child td { border-bottom: 0; }
|
||||
td strong { display: block; margin-bottom: 4px; }
|
||||
.footer-note { margin-top: 18px; color: var(--muted); font-size: 14px; line-height: 1.6; }
|
||||
a { color: var(--link); text-decoration: none; }
|
||||
a:hover { text-decoration: underline; }
|
||||
@media (max-width: 720px) {
|
||||
.page { padding: 24px 16px 48px; }
|
||||
.hero, .panel { padding: 20px; }
|
||||
h1 { font-size: 28px; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="page">
|
||||
<section class="hero">
|
||||
<span class="eyebrow">Latest Stable Release</span>
|
||||
<h1>Buckit</h1>
|
||||
<p class="subhead">Signed release binaries for the Buckit S3-compatible object storage server.</p>
|
||||
<div class="hero-actions">
|
||||
<a class="button" href="../archives/">Browse release archive</a>
|
||||
</div>
|
||||
<div class="meta">
|
||||
<div class="meta-item">
|
||||
<span class="meta-label">Release tag</span>
|
||||
<span class="meta-value">RELEASE.2026-08-08T00-55-02Z</span>
|
||||
</div>
|
||||
<div class="meta-item">
|
||||
<span class="meta-label">Repository</span>
|
||||
<span class="meta-value">buckit-io/buckit</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel">
|
||||
<h2 class="section-title">Install</h2>
|
||||
<p class="section-copy">One-line installers that download the right artifact for your platform, verify its SHA-256 checksum, and print the command to finish. They do not install for you — the privileged step is yours to review and run.</p>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>Platform</th><th>Command</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><strong>Linux</strong>rpm / deb / apk</td>
|
||||
<td><code style="font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:13px">curl -fsSL https://buckit-io.github.io/buckit/install-linux.sh | sh</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Linux</strong>standalone binary</td>
|
||||
<td><code style="font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:13px">curl -fsSL https://buckit-io.github.io/buckit/install-linux-binary.sh | sh</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>macOS</strong>Apple Silicon</td>
|
||||
<td><code style="font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:13px">curl -fsSL https://buckit-io.github.io/buckit/install-mac.sh | sh</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Windows</strong>x86_64</td>
|
||||
<td><code style="font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:13px">irm https://buckit-io.github.io/buckit/install-windows.ps1 | iex</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel">
|
||||
<h2 class="section-title">Downloads</h2>
|
||||
<p class="section-copy">Choose the binary for your OS and architecture. Each platform card includes the signed artifact, checksum, and minisign signature.</p>
|
||||
<div class="cards">
|
||||
<article class="card">
|
||||
<h3>Linux x86_64</h3>
|
||||
<p>Standard Linux build for x86_64 hosts.</p>
|
||||
<div class="card-links">
|
||||
<a class="download" href="https://github.com/buckit-io/buckit/releases/download/RELEASE.2026-08-08T00-55-02Z/buckit-linux-amd64.RELEASE.2026-08-08T00-55-02Z">Download binary</a>
|
||||
<div class="aux-links">
|
||||
<a href="https://github.com/buckit-io/buckit/releases/download/RELEASE.2026-08-08T00-55-02Z/buckit-linux-amd64.RELEASE.2026-08-08T00-55-02Z.sha256sum">Checksum</a>
|
||||
<a href="https://github.com/buckit-io/buckit/releases/download/RELEASE.2026-08-08T00-55-02Z/buckit-linux-amd64.RELEASE.2026-08-08T00-55-02Z.minisig">Signature</a>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
<article class="card">
|
||||
<h3>Linux arm64</h3>
|
||||
<p>Linux build for ARM64 systems and cloud hosts.</p>
|
||||
<div class="card-links">
|
||||
<a class="download" href="https://github.com/buckit-io/buckit/releases/download/RELEASE.2026-08-08T00-55-02Z/buckit-linux-arm64.RELEASE.2026-08-08T00-55-02Z">Download binary</a>
|
||||
<div class="aux-links">
|
||||
<a href="https://github.com/buckit-io/buckit/releases/download/RELEASE.2026-08-08T00-55-02Z/buckit-linux-arm64.RELEASE.2026-08-08T00-55-02Z.sha256sum">Checksum</a>
|
||||
<a href="https://github.com/buckit-io/buckit/releases/download/RELEASE.2026-08-08T00-55-02Z/buckit-linux-arm64.RELEASE.2026-08-08T00-55-02Z.minisig">Signature</a>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
<article class="card">
|
||||
<h3>macOS arm64</h3>
|
||||
<p>Native Apple Silicon build for modern Macs.</p>
|
||||
<div class="card-links">
|
||||
<a class="download" href="https://github.com/buckit-io/buckit/releases/download/RELEASE.2026-08-08T00-55-02Z/buckit-darwin-arm64.RELEASE.2026-08-08T00-55-02Z">Download binary</a>
|
||||
<div class="aux-links">
|
||||
<a href="https://github.com/buckit-io/buckit/releases/download/RELEASE.2026-08-08T00-55-02Z/buckit-darwin-arm64.RELEASE.2026-08-08T00-55-02Z.sha256sum">Checksum</a>
|
||||
<a href="https://github.com/buckit-io/buckit/releases/download/RELEASE.2026-08-08T00-55-02Z/buckit-darwin-arm64.RELEASE.2026-08-08T00-55-02Z.minisig">Signature</a>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
<article class="card">
|
||||
<h3>Windows x86_64</h3>
|
||||
<p>Windows build for 64-bit desktop and server environments.</p>
|
||||
<div class="card-links">
|
||||
<a class="download" href="https://github.com/buckit-io/buckit/releases/download/RELEASE.2026-08-08T00-55-02Z/buckit-windows-amd64.exe.RELEASE.2026-08-08T00-55-02Z">Download binary</a>
|
||||
<div class="aux-links">
|
||||
<a href="https://github.com/buckit-io/buckit/releases/download/RELEASE.2026-08-08T00-55-02Z/buckit-windows-amd64.exe.RELEASE.2026-08-08T00-55-02Z.sha256sum">Checksum</a>
|
||||
<a href="https://github.com/buckit-io/buckit/releases/download/RELEASE.2026-08-08T00-55-02Z/buckit-windows-amd64.exe.RELEASE.2026-08-08T00-55-02Z.minisig">Signature</a>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
<p class="footer-note">Need the raw artifact names for automation or mirrors? The manifest below keeps the exact filenames and verification links in one place.</p>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>Platform</th><th>Binary</th><th>Checksum</th><th>Signature</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><strong>Linux x86_64</strong>Standard Linux</td>
|
||||
<td><a href="https://github.com/buckit-io/buckit/releases/download/RELEASE.2026-08-08T00-55-02Z/buckit-linux-amd64.RELEASE.2026-08-08T00-55-02Z">buckit-linux-amd64.RELEASE.2026-08-08T00-55-02Z</a></td>
|
||||
<td><a href="https://github.com/buckit-io/buckit/releases/download/RELEASE.2026-08-08T00-55-02Z/buckit-linux-amd64.RELEASE.2026-08-08T00-55-02Z.sha256sum">.sha256sum</a></td>
|
||||
<td><a href="https://github.com/buckit-io/buckit/releases/download/RELEASE.2026-08-08T00-55-02Z/buckit-linux-amd64.RELEASE.2026-08-08T00-55-02Z.minisig">.minisig</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Linux arm64</strong>ARM64 Linux</td>
|
||||
<td><a href="https://github.com/buckit-io/buckit/releases/download/RELEASE.2026-08-08T00-55-02Z/buckit-linux-arm64.RELEASE.2026-08-08T00-55-02Z">buckit-linux-arm64.RELEASE.2026-08-08T00-55-02Z</a></td>
|
||||
<td><a href="https://github.com/buckit-io/buckit/releases/download/RELEASE.2026-08-08T00-55-02Z/buckit-linux-arm64.RELEASE.2026-08-08T00-55-02Z.sha256sum">.sha256sum</a></td>
|
||||
<td><a href="https://github.com/buckit-io/buckit/releases/download/RELEASE.2026-08-08T00-55-02Z/buckit-linux-arm64.RELEASE.2026-08-08T00-55-02Z.minisig">.minisig</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>macOS arm64</strong>Apple Silicon</td>
|
||||
<td><a href="https://github.com/buckit-io/buckit/releases/download/RELEASE.2026-08-08T00-55-02Z/buckit-darwin-arm64.RELEASE.2026-08-08T00-55-02Z">buckit-darwin-arm64.RELEASE.2026-08-08T00-55-02Z</a></td>
|
||||
<td><a href="https://github.com/buckit-io/buckit/releases/download/RELEASE.2026-08-08T00-55-02Z/buckit-darwin-arm64.RELEASE.2026-08-08T00-55-02Z.sha256sum">.sha256sum</a></td>
|
||||
<td><a href="https://github.com/buckit-io/buckit/releases/download/RELEASE.2026-08-08T00-55-02Z/buckit-darwin-arm64.RELEASE.2026-08-08T00-55-02Z.minisig">.minisig</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Windows x86_64</strong>64-bit Windows</td>
|
||||
<td><a href="https://github.com/buckit-io/buckit/releases/download/RELEASE.2026-08-08T00-55-02Z/buckit-windows-amd64.exe.RELEASE.2026-08-08T00-55-02Z">buckit-windows-amd64.exe.RELEASE.2026-08-08T00-55-02Z</a></td>
|
||||
<td><a href="https://github.com/buckit-io/buckit/releases/download/RELEASE.2026-08-08T00-55-02Z/buckit-windows-amd64.exe.RELEASE.2026-08-08T00-55-02Z.sha256sum">.sha256sum</a></td>
|
||||
<td><a href="https://github.com/buckit-io/buckit/releases/download/RELEASE.2026-08-08T00-55-02Z/buckit-windows-amd64.exe.RELEASE.2026-08-08T00-55-02Z.minisig">.minisig</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel">
|
||||
<h2 class="section-title">Linux packages</h2>
|
||||
<p class="section-copy">Native packages for Debian/Ubuntu, RPM, and Alpine distributions.</p>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>Format</th><th>amd64</th><th>arm64</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><strong>Debian/Ubuntu</strong>.deb</td>
|
||||
<td><a href="https://github.com/buckit-io/buckit/releases/download/RELEASE.2026-08-08T00-55-02Z/buckit_20260808005502.0.0_amd64.deb">buckit_20260808005502.0.0_amd64.deb</a></td>
|
||||
<td><a href="https://github.com/buckit-io/buckit/releases/download/RELEASE.2026-08-08T00-55-02Z/buckit_20260808005502.0.0_arm64.deb">buckit_20260808005502.0.0_arm64.deb</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>RPM</strong>.rpm</td>
|
||||
<td><a href="https://github.com/buckit-io/buckit/releases/download/RELEASE.2026-08-08T00-55-02Z/buckit-20260808005502.0.0.x86_64.rpm">buckit-20260808005502.0.0.x86_64.rpm</a></td>
|
||||
<td><a href="https://github.com/buckit-io/buckit/releases/download/RELEASE.2026-08-08T00-55-02Z/buckit-20260808005502.0.0.aarch64.rpm">buckit-20260808005502.0.0.aarch64.rpm</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Alpine</strong>.apk</td>
|
||||
<td><a href="https://github.com/buckit-io/buckit/releases/download/RELEASE.2026-08-08T00-55-02Z/buckit_20260808005502.0.0_x86_64.apk">buckit_20260808005502.0.0_x86_64.apk</a></td>
|
||||
<td><a href="https://github.com/buckit-io/buckit/releases/download/RELEASE.2026-08-08T00-55-02Z/buckit_20260808005502.0.0_aarch64.apk">buckit_20260808005502.0.0_aarch64.apk</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1 @@
|
||||
349fab1d9654751b47bd69915111b4ccf99e79a36f5ed4fc77ca8aaee21d45db buckit.RELEASE.2026-08-08T00-55-02Z
|
||||
@@ -0,0 +1 @@
|
||||
e1af0c4ca22e8a0ae13ba941fee599db8e0472c6d12f5767484878bd500bb422 buckit.RELEASE.2026-08-08T00-55-02Z
|
||||
@@ -0,0 +1 @@
|
||||
1753f05537ad3c85a9ad70e7faaab81659fd85e5266f678f56322e1f515dd675 buckit.exe.RELEASE.2026-08-08T00-55-02Z
|
||||
@@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html><html><head>
|
||||
<title>Index of /server/</title>
|
||||
<style>
|
||||
body { font-family: monospace; max-width: 800px; margin: 2em auto; }
|
||||
a { display: block; padding: 2px 0; }
|
||||
hr { margin: 1em 0; }
|
||||
</style>
|
||||
</head><body>
|
||||
<h2>Index of /server/</h2><hr><pre>
|
||||
<a href="../">../</a>
|
||||
<a href="buckit/">buckit/</a>
|
||||
</pre><hr></body></html>
|
||||
Reference in New Issue
Block a user