Skip to content

Conversation

@jeanlaurent
Copy link
Member

Adds a one-line installer for Linux users similar to Homebrew and Claude Code's installation experience.

Before: Linux users had to manually download binaries, chmod, rename, and configure PATH.

After: Single command installation with automatic setup and verification.

@jeanlaurent jeanlaurent requested a review from a team as a code owner January 31, 2026 09:08
Signed-off-by: Jean-Laurent de Morlhon <jeanlaurent@morlhon.net>
Comment on lines +118 to +120
# Make executable
chmod +x "$tmp_file"

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can do this with install later.

Suggested change
# Make executable
chmod +x "$tmp_file"

Comment on lines +143 to +144
sudo mv "$tmp_file" "$target_path"
sudo chmod +x "$target_path"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
sudo mv "$tmp_file" "$target_path"
sudo chmod +x "$target_path"
sudo install -m 755 "$tmp_file" "$target_path"

sudo mv "$tmp_file" "$target_path"
sudo chmod +x "$target_path"
else
mv "$tmp_file" "$target_path"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
mv "$tmp_file" "$target_path"
install -m 755 "$tmp_file" "$target_path"

Copy link
Contributor

@krissetto krissetto left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should probably check for the existence of curl as well, as folks end ip using convenience scripts like this in ci like environments where curl presence is not always a given


# Try using gh CLI first if available
if command -v gh &> /dev/null; then
gh release list --repo "$REPO" --limit 1 --json tagName --jq '.[0].tagName' 2>/dev/null
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i don't think we need both options here, i'd just go straight to the rest api unless there are other reasons for using gh

print_msg "$YELLOW" " 2. Use Homebrew: brew install cagent"
exit 1
;;
MINGW*|MSYS*|CYGWIN*)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: harmless, i don't think many windows users will try to run a bash script called install-linux

@krissetto
Copy link
Contributor

/review

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security Review

⚠️ Found several security issues in the new installation script that should be addressed before merging.

Critical Issues

  1. Missing checksum verification (HIGH) - The script downloads and executes binaries without cryptographic verification
  2. Predictable temporary file (MEDIUM) - Using PID-based temp files creates a security vulnerability
  3. Executing unverified binary (MEDIUM) - The verification step runs the binary before integrity checks

Additional Issues

  1. Fragile JSON parsing (MEDIUM) - grep/sed parsing could break or behave unexpectedly
  2. Unquoted variable expansion (LOW) - Could cause issues with special characters

These are all in the newly added code. Please see inline comments for details and recommended fixes.

local tmp_file="/tmp/$BINARY_NAME-$$"

# Download binary
print_msg "$BLUE" "Downloading from $download_url..."
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CRITICAL: No checksum or signature verification of downloaded binary

The script downloads a binary from GitHub and immediately makes it executable without any cryptographic verification. Since this installation script is designed to be piped to bash (curl | bash), a compromised download or MITM attack could lead to arbitrary code execution.

Recommendation: Verify the downloaded binary's checksum or GPG signature before executing it. Many projects publish SHA256 checksums alongside releases. Example:

# Download checksum file
curl -fsSL "${download_url}.sha256" -o "${tmp_file}.sha256"

# Verify checksum
expected_sha=$(cat "${tmp_file}.sha256" | awk '{print $1}')
actual_sha=$(sha256sum "$tmp_file" | awk '{print $1}')
if [ "$expected_sha" != "$actual_sha" ]; then
    print_msg "$RED" "Error: Checksum verification failed"
    exit 1
fi

This is especially critical for security-sensitive installation scripts.

print_msg "$GREEN" "Installing cagent $version for $os/$arch..."

local binary_name="${BINARY_NAME}-${os}-${arch}"
local download_url="https://github.com/$REPO/releases/download/$version/$binary_name"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Predictable temporary file name creates security vulnerability

The script uses /tmp/$BINARY_NAME-$$ where $$ is the process ID. Process IDs are predictable and sequential, allowing an attacker to:

  1. Pre-create the file with malicious content
  2. Create a symlink to redirect the download and overwrite sensitive files
  3. Exploit TOCTOU race conditions

Recommendation: Use mktemp for secure temporary file creation:

local tmp_file=$(mktemp)

mktemp creates files with unpredictable random names and secure permissions (0600), preventing these attacks.

# Verify installation
print_msg "$BLUE" "Verifying installation..."
if command -v "$BINARY_NAME" &> /dev/null; then
local installed_version
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Executes downloaded binary without prior checksum verification

The script runs "$BINARY_NAME" --version to verify installation, but executes the binary that was downloaded without any checksum verification (related to issue at line 112). If the download was compromised, this verification step itself executes malicious code.

Recommendation: Only execute the binary after cryptographic verification of its integrity. Move this verification step to occur after checksum validation is added.

gh release list --repo "$REPO" --limit 1 --json tagName --jq '.[0].tagName' 2>/dev/null
else
# Fall back to curl and parse JSON
curl -sSfL "https://api.github.com/repos/$REPO/releases/latest" |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fragile JSON parsing could break or behave unexpectedly

The fallback version detection uses grep '"tag_name"' | sed -E 's/.*"tag_name": *"([^"]+)".*/\1/' which is brittle and could break if:

  • GitHub changes JSON formatting/whitespace
  • Special characters appear in tag names
  • Response contains multiple tag_name fields
  • JSON is minified differently

Recommendation: Since the primary path already uses jq (via gh), consider checking for jq availability in the fallback:

if command -v gh &> /dev/null; then
    gh release list --repo "$REPO" --limit 1 --json tagName --jq '.[0].tagName' 2>/dev/null
elif command -v jq &> /dev/null; then
    curl -sSfL "https://api.github.com/repos/$REPO/releases/latest" | jq -r '.tag_name'
else
    # grep/sed fallback
    curl -sSfL "https://api.github.com/repos/$REPO/releases/latest" |
        grep '"tag_name"' |
        sed -E 's/.*"tag_name": *"([^"]+)".*/\1/'
fi

Or use Python/Node which are commonly available on Linux systems for more robust JSON parsing.

print_msg() {
local color=$1
shift
echo -e "${color}$@${NC}" >&2
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unquoted $@ could cause pathname expansion and word splitting

The line echo -e "${color}$@${NC}" has unquoted $@ which will cause:

  • Pathname expansion if messages contain glob characters (*, ?, [])
  • Multiple spaces collapsed to single spaces

For example: print_msg "$RED" "Error: File *.txt not found" could expand *.txt to actual filenames.

Recommendation: Use "$*" instead to properly join all arguments:

echo -e "${color}$*${NC}" >&2

This preserves the intended message without pathname expansion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants