php-devops/scripts/install-deps.sh
Snider b1aada9b0e docs: add project scope to gh auth setup
- Add read:project,project scopes to gh auth in install scripts
- Update troubleshooting docs for missing scopes
- Enable GitHub Projects access for workspace management

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 19:57:30 +00:00

322 lines
9.2 KiB
Bash
Executable file

#!/usr/bin/env bash
set -e
# Install system dependencies for Host UK development
# Supports: macOS (brew), Linux (apt/dnf), Windows (choco via WSL)
#
# SECURITY NOTES:
# - External install scripts (Homebrew, NodeSource) are downloaded over HTTPS
# - Go binary is verified via SHA256 checksum
# - Composer installer is verified via SHA256 checksum
# - Consider auditing external scripts before running in sensitive environments
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
# Pinned versions and checksums for security
GO_VERSION="1.22.0"
GO_AMD64_SHA256="f6c8a87aa03b92c4b0bf3d558e28ea03006eb29db78917daec5cfb6ec1046265"
COMPOSER_EXPECTED_SIG="dac665fdc30fdd8ec78b38b9800061b4150413ff2e3b6f88543c636f7cd84f6db9189d43a81e5503cda447da73c7e5b6"
info() { echo -e "${GREEN}[INFO]${NC} $1"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
error() { echo -e "${RED}[ERROR]${NC} $1"; exit 1; }
# Compute SHA256 hash (cross-platform)
compute_sha256() {
local file=$1
if command -v sha256sum &> /dev/null; then
sha256sum "$file" | cut -d' ' -f1
elif command -v shasum &> /dev/null; then
shasum -a 256 "$file" | cut -d' ' -f1
else
error "No SHA256 tool available (need sha256sum or shasum)"
fi
}
# Verify SHA256 hash of downloaded file
verify_hash() {
local file=$1
local expected_hash=$2
local actual_hash
actual_hash=$(compute_sha256 "$file")
if [[ "${actual_hash,,}" != "${expected_hash,,}" ]]; then
rm -f "$file"
error "Hash verification failed! Expected: $expected_hash, Got: $actual_hash"
fi
info "Hash verification passed"
}
# Detect OS
detect_os() {
case "$(uname -s)" in
Darwin*) echo "macos" ;;
Linux*) echo "linux" ;;
MINGW*|MSYS*|CYGWIN*) echo "windows" ;;
*) echo "unknown" ;;
esac
}
# Check if command exists
has() {
command -v "$1" &> /dev/null
}
# Install Homebrew (macOS/Linux)
# NOTE: Homebrew's install script changes frequently, making checksum verification impractical.
# The script is fetched over HTTPS from GitHub. For high-security environments,
# consider auditing the script manually before running.
install_brew() {
if has brew; then
info "Homebrew already installed"
return
fi
info "Installing Homebrew..."
warn "This downloads and executes a script from GitHub. Review at: https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh"
# Download to temp file first (allows manual inspection if needed)
local temp_script
temp_script=$(mktemp "${TMPDIR:-/tmp}/brew-install.XXXXXXXXXX.sh")
curl -fsSL -o "$temp_script" https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh || {
rm -f "$temp_script"
error "Failed to download Homebrew installer"
}
/bin/bash "$temp_script" || {
rm -f "$temp_script"
error "Homebrew installation failed"
}
rm -f "$temp_script"
# Add to PATH for this session
if [[ -f /opt/homebrew/bin/brew ]]; then
eval "$(/opt/homebrew/bin/brew shellenv)"
elif [[ -f /home/linuxbrew/.linuxbrew/bin/brew ]]; then
eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
fi
}
# Install packages via brew
brew_install() {
local pkg=$1
if has "$pkg"; then
info "$pkg already installed"
else
info "Installing $pkg..."
brew install "$pkg"
fi
}
# Install packages via apt
apt_install() {
local pkg=$1
if has "$pkg"; then
info "$pkg already installed"
else
info "Installing $pkg..."
sudo apt-get update -qq
sudo apt-get install -y "$pkg"
fi
}
# macOS setup
setup_macos() {
info "Setting up macOS environment..."
install_brew
brew_install git
brew_install gh
brew_install go
brew_install php
brew_install composer
brew_install node
brew_install pnpm
# Optional
if ! has docker; then
warn "Docker not installed. Install Docker Desktop manually if needed."
fi
}
# Linux setup
setup_linux() {
info "Setting up Linux environment..."
# Detect package manager
if has apt-get; then
setup_linux_apt
elif has dnf; then
setup_linux_dnf
elif has brew; then
setup_linux_brew
else
warn "Unknown package manager. Installing Homebrew..."
install_brew
setup_linux_brew
fi
}
setup_linux_apt() {
apt_install git
apt_install gh || warn "GitHub CLI may need manual install: https://cli.github.com"
# Go
if ! has go; then
info "Installing Go..."
sudo apt-get install -y golang-go || {
# Fallback to manual install for newer version with integrity verification
local go_tarball="go${GO_VERSION}.linux-amd64.tar.gz"
local go_url="https://go.dev/dl/${go_tarball}"
local temp_file
temp_file=$(mktemp "${TMPDIR:-/tmp}/go.XXXXXXXXXX.tar.gz")
info "Downloading Go $GO_VERSION..."
curl -fsSL -o "$temp_file" "$go_url" || {
rm -f "$temp_file"
error "Failed to download Go"
}
info "Verifying Go download integrity..."
verify_hash "$temp_file" "$GO_AMD64_SHA256"
sudo rm -rf /usr/local/go
sudo tar -C /usr/local -xzf "$temp_file"
rm -f "$temp_file"
export PATH=$PATH:/usr/local/go/bin
}
fi
# PHP
apt_install php
# Composer (with installer signature verification)
if ! has composer; then
info "Installing Composer..."
local temp_dir
temp_dir=$(mktemp -d "${TMPDIR:-/tmp}/composer.XXXXXXXXXX")
chmod 700 "$temp_dir"
# Download installer
curl -fsSL -o "$temp_dir/composer-setup.php" https://getcomposer.org/installer
# Verify installer signature (SHA384)
local actual_sig
actual_sig=$(php -r "echo hash_file('sha384', '$temp_dir/composer-setup.php');")
if [[ "$actual_sig" != "$COMPOSER_EXPECTED_SIG" ]]; then
rm -rf "$temp_dir"
error "Composer installer signature verification failed!"
fi
info "Composer installer signature verified"
# Run installer
php "$temp_dir/composer-setup.php" --install-dir="$temp_dir"
sudo mv "$temp_dir/composer.phar" /usr/local/bin/composer
rm -rf "$temp_dir"
fi
# Node (via NodeSource)
# NOTE: NodeSource setup script changes frequently, making checksum verification impractical.
# For high-security environments, consider using nvm or building from source.
if ! has node; then
info "Installing Node.js..."
warn "This downloads and executes a script from NodeSource. Review at: https://deb.nodesource.com/setup_20.x"
local temp_script
temp_script=$(mktemp "${TMPDIR:-/tmp}/nodesource-setup.XXXXXXXXXX.sh")
curl -fsSL -o "$temp_script" https://deb.nodesource.com/setup_20.x || {
rm -f "$temp_script"
error "Failed to download NodeSource setup script"
}
sudo -E bash "$temp_script" || {
rm -f "$temp_script"
error "NodeSource setup failed"
}
rm -f "$temp_script"
sudo apt-get install -y nodejs
fi
# pnpm
if ! has pnpm; then
info "Installing pnpm..."
npm install -g pnpm
fi
}
setup_linux_dnf() {
sudo dnf install -y git gh golang php composer nodejs
npm install -g pnpm
}
setup_linux_brew() {
install_brew
brew_install git
brew_install gh
brew_install go
brew_install php
brew_install composer
brew_install node
brew_install pnpm
}
# Windows setup (via chocolatey in PowerShell or WSL)
setup_windows() {
warn "Windows detected. Please run scripts/install-deps.ps1 in PowerShell"
warn "Or use WSL with: wsl ./scripts/install-deps.sh"
exit 1
}
# Main
main() {
local os=$(detect_os)
info "Detected OS: $os"
case "$os" in
macos) setup_macos ;;
linux) setup_linux ;;
windows) setup_windows ;;
*) error "Unsupported OS: $os" ;;
esac
info "Dependencies installed!"
echo ""
# Configure GitHub CLI if not already authenticated
if has gh; then
if ! gh auth status &>/dev/null; then
info "Configuring GitHub CLI..."
echo "You'll need to authenticate with GitHub."
echo "When prompted, select HTTPS and add the 'workflow' scope."
echo ""
gh auth login -h github.com -p https -s workflow,repo,read:org,read:project,project
else
# Check if required scopes are present
local auth_status=$(gh auth status 2>&1)
local missing_scopes=""
if ! echo "$auth_status" | grep -q workflow; then
missing_scopes="workflow"
fi
if ! echo "$auth_status" | grep -q "read:project"; then
missing_scopes="$missing_scopes read:project project"
fi
if [[ -n "$missing_scopes" ]]; then
warn "GitHub CLI missing scopes:$missing_scopes"
echo "Run: gh auth refresh -h github.com -s workflow,read:project,project"
fi
fi
fi
echo ""
echo "Next: Run './scripts/install-core.sh' to install the core CLI"
}
main "$@"