-
Notifications
You must be signed in to change notification settings - Fork 0
Feat/easy install #4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
30 commits
Select commit
Hold shift + click to select a range
3f362d3
feat: add bootstrap installer
1874407
docs: clarify quick install branch ref
2fe39da
docs: fix quick install branch example
fd3c7af
chore: update maintainer email
dfd308f
Initial plan (#5)
Copilot cca8a1d
Fix curl error handling and revert maintainer emails to project addre…
Copilot bd62efa
Initial plan (#7)
Copilot 20e7869
Initial plan (#8)
Copilot 3c7547e
docs: prioritize pinned version install for supply-chain security (#10)
Copilot 06b639f
Require explicit ref in install.sh for supply-chain security (#11)
Copilot 0098c8e
Add SHA256 verification to bootstrap installer (#12)
Copilot 410c628
Revert maintainer emails to project address in packaging metadata (#13)
Copilot 50960a3
Update install.sh
senet 6673047
Update install.sh
senet 78d4ca7
Add macOS compatibility for SHA256 verification in installer (#14)
Copilot 934ccee
Update scripts/release.sh
senet e49f322
Update README.md
senet 24f8373
Update README.md
senet eeb2322
Update CONTRIBUTING.md
senet ddc9def
Update install.sh
senet ff40a18
Update install.sh
senet c966ba6
Update README.md
senet 8fb34e7
Update libexec/kctl-env-list-remote
senet 518570d
Update scripts/release.sh
senet 17d9280
Update README.md
senet af8be08
Update install.sh
senet 517c844
fix: robust checksum parsing in installer
3642d1f
chore: make install.sh executable
0d4aa37
docs: adjust installer and release guidance
a4ae27b
Update install.sh
senet File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,211 @@ | ||
| #!/usr/bin/env bash | ||
| # kctl-env bootstrap installer | ||
| # - Requires standard Unix tools: bash, curl, tar, coreutils (incl. install, mktemp, head, basename), find, awk | ||
| # - SHA256 verification uses sha256sum (Linux), shasum (macOS), or openssl (fallback) | ||
| # - Installs into $KCTL_ENV_ROOT (default: ~/.kctl-env) | ||
| # - Preserves existing runtime dirs (versions/, cache/) | ||
|
|
||
| set -euo pipefail | ||
|
|
||
| REPO_OWNER="senet" | ||
| REPO_NAME="kctl-env" | ||
|
|
||
| KCTL_ENV_ROOT="${KCTL_ENV_ROOT:-$HOME/.kctl-env}" | ||
| KCTL_ENV_REF="${KCTL_ENV_REF:-}" | ||
| KCTL_ENV_SKIP_VERIFY="${KCTL_ENV_SKIP_VERIFY:-}" | ||
|
|
||
| usage() { | ||
| cat <<EOF | ||
| kctl-env installer | ||
|
|
||
| Usage: | ||
| ./install.sh <ref> | ||
|
|
||
| Arguments: | ||
| ref Git ref to install (required; tag like v0.1.1, or branch like main) | ||
|
|
||
| Environment: | ||
| KCTL_ENV_ROOT Install root (default: ~/.kctl-env) | ||
| KCTL_ENV_REF Alternative to passing ref as argument (required if ref not provided) | ||
|
|
||
| Examples: | ||
| ./install.sh v0.1.1 | ||
| KCTL_ENV_ROOT="$HOME/.kctl-env" ./install.sh main | ||
| KCTL_ENV_REF=v0.1.1 ./install.sh | ||
| EOF | ||
| } | ||
|
|
||
| ref_from_input="${1:-}" | ||
| if [[ "${ref_from_input:-}" == "-h" || "${ref_from_input:-}" == "--help" ]]; then | ||
| usage | ||
| exit 0 | ||
| fi | ||
|
|
||
| ref="${ref_from_input:-$KCTL_ENV_REF}" | ||
| if [[ -z "$ref" ]]; then | ||
| echo "Error: No ref specified. For supply-chain security, you must explicitly specify a version tag or branch." >&2 | ||
| echo "Usage: $0 <ref> (e.g., v0.1.1 or main)" >&2 | ||
| echo "See: curl -fsSL https://raw.githubusercontent.com/${REPO_OWNER}/${REPO_NAME}/main/install.sh | bash -s -- <ref>" >&2 | ||
| exit 1 | ||
| fi | ||
|
senet marked this conversation as resolved.
|
||
|
|
||
| archive_url="" | ||
| case "$ref" in | ||
| v*) archive_url="https://github.com/${REPO_OWNER}/${REPO_NAME}/archive/refs/tags/${ref}.tar.gz" ;; | ||
| *) archive_url="https://github.com/${REPO_OWNER}/${REPO_NAME}/archive/refs/heads/${ref}.tar.gz" ;; | ||
| esac | ||
|
|
||
| require_cmd() { | ||
| command -v "$1" >/dev/null 2>&1 || { echo "Missing required command: $1" >&2; exit 1; } | ||
| } | ||
|
|
||
| # Compute SHA256 hash using available tools | ||
| # Returns hash on stdout, exits non-zero on error | ||
| compute_sha256() { | ||
| local file="$1" | ||
| if command -v sha256sum >/dev/null 2>&1; then | ||
| sha256sum "$file" | awk '{print $1}' | ||
| elif command -v shasum >/dev/null 2>&1; then | ||
| shasum -a 256 "$file" | awk '{print $1}' | ||
| elif command -v openssl >/dev/null 2>&1; then | ||
| openssl dgst -sha256 "$file" | awk '{print $NF}' | ||
| else | ||
| echo "Error: No SHA256 tool found (tried: sha256sum, shasum, openssl)" >&2 | ||
| exit 1 | ||
| fi | ||
| } | ||
|
|
||
| require_cmd install | ||
| require_cmd mktemp | ||
| require_cmd curl | ||
| require_cmd find | ||
| require_cmd head | ||
| require_cmd tar | ||
| require_cmd awk | ||
| require_cmd basename | ||
| require_cmd tr | ||
|
|
||
|
senet marked this conversation as resolved.
|
||
| tmpdir="$(mktemp -d "${TMPDIR:-/tmp}/kctl-env.XXXXXX")" | ||
| trap 'rm -rf "$tmpdir"' EXIT | ||
|
|
||
| archive="$tmpdir/src.tar.gz" | ||
|
|
||
| echo "Downloading $archive_url" | ||
| curl -fsSL "$archive_url" -o "$archive" | ||
|
|
||
| # Verify integrity for tagged releases | ||
| # For tags (v*), try to fetch and verify SHA256 checksum from GitHub releases | ||
| # For branches, skip checksum (GitHub doesn't provide checksums for auto-generated tarballs) | ||
| if [[ "$ref" == v* ]]; then | ||
| if [[ -n "${KCTL_ENV_SKIP_VERIFY:-}" ]]; then | ||
| echo "Warning: Checksum verification explicitly skipped via KCTL_ENV_SKIP_VERIFY" >&2 | ||
| else | ||
| checksum_url="https://github.com/${REPO_OWNER}/${REPO_NAME}/releases/download/${ref}/${ref}.tar.gz.sha256" | ||
| echo "Verifying checksum..." | ||
| if curl -fsSL "$checksum_url" -o "$tmpdir/checksum.sha256" 2>/dev/null; then | ||
| # Extract just the hash (first field) and verify manually | ||
| expected_hash="$(awk 'NR==1{print $1; exit}' "$tmpdir/checksum.sha256" | tr '[:upper:]' '[:lower:]')" | ||
| actual_hash="$(compute_sha256 "$archive" | tr '[:upper:]' '[:lower:]')" | ||
|
|
||
| # Validate that hashes were extracted successfully | ||
| if [[ -z "$expected_hash" || -z "$actual_hash" ]]; then | ||
| echo "Error: Failed to extract checksum values" >&2 | ||
| echo "The checksum file may be empty or malformed" >&2 | ||
| exit 1 | ||
| fi | ||
|
|
||
| if [[ ! "$expected_hash" =~ ^[0-9a-f]{64}$ ]]; then | ||
| echo "Error: Checksum file is malformed (expected SHA256 hex)." >&2 | ||
| echo "Got: $expected_hash" >&2 | ||
| exit 1 | ||
| fi | ||
|
|
||
| if [[ "$expected_hash" != "$actual_hash" ]]; then | ||
| echo "Checksum verification failed for $ref" >&2 | ||
| echo "Expected: $expected_hash" >&2 | ||
| echo "Actual: $actual_hash" >&2 | ||
| echo "This may indicate a compromised download or release." >&2 | ||
| exit 1 | ||
| fi | ||
| echo "Checksum verified successfully" | ||
| else | ||
| echo "Error: No checksum found for $ref at $checksum_url" >&2 | ||
| echo "For security, this installer requires SHA256 verification for tagged releases." >&2 | ||
| echo "If you still want to install this older release without checksums, you can re-run with:" >&2 | ||
| echo " Local file: KCTL_ENV_SKIP_VERIFY=1 ./install.sh $ref" >&2 | ||
| echo " Via curl: KCTL_ENV_SKIP_VERIFY=1 bash -s -- $ref" >&2 | ||
| exit 1 | ||
| fi | ||
| fi | ||
| else | ||
| echo "Note: Checksum verification skipped for branch '$ref' (not available for auto-generated archives)" | ||
| fi | ||
|
|
||
| # Extract | ||
| mkdir -p "$tmpdir/src" | ||
| tar -xzf "$archive" -C "$tmpdir/src" | ||
|
|
||
|
senet marked this conversation as resolved.
|
||
| # Determine extracted directory (choose first top-level subdirectory deterministically) | ||
| src_root="" | ||
| for d in "$tmpdir/src"/*; do | ||
| if [[ -d "$d" ]]; then | ||
| src_root="$d" | ||
| break | ||
| fi | ||
| done | ||
| if [[ -z "${src_root:-}" || ! -d "$src_root" ]]; then | ||
| echo "Failed to locate extracted source directory" >&2 | ||
| exit 1 | ||
| fi | ||
|
|
||
| # Create target directories (preserve versions/cache if already exist) | ||
| mkdir -p "$KCTL_ENV_ROOT" \ | ||
| "$KCTL_ENV_ROOT/bin" \ | ||
| "$KCTL_ENV_ROOT/libexec" \ | ||
| "$KCTL_ENV_ROOT/etc" \ | ||
| "$KCTL_ENV_ROOT/packaging" \ | ||
| "$KCTL_ENV_ROOT/scripts" \ | ||
| "$KCTL_ENV_ROOT/versions" \ | ||
| "$KCTL_ENV_ROOT/cache" | ||
|
|
||
| # Install core scripts | ||
| install -m 0755 "$src_root/bin/kctl-env" "$KCTL_ENV_ROOT/bin/kctl-env" | ||
| install -m 0755 "$src_root/bin/kubectl" "$KCTL_ENV_ROOT/bin/kubectl" | ||
|
|
||
| # libexec scripts | ||
| for f in "$src_root"/libexec/*; do | ||
| [[ -f "$f" ]] || continue | ||
| install -m 0755 "$f" "$KCTL_ENV_ROOT/libexec/$(basename "$f")" | ||
| done | ||
|
|
||
| # Completion scripts (optional) | ||
| if [[ -f "$src_root/etc/kctl-env-completion.bash" ]]; then | ||
| install -m 0644 "$src_root/etc/kctl-env-completion.bash" "$KCTL_ENV_ROOT/etc/kctl-env-completion.bash" | ||
| fi | ||
| if [[ -f "$src_root/etc/kctl-env-completion.zsh" ]]; then | ||
| install -m 0644 "$src_root/etc/kctl-env-completion.zsh" "$KCTL_ENV_ROOT/etc/kctl-env-completion.zsh" | ||
| fi | ||
|
|
||
| # Scripts (optional) | ||
| if [[ -f "$src_root/scripts/release.sh" ]]; then | ||
| install -m 0755 "$src_root/scripts/release.sh" "$KCTL_ENV_ROOT/scripts/release.sh" | ||
| fi | ||
|
|
||
| # Docs + metadata (best-effort) | ||
| for f in README.md CHANGELOG.md VERSION; do | ||
| if [[ -f "$src_root/$f" ]]; then | ||
| install -m 0644 "$src_root/$f" "$KCTL_ENV_ROOT/$f" | ||
| fi | ||
| done | ||
|
|
||
| echo | ||
| echo "Installed kctl-env into: $KCTL_ENV_ROOT" | ||
| echo | ||
| echo "Next steps:" | ||
| echo " 1) Add to PATH:" | ||
| echo " export PATH=\"$KCTL_ENV_ROOT/bin:\$PATH\"" | ||
| echo " 2) Install kubectl:" | ||
| echo " kctl-env install latest" | ||
| echo " 3) Select version:" | ||
| echo " kctl-env use latest" | ||
| echo | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,10 +1,57 @@ | ||
| #!/usr/bin/env bash | ||
| set -euo pipefail | ||
|
|
||
| # List available kubectl releases from dl.k8s.io | ||
| # Zero-deps: parse HTML index | ||
| # List available kubectl releases. | ||
| # | ||
| # Kubernetes' dl.k8s.io no longer exposes a browsable release index, so we use | ||
| # the GitHub tags API and parse it with POSIX tools (no jq). | ||
| # | ||
| # Notes: | ||
| # - Unauthenticated GitHub API requests are rate-limited. | ||
| # - Increase limits by exporting GITHUB_TOKEN. | ||
|
|
||
| curl -fsSL https://dl.k8s.io/release/ | | ||
| grep -Eo 'v[0-9]+\.[0-9]+\.[0-9]+' | | ||
| sort -Vr | | ||
| uniq | ||
| MAX_PAGES="${KCTL_LIST_REMOTE_MAX_PAGES:-5}" | ||
| PER_PAGE=100 | ||
|
|
||
| api_base="https://api.github.com/repos/kubernetes/kubernetes/tags" | ||
|
|
||
| curl_args=(-sSLf) | ||
| if [[ -n "${GITHUB_TOKEN:-}" ]]; then | ||
| curl_args+=(-H "Authorization: Bearer ${GITHUB_TOKEN}") | ||
| fi | ||
|
|
||
| page=1 | ||
| while [[ "$page" -le "$MAX_PAGES" ]]; do | ||
| json="$(curl "${curl_args[@]}" "${api_base}?per_page=${PER_PAGE}&page=${page}")" || { | ||
| echo "kctl-env: failed to query GitHub tags API (page ${page})." >&2 | ||
| echo "Hint: export GITHUB_TOKEN to avoid rate limits, or set KCTL_LIST_REMOTE_MAX_PAGES lower." >&2 | ||
| exit 1 | ||
| } | ||
|
|
||
| # Extract stable semver tags like v1.29.0 | ||
| tags="$(printf '%s' "$json" | | ||
| grep -Eo '"name"[[:space:]]*:[[:space:]]*"v[0-9]+\.[0-9]+\.[0-9]+"' | | ||
| sed -E 's/.*"(v[0-9]+\.[0-9]+\.[0-9]+)".*/\1/' | ||
| )" | ||
|
|
||
| [[ -z "$tags" ]] && break | ||
| printf '%s\n' "$tags" | ||
| page=$((page + 1)) | ||
| done | | ||
| if sort -V </dev/null >/dev/null 2>&1; then | ||
| # Prefer GNU sort's version sort when available. | ||
| sort -Vr | uniq | ||
| else | ||
| # POSIX fallback: sort semantic versions vMAJOR.MINOR.PATCH numerically. | ||
| awk -F. ' | ||
| { | ||
| ver = $0 | ||
| # Strip leading "v" from major component. | ||
| sub(/^v/, "", $1) | ||
| # Print: original major minor patch | ||
| printf "%s %d %d %d\n", ver, $1, $2, $3 | ||
| } | ||
| ' | | ||
| sort -k2,2nr -k3,3nr -k4,4nr | | ||
| awk '!seen[$1]++ { print $1 }' | ||
| fi |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.