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
27 changes: 24 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,39 @@ A network firewall for agentic workflows with domain whitelisting. This tool pro

### Installation

**Recommended: One-line installer with SHA verification**

```bash
curl -sSL https://raw.githubusercontent.com/githubnext/gh-aw-firewall/main/install.sh | sudo bash
```

This installer automatically:
- Downloads the latest release binary
- Verifies SHA256 checksum to detect corruption or tampering
- Validates the file is a valid Linux executable
- Protects against 404 error pages being saved as binaries
- Installs to `/usr/local/bin/awf`

**Alternative: Manual installation**

```bash
# Download the latest release binary
curl -L https://github.com/githubnext/gh-aw-firewall/releases/latest/download/awf-linux-x64 -o awf
curl -fL https://github.com/githubnext/gh-aw-firewall/releases/latest/download/awf-linux-x64 -o awf

# Download checksums for verification
curl -fL https://github.com/githubnext/gh-aw-firewall/releases/latest/download/checksums.txt -o checksums.txt

# Verify SHA256 checksum
sha256sum -c checksums.txt --ignore-missing

# Install
chmod +x awf
sudo mv awf /usr/local/bin/

# Verify installation
sudo awf --help
```

**Note:** Verify checksums after download by downloading `checksums.txt` from the release page.

**Docker Image Verification:** All published container images are cryptographically signed with cosign. See [docs/image-verification.md](docs/image-verification.md) for verification instructions.

### Basic Usage
Expand Down
13 changes: 9 additions & 4 deletions docs-site/src/content/docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,22 @@ When AI agents like GitHub Copilot CLI run with access to tools and MCP servers,
Download the latest release binary:

```bash
# Linux (x64)
curl -L https://github.com/githubnext/gh-aw-firewall/releases/latest/download/awf-linux-x64 -o awf
# One-line installer with SHA verification (recommended)
curl -sSL https://raw.githubusercontent.com/githubnext/gh-aw-firewall/main/install.sh | sudo bash

# Or manual installation
curl -fL https://github.com/githubnext/gh-aw-firewall/releases/latest/download/awf-linux-x64 -o awf
curl -fL https://github.com/githubnext/gh-aw-firewall/releases/latest/download/checksums.txt -o checksums.txt
sha256sum -c checksums.txt --ignore-missing
chmod +x awf
sudo mv awf /usr/local/bin/

# Verify installation
sudo awf --version
```

:::note
Verify checksums after download by checking `checksums.txt` from the release page.
:::tip[Automatic SHA Verification]
The one-line installer automatically verifies the SHA256 checksum to protect against corrupted or tampered downloads.
:::

### Your First Command
Expand Down
37 changes: 22 additions & 15 deletions docs/RELEASE_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,31 @@ Everything below the `---` separator becomes the release notes.

## Installation

### Binary Installation (Recommended)
### One-Line Installer (Recommended)

**Linux (x64) with automatic SHA verification:**
```bash
curl -sSL https://raw.githubusercontent.com/{{REPOSITORY}}/main/install.sh | sudo bash
```

This installer:
- Downloads the latest release binary
- Verifies SHA256 checksum against `checksums.txt`
- Validates the file is a valid ELF executable
- Installs to `/usr/local/bin/awf`

### Manual Binary Installation (Alternative)

**Linux (x64):**
```bash
curl -L https://github.com/{{REPOSITORY}}/releases/download/{{VERSION}}/awf-linux-x64 -o awf
# Download binary and checksums
curl -fL https://github.com/{{REPOSITORY}}/releases/download/{{VERSION}}/awf-linux-x64 -o awf
curl -fL https://github.com/{{REPOSITORY}}/releases/download/{{VERSION}}/checksums.txt -o checksums.txt

# Verify checksum
sha256sum -c checksums.txt --ignore-missing

# Install
chmod +x awf
sudo mv awf /usr/local/bin/
```
Expand All @@ -45,19 +65,6 @@ sudo mv awf /usr/local/bin/
npm install -g https://github.com/{{REPOSITORY}}/releases/download/{{VERSION}}/awf.tgz
```

### Requirements

- Docker and Docker Compose must be installed
- For iptables manipulation, run with sudo: `sudo awf ...`
- Container images will be pulled automatically from GHCR on first run

## Verification

Verify checksums after download:
```bash
sha256sum -c checksums.txt
```

## Quick Start

```bash
Expand Down
247 changes: 247 additions & 0 deletions install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
#!/bin/bash
set -e

# Install script for awf (Agentic Workflow Firewall)
#
# This script downloads, verifies, and installs the awf binary with SHA256 validation
# to protect against corrupted or tampered downloads.
#
# Usage:
# curl -sSL https://raw.githubusercontent.com/githubnext/gh-aw-firewall/main/install.sh | sudo bash
#
# Security features:
# - Uses curl -f to fail on HTTP errors (404, 403, etc.)
# - Verifies SHA256 checksum from official checksums.txt
# - Validates downloaded file is a valid ELF executable
# - Detects HTML error pages that may slip through
#
# Requirements:
# - curl
# - sha256sum
# - file
# - sudo/root access
#
# Repository: https://github.com/githubnext/gh-aw-firewall
# Issue #107: https://github.com/githubnext/gh-aw-firewall/issues/107

REPO="githubnext/gh-aw-firewall"
BINARY_NAME="awf-linux-x64"
INSTALL_DIR="/usr/local/bin"
INSTALL_NAME="awf"

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

# Helper functions
info() {
echo -e "${GREEN}[INFO]${NC} $1"
}

error() {
echo -e "${RED}[ERROR]${NC} $1" >&2
}

warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}

# Check if running as root
check_sudo() {
if [ "$EUID" -ne 0 ]; then
error "This script must be run with sudo or as root"
exit 1
fi
}

# Check required commands
check_requirements() {
local missing=()

for cmd in curl sha256sum file; do
if ! command -v "$cmd" &> /dev/null; then
missing+=("$cmd")
fi
done

if [ ${#missing[@]} -ne 0 ]; then
error "Missing required commands: ${missing[*]}"
error "Please install them and try again"
exit 1
fi
}

# Check OS and architecture
check_platform() {
local os arch
os=$(uname -s)
arch=$(uname -m)

if [ "$os" != "Linux" ]; then
error "Unsupported OS: $os (this installer supports Linux only)"
exit 1
fi

case "$arch" in
x86_64|amd64)
;;
*)
error "Unsupported architecture: $arch (supported: x86_64)"
exit 1
;;
esac
}

# Get latest release version
get_latest_version() {
info "Fetching latest release version..."

# Try GitHub API with -f to fail on HTTP errors
VERSION=$(curl -fsSL "https://api.github.com/repos/${REPO}/releases/latest" 2>/dev/null | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')

if [ -z "$VERSION" ]; then
error "Failed to fetch latest version from GitHub API"
error "Please check your internet connection and try again"
exit 1
fi

info "Latest version: $VERSION"
}

# Download file
download_file() {
local url="$1"
local output="$2"

info "Downloading from $url..."

# Use -f to fail on HTTP errors (like 404)
if ! curl -fsSL "$url" -o "$output"; then
error "Failed to download $url"
error "Please check if the release exists and try again"
exit 1
fi

# Check if file is not empty
if [ ! -s "$output" ]; then
error "Downloaded file is empty"
rm -f "$output"
exit 1
fi

# Check if file is HTML (common for 404 pages)
if file "$output" | grep -q "HTML"; then
error "Downloaded file appears to be an HTML page (possibly 404)"
error "Please check if the release exists: https://github.com/${REPO}/releases"
rm -f "$output"
exit 1
fi
}

# Verify checksum
verify_checksum() {
local file="$1"
local checksums_file="$2"

info "Verifying SHA256 checksum..."

# Extract the checksum for our binary from checksums.txt
# Format: "checksum filename" (two spaces) - use exact filename match at end of line
local expected_sum
expected_sum=$(awk -v fname="$BINARY_NAME" '$2 == fname {print $1; exit}' "$checksums_file")

if [ -z "$expected_sum" ]; then
error "Could not find checksum for $BINARY_NAME in checksums.txt"
exit 1
fi

# Validate checksum format (64 hex characters, case-insensitive)
if ! echo "$expected_sum" | grep -qE '^[a-fA-F0-9]{64}$'; then
error "Invalid checksum format: $expected_sum"
exit 1
fi

# Normalize checksum case
expected_sum=$(echo "$expected_sum" | tr 'A-F' 'a-f')

# Calculate actual checksum
local actual_sum
actual_sum=$(sha256sum "$file" | awk '{print $1}' | tr 'A-F' 'a-f')

if [ "$expected_sum" != "$actual_sum" ]; then
error "Checksum verification failed!"
error "Expected: $expected_sum"
error "Got: $actual_sum"
error "The downloaded file may be corrupted or tampered with"
exit 1
fi

info "Checksum verification passed ✓"
}

# Main installation function
main() {
info "Starting awf installation..."

# Check requirements
check_sudo
check_requirements
check_platform

# Get version
get_latest_version

# Create temp directory with prefix for identification
# mktemp creates secure temporary directories with proper permissions (0700)
TEMP_DIR=$(mktemp -d -t awf-install.XXXXXX)

# Validate temp directory was created
if [ -z "$TEMP_DIR" ] || [ ! -d "$TEMP_DIR" ]; then
error "Failed to create temporary directory"
exit 1
fi

# Set up cleanup trap (mktemp already ensures secure location)
trap 'rm -rf "$TEMP_DIR"' EXIT

# Download URLs
BASE_URL="https://github.com/${REPO}/releases/download/${VERSION}"
BINARY_URL="${BASE_URL}/${BINARY_NAME}"
CHECKSUMS_URL="${BASE_URL}/checksums.txt"

# Download binary and checksums
download_file "$BINARY_URL" "$TEMP_DIR/$BINARY_NAME"
download_file "$CHECKSUMS_URL" "$TEMP_DIR/checksums.txt"

# Verify checksum
verify_checksum "$TEMP_DIR/$BINARY_NAME" "$TEMP_DIR/checksums.txt"

# Make binary executable
chmod +x "$TEMP_DIR/$BINARY_NAME"

# Test if it's a valid ELF executable
if ! file "$TEMP_DIR/$BINARY_NAME" | grep -q "ELF.*executable"; then
error "Downloaded file is not a valid Linux executable"
exit 1
fi

# Install binary
info "Installing to $INSTALL_DIR/$INSTALL_NAME..."
mv "$TEMP_DIR/$BINARY_NAME" "$INSTALL_DIR/$INSTALL_NAME"

# Verify installation
if [ -x "$INSTALL_DIR/$INSTALL_NAME" ]; then
info "Installation successful! ✓"
info ""
info "Run 'awf --help' to get started"
info "Note: awf requires Docker to be installed and running"
else
error "Installation failed - binary not found at $INSTALL_DIR/$INSTALL_NAME"
exit 1
fi
}

# Run main function
main