Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

60 changes: 40 additions & 20 deletions arcup/arcup
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ GPG_KEYSERVER="keyserver.ubuntu.com"
BIN_DIR="${ARC_BIN_DIR:-$HOME/.arc/bin}"
ARCUP_BIN_URL="https://raw.githubusercontent.com/circlefin/arc-node/main/arcup/arcup"
ARCUP_BIN_PATH="$BIN_DIR/arcup"
CURL_HEADERS=()
if [ "${CURL_HEADER:-}" ]; then
CURL_HEADERS=(-H "$CURL_HEADER")
fi

# Binaries included in each release archive
BINARIES=("arc-node-execution" "arc-node-consensus" "arc-snapshots")
Expand All @@ -25,6 +29,15 @@ GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

# Temp paths populated by update_arcup() and main(); cleaned up on EXIT.
_ARCUP_TMP_FILE=""
TMP_DIR=$(mktemp -d)
_arcup_cleanup() {
[[ -n "$_ARCUP_TMP_FILE" ]] && rm -f "$_ARCUP_TMP_FILE"
[[ -n "$TMP_DIR" ]] && rm -rf "$TMP_DIR"
}
trap _arcup_cleanup EXIT

info() {
echo -e "${GREEN}info${NC}: $1" >&2
}
Expand Down Expand Up @@ -79,8 +92,12 @@ download_file() {
local url="https://github.com/${REPO}/releases/download/${tag}/${filename}"
local output_path="$output_dir/$filename"

if ! command -v curl >/dev/null 2>&1; then
error "curl not found. Please install curl."
fi

info "Downloading $filename..."
if ! curl -#fLo "$output_path" "$url"; then
if ! curl -#fL "${CURL_HEADERS[@]}" -o "$output_path" "$url"; then
error "Failed to download $filename from $url"
fi
}
Expand All @@ -97,11 +114,11 @@ compute_sha256() {
# Check if arcup installer is up to date
check_installer_up_to_date() {
if ! command -v curl >/dev/null 2>&1; then
return
error "curl not found. Please install curl."
fi

local remote_version
remote_version=$(curl -fsSL "$ARCUP_BIN_URL" 2>/dev/null | \
remote_version=$(curl -fsSL "${CURL_HEADERS[@]}" "$ARCUP_BIN_URL" 2>/dev/null | \
grep '^ARCUP_INSTALLER_VERSION=' | sed -E 's/ARCUP_INSTALLER_VERSION="(.+)"/\1/')

if [[ -z "$remote_version" ]]; then
Expand All @@ -125,17 +142,15 @@ update_arcup() {
error "curl not found. Please install curl."
fi

local tmp_file
tmp_file=$(mktemp)
trap "rm -f $tmp_file" EXIT
_ARCUP_TMP_FILE=$(mktemp)

info "Downloading latest arcup..."
if ! curl -fsSL "$ARCUP_BIN_URL" -o "$tmp_file"; then
if ! curl -fsSL "${CURL_HEADERS[@]}" -o "$_ARCUP_TMP_FILE" "$ARCUP_BIN_URL"; then
error "Failed to download arcup update"
fi

local remote_version
remote_version=$(grep '^ARCUP_INSTALLER_VERSION=' "$tmp_file" | sed -E 's/ARCUP_INSTALLER_VERSION="(.+)"/\1/')
remote_version=$(grep '^ARCUP_INSTALLER_VERSION=' "$_ARCUP_TMP_FILE" | sed -E 's/ARCUP_INSTALLER_VERSION="(.+)"/\1/')

if [[ -z "$remote_version" ]]; then
error "Failed to determine remote version"
Expand All @@ -147,12 +162,10 @@ update_arcup() {
fi

info "Updating from $ARCUP_INSTALLER_VERSION to $remote_version..."
if cp "$tmp_file" "$ARCUP_BIN_PATH" 2>/dev/null; then
if cp "$_ARCUP_TMP_FILE" "$ARCUP_BIN_PATH" 2>/dev/null; then
chmod 755 "$ARCUP_BIN_PATH"
elif sudo cp "$tmp_file" "$ARCUP_BIN_PATH" 2>/dev/null; then
sudo chmod 755 "$ARCUP_BIN_PATH"
else
error "Failed to update arcup at $ARCUP_BIN_PATH. Try running with sudo."
error "Failed to update arcup at '$ARCUP_BIN_PATH' — ensure it is writable"
fi

echo ""
Expand Down Expand Up @@ -196,6 +209,10 @@ while [[ $# -gt 0 ]]; do
esac
done

if [[ -n "$VERSION" ]] && [[ ! "$VERSION" =~ ^v?[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$ ]]; then
error "Invalid version format: '$VERSION' (expected e.g. v1.2.3)"
fi

# Detect platform
detect_platform() {
local platform
Expand Down Expand Up @@ -272,8 +289,8 @@ get_latest_version() {

local api_url="https://api.github.com/repos/$REPO/releases/latest"
local response
if ! response=$(curl -fsSL "$api_url" 2>&1); then
error "Failed to fetch latest version from GitHub: $response"
if ! response=$(curl -fsSL "${CURL_HEADERS[@]}" "$api_url" 2>&1); then
error "Failed to fetch latest version from '$api_url': $response"
fi

local version
Expand Down Expand Up @@ -302,11 +319,9 @@ install_binary() {
mv -f "$dst" "$old" 2>/dev/null || true
if cp "$src" "$dst" 2>/dev/null; then
chmod 755 "$dst"
elif sudo cp "$src" "$dst" 2>/dev/null; then
sudo chmod 755 "$dst"
else
mv -f "$old" "$dst" 2>/dev/null || true
error "Failed to install $name to $BIN_DIR. Try running with sudo."
error "Failed to install $name to '$BIN_DIR' — ensure it is writable"
fi
rm -f "$old" 2>/dev/null || true

Expand Down Expand Up @@ -340,9 +355,6 @@ main() {

ARCHIVE_NAME="arc-node-${VERSION_TAG}-${TARGET}.tar.gz"

TMP_DIR=$(mktemp -d)
trap "rm -rf $TMP_DIR" EXIT

# Download archive
download_file "$VERSION_TAG" "$ARCHIVE_NAME" "$TMP_DIR"

Expand Down Expand Up @@ -390,6 +402,14 @@ main() {
fi
fi

# Validate archive contents before extracting (guard against path traversal)
while IFS= read -r entry; do
case "$entry" in
/* | .. | ../* | */../* | */.. )
error "Archive contains unsafe path: $entry" ;;
esac
done < <(tar -tzf "$ARCHIVE_PATH")

# Extract archive
info "Extracting archive..."
tar -xzf "$ARCHIVE_PATH" -C "$TMP_DIR"
Expand Down
134 changes: 36 additions & 98 deletions arcup/install
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,17 @@ ARC_DIR="${ARC_DIR:-$HOME/.arc}"
BIN_DIR="${ARC_BIN_DIR:-$ARC_DIR/bin}"
ENV_FILE="$ARC_DIR/env"
ARCUP_URL="https://raw.githubusercontent.com/circlefin/arc-node/main/arcup/arcup"
CURL_HEADERS=()
if [ "${CURL_HEADER:-}" ]; then
CURL_HEADERS=(-H "$CURL_HEADER")
fi

_INSTALL_TMP_FILE=""
_install_cleanup() { rm -f "$_INSTALL_TMP_FILE"; }
trap _install_cleanup EXIT

# Color output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
Expand All @@ -22,19 +31,19 @@ warn() {
echo -e "${YELLOW}warn${NC}: $1" >&2
}

# Install a file to BIN_DIR, using sudo if necessary
error() {
echo -e "${RED}error${NC}: $1" >&2
exit 1
}

install_bin() {
local src="$1"
local dst="$2"

if cp "$src" "$dst" 2>/dev/null; then
chmod +x "$dst"
elif sudo cp "$src" "$dst" 2>/dev/null; then
sudo chmod +x "$dst"
else
echo "error: failed to install to $dst"
echo " try running with sudo"
exit 1
error "failed to install to '$dst' — ensure it is writable"
fi
}

Expand All @@ -47,22 +56,19 @@ main() {
mkdir -p "$BIN_DIR"

# Download arcup script to a temp file
local tmp_file
tmp_file="$(mktemp 2>/dev/null || mktemp -t arcup)"
trap "rm -f '$tmp_file'" EXIT
_INSTALL_TMP_FILE="$(mktemp 2>/dev/null || mktemp -t arcup)"

info "Downloading arcup script..."
if command -v curl >/dev/null 2>&1; then
curl -#fL "$ARCUP_URL" -o "$tmp_file"
elif command -v wget >/dev/null 2>&1; then
wget --show-progress -q -O "$tmp_file" "$ARCUP_URL"
else
echo "error: neither curl nor wget found"
exit 1
if ! command -v curl >/dev/null 2>&1; then
error "curl not found. Please install curl."
fi

if ! curl -#fL "${CURL_HEADERS[@]}" -o "$_INSTALL_TMP_FILE" "$ARCUP_URL" ; then
error "failed to download arcup from '$ARCUP_URL'"
fi

# Install arcup to BIN_DIR
install_bin "$tmp_file" "$BIN_DIR/arcup"
install_bin "$_INSTALL_TMP_FILE" "$BIN_DIR/arcup"
info "Arcup installed to $BIN_DIR/arcup"

# Create env file that can be sourced to set PATH (POSIX shells)
Expand All @@ -80,9 +86,6 @@ ENVEOF
# Add BIN_DIR to PATH for current session
export PATH="$BIN_DIR:$PATH"

# Configure shell profiles
configure_shell

# Run arcup to install arc-node binaries
info "Running arcup to install arc-node binaries..."
echo ""
Expand All @@ -92,88 +95,23 @@ ENVEOF
echo ""
local user_shell
user_shell="$(basename "$SHELL")"
info "Arc binaries are in your PATH for this session."
info "To make that permanent, add to your shell config file:"
echo ""
if [[ "$user_shell" == "fish" ]]; then
info "To get started, either restart your shell or run:"
echo ""
echo " source $ENV_FILE.fish"
cat << EOF
# ~/.config/fish/conf.d/arc.fish
test -f "$ENV_FILE.fish" && source "$ENV_FILE.fish"
EOF
else
info "To get started, either restart your shell or run:"
echo ""
echo " source $ENV_FILE"
cat << EOF
# ~/.zshenv or ~/.bashrc
[ -f "$ENV_FILE" ] && . "$ENV_FILE"
EOF
fi
echo ""
}

# Add sourcing of env file to shell config files
configure_shell() {
local source_line=". \"$ENV_FILE\""

local shell_configs=()

# Detect POSIX shell configs to modify
if [[ -n "${ZDOTDIR:-}" ]]; then
shell_configs+=("$ZDOTDIR/.zshenv")
fi

if [[ -f "$HOME/.zshenv" ]] || [[ "$(basename "$SHELL")" == "zsh" ]]; then
shell_configs+=("$HOME/.zshenv")
fi

if [[ -f "$HOME/.bashrc" ]] || [[ "$(basename "$SHELL")" == "bash" ]]; then
shell_configs+=("$HOME/.bashrc")
fi

if [[ -f "$HOME/.bash_profile" ]]; then
shell_configs+=("$HOME/.bash_profile")
fi

if [[ -f "$HOME/.profile" ]]; then
shell_configs+=("$HOME/.profile")
fi

# Deduplicate (bash 3 compatible)
local unique_configs=()
local seen=""
for cfg in "${shell_configs[@]}"; do
case "$seen" in
*"|$cfg|"*) ;;
*)
seen="$seen|$cfg|"
unique_configs+=("$cfg")
;;
esac
done

local modified=0

# Configure POSIX shells
for cfg in "${unique_configs[@]}"; do
if [[ -f "$cfg" ]] && grep -qF "$ENV_FILE" "$cfg" 2>/dev/null; then
continue
fi

echo >> "$cfg"
echo "# Added by arcup installer" >> "$cfg"
echo "$source_line" >> "$cfg"
info "Added arc to PATH in $cfg"
modified=1
done

# Configure fish shell
local fish_config="${XDG_CONFIG_HOME:-$HOME/.config}/fish/conf.d/arc.fish"
if [[ -d "$(dirname "$fish_config")" ]] || [[ "$(basename "$SHELL")" == "fish" ]]; then
if [[ ! -f "$fish_config" ]] || ! grep -qF "$ENV_FILE.fish" "$fish_config" 2>/dev/null; then
mkdir -p "$(dirname "$fish_config")"
echo "# Added by arcup installer" > "$fish_config"
echo "source $ENV_FILE.fish" >> "$fish_config"
info "Added arc to PATH in $fish_config"
modified=1
fi
fi

if [[ $modified -eq 0 ]]; then
info "Arc is already in your shell config"
fi
info "Then restart your shell or source the config file directly."
echo ""
}

main
Loading