Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
11 changes: 11 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,16 @@ jobs:
- name: Build TypeScript
run: npm run build

- name: Create esbuild bundle
run: |
npm install esbuild

Copilot AI Apr 1, 2026

Copy link

Choose a reason for hiding this comment

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

This step runs npm install esbuild even though npm ci already installed devDependencies (including esbuild from package.json). This adds extra time and can introduce version drift from the lockfile. Prefer removing the install and just running the build script (e.g., npm run build:bundle or node scripts/build-bundle.mjs).

Suggested change
npm install esbuild

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in d1d4c65. Removed the redundant npm install esbuild since it's already a devDependency installed by npm ci.

node scripts/build-bundle.mjs
echo "=== Bundle size ==="
ls -lh release/awf-bundle.js
echo "=== Bundle smoke test ==="
node release/awf-bundle.js --version
node release/awf-bundle.js --help | head -5

Copilot AI Apr 1, 2026

Copy link

Choose a reason for hiding this comment

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

Piping --help output into head -5 can intermittently fail the step due to EPIPE (the consumer exits early while Node is still writing). To keep the smoke test reliable, redirect help output to a file (or /dev/null) and then head the file, or otherwise avoid truncating via a pipe that closes early.

Suggested change
node release/awf-bundle.js --help | head -5
node release/awf-bundle.js --help > awf-help.txt
head -5 awf-help.txt

Copilot uses AI. Check for mistakes.

- name: Install pkg for binary creation
run: npm install -g pkg

Expand Down Expand Up @@ -550,6 +560,7 @@ jobs:
release/awf-linux-arm64
release/awf-darwin-x64
release/awf-darwin-arm64
release/awf-bundle.js
release/awf.tgz
release/checksums.txt
env:
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,6 @@ _codeql_detected_source_root

# Design docs (working drafts, not checked in)
design-docs/

# Release build artifacts
release/
112 changes: 81 additions & 31 deletions install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ REPO="github/gh-aw-firewall"
BINARY_NAME="" # Set dynamically by check_platform
INSTALL_DIR="/usr/local/bin"
INSTALL_NAME="awf"
USE_BUNDLE=false # Set by check_node

# Colors for output
RED='\033[0;31m'
Expand Down Expand Up @@ -142,6 +143,26 @@ check_platform() {
info "Detected platform: $os $arch (binary: $BINARY_NAME)"
}

# Check for Node.js >= 20 to decide between bundle and pkg binary
check_node() {
if [ "${AWF_FORCE_BINARY:-}" = "1" ]; then
info "AWF_FORCE_BINARY=1 set, using standalone binary"
USE_BUNDLE=false
return
fi
if command -v node &> /dev/null; then
NODE_VERSION=$(node -v | sed 's/^v//')
NODE_MAJOR=$(echo "$NODE_VERSION" | cut -d. -f1)
if [ "$NODE_MAJOR" -ge 20 ]; then
info "Node.js v${NODE_VERSION} detected (>= 20), using lightweight bundle"
USE_BUNDLE=true
return
fi
warn "Node.js v${NODE_VERSION} detected but < 20, using standalone binary"
fi

Copilot AI Apr 1, 2026

Copy link

Choose a reason for hiding this comment

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

check_node treats any Node.js 20.x as eligible for the bundle, but package.json declares engines.node >=20.12.0. This can select the bundle on Node 20.0–20.11 where runtime behavior may be unsupported. Consider parsing the full semver (major/minor/patch) and requiring >=20.12.0 to match the engine constraint (or update the stated requirement if >=20.0.0 is truly sufficient).

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in d1d4c65. The version check now requires >=20.12.0 (matching engines.node in package.json) by parsing both major and minor version components.

USE_BUNDLE=false
}

# Validate version format (should be like v1.0.0, v1.2.3, etc.)
validate_version() {
local version="$1"
Expand Down Expand Up @@ -263,54 +284,83 @@ main() {
check_sudo
check_requirements
check_platform

check_node

# Get version (from argument, env var, or fetch latest)
set_version "$1"

# 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 executable (ELF on Linux, Mach-O on macOS)
local file_type
file_type=$(file "$TEMP_DIR/$BINARY_NAME")
if echo "$file_type" | grep -q "ELF.*executable"; then
info "Valid Linux ELF executable"
elif echo "$file_type" | grep -q "Mach-O 64-bit"; then
info "Valid macOS Mach-O executable"

if [ "$USE_BUNDLE" = true ]; then
# Lightweight bundle path — requires Node.js >= 20
ASSET_NAME="awf-bundle.js"
ASSET_URL="${BASE_URL}/${ASSET_NAME}"

download_file "$ASSET_URL" "$TEMP_DIR/$ASSET_NAME"
download_file "$CHECKSUMS_URL" "$TEMP_DIR/checksums.txt"

# Verify checksum (reuse BINARY_NAME for the checksum lookup)
BINARY_NAME="$ASSET_NAME"
verify_checksum "$TEMP_DIR/$ASSET_NAME" "$TEMP_DIR/checksums.txt"

# Validate the file starts with the expected shebang
if head -c 20 "$TEMP_DIR/$ASSET_NAME" | grep -q '#!/usr/bin/env node'; then
info "Valid Node.js bundle"
else
error "Downloaded file does not appear to be a valid Node.js bundle"
exit 1
fi

# Make executable and install
chmod +x "$TEMP_DIR/$ASSET_NAME"
info "Installing bundle to $INSTALL_DIR/$INSTALL_NAME..."
mv "$TEMP_DIR/$ASSET_NAME" "$INSTALL_DIR/$INSTALL_NAME"
else
error "Downloaded file is not a valid executable: $file_type"
exit 1
# Standalone pkg binary path
BINARY_URL="${BASE_URL}/${BINARY_NAME}"

# 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 executable (ELF on Linux, Mach-O on macOS)
local file_type
file_type=$(file "$TEMP_DIR/$BINARY_NAME")
if echo "$file_type" | grep -q "ELF.*executable"; then
info "Valid Linux ELF executable"
elif echo "$file_type" | grep -q "Mach-O 64-bit"; then
info "Valid macOS Mach-O executable"
else
error "Downloaded file is not a valid executable: $file_type"
exit 1
fi

# Install binary
info "Installing to $INSTALL_DIR/$INSTALL_NAME..."
mv "$TEMP_DIR/$BINARY_NAME" "$INSTALL_DIR/$INSTALL_NAME"
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! ✓"
Expand Down
Loading
Loading